diff --git a/.github/workflows/ci.generate.ts b/.github/workflows/ci.generate.ts index cbf3a92d3a..02fd070d49 100755 --- a/.github/workflows/ci.generate.ts +++ b/.github/workflows/ci.generate.ts @@ -5,7 +5,7 @@ import { stringify } from "jsr:@std/yaml@^0.221/stringify"; // Bump this number when you want to purge the cache. // Note: the tools/release/01_bump_crate_versions.ts script will update this version // automatically via regex, so ensure that this line maintains this format. -const cacheVersion = 14; +const cacheVersion = 15; const ubuntuX86Runner = "ubuntu-22.04"; const ubuntuX86XlRunner = "ubuntu-22.04-xl"; diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b4aa0abdd7..3e8c6248b6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -367,8 +367,8 @@ jobs: path: |- ~/.cargo/registry/index ~/.cargo/registry/cache - key: '14-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}' - restore-keys: '14-cargo-home-${{ matrix.os }}-${{ matrix.arch }}' + key: '15-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}' + restore-keys: '15-cargo-home-${{ matrix.os }}-${{ matrix.arch }}' if: '!(matrix.skip)' - name: Restore cache build output (PR) uses: actions/cache/restore@v4 @@ -381,7 +381,7 @@ jobs: !./target/*/*.zip !./target/*/*.tar.gz key: never_saved - restore-keys: '14-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-' + restore-keys: '15-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-' - name: Apply and update mtime cache if: '!(matrix.skip) && (!startsWith(github.ref, ''refs/tags/''))' uses: ./.github/mtime_cache @@ -670,7 +670,7 @@ jobs: !./target/*/gn_out !./target/*/*.zip !./target/*/*.tar.gz - key: '14-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}' + key: '15-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}' publish-canary: name: publish canary runs-on: ubuntu-22.04 diff --git a/Cargo.lock b/Cargo.lock index ea3ea416b6..e45a739807 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -167,9 +167,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" @@ -465,7 +465,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash", + "rustc-hash 1.1.0", "shlex", "syn 2.0.72", "which 4.4.2", @@ -693,18 +693,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.13" +version = "4.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc" +checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.13" +version = "4.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99" +checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" dependencies = [ "anstream", "anstyle", @@ -715,9 +715,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.12" +version = "4.5.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8670053e87c316345e384ca1f3eba3006fc6355ed8b8a1140d104e109e3df34" +checksum = "6d7db6eca8c205649e8d3ccd05aa5042b1800a784e56bc7c43524fde8abbfa9b" dependencies = [ "clap", ] @@ -1113,7 +1113,7 @@ dependencies = [ "hashbrown", "lock_api", "once_cell", - "parking_lot_core 0.9.9", + "parking_lot_core", ] [[package]] @@ -1169,7 +1169,6 @@ dependencies = [ "deno_config", "deno_core", "deno_doc", - "deno_emit", "deno_graph", "deno_lint", "deno_lockfile", @@ -1316,7 +1315,7 @@ dependencies = [ [[package]] name = "deno_bench_util" -version = "0.161.0" +version = "0.162.0" dependencies = [ "bencher", "deno_core", @@ -1325,7 +1324,7 @@ dependencies = [ [[package]] name = "deno_broadcast_channel" -version = "0.161.0" +version = "0.162.0" dependencies = [ "async-trait", "deno_core", @@ -1335,7 +1334,7 @@ dependencies = [ [[package]] name = "deno_cache" -version = "0.99.0" +version = "0.100.0" dependencies = [ "async-trait", "deno_core", @@ -1355,7 +1354,7 @@ dependencies = [ "indexmap", "log", "once_cell", - "parking_lot 0.12.3", + "parking_lot", "serde", "serde_json", "sha2", @@ -1365,7 +1364,7 @@ dependencies = [ [[package]] name = "deno_canvas" -version = "0.36.0" +version = "0.37.0" dependencies = [ "deno_core", "deno_webgpu", @@ -1375,9 +1374,9 @@ dependencies = [ [[package]] name = "deno_config" -version = "0.32.0" +version = "0.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c774f2e49b4ca47f1fe5c39e1775d1434280a4f168252fed8f4a3f2230868448" +checksum = "495df7ebed4feee5c0eb7631b0b86432bb6370638cf81d5eeb5769aab55fb2de" dependencies = [ "anyhow", "deno_package_json", @@ -1389,6 +1388,7 @@ dependencies = [ "jsonc-parser", "log", "percent-encoding", + "phf 0.11.2", "serde", "serde_json", "thiserror", @@ -1397,7 +1397,7 @@ dependencies = [ [[package]] name = "deno_console" -version = "0.167.0" +version = "0.168.0" dependencies = [ "deno_core", ] @@ -1420,7 +1420,7 @@ dependencies = [ "futures", "libc", "memoffset 0.9.1", - "parking_lot 0.12.3", + "parking_lot", "percent-encoding", "pin-project", "serde", @@ -1442,7 +1442,7 @@ checksum = "a13951ea98c0a4c372f162d669193b4c9d991512de9f2381dd161027f34b26b1" [[package]] name = "deno_cron" -version = "0.47.0" +version = "0.48.0" dependencies = [ "anyhow", "async-trait", @@ -1454,7 +1454,7 @@ dependencies = [ [[package]] name = "deno_crypto" -version = "0.181.0" +version = "0.182.0" dependencies = [ "aes", "aes-gcm", @@ -1511,26 +1511,9 @@ dependencies = [ "termcolor", ] -[[package]] -name = "deno_emit" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33aca9546e36a1b85efb630add94a4c2ac13c2333bb48df4439002c002f4c5b2" -dependencies = [ - "anyhow", - "base64 0.21.7", - "deno_ast", - "deno_graph", - "escape8259", - "futures", - "import_map", - "parking_lot 0.11.2", - "url", -] - [[package]] name = "deno_fetch" -version = "0.191.0" +version = "0.192.0" dependencies = [ "base64 0.21.7", "bytes", @@ -1562,7 +1545,7 @@ dependencies = [ [[package]] name = "deno_ffi" -version = "0.154.0" +version = "0.155.0" dependencies = [ "deno_core", "deno_permissions", @@ -1579,7 +1562,7 @@ dependencies = [ [[package]] name = "deno_fs" -version = "0.77.0" +version = "0.78.0" dependencies = [ "async-trait", "base32", @@ -1616,7 +1599,7 @@ dependencies = [ "log", "monch", "once_cell", - "parking_lot 0.12.3", + "parking_lot", "regex", "serde", "serde_json", @@ -1628,7 +1611,7 @@ dependencies = [ [[package]] name = "deno_http" -version = "0.165.0" +version = "0.166.0" dependencies = [ "async-compression", "async-trait", @@ -1667,7 +1650,7 @@ dependencies = [ [[package]] name = "deno_io" -version = "0.77.0" +version = "0.78.0" dependencies = [ "async-trait", "deno_core", @@ -1677,7 +1660,7 @@ dependencies = [ "log", "once_cell", "os_pipe", - "parking_lot 0.12.3", + "parking_lot", "pin-project", "rand", "tokio", @@ -1688,7 +1671,7 @@ dependencies = [ [[package]] name = "deno_kv" -version = "0.75.0" +version = "0.76.0" dependencies = [ "anyhow", "async-trait", @@ -1758,7 +1741,7 @@ dependencies = [ [[package]] name = "deno_napi" -version = "0.98.0" +version = "0.99.0" dependencies = [ "deno_core", "deno_permissions", @@ -1780,7 +1763,7 @@ dependencies = [ [[package]] name = "deno_net" -version = "0.159.0" +version = "0.160.0" dependencies = [ "deno_core", "deno_permissions", @@ -1796,7 +1779,7 @@ dependencies = [ [[package]] name = "deno_node" -version = "0.104.0" +version = "0.105.0" dependencies = [ "aead-gcm-stream", "aes", @@ -1932,7 +1915,7 @@ dependencies = [ [[package]] name = "deno_permissions" -version = "0.27.0" +version = "0.28.0" dependencies = [ "deno_core", "deno_terminal 0.2.0", @@ -1947,7 +1930,7 @@ dependencies = [ [[package]] name = "deno_runtime" -version = "0.176.0" +version = "0.177.0" dependencies = [ "deno_ast", "deno_broadcast_channel", @@ -2060,7 +2043,7 @@ dependencies = [ [[package]] name = "deno_tls" -version = "0.154.0" +version = "0.155.0" dependencies = [ "deno_core", "deno_native_certs", @@ -2102,13 +2085,13 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f36b4ef61a04ce201b925a5dffa90f88437d37fee4836c758470dd15ba7f05e" dependencies = [ - "parking_lot 0.12.3", + "parking_lot", "tokio", ] [[package]] name = "deno_url" -version = "0.167.0" +version = "0.168.0" dependencies = [ "deno_bench_util", "deno_console", @@ -2119,7 +2102,7 @@ dependencies = [ [[package]] name = "deno_web" -version = "0.198.0" +version = "0.199.0" dependencies = [ "async-trait", "base64-simd 0.8.0", @@ -2140,7 +2123,7 @@ dependencies = [ [[package]] name = "deno_webgpu" -version = "0.134.0" +version = "0.135.0" dependencies = [ "deno_core", "raw-window-handle", @@ -2152,7 +2135,7 @@ dependencies = [ [[package]] name = "deno_webidl" -version = "0.167.0" +version = "0.168.0" dependencies = [ "deno_bench_util", "deno_core", @@ -2160,7 +2143,7 @@ dependencies = [ [[package]] name = "deno_websocket" -version = "0.172.0" +version = "0.173.0" dependencies = [ "bytes", "deno_core", @@ -2181,7 +2164,7 @@ dependencies = [ [[package]] name = "deno_webstorage" -version = "0.162.0" +version = "0.163.0" dependencies = [ "deno_core", "deno_web", @@ -2475,7 +2458,7 @@ dependencies = [ "bumpalo", "hashbrown", "indexmap", - "rustc-hash", + "rustc-hash 1.1.0", "serde", "unicode-width", ] @@ -2543,7 +2526,7 @@ dependencies = [ "dprint-core", "dprint-core-macros", "percent-encoding", - "rustc-hash", + "rustc-hash 1.1.0", "serde", ] @@ -2556,7 +2539,7 @@ dependencies = [ "allocator-api2", "bumpalo", "num-bigint", - "rustc-hash", + "rustc-hash 1.1.0", "swc_atoms", "swc_common", "swc_ecma_ast", @@ -2808,15 +2791,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31ae425815400e5ed474178a7a22e275a9687086a12ca63ec793ff292d8fdae8" -[[package]] -name = "escape8259" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4911e3666fcd7826997b4745c8224295a6f3072f1418c3067b97a67557ee" -dependencies = [ - "rustversion", -] - [[package]] name = "eszip" version = "0.78.0" @@ -2956,7 +2930,7 @@ dependencies = [ "anyhow", "crossbeam-channel", "deno_terminal 0.1.1", - "parking_lot 0.12.3", + "parking_lot", "regex", "thiserror", ] @@ -2969,7 +2943,7 @@ checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", + "redox_syscall", "windows-sys 0.52.0", ] @@ -3551,7 +3525,7 @@ dependencies = [ "new_debug_unreachable", "once_cell", "phf 0.11.2", - "rustc-hash", + "rustc-hash 1.1.0", "triomphe", ] @@ -3853,15 +3827,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - [[package]] name = "ipconfig" version = "0.3.2" @@ -4523,7 +4488,7 @@ dependencies = [ "indexmap", "log", "num-traits", - "rustc-hash", + "rustc-hash 1.1.0", "serde", "spirv", "termcolor", @@ -4548,7 +4513,7 @@ dependencies = [ [[package]] name = "napi_sym" -version = "0.97.0" +version = "0.98.0" dependencies = [ "quote", "serde", @@ -4617,7 +4582,7 @@ dependencies = [ [[package]] name = "node_resolver" -version = "0.6.0" +version = "0.7.0" dependencies = [ "anyhow", "async-trait", @@ -4924,17 +4889,6 @@ dependencies = [ "sha2", ] -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - [[package]] name = "parking_lot" version = "0.12.3" @@ -4942,21 +4896,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core 0.9.9", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -4967,7 +4907,7 @@ checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", + "redox_syscall", "smallvec", "windows-targets 0.48.5", ] @@ -5534,7 +5474,7 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash", + "rustc-hash 1.1.0", "rustls", "thiserror", "tokio", @@ -5543,14 +5483,14 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.3" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddf517c03a109db8100448a4be38d498df8a210a99fe0e1b9eaf39e78c640efe" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" dependencies = [ "bytes", "rand", "ring", - "rustc-hash", + "rustc-hash 2.0.0", "rustls", "slab", "thiserror", @@ -5685,15 +5625,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -5881,7 +5812,7 @@ dependencies = [ "countme", "hashbrown", "memoffset 0.9.1", - "rustc-hash", + "rustc-hash 1.1.0", "text-size", ] @@ -5955,6 +5886,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + [[package]] name = "rustc_version" version = "0.2.3" @@ -6546,7 +6483,7 @@ dependencies = [ "data-encoding", "debugid", "if_chain", - "rustc-hash", + "rustc-hash 1.1.0", "rustc_version 0.2.3", "serde", "serde_json", @@ -6565,7 +6502,7 @@ dependencies = [ "data-encoding", "debugid", "if_chain", - "rustc-hash", + "rustc-hash 1.1.0", "rustc_version 0.2.3", "serde", "serde_json", @@ -6631,7 +6568,7 @@ checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" dependencies = [ "new_debug_unreachable", "once_cell", - "parking_lot 0.12.3", + "parking_lot", "phf_shared 0.10.0", "precomputed-hash", "serde", @@ -6713,7 +6650,7 @@ dependencies = [ "bumpalo", "hashbrown", "ptr_meta", - "rustc-hash", + "rustc-hash 1.1.0", "triomphe", ] @@ -6725,7 +6662,7 @@ checksum = "bb6567e4e67485b3e7662b486f1565bdae54bd5b9d6b16b2ba1a9babb1e42125" dependencies = [ "hstr", "once_cell", - "rustc-hash", + "rustc-hash 1.1.0", "serde", ] @@ -6740,7 +6677,7 @@ dependencies = [ "indexmap", "is-macro", "once_cell", - "parking_lot 0.12.3", + "parking_lot", "petgraph", "radix_fmt", "relative-path", @@ -6787,7 +6724,7 @@ dependencies = [ "new_debug_unreachable", "num-bigint", "once_cell", - "rustc-hash", + "rustc-hash 1.1.0", "serde", "siphasher", "sourcemap 9.0.0", @@ -6922,7 +6859,7 @@ dependencies = [ "indexmap", "once_cell", "phf 0.11.2", - "rustc-hash", + "rustc-hash 1.1.0", "serde", "smallvec", "swc_atoms", @@ -6970,7 +6907,7 @@ dependencies = [ "indexmap", "once_cell", "petgraph", - "rustc-hash", + "rustc-hash 1.1.0", "serde_json", "swc_atoms", "swc_common", @@ -6991,7 +6928,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79938ff510fc647febd8c6c3ef4143d099fdad87a223680e632623d056dae2dd" dependencies = [ "either", - "rustc-hash", + "rustc-hash 1.1.0", "serde", "smallvec", "swc_atoms", @@ -7055,7 +6992,7 @@ dependencies = [ "indexmap", "num_cpus", "once_cell", - "rustc-hash", + "rustc-hash 1.1.0", "ryu-js", "swc_atoms", "swc_common", @@ -7099,7 +7036,7 @@ checksum = "357e2c97bb51431d65080f25b436bc4e2fc1a7f64a643bc21a8353e478dc799f" dependencies = [ "indexmap", "petgraph", - "rustc-hash", + "rustc-hash 1.1.0", "swc_common", ] @@ -7325,7 +7262,7 @@ dependencies = [ "nix 0.26.2", "once_cell", "os_pipe", - "parking_lot 0.12.3", + "parking_lot", "pretty_assertions", "prost", "prost-build", @@ -7457,7 +7394,7 @@ dependencies = [ "libc", "mio", "num_cpus", - "parking_lot 0.12.3", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", @@ -7728,7 +7665,7 @@ dependencies = [ "ipconfig", "lru-cache", "once_cell", - "parking_lot 0.12.3", + "parking_lot", "rand", "resolv-conf", "serde", @@ -8201,11 +8138,11 @@ dependencies = [ "log", "naga", "once_cell", - "parking_lot 0.12.3", + "parking_lot", "profiling", "raw-window-handle", "ron", - "rustc-hash", + "rustc-hash 1.1.0", "serde", "smallvec", "thiserror", @@ -8243,11 +8180,11 @@ dependencies = [ "ndk-sys", "objc", "once_cell", - "parking_lot 0.12.3", + "parking_lot", "profiling", "range-alloc", "raw-window-handle", - "rustc-hash", + "rustc-hash 1.1.0", "smallvec", "thiserror", "wasm-bindgen", @@ -8298,7 +8235,7 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" dependencies = [ - "redox_syscall 0.4.1", + "redox_syscall", "wasite", "web-sys", ] @@ -8735,7 +8672,7 @@ dependencies = [ "log", "num-traits", "once_cell", - "parking_lot 0.12.3", + "parking_lot", "rand", "regex", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index 70d74eb9a9..a33fa6d94c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,14 +47,14 @@ repository = "https://github.com/denoland/deno" deno_ast = { version = "=0.42.0", features = ["transpiling"] } deno_core = { version = "0.307.0" } -deno_bench_util = { version = "0.161.0", path = "./bench_util" } +deno_bench_util = { version = "0.162.0", path = "./bench_util" } deno_lockfile = "=0.23.0" deno_media_type = { version = "0.1.4", features = ["module_specifier"] } -deno_permissions = { version = "0.27.0", path = "./runtime/permissions" } -deno_runtime = { version = "0.176.0", path = "./runtime" } +deno_permissions = { version = "0.28.0", path = "./runtime/permissions" } +deno_runtime = { version = "0.177.0", path = "./runtime" } deno_semver = "=0.5.13" deno_terminal = "0.2.0" -napi_sym = { version = "0.97.0", path = "./cli/napi/sym" } +napi_sym = { version = "0.98.0", path = "./cli/napi/sym" } test_util = { package = "test_server", path = "./tests/util/server" } denokv_proto = "0.8.1" @@ -63,29 +63,29 @@ denokv_remote = "0.8.1" denokv_sqlite = { default-features = false, version = "0.8.2" } # exts -deno_broadcast_channel = { version = "0.161.0", path = "./ext/broadcast_channel" } -deno_cache = { version = "0.99.0", path = "./ext/cache" } -deno_canvas = { version = "0.36.0", path = "./ext/canvas" } -deno_console = { version = "0.167.0", path = "./ext/console" } -deno_cron = { version = "0.47.0", path = "./ext/cron" } -deno_crypto = { version = "0.181.0", path = "./ext/crypto" } -deno_fetch = { version = "0.191.0", path = "./ext/fetch" } -deno_ffi = { version = "0.154.0", path = "./ext/ffi" } -deno_fs = { version = "0.77.0", path = "./ext/fs" } -deno_http = { version = "0.165.0", path = "./ext/http" } -deno_io = { version = "0.77.0", path = "./ext/io" } -deno_kv = { version = "0.75.0", path = "./ext/kv" } -deno_napi = { version = "0.98.0", path = "./ext/napi" } -deno_net = { version = "0.159.0", path = "./ext/net" } -deno_node = { version = "0.104.0", path = "./ext/node" } -deno_tls = { version = "0.154.0", path = "./ext/tls" } -deno_url = { version = "0.167.0", path = "./ext/url" } -deno_web = { version = "0.198.0", path = "./ext/web" } -deno_webgpu = { version = "0.134.0", path = "./ext/webgpu" } -deno_webidl = { version = "0.167.0", path = "./ext/webidl" } -deno_websocket = { version = "0.172.0", path = "./ext/websocket" } -deno_webstorage = { version = "0.162.0", path = "./ext/webstorage" } -node_resolver = { version = "0.6.0", path = "./ext/node_resolver" } +deno_broadcast_channel = { version = "0.162.0", path = "./ext/broadcast_channel" } +deno_cache = { version = "0.100.0", path = "./ext/cache" } +deno_canvas = { version = "0.37.0", path = "./ext/canvas" } +deno_console = { version = "0.168.0", path = "./ext/console" } +deno_cron = { version = "0.48.0", path = "./ext/cron" } +deno_crypto = { version = "0.182.0", path = "./ext/crypto" } +deno_fetch = { version = "0.192.0", path = "./ext/fetch" } +deno_ffi = { version = "0.155.0", path = "./ext/ffi" } +deno_fs = { version = "0.78.0", path = "./ext/fs" } +deno_http = { version = "0.166.0", path = "./ext/http" } +deno_io = { version = "0.78.0", path = "./ext/io" } +deno_kv = { version = "0.76.0", path = "./ext/kv" } +deno_napi = { version = "0.99.0", path = "./ext/napi" } +deno_net = { version = "0.160.0", path = "./ext/net" } +deno_node = { version = "0.105.0", path = "./ext/node" } +deno_tls = { version = "0.155.0", path = "./ext/tls" } +deno_url = { version = "0.168.0", path = "./ext/url" } +deno_web = { version = "0.199.0", path = "./ext/web" } +deno_webgpu = { version = "0.135.0", path = "./ext/webgpu" } +deno_webidl = { version = "0.168.0", path = "./ext/webidl" } +deno_websocket = { version = "0.173.0", path = "./ext/websocket" } +deno_webstorage = { version = "0.163.0", path = "./ext/webstorage" } +node_resolver = { version = "0.7.0", path = "./ext/node_resolver" } aes = "=0.8.3" anyhow = "1.0.57" diff --git a/Releases.md b/Releases.md index 87460ddc7b..a6e4d84e7b 100644 --- a/Releases.md +++ b/Releases.md @@ -6,6 +6,17 @@ https://github.com/denoland/deno/releases We also have one-line install commands at: https://github.com/denoland/deno_install +### 1.46.3 / 2024.09.04 + +- feat(upgrade): print info links for Deno 2 RC releases (#25225) +- fix(cli): Map error kind to `PermissionDenied` when symlinking fails due to + permissions (#25398) +- fix(cli/tools): correct `deno init --serve` template behavior (#25318) +- fix(ext/node): session close during stream setup (#25170) +- fix(publish): ensure provenance is spec compliant (#25200) +- fix(upgrade): more informative information on invalid version (#25319) +- fix: fix jupyter display function type (#25326) + ### 1.46.2 / 2024.08.29 - Revert "feat(fetch): accept async iterables for body" (#25207) diff --git a/bench_util/Cargo.toml b/bench_util/Cargo.toml index 37c8b0459c..5a04ab5355 100644 --- a/bench_util/Cargo.toml +++ b/bench_util/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_bench_util" -version = "0.161.0" +version = "0.162.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 9c62406ffe..016488e5c2 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -65,10 +65,9 @@ winres.workspace = true [dependencies] deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "proposal", "react", "sourcemap", "transforms", "typescript", "view", "visit"] } deno_cache_dir = { workspace = true } -deno_config = { version = "=0.32.0", features = ["workspace", "sync"] } +deno_config = { version = "=0.33.1", features = ["workspace", "sync"] } deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] } deno_doc = { version = "0.148.0", features = ["html", "syntect"] } -deno_emit = "=0.45.0" deno_graph = { version = "=0.82.0" } deno_lint = { version = "=0.64.0", features = ["docs"] } deno_lockfile.workspace = true @@ -91,8 +90,8 @@ bincode = "=1.3.3" bytes.workspace = true cache_control.workspace = true chrono = { workspace = true, features = ["now"] } -clap = { version = "=4.5.13", features = ["env", "string", "wrap_help"] } -clap_complete = "=4.5.12" +clap = { version = "=4.5.16", features = ["env", "string", "wrap_help", "error-context"] } +clap_complete = "=4.5.24" clap_complete_fig = "=4.5.2" color-print = "0.3.5" console_static_text.workspace = true diff --git a/cli/args/deno_json.rs b/cli/args/deno_json.rs index cbc33aa0b2..e9ab0189f5 100644 --- a/cli/args/deno_json.rs +++ b/cli/args/deno_json.rs @@ -2,6 +2,7 @@ use std::collections::HashSet; +use deno_config::deno_json::TsConfigForEmit; use deno_core::serde_json; use deno_semver::jsr::JsrDepPackageReq; use deno_semver::jsr::JsrPackageReqReference; @@ -105,3 +106,18 @@ fn values_to_set<'a>( } entries } + +pub fn check_warn_tsconfig(ts_config: &TsConfigForEmit) { + if let Some(ignored_options) = &ts_config.maybe_ignored_options { + log::warn!("{}", ignored_options); + } + let serde_json::Value::Object(obj) = &ts_config.ts_config.0 else { + return; + }; + if obj.get("experimentalDecorators") == Some(&serde_json::Value::Bool(true)) { + log::warn!( + "{} experimentalDecorators compiler option is deprecated and may be removed at any time", + deno_runtime::colors::yellow("Warning"), + ); + } +} diff --git a/cli/args/flags.rs b/cli/args/flags.rs index 44f97010f0..9397f21807 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -1,7 +1,19 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use std::collections::HashSet; +use std::env; +use std::ffi::OsString; +use std::net::SocketAddr; +use std::num::NonZeroU32; +use std::num::NonZeroU8; +use std::num::NonZeroUsize; +use std::path::Path; +use std::path::PathBuf; +use std::str::FromStr; + use clap::builder::styling::AnsiColor; use clap::builder::FalseyValueParser; +use clap::error::ErrorKind; use clap::value_parser; use clap::Arg; use clap::ArgAction; @@ -20,22 +32,13 @@ use deno_core::normalize_path; use deno_core::resolve_url_or_path; use deno_core::url::Url; use deno_graph::GraphKind; +use deno_runtime::colors; use deno_runtime::deno_permissions::parse_sys_kind; use deno_runtime::deno_permissions::PermissionsOptions; use log::debug; use log::Level; use serde::Deserialize; use serde::Serialize; -use std::collections::HashSet; -use std::env; -use std::ffi::OsString; -use std::net::SocketAddr; -use std::num::NonZeroU32; -use std::num::NonZeroU8; -use std::num::NonZeroUsize; -use std::path::Path; -use std::path::PathBuf; -use std::str::FromStr; use crate::args::resolve_no_prompt; use crate::util::fs::canonicalize_path; @@ -237,11 +240,17 @@ pub struct InstallFlagsGlobal { #[derive(Clone, Debug, Eq, PartialEq)] pub enum InstallKind { - #[allow(unused)] - Local(Option), + Local(InstallFlagsLocal), Global(InstallFlagsGlobal), } +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum InstallFlagsLocal { + Add(AddFlags), + TopLevel, + Entrypoints(Vec), +} + #[derive(Clone, Debug, Eq, PartialEq)] pub struct InstallFlags { pub global: bool, @@ -682,6 +691,54 @@ impl PermissionFlags { Ok(Some(new_paths)) } + fn resolve_allow_run( + allow_run: &[String], + ) -> Result, AnyError> { + let mut new_allow_run = Vec::with_capacity(allow_run.len()); + for command_name in allow_run { + if command_name.is_empty() { + bail!("Empty command name not allowed in --allow-run=...") + } + let command_path_result = which::which(command_name); + match command_path_result { + Ok(command_path) => new_allow_run.push(command_path), + Err(err) => { + log::info!( + "{} Failed to resolve '{}' for allow-run: {}", + colors::gray("Info"), + command_name, + err + ); + } + } + } + Ok(new_allow_run) + } + + let mut deny_write = + convert_option_str_to_path_buf(&self.deny_write, initial_cwd)?; + let allow_run = self + .allow_run + .as_ref() + .and_then(|raw_allow_run| match resolve_allow_run(raw_allow_run) { + Ok(resolved_allow_run) => { + if resolved_allow_run.is_empty() && !raw_allow_run.is_empty() { + None // convert to no permissions if now empty + } else { + Some(Ok(resolved_allow_run)) + } + } + Err(err) => Some(Err(err)), + }) + .transpose()?; + // add the allow_run list to deno_write + if let Some(allow_run_vec) = &allow_run { + if !allow_run_vec.is_empty() { + let deno_write = deny_write.get_or_insert_with(Vec::new); + deno_write.extend(allow_run_vec.iter().cloned()); + } + } + Ok(PermissionsOptions { allow_all: self.allow_all, allow_env: self.allow_env.clone(), @@ -695,7 +752,7 @@ impl PermissionFlags { initial_cwd, )?, deny_read: convert_option_str_to_path_buf(&self.deny_read, initial_cwd)?, - allow_run: self.allow_run.clone(), + allow_run, deny_run: self.deny_run.clone(), allow_sys: self.allow_sys.clone(), deny_sys: self.deny_sys.clone(), @@ -703,10 +760,7 @@ impl PermissionFlags { &self.allow_write, initial_cwd, )?, - deny_write: convert_option_str_to_path_buf( - &self.deny_write, - initial_cwd, - )?, + deny_write, prompt: !resolve_no_prompt(self), }) } @@ -1119,6 +1173,7 @@ static DENO_HELP: &str = cstr!( deno bench bench.ts cache Cache the dependencies check Type-check the dependencies + clean Remove the cache directory compile Compile the script into a self contained executable deno compile main.ts | deno compile --target=x86_64-unknown-linux-gnu coverage Print coverage reports @@ -1146,7 +1201,32 @@ static DENO_HELP: &str = cstr!( /// Main entry point for parsing deno's command line flags. pub fn flags_from_vec(args: Vec) -> clap::error::Result { let mut app = clap_root(); - let mut matches = app.try_get_matches_from_mut(&args)?; + let mut matches = + app + .try_get_matches_from_mut(&args) + .map_err(|mut e| match e.kind() { + ErrorKind::MissingRequiredArgument => { + if let Some(clap::error::ContextValue::Strings(s)) = + e.get(clap::error::ContextKind::InvalidArg) + { + if s.len() == 1 + && s[0] == "--global" + && args.iter().any(|arg| arg == "install") + { + e.insert( + clap::error::ContextKind::Usage, + clap::error::ContextValue::StyledStr( + "Note: Permission flags can only be used in a global setting" + .into(), + ), + ); + } + } + + e + } + _ => e, + })?; let mut flags = Flags::default(); @@ -1464,7 +1544,7 @@ pub fn clap_root() -> Command { .subcommand(fmt_subcommand()) .subcommand(init_subcommand()) .subcommand(info_subcommand()) - .subcommand(future_install_subcommand()) + .subcommand(install_subcommand()) .subcommand(json_reference_subcommand()) .subcommand(jupyter_subcommand()) .subcommand(uninstall_subcommand()) @@ -1511,13 +1591,13 @@ fn help_subcommand(app: &Command) -> Command { fn add_subcommand() -> Command { command( "add", - "Add dependencies to the configuration file. - - deno add @std/path + cstr!( + "Add dependencies to your configuration file. + deno add @std/path You can add multiple dependencies at once: - deno add @std/path @std/assert -", + deno add @std/path @std/assert" + ), UnstableArgsConfig::None, ) .defer(|cmd| { @@ -1536,8 +1616,7 @@ fn remove_subcommand() -> Command { "remove", cstr!( "Remove dependencies from the configuration file. - - deno remove @std/path + deno remove @std/path You can remove multiple dependencies at once: deno remove @std/path @std/assert @@ -1559,15 +1638,15 @@ You can remove multiple dependencies at once: fn bench_subcommand() -> Command { command( "bench", - "Run benchmarks using Deno's built-in bench tool. + cstr!("Run benchmarks using Deno's built-in bench tool. -Evaluate the given modules, run all benches declared with 'Deno.bench()' -and report results to standard output: - deno bench src/fetch_bench.ts src/signal_bench.ts +Evaluate the given files, run all benches declared with 'Deno.bench()' and report results to standard output: + deno bench src/fetch_bench.ts src/signal_bench.ts -Directory arguments are expanded to all contained files matching the -glob {*_,*.,}bench.{js,mjs,ts,mts,jsx,tsx}: - deno bench src/", +If you specify a directory instead of a file, the path is expanded to all contained files matching the glob {*_,*.,}bench.{js,mjs,ts,mts,jsx,tsx}: + deno bench src/ + +Read more: https://docs.deno.com/go/cmd/bench"), UnstableArgsConfig::ResolutionAndRuntime, ) .defer(|cmd| { @@ -1625,14 +1704,14 @@ See the Deno 1.x to 2.x Migration Guide for migration instructions: https://docs fn cache_subcommand() -> Command { command( "cache", - "Cache and compile remote dependencies recursively. + cstr!("Cache and compile remote dependencies. -Download and compile a module with all of its static dependencies and save -them in the local cache, without running any code: - deno cache jsr:@std/http/file-server +Download and compile a module with all of its static dependencies and save them in the local cache, without running any code: + deno cache jsr:@std/http/file-server -Future runs of this module will trigger no downloads or compilation unless ---reload is specified.", +Future runs of this module will trigger no downloads or compilation unless --reload is specified + +Read more: https://docs.deno.com/go/cmd/cache"), UnstableArgsConfig::ResolutionOnly, ) .defer(|cmd| { @@ -1652,18 +1731,20 @@ Future runs of this module will trigger no downloads or compilation unless fn clean_subcommand() -> Command { command( "clean", - "Remove the cache directory ($DENO_DIR)", + cstr!("Remove the cache directory ($DENO_DIR)"), UnstableArgsConfig::None, ) } fn check_subcommand() -> Command { command("check", - "Download and type-check without execution. + cstr!("Download and type-check without execution. - deno check jsr:@std/http/file-server + deno check jsr:@std/http/file-server -Unless --reload is specified, this command will not re-download already cached dependencies.", +Unless --reload is specified, this command will not re-download already cached dependencies + +Read more: https://docs.deno.com/go/cmd/check"), UnstableArgsConfig::ResolutionAndRuntime ) .defer(|cmd| { @@ -1697,26 +1778,18 @@ Unless --reload is specified, this command will not re-download already cached d fn compile_subcommand() -> Command { command( "compile", - "Compiles the given script into a self contained executable. + cstr!("Compiles the given script into a self contained executable. - deno compile -A jsr:@std/http/file-server - deno compile --output file_server jsr:@std/http/file-server + deno compile -A jsr:@std/http/file-server + deno compile --output file_server jsr:@std/http/file-server -Any flags passed which affect runtime behavior, such as '--unstable', -'--allow-*', '--v8-flags', etc. are encoded into the output executable and -used at runtime as if they were passed to a similar 'deno run' command. +Any flags specified which affect runtime behavior will be applied to the resulting binary. -The executable name is inferred by default: Attempt to take the file stem of -the URL path. The above example would become 'file_server'. If the file stem -is something generic like 'main', 'mod', 'index' or 'cli', and the path has no -parent, take the file name of the parent path. Otherwise settle with the -generic name. If the resulting name has an '@...' suffix, strip it. +Cross-compiling to different target architectures is supported using the --target flag. +On the first invocation with deno will download the proper binary and cache it in $DENO_DIR. -Cross-compiling to different target architectures is supported using the -`--target` flag. On the first invocation with deno will download proper -binary and cache it in $DENO_DIR. The aarch64-apple-darwin target is not -supported in canary. -", +Read more: https://docs.deno.com/go/cmd/compile +"), UnstableArgsConfig::ResolutionAndRuntime, ) .defer(|cmd| { @@ -1784,10 +1857,12 @@ supported in canary. fn completions_subcommand() -> Command { command( "completions", - "Output shell completion script to standard output. + cstr!( + "Output shell completion script to standard output. - deno completions bash > /usr/local/etc/bash_completion.d/deno.bash - source /usr/local/etc/bash_completion.d/deno.bash", + deno completions bash > /usr/local/etc/bash_completion.d/deno.bash + source /usr/local/etc/bash_completion.d/deno.bash" + ), UnstableArgsConfig::None, ) .defer(|cmd| { @@ -1802,31 +1877,25 @@ fn completions_subcommand() -> Command { fn coverage_subcommand() -> Command { command( "coverage", - "Print coverage reports from coverage profiles. + cstr!("Print coverage reports from coverage profiles. Collect a coverage profile with deno test: - deno test --coverage=cov_profile + deno test --coverage=cov_profile Print a report to stdout: - deno coverage cov_profile + deno coverage cov_profile -Include urls that start with the file schema: - deno coverage --include=\"^file:\" cov_profile - -Exclude urls ending with test.ts and test.js: - deno coverage --exclude=\"test\\.(ts|js)\" cov_profile - -Include urls that start with the file schema and exclude files ending with -test.ts and test.js, for an url to match it must match the include pattern and -not match the exclude pattern: - deno coverage --include=\"^file:\" --exclude=\"test\\.(ts|js)\" cov_profile +Include urls that start with the file schema and exclude files ending with test.ts and test.js, +for an url to match it must match the include pattern and not match the exclude pattern: + deno coverage --include=\"^file:\" --exclude=\"test\\.(ts|js)\" cov_profile Write a report using the lcov format: - deno coverage --lcov --output=cov.lcov cov_profile/ + deno coverage --lcov --output=cov.lcov cov_profile/ Generate html reports from lcov: - genhtml -o html_cov cov.lcov -", + genhtml -o html_cov cov.lcov + +Read more: https://docs.deno.com/go/cmd/coverage"), UnstableArgsConfig::None, ) .defer(|cmd| { @@ -1901,31 +1970,25 @@ Generate html reports from lcov: fn doc_subcommand() -> Command { command("doc", - "Show documentation for a module. + cstr!("Show documentation for a module. Output documentation to standard output: - deno doc ./path/to/module.ts + deno doc ./path/to/module.ts Output documentation in HTML format: - deno doc --html --name=\"My library\" ./path/to/module.ts - deno doc --html --name=\"My library\" ./main.ts ./dev.ts - deno doc --html --name=\"My library\" --output=./documentation/ ./path/to/module.ts - -Output private documentation to standard output: - deno doc --private ./path/to/module.ts - -Output documentation in JSON format: - deno doc --json ./path/to/module.ts + deno doc --html --name=\"My library\" ./path/to/module.ts Lint a module for documentation diagnostics: - deno doc --lint ./path/to/module.ts + deno doc --lint ./path/to/module.ts Target a specific symbol: - deno doc ./path/to/module.ts MyClass.someField + deno doc ./path/to/module.ts MyClass.someField Show documentation for runtime built-ins: - deno doc - deno doc --filter Deno.Listener", + deno doc + deno doc --filter Deno.Listener + +Read more: https://docs.deno.com/go/cmd/doc"), UnstableArgsConfig::ResolutionOnly ) .defer(|cmd| { @@ -2036,14 +2099,17 @@ Show documentation for runtime built-ins: fn eval_subcommand() -> Command { command( "eval", - "Evaluate JavaScript from the command line. - - deno eval \"console.log('hello world')\" + cstr!( + "Evaluate JavaScript from the command line. + deno eval \"console.log('hello world')\" To evaluate as TypeScript: - deno eval --ext=ts \"const v: string = 'hello'; console.log(v)\" + deno eval --ext=ts \"const v: string = 'hello'; console.log(v)\" -This command has implicit access to all permissions (--allow-all).", +This command has implicit access to all permissions. + +Read more: https://docs.deno.com/go/cmd/eval" + ), UnstableArgsConfig::ResolutionAndRuntime, ) .defer(|cmd| { @@ -2072,20 +2138,25 @@ This command has implicit access to all permissions (--allow-all).", fn fmt_subcommand() -> Command { command( "fmt", - "Auto-format JavaScript, TypeScript, Markdown, and JSON files. + cstr!("Auto-format various file types. + deno fmt myfile1.ts myfile2.ts - deno fmt - deno fmt myfile1.ts myfile2.ts - deno fmt --check +Supported file types are: + JavaScript, TypeScript, Markdown, JSON(C) and Jupyter Notebooks + +Supported file types which are behind corresponding unstable flags (see formatting options): + HTML, CSS, SCSS, SASS, LESS, YAML, Svelte, Vue, Astro and Angular Format stdin and write to stdout: - cat file.ts | deno fmt - + cat file.ts | deno fmt - Ignore formatting code by preceding it with an ignore comment: - // deno-fmt-ignore + // deno-fmt-ignore Ignore formatting a file by adding an ignore comment at the top of the file: - // deno-fmt-ignore-file", + // deno-fmt-ignore-file + +Read more: https://docs.deno.com/go/cmd/fmt"), UnstableArgsConfig::None, ) .defer(|cmd| { @@ -2105,6 +2176,7 @@ Ignore formatting a file by adding an ignore comment at the top of the file: .help("Set content type of the supplied file") // prefer using ts for formatting instead of js because ts works in more scenarios .default_value("ts") + .hide_default_value(true) .value_parser([ "ts", "tsx", "js", "jsx", "md", "json", "jsonc", "css", "scss", "sass", "less", "html", "svelte", "vue", "astro", "yml", "yaml", @@ -2251,23 +2323,18 @@ fn init_subcommand() -> Command { fn info_subcommand() -> Command { command("info", - "Information about a module or the cache directories. + cstr!("Show information about a module or the cache directories. Get information about a module: - deno info jsr:@std/http/file-server + deno info jsr:@std/http/file-server The following information is shown: + local: Local path of the file + type: JavaScript, TypeScript, or JSON + emit: Local path of compiled source code (TypeScript only) + dependencies: Dependency tree of the source file -local: Local path of the file. -type: JavaScript, TypeScript, or JSON. -emit: Local path of compiled source code. (TypeScript only.) -dependencies: Dependency tree of the source file. - -Without any additional arguments, 'deno info' shows: - -DENO_DIR: Directory containing Deno-managed files. -Remote modules cache: Subdirectory containing downloaded remote modules. -TypeScript compiler cache: Subdirectory containing TS compiler output.", +Read more: https://docs.deno.com/go/cmd/info"), UnstableArgsConfig::ResolutionOnly ) .defer(|cmd| cmd @@ -2298,89 +2365,97 @@ TypeScript compiler cache: Subdirectory containing TS compiler output.", )) } -fn install_args(cmd: Command) -> Command { - let cmd = cmd.arg( - Arg::new("cmd") - .required_if_eq("global", "true") - .num_args(1..) - .value_hint(ValueHint::FilePath), - ); - cmd - .arg( - Arg::new("name") - .long("name") - .short('n') - .help("Executable file name"), - ) - .arg( - Arg::new("root") - .long("root") - .help("Installation root") - .value_hint(ValueHint::DirPath), - ) - .arg( - Arg::new("force") - .long("force") - .short('f') - .help("Forcefully overwrite existing installation") - .action(ArgAction::SetTrue), - ) - .arg( - Arg::new("global") - .long("global") - .short('g') - .help("Install a package or script as a globally available executable") - .action(ArgAction::SetTrue), - ) - .arg(env_file_arg()) -} +fn install_subcommand() -> Command { + command("install", cstr!("Installs dependencies either in the local project or globally to a bin directory. -fn future_install_subcommand() -> Command { - command("install", "Installs dependencies either in the local project or globally to a bin directory. +Local installation -Local installation -------------------- -If the --global flag is not set, adds dependencies to the local project's configuration -(package.json / deno.json) and installs them in the package cache. If no dependency -is specified, installs all dependencies listed in package.json. +Add dependencies to the local project's configuration (deno.json / package.json) and installs them +in the package cache. If no dependency is specified, installs all dependencies listed in the config file. +If the --entrypoint flag is passed, installs the dependencies of the specified entrypoint(s). - deno install - deno install @std/bytes - deno install npm:chalk + deno install + deno install @std/bytes + deno install npm:chalk + deno install --entrypoint entry1.ts entry2.ts -Global installation -------------------- -If the --global flag is set, installs a script as an executable in the installation root's bin directory. +Global installation - deno install --global --allow-net --allow-read jsr:@std/http/file-server - deno install -g https://examples.deno.land/color-logging.ts +If the --global flag is set, installs a script as an executable in the installation root's bin directory. + + deno install --global --allow-net --allow-read jsr:@std/http/file-server + deno install -g https://examples.deno.land/color-logging.ts To change the executable name, use -n/--name: - - deno install -g --allow-net --allow-read -n serve jsr:@std/http/file-server + deno install -g --allow-net --allow-read -n serve jsr:@std/http/file-server The executable name is inferred by default: - Attempt to take the file stem of the URL path. The above example would - become 'file_server'. - - If the file stem is something generic like 'main', 'mod', 'index' or 'cli', + become file_server. + - If the file stem is something generic like main, mod, index or cli, and the path has no parent, take the file name of the parent path. Otherwise settle with the generic name. - - If the resulting name has an '@...' suffix, strip it. + - If the resulting name has an @... suffix, strip it. -To change the installation root, use --root: - - deno install -g --allow-net --allow-read --root /usr/local jsr:@std/http/file-server +To change the installation root, use --root: + deno install -g --allow-net --allow-read --root /usr/local jsr:@std/http/file-server The installation root is determined, in order of precedence: - - --root option - - DENO_INSTALL_ROOT environment variable - - $HOME/.deno + - --root option + - DENO_INSTALL_ROOT environment variable + - $HOME/.deno -These must be added to the path manually if required.", UnstableArgsConfig::ResolutionAndRuntime) +These must be added to the path manually if required."), UnstableArgsConfig::ResolutionAndRuntime) .visible_alias("i") .defer(|cmd| { - let cmd = runtime_args(cmd, true, true).arg(check_arg(true)).arg(allow_scripts_arg()); - install_args(cmd) + permission_args(runtime_args(cmd, false, true), Some("global")) + .arg(check_arg(true)) + .arg(allow_scripts_arg()) + .arg( + Arg::new("cmd") + .required_if_eq("global", "true") + .required_if_eq("entrypoint", "true") + .num_args(1..) + .value_hint(ValueHint::FilePath), + ) + .arg( + Arg::new("name") + .long("name") + .short('n') + .requires("global") + .help("Executable file name"), + ) + .arg( + Arg::new("root") + .long("root") + .requires("global") + .help("Installation root") + .value_hint(ValueHint::DirPath), + ) + .arg( + Arg::new("force") + .long("force") + .requires("global") + .short('f') + .help("Forcefully overwrite existing installation") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("global") + .long("global") + .short('g') + .help("Install a package or script as a globally available executable") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("entrypoint") + .long("entrypoint") + .short('e') + .conflicts_with("global") + .action(ArgAction::SetTrue) + .help("Install dependents of the specified entrypoint(s)"), + ) + .arg(env_file_arg()) }) } @@ -2418,17 +2493,16 @@ fn jupyter_subcommand() -> Command { fn uninstall_subcommand() -> Command { command( "uninstall", - "Uninstalls an executable script in the installation root's bin directory. + cstr!("Uninstalls an executable script in the installation root's bin directory. + deno uninstall serve - deno uninstall serve - -To change the installation root, use --root: - deno uninstall --root /usr/local serve +To change the installation root, use --root flag: + deno uninstall --root /usr/local serve The installation root is determined, in order of precedence: - - --root option - - DENO_INSTALL_ROOT environment variable - - $HOME/.deno", + - --root option + - DENO_INSTALL_ROOT environment variable + - $HOME/.deno"), UnstableArgsConfig::None, ) .defer(|cmd| { @@ -2452,44 +2526,41 @@ The installation root is determined, in order of precedence: fn lsp_subcommand() -> Command { Command::new("lsp").about( - "The 'deno lsp' subcommand provides a way for code editors and IDEs to -interact with Deno using the Language Server Protocol. Usually humans do not -use this subcommand directly. For example, 'deno lsp' can provide IDEs with -go-to-definition support and automatic code formatting. + "The 'deno lsp' subcommand provides a way for code editors and IDEs to interact with Deno +using the Language Server Protocol. Usually humans do not use this subcommand directly. +For example, 'deno lsp' can provide IDEs with go-to-definition support and automatic code formatting. -How to connect various editors and IDEs to 'deno lsp': -https://docs.deno.com/go/lsp", +How to connect various editors and IDEs to 'deno lsp': https://docs.deno.com/go/lsp", ) } fn lint_subcommand() -> Command { command( "lint", - "Lint JavaScript/TypeScript source code. + cstr!("Lint JavaScript/TypeScript source code. - deno lint - deno lint myfile1.ts myfile2.js + deno lint + deno lint myfile1.ts myfile2.js Print result as JSON: - deno lint --json + deno lint --json Read from stdin: - cat file.ts | deno lint - - cat file.ts | deno lint --json - + cat file.ts | deno lint - + cat file.ts | deno lint --json - List available rules: - deno lint --rules + deno lint --rules -Ignore diagnostics on the next line by preceding it with an ignore comment and -rule name: - // deno-lint-ignore no-explicit-any - // deno-lint-ignore require-await no-empty +To ignore specific diagnostics, you can write an ignore comment on the preceding line with a rule name (or multiple): + // deno-lint-ignore no-explicit-any + // deno-lint-ignore require-await no-empty -Names of rules to ignore must be specified after ignore comment. +To ignore linting on an entire file, you can add an ignore comment at the top of the file: + // deno-lint-ignore-file -Ignore linting a file by adding an ignore comment at the top of the file: - // deno-lint-ignore-file -", +Read more: https://docs.deno.com/go/cmd/lint +"), UnstableArgsConfig::ResolutionOnly, ) .defer(|cmd| { @@ -2646,7 +2717,9 @@ Grant all permissions: deno run -A jsr:@std/http/file-server Specifying the filename '-' to read the file from stdin. - curl https://examples.deno.land/hello-world.ts | deno run -"), UnstableArgsConfig::ResolutionAndRuntime), false) + curl https://examples.deno.land/hello-world.ts | deno run - + +Read more: https://docs.deno.com/go/cmd/run"), UnstableArgsConfig::ResolutionAndRuntime), false) } fn serve_host_validator(host: &str) -> Result { @@ -2658,7 +2731,19 @@ fn serve_host_validator(host: &str) -> Result { } fn serve_subcommand() -> Command { - runtime_args(command("serve", None, UnstableArgsConfig::ResolutionAndRuntime), true, true) + runtime_args(command("serve", cstr!("Run a server defined in a main module + +The serve command uses the default exports of the main module to determine which servers to start. + +See https://docs.deno.com/runtime/manual/tools/serve for more detailed information. + +Start a server defined in server.ts: + deno serve server.ts + +Start a server defined in server.ts, watching for changes and running on port 5050: + deno serve --watch --port 5050 server.ts + +Read more: https://docs.deno.com/go/cmd/serve"), UnstableArgsConfig::ResolutionAndRuntime), true, true) .arg( Arg::new("port") .long("port") @@ -2687,29 +2772,18 @@ fn serve_subcommand() -> Command { ) .arg(env_file_arg()) .arg(no_code_cache_arg()) - .about("Run a server defined in a main module - -The serve command uses the default exports of the main module to determine which -servers to start. - -See https://docs.deno.com/runtime/manual/tools/serve for -more detailed information. - -Start a server defined in server.ts: - - deno serve server.ts - -Start a server defined in server.ts, watching for changes and running on port 5050: - - deno serve --watch --port 5050 server.ts") } fn task_subcommand() -> Command { command( "task", - "Run a task defined in the configuration file - - deno task build", + cstr!( + "Run a task defined in the configuration file. + deno task build + +List all available tasks: + deno task" + ), UnstableArgsConfig::ResolutionAndRuntime, ) .defer(|cmd| { @@ -2729,15 +2803,16 @@ fn task_subcommand() -> Command { fn test_subcommand() -> Command { command("test", - "Run tests using Deno's built-in test runner. + cstr!("Run tests using Deno's built-in test runner. -Evaluate the given modules, run all tests declared with 'Deno.test()' and -report results to standard output: - deno test src/fetch_test.ts src/signal_test.ts +Evaluate the given modules, run all tests declared with Deno.test() and report results to standard output: + deno test src/fetch_test.ts src/signal_test.ts -Directory arguments are expanded to all contained files matching the glob -{*_,*.,}test.{js,mjs,ts,mts,jsx,tsx} or **/__tests__/**: - deno test src/", +Directory arguments are expanded to all contained files matching the glob {*_,*.,}test.{js,mjs,ts,mts,jsx,tsx} +or **/__tests__/**: + deno test src/ + +Read more: https://docs.deno.com/go/cmd/test"), UnstableArgsConfig::ResolutionAndRuntime ) .defer(|cmd| @@ -2883,7 +2958,7 @@ fn types_subcommand() -> Command { "types", "Print runtime TypeScript declarations. - deno types > lib.deno.d.ts + deno types > lib.deno.d.ts The declaration file could be saved and used for typing information.", UnstableArgsConfig::None, @@ -2893,31 +2968,28 @@ The declaration file could be saved and used for typing information.", fn upgrade_subcommand() -> Command { command( "upgrade", - color_print::cstr!("Upgrade deno executable to the given version. + cstr!("Upgrade deno executable to the given version. Latest - - deno upgrade + deno upgrade Specific version - - deno upgrade 1.45.0 - deno upgrade 1.46.0-rc.1 - deno upgrade 9bc2dd29ad6ba334fd57a20114e367d3c04763d4 + deno upgrade 1.45.0 + deno upgrade 1.46.0-rc.1 + deno upgrade 9bc2dd29ad6ba334fd57a20114e367d3c04763d4 Channel + deno upgrade stable + deno upgrade rc + deno upgrade canary - deno upgrade stable - deno upgrade rc - deno upgrade canary +The version is downloaded from https://dl.deno.land and is used to replace the current executable. -The version is downloaded from -https://github.com/denoland/deno/releases -and is used to replace the current executable. +If you want to not replace the current Deno executable but instead download an update to a +different location, use the --output flag: + deno upgrade --output $HOME/my_deno -If you want to not replace the current Deno executable but instead download an -update to a different location, use the --output flag: - deno upgrade --output $HOME/my_deno"), +Read more: https://docs.deno.com/go/cmd/upgrade"), UnstableArgsConfig::None, ) .hide(cfg!(not(feature = "upgrade"))) @@ -2973,7 +3045,7 @@ update to a different location, use the --output flag: ) .arg( Arg::new("version-or-hash-or-channel") - .help(color_print::cstr!("Version (v1.46.0), channel (rc, canary) or commit hash (9bc2dd29ad6ba334fd57a20114e367d3c04763d4)")) + .help(cstr!("Version (v1.46.0), channel (rc, canary) or commit hash (9bc2dd29ad6ba334fd57a20114e367d3c04763d4)")) .value_name("VERSION") .action(ArgAction::Append) .trailing_var_arg(true), @@ -3058,7 +3130,7 @@ fn compile_args_without_check_args(app: Command) -> Command { .arg(unsafely_ignore_certificate_errors_arg()) } -fn permission_args(app: Command) -> Command { +fn permission_args(app: Command, requires: Option<&'static str>) -> Command { app .after_help(cstr!(r#"Permission options: Docs: https://docs.deno.com/go/permissions @@ -3096,216 +3168,342 @@ Docs: https://docs.deno.com/go/permissions --deny-ffi | --deny-ffi="./libfoo.so" "#)) .arg( - Arg::new("allow-all") - .short('A') - .long("allow-all") - .action(ArgAction::SetTrue) - .help("Allow all permissions") - .hide(true), + { + let mut arg = Arg::new("allow-all") + .short('A') + .long("allow-all") + .action(ArgAction::SetTrue) + .help("Allow all permissions") + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("allow-read") - .long("allow-read") - .short('R') - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("PATH") - .help("Allow file system read access. Optionally specify allowed paths") - .value_parser(value_parser!(String)) - .value_hint(ValueHint::AnyPath) - .hide(true), + { + let mut arg = Arg::new("allow-read") + .long("allow-read") + .short('R') + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("PATH") + .help("Allow file system read access. Optionally specify allowed paths") + .value_parser(value_parser!(String)) + .value_hint(ValueHint::AnyPath) + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("deny-read") - .long("deny-read") - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("PATH") - .help("Deny file system read access. Optionally specify denied paths") - .value_parser(value_parser!(String)) - .value_hint(ValueHint::AnyPath) - .hide(true), + { + let mut arg = Arg::new("deny-read") + .long("deny-read") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("PATH") + .help("Deny file system read access. Optionally specify denied paths") + .value_parser(value_parser!(String)) + .value_hint(ValueHint::AnyPath) + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("allow-write") - .long("allow-write") - .short('W') - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("PATH") - .help("Allow file system write access. Optionally specify allowed paths") - .value_parser(value_parser!(String)) - .value_hint(ValueHint::AnyPath) - .hide(true), + { + let mut arg = Arg::new("allow-write") + .long("allow-write") + .short('W') + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("PATH") + .help("Allow file system write access. Optionally specify allowed paths") + .value_parser(value_parser!(String)) + .value_hint(ValueHint::AnyPath) + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("deny-write") - .long("deny-write") - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("PATH") - .help("Deny file system write access. Optionally specify denied paths") - .value_parser(value_parser!(String)) - .value_hint(ValueHint::AnyPath) - .hide(true), + { + let mut arg = Arg::new("deny-write") + .long("deny-write") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("PATH") + .help("Deny file system write access. Optionally specify denied paths") + .value_parser(value_parser!(String)) + .value_hint(ValueHint::AnyPath) + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("allow-net") - .long("allow-net") - .short('N') - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("IP_OR_HOSTNAME") - .help("Allow network access. Optionally specify allowed IP addresses and host names, with ports as necessary") - .value_parser(flags_net::validator) - .hide(true), + { + let mut arg = Arg::new("allow-net") + .long("allow-net") + .short('N') + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("IP_OR_HOSTNAME") + .help("Allow network access. Optionally specify allowed IP addresses and host names, with ports as necessary") + .value_parser(flags_net::validator) + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("deny-net") - .long("deny-net") - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("IP_OR_HOSTNAME") - .help("Deny network access. Optionally specify denied IP addresses and host names, with ports as necessary") - .value_parser(flags_net::validator) - .hide(true), + { + let mut arg = Arg::new("deny-net") + .long("deny-net") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("IP_OR_HOSTNAME") + .help("Deny network access. Optionally specify denied IP addresses and host names, with ports as necessary") + .value_parser(flags_net::validator) + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("allow-env") - .long("allow-env") - .short('E') - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("VARIABLE_NAME") - .help("Allow access to system environment information. Optionally specify accessible environment variables") - .value_parser(|key: &str| { - if key.is_empty() || key.contains(&['=', '\0'] as &[char]) { - return Err(format!("invalid key \"{key}\"")); - } + { + let mut arg = Arg::new("allow-env") + .long("allow-env") + .short('E') + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("VARIABLE_NAME") + .help("Allow access to system environment information. Optionally specify accessible environment variables") + .value_parser(|key: &str| { + if key.is_empty() || key.contains(&['=', '\0'] as &[char]) { + return Err(format!("invalid key \"{key}\"")); + } - Ok(if cfg!(windows) { - key.to_uppercase() - } else { - key.to_string() + Ok(if cfg!(windows) { + key.to_uppercase() + } else { + key.to_string() + }) }) - }) - .hide(true), + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("deny-env") - .long("deny-env") - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("VARIABLE_NAME") - .help("Deny access to system environment information. Optionally specify accessible environment variables") - .value_parser(|key: &str| { - if key.is_empty() || key.contains(&['=', '\0'] as &[char]) { - return Err(format!("invalid key \"{key}\"")); - } + { + let mut arg = Arg::new("deny-env") + .long("deny-env") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("VARIABLE_NAME") + .help("Deny access to system environment information. Optionally specify accessible environment variables") + .value_parser(|key: &str| { + if key.is_empty() || key.contains(&['=', '\0'] as &[char]) { + return Err(format!("invalid key \"{key}\"")); + } - Ok(if cfg!(windows) { - key.to_uppercase() - } else { - key.to_string() + Ok(if cfg!(windows) { + key.to_uppercase() + } else { + key.to_string() + }) }) - }) - .hide(true), + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("allow-sys") - .long("allow-sys") - .short('S') - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("API_NAME") - .help("Allow access to OS information. Optionally allow specific APIs by function name") - .value_parser(|key: &str| parse_sys_kind(key).map(ToString::to_string)) - .hide(true), + { + let mut arg = Arg::new("allow-sys") + .long("allow-sys") + .short('S') + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("API_NAME") + .help("Allow access to OS information. Optionally allow specific APIs by function name") + .value_parser(|key: &str| parse_sys_kind(key).map(ToString::to_string)) + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("deny-sys") - .long("deny-sys") - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("API_NAME") - .help("Deny access to OS information. Optionally deny specific APIs by function name") - .value_parser(|key: &str| parse_sys_kind(key).map(ToString::to_string)) - .hide(true), + { + let mut arg = Arg::new("deny-sys") + .long("deny-sys") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("API_NAME") + .help("Deny access to OS information. Optionally deny specific APIs by function name") + .value_parser(|key: &str| parse_sys_kind(key).map(ToString::to_string)) + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("allow-run") - .long("allow-run") - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("PROGRAM_NAME") - .help("Allow running subprocesses. Optionally specify allowed runnable program names") - .hide(true), + { + let mut arg = Arg::new("allow-run") + .long("allow-run") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("PROGRAM_NAME") + .help("Allow running subprocesses. Optionally specify allowed runnable program names") + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("deny-run") - .long("deny-run") - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("PROGRAM_NAME") - .help("Deny running subprocesses. Optionally specify denied runnable program names") - .hide(true), + { + let mut arg = Arg::new("deny-run") + .long("deny-run") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("PROGRAM_NAME") + .help("Deny running subprocesses. Optionally specify denied runnable program names") + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + + } ) .arg( - Arg::new("allow-ffi") - .long("allow-ffi") - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("PATH") - .help("(Unstable) Allow loading dynamic libraries. Optionally specify allowed directories or files") - .value_parser(value_parser!(String)) - .value_hint(ValueHint::AnyPath) - .hide(true), + { + let mut arg = Arg::new("allow-ffi") + .long("allow-ffi") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("PATH") + .help("(Unstable) Allow loading dynamic libraries. Optionally specify allowed directories or files") + .value_parser(value_parser!(String)) + .value_hint(ValueHint::AnyPath) + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("deny-ffi") - .long("deny-ffi") - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("PATH") - .help("(Unstable) Deny loading dynamic libraries. Optionally specify denied directories or files") - .value_parser(value_parser!(String)) - .value_hint(ValueHint::AnyPath) - .hide(true), + { + let mut arg = Arg::new("deny-ffi") + .long("deny-ffi") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("PATH") + .help("(Unstable) Deny loading dynamic libraries. Optionally specify denied directories or files") + .value_parser(value_parser!(String)) + .value_hint(ValueHint::AnyPath) + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("allow-hrtime") - .long("allow-hrtime") - .action(ArgAction::SetTrue) - .help("REMOVED in Deno 2.0") - .hide(true), + { + let mut arg = Arg::new("allow-hrtime") + .long("allow-hrtime") + .action(ArgAction::SetTrue) + .help("REMOVED in Deno 2.0") + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("deny-hrtime") - .long("deny-hrtime") - .action(ArgAction::SetTrue) - .help("REMOVED in Deno 2.0") - .hide(true), + { + let mut arg = Arg::new("deny-hrtime") + .long("deny-hrtime") + .action(ArgAction::SetTrue) + .help("REMOVED in Deno 2.0") + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("no-prompt") - .long("no-prompt") - .action(ArgAction::SetTrue) - .hide(true) - .help("Always throw if required permission wasn't passed"), + { + let mut arg = Arg::new("no-prompt") + .long("no-prompt") + .action(ArgAction::SetTrue) + .hide(true) + .help("Always throw if required permission wasn't passed"); + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) } @@ -3316,7 +3514,7 @@ fn runtime_args( ) -> Command { let app = compile_args(app); let app = if include_perms { - permission_args(app) + permission_args(app, None) } else { app }; @@ -4242,15 +4440,32 @@ fn install_parse(flags: &mut Flags, matches: &mut ArgMatches) { force, }), }); - } else { - let local_flags = matches - .remove_many("cmd") - .map(|packages| add_parse_inner(matches, Some(packages))); - allow_scripts_arg_parse(flags, matches); + return; + } + + // allow scripts only applies to local install + allow_scripts_arg_parse(flags, matches); + if matches.get_flag("entrypoint") { + let entrypoints = matches.remove_many::("cmd").unwrap_or_default(); flags.subcommand = DenoSubcommand::Install(InstallFlags { global, - kind: InstallKind::Local(local_flags), + kind: InstallKind::Local(InstallFlagsLocal::Entrypoints( + entrypoints.collect(), + )), + }); + } else if let Some(add_files) = matches + .remove_many("cmd") + .map(|packages| add_parse_inner(matches, Some(packages))) + { + flags.subcommand = DenoSubcommand::Install(InstallFlags { + global, + kind: InstallKind::Local(InstallFlagsLocal::Add(add_files)), }) + } else { + flags.subcommand = DenoSubcommand::Install(InstallFlags { + global, + kind: InstallKind::Local(InstallFlagsLocal::TopLevel), + }); } } @@ -10296,4 +10511,15 @@ mod tests { assert_eq!(long_flag, subcommand, "{} subcommand", command.get_name()); } } + + #[test] + fn install_permissions_non_global() { + let r = + flags_from_vec(svec!["deno", "install", "--allow-net", "jsr:@std/fs"]); + + assert!(r + .unwrap_err() + .to_string() + .contains("Note: Permission flags can only be used in a global setting")); + } } diff --git a/cli/args/mod.rs b/cli/args/mod.rs index be8eccd6c3..f7623323fe 100644 --- a/cli/args/mod.rs +++ b/cli/args/mod.rs @@ -42,9 +42,10 @@ pub use deno_config::deno_json::TsConfigForEmit; pub use deno_config::deno_json::TsConfigType; pub use deno_config::deno_json::TsTypeLib; pub use deno_config::glob::FilePatterns; +pub use deno_json::check_warn_tsconfig; pub use flags::*; pub use lockfile::CliLockfile; -pub use package_json::PackageJsonInstallDepsProvider; +pub use package_json::NpmInstallDepsProvider; use deno_ast::ModuleSpecifier; use deno_core::anyhow::bail; @@ -1220,7 +1221,7 @@ impl CliOptions { if let Some(flag) = self.flags.node_modules_dir { return Ok(Some(flag)); } - self.workspace().node_modules_dir_mode().map_err(Into::into) + self.workspace().node_modules_dir().map_err(Into::into) } pub fn vendor_dir_path(&self) -> Option<&PathBuf> { @@ -1731,7 +1732,7 @@ fn resolve_node_modules_folder( Some(mode.uses_node_modules_dir()) } else { workspace - .node_modules_dir_mode()? + .node_modules_dir()? .map(|m| m.uses_node_modules_dir()) .or(flags.vendor) .or_else(|| root_folder.deno_json.as_ref().and_then(|c| c.json.vendor)) diff --git a/cli/args/package_json.rs b/cli/args/package_json.rs index eedd0a1941..b9f0919d5d 100644 --- a/cli/args/package_json.rs +++ b/cli/args/package_json.rs @@ -1,17 +1,20 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use std::collections::HashSet; use std::path::PathBuf; use std::sync::Arc; use deno_config::workspace::Workspace; +use deno_core::serde_json; use deno_package_json::PackageJsonDepValue; +use deno_semver::npm::NpmPackageReqReference; use deno_semver::package::PackageReq; +use crate::util::path::is_banned_path_char; + #[derive(Debug)] pub struct InstallNpmRemotePkg { pub alias: String, - // todo(24419): use this when setting up the node_modules dir - #[allow(dead_code)] pub base_dir: PathBuf, pub req: PackageReq, } @@ -19,74 +22,126 @@ pub struct InstallNpmRemotePkg { #[derive(Debug)] pub struct InstallNpmWorkspacePkg { pub alias: String, - // todo(24419): use this when setting up the node_modules dir - #[allow(dead_code)] - pub base_dir: PathBuf, pub target_dir: PathBuf, } #[derive(Debug, Default)] -pub struct PackageJsonInstallDepsProvider { +pub struct NpmInstallDepsProvider { remote_pkgs: Vec, workspace_pkgs: Vec, } -impl PackageJsonInstallDepsProvider { +impl NpmInstallDepsProvider { pub fn empty() -> Self { Self::default() } pub fn from_workspace(workspace: &Arc) -> Self { + // todo(dsherret): estimate capacity? let mut workspace_pkgs = Vec::new(); let mut remote_pkgs = Vec::new(); let workspace_npm_pkgs = workspace.npm_packages(); - for pkg_json in workspace.package_jsons() { - let deps = pkg_json.resolve_local_package_json_deps(); - let mut pkg_pkgs = Vec::with_capacity(deps.len()); - for (alias, dep) in deps { - let Ok(dep) = dep else { - continue; - }; - match dep { - PackageJsonDepValue::Req(pkg_req) => { - let workspace_pkg = workspace_npm_pkgs.iter().find(|pkg| { - pkg.matches_req(&pkg_req) - // do not resolve to the current package - && pkg.pkg_json.path != pkg_json.path - }); + + for (_, folder) in workspace.config_folders() { + let mut deno_json_aliases = HashSet::new(); + + // deal with the deno.json first because it takes precedence during resolution + if let Some(deno_json) = &folder.deno_json { + // don't bother with externally referenced import maps as users + // should inline their import map to get this behaviour + if let Some(serde_json::Value::Object(obj)) = &deno_json.json.imports { + deno_json_aliases.reserve(obj.len()); + let mut pkg_pkgs = Vec::with_capacity(obj.len()); + for (alias, value) in obj { + let serde_json::Value::String(specifier) = value else { + continue; + }; + let Ok(npm_req_ref) = NpmPackageReqReference::from_str(specifier) + else { + continue; + }; + // skip any aliases with banned characters + if alias.chars().any(|c| c == '\\' || is_banned_path_char(c)) { + continue; + } + deno_json_aliases.insert(alias.to_lowercase()); + let pkg_req = npm_req_ref.into_inner().req; + let workspace_pkg = workspace_npm_pkgs + .iter() + .find(|pkg| pkg.matches_req(&pkg_req)); if let Some(pkg) = workspace_pkg { workspace_pkgs.push(InstallNpmWorkspacePkg { - alias, - base_dir: pkg_json.dir_path().to_path_buf(), + alias: alias.to_string(), target_dir: pkg.pkg_json.dir_path().to_path_buf(), }); } else { pkg_pkgs.push(InstallNpmRemotePkg { - alias, - base_dir: pkg_json.dir_path().to_path_buf(), + alias: alias.to_string(), + base_dir: deno_json.dir_path(), req: pkg_req, }); } } - PackageJsonDepValue::Workspace(version_req) => { - if let Some(pkg) = workspace_npm_pkgs.iter().find(|pkg| { - pkg.matches_name_and_version_req(&alias, &version_req) - }) { - workspace_pkgs.push(InstallNpmWorkspacePkg { - alias, - base_dir: pkg_json.dir_path().to_path_buf(), - target_dir: pkg.pkg_json.dir_path().to_path_buf(), + + // sort within each package (more like npm resolution) + pkg_pkgs.sort_by(|a, b| a.alias.cmp(&b.alias)); + remote_pkgs.extend(pkg_pkgs); + } + } + + if let Some(pkg_json) = &folder.pkg_json { + let deps = pkg_json.resolve_local_package_json_deps(); + let mut pkg_pkgs = Vec::with_capacity(deps.len()); + for (alias, dep) in deps { + let Ok(dep) = dep else { + continue; + }; + if deno_json_aliases.contains(&alias.to_lowercase()) { + // aliases in deno.json take precedence over package.json, so + // since this can't be resolved don't bother installing it + continue; + } + match dep { + PackageJsonDepValue::Req(pkg_req) => { + let workspace_pkg = workspace_npm_pkgs.iter().find(|pkg| { + pkg.matches_req(&pkg_req) + // do not resolve to the current package + && pkg.pkg_json.path != pkg_json.path }); + + if let Some(pkg) = workspace_pkg { + workspace_pkgs.push(InstallNpmWorkspacePkg { + alias, + target_dir: pkg.pkg_json.dir_path().to_path_buf(), + }); + } else { + pkg_pkgs.push(InstallNpmRemotePkg { + alias, + base_dir: pkg_json.dir_path().to_path_buf(), + req: pkg_req, + }); + } + } + PackageJsonDepValue::Workspace(version_req) => { + if let Some(pkg) = workspace_npm_pkgs.iter().find(|pkg| { + pkg.matches_name_and_version_req(&alias, &version_req) + }) { + workspace_pkgs.push(InstallNpmWorkspacePkg { + alias, + target_dir: pkg.pkg_json.dir_path().to_path_buf(), + }); + } } } } - } - // sort within each package - pkg_pkgs.sort_by(|a, b| a.alias.cmp(&b.alias)); - remote_pkgs.extend(pkg_pkgs); + // sort within each package as npm does + pkg_pkgs.sort_by(|a, b| a.alias.cmp(&b.alias)); + remote_pkgs.extend(pkg_pkgs); + } } + remote_pkgs.shrink_to_fit(); workspace_pkgs.shrink_to_fit(); Self { diff --git a/cli/bench/deno_common.js b/cli/bench/deno_common.js index ba88c79ca4..3693333915 100644 --- a/cli/bench/deno_common.js +++ b/cli/bench/deno_common.js @@ -46,8 +46,7 @@ Deno.bench("b64_rt_short", { n: 1e6 }, () => { const buf = new Uint8Array(100); const file = Deno.openSync("/dev/zero"); Deno.bench("read_zero", { n: 5e5 }, () => { - // deno-lint-ignore no-deprecated-deno-api - Deno.readSync(file.rid, buf); + file.readSync(buf); }); } diff --git a/cli/factory.rs b/cli/factory.rs index d1ccac6ceb..81212c7885 100644 --- a/cli/factory.rs +++ b/cli/factory.rs @@ -1,11 +1,12 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +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; -use crate::args::PackageJsonInstallDepsProvider; +use crate::args::NpmInstallDepsProvider; use crate::args::StorageKeyResolver; use crate::args::TsConfigType; use crate::cache::Caches; @@ -386,9 +387,7 @@ impl CliFactory { cache_setting: cli_options.cache_setting(), text_only_progress_bar: self.text_only_progress_bar().clone(), maybe_node_modules_path: cli_options.node_modules_dir_path().cloned(), - package_json_deps_provider: Arc::new(PackageJsonInstallDepsProvider::from_workspace( - cli_options.workspace(), - )), + npm_install_deps_provider: Arc::new(NpmInstallDepsProvider::from_workspace(cli_options.workspace())), npm_system_info: cli_options.npm_system_info(), npmrc: cli_options.npmrc().clone(), lifecycle_scripts: cli_options.lifecycle_scripts_config(), @@ -522,9 +521,7 @@ impl CliFactory { let cli_options = self.cli_options()?; let ts_config_result = cli_options.resolve_ts_config_for_emit(TsConfigType::Emit)?; - if let Some(ignored_options) = ts_config_result.maybe_ignored_options { - warn!("{}", ignored_options); - } + check_warn_tsconfig(&ts_config_result); let (transpile_options, emit_options) = crate::args::ts_config_to_transpile_and_emit_options( ts_config_result.ts_config, diff --git a/cli/graph_util.rs b/cli/graph_util.rs index bfd547a124..f3ac64a434 100644 --- a/cli/graph_util.rs +++ b/cli/graph_util.rs @@ -20,7 +20,7 @@ use crate::tools::check::TypeChecker; use crate::util::file_watcher::WatcherCommunicator; use crate::util::fs::canonicalize_path; use deno_config::workspace::JsrPackageConfig; -use deno_emit::LoaderChecksum; +use deno_graph::source::LoaderChecksum; use deno_graph::JsrLoadError; use deno_graph::ModuleLoadError; use deno_graph::WorkspaceFastCheckOption; @@ -724,12 +724,25 @@ impl ModuleGraphBuilder { pub fn enhanced_resolution_error_message(error: &ResolutionError) -> String { let mut message = format_deno_graph_error(error); - if let Some(specifier) = get_resolution_error_bare_node_specifier(error) { + let maybe_hint = if let Some(specifier) = + get_resolution_error_bare_node_specifier(error) + { if !*DENO_DISABLE_PEDANTIC_NODE_WARNINGS { - message.push_str(&format!( - "\nIf you want to use a built-in Node module, add a \"node:\" prefix (ex. \"node:{specifier}\")." - )); + Some(format!("If you want to use a built-in Node module, add a \"node:\" prefix (ex. \"node:{specifier}\").")) + } else { + None } + } else { + get_import_prefix_missing_error(error).map(|specifier| { + format!( + "If you want to use a JSR or npm package, try running `deno add {}`", + specifier + ) + }) + }; + + if let Some(hint) = maybe_hint { + message.push_str(&format!("\n {} {}", colors::cyan("hint:"), hint)); } message @@ -864,6 +877,45 @@ fn get_resolution_error_bare_specifier( } } +fn get_import_prefix_missing_error(error: &ResolutionError) -> Option<&str> { + let mut maybe_specifier = None; + if let ResolutionError::InvalidSpecifier { + error: SpecifierError::ImportPrefixMissing { specifier, .. }, + .. + } = error + { + maybe_specifier = Some(specifier); + } else if let ResolutionError::ResolverError { error, .. } = error { + match error.as_ref() { + ResolveError::Specifier(specifier_error) => { + if let SpecifierError::ImportPrefixMissing { specifier, .. } = + specifier_error + { + maybe_specifier = Some(specifier); + } + } + ResolveError::Other(other_error) => { + if let Some(SpecifierError::ImportPrefixMissing { specifier, .. }) = + other_error.downcast_ref::() + { + maybe_specifier = Some(specifier); + } + } + } + } + + // NOTE(bartlomieju): For now, return None if a specifier contains a dot or a space. This is because + // suggesting to `deno add bad-module.ts` makes no sense and is worse than not providing + // a suggestion at all. This should be improved further in the future + if let Some(specifier) = maybe_specifier { + if specifier.contains('.') || specifier.contains(' ') { + return None; + } + } + + maybe_specifier.map(|s| s.as_str()) +} + /// Gets if any of the specified root's "file:" dependents are in the /// provided changed set. pub fn has_graph_root_local_dependent_changed( diff --git a/cli/js/40_bench.js b/cli/js/40_bench.js index a94c782fc5..b07df3993c 100644 --- a/cli/js/40_bench.js +++ b/cli/js/40_bench.js @@ -104,12 +104,12 @@ function bench( } if (optionsOrFn.fn != undefined) { throw new TypeError( - "Unexpected 'fn' field in options, bench function is already provided as the third argument.", + "Unexpected 'fn' field in options, bench function is already provided as the third argument", ); } if (optionsOrFn.name != undefined) { throw new TypeError( - "Unexpected 'name' field in options, bench name is already provided as the first argument.", + "Unexpected 'name' field in options, bench name is already provided as the first argument", ); } benchDesc = { @@ -141,7 +141,7 @@ function bench( fn = optionsOrFn; if (nameOrFnOrOptions.fn != undefined) { throw new TypeError( - "Unexpected 'fn' field in options, bench function is already provided as the second argument.", + "Unexpected 'fn' field in options, bench function is already provided as the second argument", ); } name = nameOrFnOrOptions.name ?? fn.name; @@ -150,7 +150,7 @@ function bench( !nameOrFnOrOptions.fn || typeof nameOrFnOrOptions.fn !== "function" ) { throw new TypeError( - "Expected 'fn' field in the first argument to be a bench function.", + "Expected 'fn' field in the first argument to be a bench function", ); } fn = nameOrFnOrOptions.fn; @@ -385,12 +385,12 @@ function createBenchContext(desc) { start() { if (currentBenchId !== desc.id) { throw new TypeError( - "The benchmark which this context belongs to is not being executed.", + "The benchmark which this context belongs to is not being executed", ); } if (currentBenchUserExplicitStart != null) { throw new TypeError( - "BenchContext::start() has already been invoked.", + "BenchContext::start() has already been invoked", ); } currentBenchUserExplicitStart = benchNow(); @@ -399,11 +399,11 @@ function createBenchContext(desc) { const end = benchNow(); if (currentBenchId !== desc.id) { throw new TypeError( - "The benchmark which this context belongs to is not being executed.", + "The benchmark which this context belongs to is not being executed", ); } if (currentBenchUserExplicitEnd != null) { - throw new TypeError("BenchContext::end() has already been invoked."); + throw new TypeError("BenchContext::end() has already been invoked"); } currentBenchUserExplicitEnd = end; }, diff --git a/cli/js/40_test.js b/cli/js/40_test.js index 5a081e2175..ea526a17d4 100644 --- a/cli/js/40_test.js +++ b/cli/js/40_test.js @@ -113,7 +113,7 @@ function assertExit(fn, isTest) { throw new Error( `${ isTest ? "Test case" : "Bench" - } finished with exit code set to ${exitCode}.`, + } finished with exit code set to ${exitCode}`, ); } if (innerResult) { @@ -242,12 +242,12 @@ function testInner( } if (optionsOrFn.fn != undefined) { throw new TypeError( - "Unexpected 'fn' field in options, test function is already provided as the third argument.", + "Unexpected 'fn' field in options, test function is already provided as the third argument", ); } if (optionsOrFn.name != undefined) { throw new TypeError( - "Unexpected 'name' field in options, test name is already provided as the first argument.", + "Unexpected 'name' field in options, test name is already provided as the first argument", ); } testDesc = { @@ -279,7 +279,7 @@ function testInner( fn = optionsOrFn; if (nameOrFnOrOptions.fn != undefined) { throw new TypeError( - "Unexpected 'fn' field in options, test function is already provided as the second argument.", + "Unexpected 'fn' field in options, test function is already provided as the second argument", ); } name = nameOrFnOrOptions.name ?? fn.name; @@ -288,7 +288,7 @@ function testInner( !nameOrFnOrOptions.fn || typeof nameOrFnOrOptions.fn !== "function" ) { throw new TypeError( - "Expected 'fn' field in the first argument to be a test function.", + "Expected 'fn' field in the first argument to be a test function", ); } fn = nameOrFnOrOptions.fn; @@ -426,7 +426,7 @@ function createTestContext(desc) { let stepDesc; if (typeof nameOrFnOrOptions === "string") { if (typeof maybeFn !== "function") { - throw new TypeError("Expected function for second argument."); + throw new TypeError("Expected function for second argument"); } stepDesc = { name: nameOrFnOrOptions, @@ -434,7 +434,7 @@ function createTestContext(desc) { }; } else if (typeof nameOrFnOrOptions === "function") { if (!nameOrFnOrOptions.name) { - throw new TypeError("The step function must have a name."); + throw new TypeError("The step function must have a name"); } if (maybeFn != undefined) { throw new TypeError( @@ -449,7 +449,7 @@ function createTestContext(desc) { stepDesc = nameOrFnOrOptions; } else { throw new TypeError( - "Expected a test definition or name and function.", + "Expected a test definition or name and function", ); } stepDesc.ignore ??= false; diff --git a/cli/lsp/config.rs b/cli/lsp/config.rs index d204dce646..fcea96aa5d 100644 --- a/cli/lsp/config.rs +++ b/cli/lsp/config.rs @@ -1387,10 +1387,8 @@ impl ConfigData { } } - let node_modules_dir = member_dir - .workspace - .node_modules_dir_mode() - .unwrap_or_default(); + let node_modules_dir = + member_dir.workspace.node_modules_dir().unwrap_or_default(); let byonm = match node_modules_dir { Some(mode) => mode == NodeModulesDirMode::Manual, None => member_dir.workspace.root_pkg_json().is_some(), @@ -1697,9 +1695,14 @@ impl ConfigTree { } pub fn is_watched_file(&self, specifier: &ModuleSpecifier) -> bool { - if specifier.path().ends_with("/deno.json") - || specifier.path().ends_with("/deno.jsonc") - || specifier.path().ends_with("/package.json") + let path = specifier.path(); + if path.ends_with("/deno.json") + || path.ends_with("/deno.jsonc") + || path.ends_with("/package.json") + || path.ends_with("/node_modules/.package-lock.json") + || path.ends_with("/node_modules/.yarn-integrity.json") + || path.ends_with("/node_modules/.modules.yaml") + || path.ends_with("/node_modules/.deno/.setup-cache.bin") { return true; } @@ -1868,7 +1871,7 @@ fn resolve_node_modules_dir( // `nodeModulesDir: true` setting in the deno.json file. This is to // reduce the chance of modifying someone's node_modules directory // without them having asked us to do so. - let node_modules_mode = workspace.node_modules_dir_mode().ok().flatten(); + let node_modules_mode = workspace.node_modules_dir().ok().flatten(); let explicitly_disabled = node_modules_mode == Some(NodeModulesDirMode::None); if explicitly_disabled { return None; diff --git a/cli/lsp/documents.rs b/cli/lsp/documents.rs index b58d7292b0..ee9a522974 100644 --- a/cli/lsp/documents.rs +++ b/cli/lsp/documents.rs @@ -1251,7 +1251,7 @@ impl Documents { /// tsc when type checking. pub fn resolve( &self, - specifiers: &[String], + raw_specifiers: &[String], referrer: &ModuleSpecifier, file_referrer: Option<&ModuleSpecifier>, ) -> Vec> { @@ -1262,16 +1262,16 @@ impl Documents { .or(file_referrer); let dependencies = document.as_ref().map(|d| d.dependencies()); let mut results = Vec::new(); - for specifier in specifiers { - if specifier.starts_with("asset:") { - if let Ok(specifier) = ModuleSpecifier::parse(specifier) { + for raw_specifier in raw_specifiers { + if raw_specifier.starts_with("asset:") { + if let Ok(specifier) = ModuleSpecifier::parse(raw_specifier) { let media_type = MediaType::from_specifier(&specifier); results.push(Some((specifier, media_type))); } else { results.push(None); } } else if let Some(dep) = - dependencies.as_ref().and_then(|d| d.get(specifier)) + dependencies.as_ref().and_then(|d| d.get(raw_specifier)) { if let Some(specifier) = dep.maybe_type.maybe_specifier() { results.push(self.resolve_dependency( @@ -1290,7 +1290,7 @@ impl Documents { } } else if let Ok(specifier) = self.resolver.as_graph_resolver(file_referrer).resolve( - specifier, + raw_specifier, &deno_graph::Range { specifier: referrer.clone(), start: deno_graph::Position::zeroed(), diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index 05c54dfc67..2bb13e5e4c 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -966,9 +966,8 @@ impl Inner { .await; for config_file in self.config.tree.config_files() { (|| { - let compiler_options = config_file.to_compiler_options().ok()?.0; - let compiler_options_obj = compiler_options.as_object()?; - let jsx_import_source = compiler_options_obj.get("jsxImportSource")?; + let compiler_options = config_file.to_compiler_options().ok()?.options; + let jsx_import_source = compiler_options.get("jsxImportSource")?; let jsx_import_source = jsx_import_source.as_str()?; let referrer = config_file.specifier.clone(); let specifier = Url::parse(&format!( diff --git a/cli/lsp/resolver.rs b/cli/lsp/resolver.rs index d279031e32..1c3d5c88b2 100644 --- a/cli/lsp/resolver.rs +++ b/cli/lsp/resolver.rs @@ -3,7 +3,7 @@ use crate::args::create_default_npmrc; use crate::args::CacheSetting; use crate::args::CliLockfile; -use crate::args::PackageJsonInstallDepsProvider; +use crate::args::NpmInstallDepsProvider; use crate::graph_util::CliJsrUrlProvider; use crate::http_util::HttpClientProvider; use crate::lsp::config::Config; @@ -474,9 +474,7 @@ async fn create_npm_resolver( maybe_node_modules_path: config_data .and_then(|d| d.node_modules_dir.clone()), // only used for top level install, so we can ignore this - package_json_deps_provider: Arc::new( - PackageJsonInstallDepsProvider::empty(), - ), + npm_install_deps_provider: Arc::new(NpmInstallDepsProvider::empty()), npmrc: config_data .and_then(|d| d.npmrc.clone()) .unwrap_or_else(create_default_npmrc), diff --git a/cli/main.rs b/cli/main.rs index c963cb21ca..c0899ee100 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -32,7 +32,6 @@ mod worker; use crate::args::flags_from_vec; use crate::args::DenoSubcommand; use crate::args::Flags; -use crate::graph_container::ModuleGraphContainer; use crate::util::display; use crate::util::v8::get_v8_flags_from_env; use crate::util::v8::init_v8_flags; @@ -118,14 +117,7 @@ async fn run_subcommand(flags: Arc) -> Result { tools::run::eval_command(flags, eval_flags).await }), DenoSubcommand::Cache(cache_flags) => spawn_subcommand(async move { - let factory = CliFactory::from_flags(flags); - let emitter = factory.emitter()?; - let main_graph_container = - factory.main_module_graph_container().await?; - main_graph_container - .load_and_type_check_files(&cache_flags.files) - .await?; - emitter.cache_module_emits(&main_graph_container.graph()).await + tools::installer::install_from_entrypoints(flags, &cache_flags.files).await }), DenoSubcommand::Check(check_flags) => spawn_subcommand(async move { let factory = CliFactory::from_flags(flags); diff --git a/cli/module_loader.rs b/cli/module_loader.rs index 3208d13657..186eb02101 100644 --- a/cli/module_loader.rs +++ b/cli/module_loader.rs @@ -401,7 +401,7 @@ impl fn inner_resolve( &self, - specifier: &str, + raw_specifier: &str, referrer: &ModuleSpecifier, ) -> Result { if self.shared.node_resolver.in_npm_package(referrer) { @@ -409,7 +409,7 @@ impl self .shared .node_resolver - .resolve(specifier, referrer, NodeResolutionMode::Execution)? + .resolve(raw_specifier, referrer, NodeResolutionMode::Execution)? .into_url(), ); } @@ -418,7 +418,7 @@ impl let resolution = match graph.get(referrer) { Some(Module::Js(module)) => module .dependencies - .get(specifier) + .get(raw_specifier) .map(|d| &d.maybe_code) .unwrap_or(&Resolution::None), _ => &Resolution::None, @@ -433,7 +433,7 @@ impl )); } Resolution::None => Cow::Owned(self.shared.resolver.resolve( - specifier, + raw_specifier, &deno_graph::Range { specifier: referrer.clone(), start: deno_graph::Position::zeroed(), diff --git a/cli/napi/sym/Cargo.toml b/cli/napi/sym/Cargo.toml index 909421adbb..eba5fa41cf 100644 --- a/cli/napi/sym/Cargo.toml +++ b/cli/napi/sym/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "napi_sym" -version = "0.97.0" +version = "0.98.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/cli/npm/byonm.rs b/cli/npm/byonm.rs index e62650d8a9..3249b2ed19 100644 --- a/cli/npm/byonm.rs +++ b/cli/npm/byonm.rs @@ -17,6 +17,7 @@ use deno_runtime::deno_node::NodeRequireResolver; use deno_runtime::deno_node::NpmProcessStateProvider; use deno_runtime::deno_node::PackageJson; use deno_semver::package::PackageReq; +use deno_semver::Version; use node_resolver::errors::PackageFolderResolveError; use node_resolver::errors::PackageFolderResolveIoError; use node_resolver::errors::PackageJsonLoadError; @@ -29,6 +30,7 @@ use crate::args::NpmProcessStateKind; use crate::util::fs::canonicalize_path_maybe_not_exists_with_fs; use deno_runtime::fs_util::specifier_to_file_path; +use super::managed::normalize_pkg_name_for_node_modules_deno_folder; use super::CliNpmResolver; use super::InnerCliNpmResolverRef; @@ -60,9 +62,7 @@ impl ByonmCliNpmResolver { ) -> Result>, PackageJsonLoadError> { load_pkg_json(&DenoPkgJsonFsAdapter(self.fs.as_ref()), path) } -} -impl ByonmCliNpmResolver { /// Finds the ancestor package.json that contains the specified dependency. pub fn find_ancestor_package_json_with_dep( &self, @@ -98,7 +98,7 @@ impl ByonmCliNpmResolver { &self, req: &PackageReq, referrer: &ModuleSpecifier, - ) -> Result<(Arc, String), AnyError> { + ) -> Result, String)>, AnyError> { fn resolve_alias_from_pkg_json( req: &PackageReq, pkg_json: &PackageJson, @@ -134,7 +134,7 @@ impl ByonmCliNpmResolver { if let Some(alias) = resolve_alias_from_pkg_json(req, pkg_json.as_ref()) { - return Ok((pkg_json, alias)); + return Ok(Some((pkg_json, alias))); } } current_path = dir_path; @@ -148,19 +148,65 @@ impl ByonmCliNpmResolver { if let Some(pkg_json) = self.load_pkg_json(&root_pkg_json_path)? { if let Some(alias) = resolve_alias_from_pkg_json(req, pkg_json.as_ref()) { - return Ok((pkg_json, alias)); + return Ok(Some((pkg_json, alias))); } } } - bail!( - concat!( - "Could not find a matching package for 'npm:{}' in a package.json file. ", - "You must specify this as a package.json dependency when the ", - "node_modules folder is not managed by Deno.", - ), - req, + Ok(None) + } + + fn resolve_folder_in_root_node_modules( + &self, + req: &PackageReq, + ) -> Option { + // now check if node_modules/.deno/ matches this constraint + let root_node_modules_dir = self.root_node_modules_dir.as_ref()?; + let node_modules_deno_dir = root_node_modules_dir.join(".deno"); + let Ok(entries) = self.fs.read_dir_sync(&node_modules_deno_dir) else { + return None; + }; + let search_prefix = format!( + "{}@", + normalize_pkg_name_for_node_modules_deno_folder(&req.name) ); + let mut best_version = None; + + // example entries: + // - @denotest+add@1.0.0 + // - @denotest+add@1.0.0_1 + for entry in entries { + if !entry.is_directory { + continue; + } + let Some(version_and_copy_idx) = entry.name.strip_prefix(&search_prefix) + else { + continue; + }; + let version = version_and_copy_idx + .rsplit_once('_') + .map(|(v, _)| v) + .unwrap_or(version_and_copy_idx); + let Ok(version) = Version::parse_from_npm(version) else { + continue; + }; + if req.version_req.matches(&version) { + if let Some((best_version_version, _)) = &best_version { + if version > *best_version_version { + best_version = Some((version, entry.name)); + } + } else { + best_version = Some((version, entry.name)); + } + } + } + + best_version.map(|(_version, entry_name)| { + join_package_name( + &node_modules_deno_dir.join(entry_name).join("node_modules"), + &req.name, + ) + }) } } @@ -288,29 +334,62 @@ impl CliNpmResolver for ByonmCliNpmResolver { req: &PackageReq, referrer: &ModuleSpecifier, ) -> Result { - // resolve the pkg json and alias - let (pkg_json, alias) = - self.resolve_pkg_json_and_alias_for_req(req, referrer)?; - // now try node resolution - for ancestor in pkg_json.path.parent().unwrap().ancestors() { - let node_modules_folder = ancestor.join("node_modules"); - let sub_dir = join_package_name(&node_modules_folder, &alias); - if self.fs.is_dir_sync(&sub_dir) { - return Ok(canonicalize_path_maybe_not_exists_with_fs( - &sub_dir, - self.fs.as_ref(), - )?); + fn node_resolve_dir( + fs: &dyn FileSystem, + alias: &str, + start_dir: &Path, + ) -> Result, AnyError> { + for ancestor in start_dir.ancestors() { + let node_modules_folder = ancestor.join("node_modules"); + let sub_dir = join_package_name(&node_modules_folder, alias); + if fs.is_dir_sync(&sub_dir) { + return Ok(Some(canonicalize_path_maybe_not_exists_with_fs( + &sub_dir, fs, + )?)); + } } + Ok(None) } - bail!( - concat!( - "Could not find \"{}\" in a node_modules folder. ", - "Deno expects the node_modules/ directory to be up to date. ", - "Did you forget to run `deno install`?" - ), - alias, - ); + // now attempt to resolve if it's found in any package.json + let maybe_pkg_json_and_alias = + self.resolve_pkg_json_and_alias_for_req(req, referrer)?; + match maybe_pkg_json_and_alias { + Some((pkg_json, alias)) => { + // now try node resolution + if let Some(resolved) = + node_resolve_dir(self.fs.as_ref(), &alias, pkg_json.dir_path())? + { + return Ok(resolved); + } + + bail!( + concat!( + "Could not find \"{}\" in a node_modules folder. ", + "Deno expects the node_modules/ directory to be up to date. ", + "Did you forget to run `deno install`?" + ), + alias, + ); + } + None => { + // now check if node_modules/.deno/ matches this constraint + if let Some(folder) = self.resolve_folder_in_root_node_modules(req) { + return Ok(folder); + } + + bail!( + concat!( + "Could not find a matching package for 'npm:{}' in the node_modules ", + "directory. Ensure you have all your JSR and npm dependencies listed ", + "in your deno.json or package.json, then run `deno install`. Alternatively, ", + r#"turn on auto-install by specifying `"nodeModulesDir": "auto"` in your "#, + "deno.json file." + ), + req, + ); + } + } } fn check_state_hash(&self) -> Option { diff --git a/cli/npm/managed/mod.rs b/cli/npm/managed/mod.rs index a0148c6482..0be26b7857 100644 --- a/cli/npm/managed/mod.rs +++ b/cli/npm/managed/mod.rs @@ -32,9 +32,9 @@ use resolution::AddPkgReqsResult; use crate::args::CliLockfile; use crate::args::LifecycleScriptsConfig; +use crate::args::NpmInstallDepsProvider; use crate::args::NpmProcessState; use crate::args::NpmProcessStateKind; -use crate::args::PackageJsonInstallDepsProvider; use crate::cache::FastInsecureHasher; use crate::http_util::HttpClientProvider; use crate::util::fs::canonicalize_path_maybe_not_exists_with_fs; @@ -45,6 +45,7 @@ use self::cache::NpmCache; use self::registry::CliNpmRegistryApi; use self::resolution::NpmResolution; use self::resolvers::create_npm_fs_resolver; +pub use self::resolvers::normalize_pkg_name_for_node_modules_deno_folder; use self::resolvers::NpmPackageFsResolver; use super::CliNpmResolver; @@ -71,7 +72,7 @@ pub struct CliNpmResolverManagedCreateOptions { pub text_only_progress_bar: crate::util::progress_bar::ProgressBar, pub maybe_node_modules_path: Option, pub npm_system_info: NpmSystemInfo, - pub package_json_deps_provider: Arc, + pub npm_install_deps_provider: Arc, pub npmrc: Arc, pub lifecycle_scripts: LifecycleScriptsConfig, } @@ -97,7 +98,7 @@ pub async fn create_managed_npm_resolver_for_lsp( npm_api, npm_cache, options.npmrc, - options.package_json_deps_provider, + options.npm_install_deps_provider, options.text_only_progress_bar, options.maybe_node_modules_path, options.npm_system_info, @@ -122,7 +123,7 @@ pub async fn create_managed_npm_resolver( npm_api, npm_cache, options.npmrc, - options.package_json_deps_provider, + options.npm_install_deps_provider, options.text_only_progress_bar, options.maybe_node_modules_path, options.npm_system_info, @@ -139,7 +140,7 @@ fn create_inner( npm_api: Arc, npm_cache: Arc, npm_rc: Arc, - package_json_deps_provider: Arc, + npm_install_deps_provider: Arc, text_only_progress_bar: crate::util::progress_bar::ProgressBar, node_modules_dir_path: Option, npm_system_info: NpmSystemInfo, @@ -161,7 +162,7 @@ fn create_inner( let fs_resolver = create_npm_fs_resolver( fs.clone(), npm_cache.clone(), - &package_json_deps_provider, + &npm_install_deps_provider, &text_only_progress_bar, resolution.clone(), tarball_cache.clone(), @@ -175,7 +176,7 @@ fn create_inner( maybe_lockfile, npm_api, npm_cache, - package_json_deps_provider, + npm_install_deps_provider, resolution, tarball_cache, text_only_progress_bar, @@ -261,7 +262,7 @@ pub struct ManagedCliNpmResolver { maybe_lockfile: Option>, npm_api: Arc, npm_cache: Arc, - package_json_deps_provider: Arc, + npm_install_deps_provider: Arc, resolution: Arc, tarball_cache: Arc, text_only_progress_bar: ProgressBar, @@ -286,7 +287,7 @@ impl ManagedCliNpmResolver { maybe_lockfile: Option>, npm_api: Arc, npm_cache: Arc, - package_json_deps_provider: Arc, + npm_install_deps_provider: Arc, resolution: Arc, tarball_cache: Arc, text_only_progress_bar: ProgressBar, @@ -299,7 +300,7 @@ impl ManagedCliNpmResolver { maybe_lockfile, npm_api, npm_cache, - package_json_deps_provider, + npm_install_deps_provider, text_only_progress_bar, resolution, tarball_cache, @@ -476,7 +477,7 @@ impl ManagedCliNpmResolver { if !self.top_level_install_flag.raise() { return Ok(false); // already did this } - let pkg_json_remote_pkgs = self.package_json_deps_provider.remote_pkgs(); + let pkg_json_remote_pkgs = self.npm_install_deps_provider.remote_pkgs(); if pkg_json_remote_pkgs.is_empty() { return Ok(false); } @@ -605,7 +606,7 @@ impl CliNpmResolver for ManagedCliNpmResolver { create_npm_fs_resolver( self.fs.clone(), self.npm_cache.clone(), - &self.package_json_deps_provider, + &self.npm_install_deps_provider, &self.text_only_progress_bar, npm_resolution.clone(), self.tarball_cache.clone(), @@ -616,7 +617,7 @@ impl CliNpmResolver for ManagedCliNpmResolver { self.maybe_lockfile.clone(), self.npm_api.clone(), self.npm_cache.clone(), - self.package_json_deps_provider.clone(), + self.npm_install_deps_provider.clone(), npm_resolution, self.tarball_cache.clone(), self.text_only_progress_bar.clone(), diff --git a/cli/npm/managed/resolvers/local.rs b/cli/npm/managed/resolvers/local.rs index 6ac83ee949..eb6f9de9b5 100644 --- a/cli/npm/managed/resolvers/local.rs +++ b/cli/npm/managed/resolvers/local.rs @@ -41,7 +41,7 @@ use node_resolver::errors::ReferrerNotFoundError; use serde::Deserialize; use serde::Serialize; -use crate::args::PackageJsonInstallDepsProvider; +use crate::args::NpmInstallDepsProvider; use crate::cache::CACHE_PERM; use crate::npm::cache_dir::mixed_case_package_name_decode; use crate::npm::cache_dir::mixed_case_package_name_encode; @@ -65,7 +65,7 @@ use super::common::RegistryReadPermissionChecker; pub struct LocalNpmPackageResolver { cache: Arc, fs: Arc, - pkg_json_deps_provider: Arc, + npm_install_deps_provider: Arc, progress_bar: ProgressBar, resolution: Arc, tarball_cache: Arc, @@ -81,7 +81,7 @@ impl LocalNpmPackageResolver { pub fn new( cache: Arc, fs: Arc, - pkg_json_deps_provider: Arc, + npm_install_deps_provider: Arc, progress_bar: ProgressBar, resolution: Arc, tarball_cache: Arc, @@ -92,7 +92,7 @@ impl LocalNpmPackageResolver { Self { cache, fs: fs.clone(), - pkg_json_deps_provider, + npm_install_deps_provider, progress_bar, resolution, tarball_cache, @@ -248,7 +248,7 @@ impl NpmPackageFsResolver for LocalNpmPackageResolver { sync_resolution_with_fs( &self.resolution.snapshot(), &self.cache, - &self.pkg_json_deps_provider, + &self.npm_install_deps_provider, &self.progress_bar, &self.tarball_cache, &self.root_node_modules_path, @@ -412,14 +412,16 @@ fn has_lifecycle_scripts( async fn sync_resolution_with_fs( snapshot: &NpmResolutionSnapshot, cache: &Arc, - pkg_json_deps_provider: &PackageJsonInstallDepsProvider, + npm_install_deps_provider: &NpmInstallDepsProvider, progress_bar: &ProgressBar, tarball_cache: &Arc, root_node_modules_dir_path: &Path, system_info: &NpmSystemInfo, lifecycle_scripts: &LifecycleScriptsConfig, ) -> Result<(), AnyError> { - if snapshot.is_empty() && pkg_json_deps_provider.workspace_pkgs().is_empty() { + if snapshot.is_empty() + && npm_install_deps_provider.workspace_pkgs().is_empty() + { return Ok(()); // don't create the directory } @@ -620,7 +622,7 @@ async fn sync_resolution_with_fs( // 4. Create symlinks for package json dependencies { - for remote in pkg_json_deps_provider.remote_pkgs() { + for remote in npm_install_deps_provider.remote_pkgs() { let remote_pkg = if let Ok(remote_pkg) = snapshot.resolve_pkg_from_pkg_req(&remote.req) { @@ -684,7 +686,7 @@ async fn sync_resolution_with_fs( } // 5. Create symlinks for the remaining top level packages in the node_modules folder. - // (These may be present if they are not in the package.json dependencies, such as ) + // (These may be present if they are not in the package.json dependencies) // Symlink node_modules/.deno//node_modules/ to // node_modules/ let mut ids = snapshot @@ -757,10 +759,10 @@ async fn sync_resolution_with_fs( // 8. Create symlinks for the workspace packages { - // todo(#24419): this is not exactly correct because it should + // todo(dsherret): this is not exactly correct because it should // install correctly for a workspace (potentially in sub directories), // but this is good enough for a first pass - for workspace in pkg_json_deps_provider.workspace_pkgs() { + for workspace in npm_install_deps_provider.workspace_pkgs() { symlink_package_dir( &workspace.target_dir, &root_node_modules_dir_path.join(&workspace.alias), @@ -985,21 +987,31 @@ impl SetupCache { } } +/// Normalizes a package name for use at `node_modules/.deno/@[_]` +pub fn normalize_pkg_name_for_node_modules_deno_folder(name: &str) -> Cow { + let name = if name.to_lowercase() == name { + Cow::Borrowed(name) + } else { + Cow::Owned(format!("_{}", mixed_case_package_name_encode(name))) + }; + if name.starts_with('@') { + name.replace('/', "+").into() + } else { + name + } +} + fn get_package_folder_id_folder_name( folder_id: &NpmPackageCacheFolderId, ) -> String { let copy_str = if folder_id.copy_index == 0 { - "".to_string() + Cow::Borrowed("") } else { - format!("_{}", folder_id.copy_index) + Cow::Owned(format!("_{}", folder_id.copy_index)) }; let nv = &folder_id.nv; - let name = if nv.name.to_lowercase() == nv.name { - Cow::Borrowed(&nv.name) - } else { - Cow::Owned(format!("_{}", mixed_case_package_name_encode(&nv.name))) - }; - format!("{}@{}{}", name, nv.version, copy_str).replace('/', "+") + let name = normalize_pkg_name_for_node_modules_deno_folder(&nv.name); + format!("{}@{}{}", name, nv.version, copy_str) } fn get_package_folder_id_from_folder_name( diff --git a/cli/npm/managed/resolvers/mod.rs b/cli/npm/managed/resolvers/mod.rs index 2dfc323e91..f5d9e4b057 100644 --- a/cli/npm/managed/resolvers/mod.rs +++ b/cli/npm/managed/resolvers/mod.rs @@ -11,10 +11,11 @@ use deno_npm::NpmSystemInfo; use deno_runtime::deno_fs::FileSystem; use crate::args::LifecycleScriptsConfig; -use crate::args::PackageJsonInstallDepsProvider; +use crate::args::NpmInstallDepsProvider; use crate::util::progress_bar::ProgressBar; pub use self::common::NpmPackageFsResolver; +pub use self::local::normalize_pkg_name_for_node_modules_deno_folder; use self::global::GlobalNpmPackageResolver; use self::local::LocalNpmPackageResolver; @@ -27,7 +28,7 @@ use super::resolution::NpmResolution; pub fn create_npm_fs_resolver( fs: Arc, npm_cache: Arc, - pkg_json_deps_provider: &Arc, + npm_install_deps_provider: &Arc, progress_bar: &ProgressBar, resolution: Arc, tarball_cache: Arc, @@ -39,7 +40,7 @@ pub fn create_npm_fs_resolver( Some(node_modules_folder) => Arc::new(LocalNpmPackageResolver::new( npm_cache, fs, - pkg_json_deps_provider.clone(), + npm_install_deps_provider.clone(), progress_bar.clone(), resolution, tarball_cache, diff --git a/cli/resolver.rs b/cli/resolver.rs index 3f5f79f778..987e23ee11 100644 --- a/cli/resolver.rs +++ b/cli/resolver.rs @@ -502,7 +502,7 @@ impl Resolver for CliGraphResolver { fn resolve( &self, - specifier: &str, + raw_specifier: &str, referrer_range: &deno_graph::Range, mode: ResolutionMode, ) -> Result { @@ -519,7 +519,7 @@ impl Resolver for CliGraphResolver { if let Some(node_resolver) = self.node_resolver.as_ref() { if referrer.scheme() == "file" && node_resolver.in_npm_package(referrer) { return node_resolver - .resolve(specifier, referrer, to_node_mode(mode)) + .resolve(raw_specifier, referrer, to_node_mode(mode)) .map(|res| res.into_url()) .map_err(|e| ResolveError::Other(e.into())); } @@ -528,7 +528,7 @@ impl Resolver for CliGraphResolver { // Attempt to resolve with the workspace resolver let result: Result<_, ResolveError> = self .workspace_resolver - .resolve(specifier, referrer) + .resolve(raw_specifier, referrer) .map_err(|err| match err { MappedResolutionError::Specifier(err) => ResolveError::Specifier(err), MappedResolutionError::ImportMap(err) => { @@ -700,7 +700,7 @@ impl Resolver for CliGraphResolver { // If byonm, check if the bare specifier resolves to an npm package if is_byonm && referrer.scheme() == "file" { let maybe_resolution = node_resolver - .resolve_if_for_npm_pkg(specifier, referrer, to_node_mode(mode)) + .resolve_if_for_npm_pkg(raw_specifier, referrer, to_node_mode(mode)) .map_err(ResolveError::Other)?; if let Some(res) = maybe_resolution { return Ok(res.into_url()); diff --git a/cli/schemas/config-file.v1.json b/cli/schemas/config-file.v1.json index cc2c1eb6ff..df8177af29 100644 --- a/cli/schemas/config-file.v1.json +++ b/cli/schemas/config-file.v1.json @@ -622,6 +622,11 @@ { "type": "object", "description": "A map of package exports to files in this JSR package.", + "propertyNames": { + "description": "Package export name", + "examples": [".", "./foo", "./bar"], + "pattern": "^\\.(/.*)?$" + }, "patternProperties": { "^\\.(/.*)?$": { "type": "string", diff --git a/cli/standalone/binary.rs b/cli/standalone/binary.rs index 45d9b7c63b..27308c9013 100644 --- a/cli/standalone/binary.rs +++ b/cli/standalone/binary.rs @@ -45,7 +45,7 @@ use serde::Serialize; use crate::args::CaData; use crate::args::CliOptions; use crate::args::CompileFlags; -use crate::args::PackageJsonInstallDepsProvider; +use crate::args::NpmInstallDepsProvider; use crate::args::PermissionFlags; use crate::args::UnstableConfig; use crate::cache::DenoDir; diff --git a/cli/standalone/mod.rs b/cli/standalone/mod.rs index a0a312ad9e..f1f687eed5 100644 --- a/cli/standalone/mod.rs +++ b/cli/standalone/mod.rs @@ -48,7 +48,7 @@ use crate::args::get_root_cert_store; use crate::args::npm_pkg_req_ref_to_binary_command; use crate::args::CaData; use crate::args::CacheSetting; -use crate::args::PackageJsonInstallDepsProvider; +use crate::args::NpmInstallDepsProvider; use crate::args::StorageKeyResolver; use crate::cache::Caches; use crate::cache::DenoDirProvider; @@ -138,7 +138,7 @@ pub const UNSUPPORTED_SCHEME: &str = "Unsupported scheme"; impl ModuleLoader for EmbeddedModuleLoader { fn resolve( &self, - specifier: &str, + raw_specifier: &str, referrer: &str, kind: ResolutionKind, ) -> Result { @@ -162,13 +162,15 @@ impl ModuleLoader for EmbeddedModuleLoader { self .shared .node_resolver - .resolve(specifier, &referrer, NodeResolutionMode::Execution)? + .resolve(raw_specifier, &referrer, NodeResolutionMode::Execution)? .into_url(), ); } - let mapped_resolution = - self.shared.workspace_resolver.resolve(specifier, &referrer); + let mapped_resolution = self + .shared + .workspace_resolver + .resolve(raw_specifier, &referrer); match mapped_resolution { Ok(MappedResolution::WorkspaceJsrPackage { specifier, .. }) => { @@ -262,7 +264,7 @@ impl ModuleLoader for EmbeddedModuleLoader { if err.is_unmapped_bare_specifier() && referrer.scheme() == "file" => { let maybe_res = self.shared.node_resolver.resolve_if_for_npm_pkg( - specifier, + raw_specifier, &referrer, NodeResolutionMode::Execution, )?; @@ -502,9 +504,9 @@ pub async fn run( text_only_progress_bar: progress_bar, maybe_node_modules_path, npm_system_info: Default::default(), - package_json_deps_provider: Arc::new( + npm_install_deps_provider: Arc::new( // this is only used for installing packages, which isn't necessary with deno compile - PackageJsonInstallDepsProvider::empty(), + NpmInstallDepsProvider::empty(), ), // create an npmrc that uses the fake npm_registry_url to resolve packages npmrc: Arc::new(ResolvedNpmRc { @@ -554,9 +556,9 @@ pub async fn run( text_only_progress_bar: progress_bar, maybe_node_modules_path: None, npm_system_info: Default::default(), - package_json_deps_provider: Arc::new( + npm_install_deps_provider: Arc::new( // this is only used for installing packages, which isn't necessary with deno compile - PackageJsonInstallDepsProvider::empty(), + NpmInstallDepsProvider::empty(), ), // Packages from different registries are already inlined in the ESZip, // so no need to create actual `.npmrc` configuration. diff --git a/cli/task_runner.rs b/cli/task_runner.rs index e8937590db..ab7163bc93 100644 --- a/cli/task_runner.rs +++ b/cli/task_runner.rs @@ -213,8 +213,8 @@ impl ShellCommand for NodeGypCommand { ) -> LocalBoxFuture<'static, ExecuteResult> { // at the moment this shell command is just to give a warning if node-gyp is not found // in the future, we could try to run/install node-gyp for the user with deno - if which::which("node-gyp").is_err() { - log::warn!("{}: node-gyp was used in a script, but was not listed as a dependency. Either add it as a dependency or install it globally (e.g. `npm install -g node-gyp`)", crate::colors::yellow("warning")); + if context.state.resolve_command_path("node-gyp").is_err() { + log::warn!("{} node-gyp was used in a script, but was not listed as a dependency. Either add it as a dependency or install it globally (e.g. `npm install -g node-gyp`)", crate::colors::yellow("Warning")); } ExecutableCommand::new( "node-gyp".to_string(), diff --git a/cli/tools/check.rs b/cli/tools/check.rs index a2bfb9d9bb..9232f324be 100644 --- a/cli/tools/check.rs +++ b/cli/tools/check.rs @@ -14,6 +14,7 @@ use deno_terminal::colors; use once_cell::sync::Lazy; use regex::Regex; +use crate::args::check_warn_tsconfig; use crate::args::CliOptions; use crate::args::TsConfig; use crate::args::TsConfigType; @@ -118,9 +119,7 @@ impl TypeChecker { .cli_options .resolve_ts_config_for_emit(TsConfigType::Check { lib: options.lib })?; if options.log_ignored_options { - if let Some(ignored_options) = ts_config_result.maybe_ignored_options { - log::warn!("{}", ignored_options); - } + check_warn_tsconfig(&ts_config_result); } let type_check_mode = options.type_check_mode; diff --git a/cli/tools/compile.rs b/cli/tools/compile.rs index 90ee0e2706..b9620cfded 100644 --- a/cli/tools/compile.rs +++ b/cli/tools/compile.rs @@ -1,5 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use crate::args::check_warn_tsconfig; use crate::args::CompileFlags; use crate::args::Flags; use crate::factory::CliFactory; @@ -79,6 +80,7 @@ pub async fn compile( let ts_config_for_emit = cli_options .resolve_ts_config_for_emit(deno_config::deno_json::TsConfigType::Emit)?; + check_warn_tsconfig(&ts_config_for_emit); let (transpile_options, emit_options) = crate::args::ts_config_to_transpile_and_emit_options( ts_config_for_emit.ts_config, diff --git a/cli/tools/installer.rs b/cli/tools/installer.rs index c3f415dc7f..987f3c0694 100644 --- a/cli/tools/installer.rs +++ b/cli/tools/installer.rs @@ -7,14 +7,17 @@ use crate::args::ConfigFlag; use crate::args::Flags; use crate::args::InstallFlags; use crate::args::InstallFlagsGlobal; +use crate::args::InstallFlagsLocal; use crate::args::InstallKind; use crate::args::TypeCheckMode; use crate::args::UninstallFlags; use crate::args::UninstallKind; use crate::factory::CliFactory; +use crate::graph_container::ModuleGraphContainer; use crate::http_util::HttpClientProvider; use crate::util::fs::canonicalize_path_maybe_not_exists; +use deno_core::anyhow::bail; use deno_core::anyhow::Context; use deno_core::error::generic_error; use deno_core::error::AnyError; @@ -261,26 +264,65 @@ pub fn uninstall(uninstall_flags: UninstallFlags) -> Result<(), AnyError> { Ok(()) } +pub(crate) async fn install_from_entrypoints( + flags: Arc, + entrypoints: &[String], +) -> Result<(), AnyError> { + let factory = CliFactory::from_flags(flags.clone()); + let emitter = factory.emitter()?; + let main_graph_container = factory.main_module_graph_container().await?; + main_graph_container + .load_and_type_check_files(entrypoints) + .await?; + emitter + .cache_module_emits(&main_graph_container.graph()) + .await +} + async fn install_local( flags: Arc, - maybe_add_flags: Option, + install_flags: InstallFlagsLocal, ) -> Result<(), AnyError> { - if let Some(add_flags) = maybe_add_flags { - return super::registry::add( - flags, - add_flags, - super::registry::AddCommandName::Install, - ) - .await; + match install_flags { + InstallFlagsLocal::Add(add_flags) => { + super::registry::add( + flags, + add_flags, + super::registry::AddCommandName::Install, + ) + .await + } + InstallFlagsLocal::Entrypoints(entrypoints) => { + install_from_entrypoints(flags, &entrypoints).await + } + InstallFlagsLocal::TopLevel => { + let factory = CliFactory::from_flags(flags); + crate::tools::registry::cache_top_level_deps(&factory, None).await?; + + if let Some(lockfile) = factory.cli_options()?.maybe_lockfile() { + lockfile.write_if_changed()?; + } + + Ok(()) + } } +} - let factory = CliFactory::from_flags(flags); - crate::tools::registry::cache_top_level_deps(&factory, None).await?; - - if let Some(lockfile) = factory.cli_options()?.maybe_lockfile() { - lockfile.write_if_changed()?; +fn check_if_installs_a_single_package_globally( + maybe_add_flags: Option<&AddFlags>, +) -> Result<(), AnyError> { + let Some(add_flags) = maybe_add_flags else { + return Ok(()); + }; + if add_flags.packages.len() != 1 { + return Ok(()); + } + let Ok(url) = Url::parse(&add_flags.packages[0]) else { + return Ok(()); + }; + if matches!(url.scheme(), "http" | "https") { + bail!("Failed to install \"{}\" specifier. If you are trying to install {} globally, run again with `-g` flag:\n deno install -g {}", url.scheme(), url.as_str(), url.as_str()); } - Ok(()) } @@ -296,8 +338,11 @@ pub async fn install_command( install_global(flags, global_flags).await } - InstallKind::Local(maybe_add_flags) => { - install_local(flags, maybe_add_flags).await + InstallKind::Local(local_flags) => { + if let InstallFlagsLocal::Add(add_flags) = &local_flags { + check_if_installs_a_single_package_globally(Some(add_flags))?; + } + install_local(flags, local_flags).await } } } diff --git a/cli/tools/registry/pm.rs b/cli/tools/registry/pm.rs index 4a36b459a8..e61da31d58 100644 --- a/cli/tools/registry/pm.rs +++ b/cli/tools/registry/pm.rs @@ -3,6 +3,8 @@ mod cache_deps; pub use cache_deps::cache_top_level_deps; +use deno_semver::jsr::JsrPackageReqReference; +use deno_semver::npm::NpmPackageReqReference; use std::borrow::Cow; use std::path::Path; @@ -501,14 +503,18 @@ impl AddPackageReq { match prefix { Prefix::Jsr => { - let package_req = PackageReq::from_str(entry_text)?; + let req_ref = + JsrPackageReqReference::from_str(&format!("jsr:{}", entry_text))?; + let package_req = req_ref.into_inner().req; Ok(AddPackageReq { alias: maybe_alias.unwrap_or_else(|| package_req.name.to_string()), value: AddPackageReqValue::Jsr(package_req), }) } Prefix::Npm => { - let package_req = PackageReq::from_str(entry_text)?; + let req_ref = + NpmPackageReqReference::from_str(&format!("npm:{}", entry_text))?; + let package_req = req_ref.into_inner().req; Ok(AddPackageReq { alias: maybe_alias.unwrap_or_else(|| package_req.name.to_string()), value: AddPackageReqValue::Npm(package_req), diff --git a/cli/tools/task.rs b/cli/tools/task.rs index 23da5b4fb9..cc16bb9a3f 100644 --- a/cli/tools/task.rs +++ b/cli/tools/task.rs @@ -1,13 +1,13 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use crate::args::CliOptions; -use crate::args::Flags; -use crate::args::TaskFlags; -use crate::colors; -use crate::factory::CliFactory; -use crate::npm::CliNpmResolver; -use crate::task_runner; -use crate::util::fs::canonicalize_path; +use std::borrow::Cow; +use std::collections::HashMap; +use std::collections::HashSet; +use std::path::Path; +use std::path::PathBuf; +use std::rc::Rc; +use std::sync::Arc; + use deno_config::deno_json::Task; use deno_config::workspace::TaskOrScript; use deno_config::workspace::WorkspaceDirectory; @@ -18,13 +18,15 @@ use deno_core::anyhow::Context; use deno_core::error::AnyError; use deno_core::normalize_path; use deno_task_shell::ShellCommand; -use std::borrow::Cow; -use std::collections::HashMap; -use std::collections::HashSet; -use std::path::Path; -use std::path::PathBuf; -use std::rc::Rc; -use std::sync::Arc; + +use crate::args::CliOptions; +use crate::args::Flags; +use crate::args::TaskFlags; +use crate::colors; +use crate::factory::CliFactory; +use crate::npm::CliNpmResolver; +use crate::task_runner; +use crate::util::fs::canonicalize_path; pub async fn execute_script( flags: Arc, @@ -106,12 +108,9 @@ See https://docs.deno.com/go/config"# .await } TaskOrScript::Script(scripts, _script) => { - // ensure the npm packages are installed if using a node_modules - // directory and managed resolver - if cli_options.has_node_modules_dir() { - if let Some(npm_resolver) = npm_resolver.as_managed() { - npm_resolver.ensure_top_level_package_json_install().await?; - } + // ensure the npm packages are installed if using a managed resolver + if let Some(npm_resolver) = npm_resolver.as_managed() { + npm_resolver.ensure_top_level_package_json_install().await?; } let cwd = match task_flags.cwd { diff --git a/cli/tools/test/fmt.rs b/cli/tools/test/fmt.rs index 0cdb3f05ab..5201bead65 100644 --- a/cli/tools/test/fmt.rs +++ b/cli/tools/test/fmt.rs @@ -319,10 +319,10 @@ pub const OP_DETAILS: phf::Map<&'static str, [&'static str; 2]> = phf_map! { "op_fs_copy_file_async" => ["copy a file", "awaiting the result of a `Deno.copyFile` call"], "op_fs_events_poll" => ["get the next file system event", "breaking out of a for await loop looping over `Deno.FsEvents`"], "op_fs_fdatasync_async" => ["flush pending data operations for a file to disk", "awaiting the result of a `Deno.fdatasync` or `Deno.FsFile.syncData` call"], - "op_fs_file_stat_async" => ["get file metadata", "awaiting the result of a `Deno.fstat` or `Deno.FsFile.stat` call"], + "op_fs_file_stat_async" => ["get file metadata", "awaiting the result of a `Deno.FsFile.prototype.stat` call"], "op_fs_flock_async" => ["lock a file", "awaiting the result of a `Deno.FsFile.lock` call"], "op_fs_fsync_async" => ["flush pending data operations for a file to disk", "awaiting the result of a `Deno.fsync` or `Deno.FsFile.sync` call"], - "op_fs_ftruncate_async" => ["truncate a file", "awaiting the result of a `Deno.ftruncate` or `Deno.FsFile.truncate` call"], + "op_fs_file_truncate_async" => ["truncate a file", "awaiting the result of a `Deno.FsFile.prototype.truncate` call"], "op_fs_funlock_async_unstable" => ["unlock a file", "awaiting the result of a `Deno.funlock` call"], "op_fs_funlock_async" => ["unlock a file", "awaiting the result of a `Deno.FsFile.unlock` call"], "op_fs_link_async" => ["create a hard link", "awaiting the result of a `Deno.link` call"], diff --git a/cli/tsc/dts/lib.deno.ns.d.ts b/cli/tsc/dts/lib.deno.ns.d.ts index dd245b613d..cc6a1d4a88 100644 --- a/cli/tsc/dts/lib.deno.ns.d.ts +++ b/cli/tsc/dts/lib.deno.ns.d.ts @@ -1833,27 +1833,6 @@ declare namespace Deno { seekSync(offset: number | bigint, whence: SeekMode): number; } - /** - * Copies from `src` to `dst` until either EOF (`null`) is read from `src` or - * an error occurs. It resolves to the number of bytes copied or rejects with - * the first error encountered while copying. - * - * @deprecated This will be removed in Deno 2.0. See the - * {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide} - * for migration instructions. - * - * @category I/O - * - * @param src The source to copy from - * @param dst The destination to copy to - * @param options Can be used to tune size of the buffer. Default size is 32kB - */ - export function copy( - src: Reader, - dst: Writer, - options?: { bufSize?: number }, - ): Promise; - /** Open a file and resolve to an instance of {@linkcode Deno.FsFile}. The * file does not need to previously exist if using the `create` or `createNew` * open options. The caller may have the resulting file automatically closed @@ -1941,121 +1920,6 @@ declare namespace Deno { */ export function createSync(path: string | URL): FsFile; - /** Read from a resource ID (`rid`) into an array buffer (`buffer`). - * - * Resolves to either the number of bytes read during the operation or EOF - * (`null`) if there was nothing more to read. - * - * It is possible for a read to successfully return with `0` bytes. This does - * not indicate EOF. - * - * This function is one of the lowest level APIs and most users should not - * work with this directly, but rather use {@linkcode ReadableStream} and - * {@linkcode https://jsr.io/@std/streams/doc/to-array-buffer/~/toArrayBuffer | toArrayBuffer} - * instead. - * - * **It is not guaranteed that the full buffer will be read in a single call.** - * - * ```ts - * // if "/foo/bar.txt" contains the text "hello world": - * using file = await Deno.open("/foo/bar.txt"); - * const buf = new Uint8Array(100); - * const numberOfBytesRead = await Deno.read(file.rid, buf); // 11 bytes - * const text = new TextDecoder().decode(buf); // "hello world" - * ``` - * - * @deprecated This will be removed in Deno 2.0. See the - * {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide} - * for migration instructions. - * - * @category I/O - */ - export function read(rid: number, buffer: Uint8Array): Promise; - - /** Synchronously read from a resource ID (`rid`) into an array buffer - * (`buffer`). - * - * Returns either the number of bytes read during the operation or EOF - * (`null`) if there was nothing more to read. - * - * It is possible for a read to successfully return with `0` bytes. This does - * not indicate EOF. - * - * This function is one of the lowest level APIs and most users should not - * work with this directly, but rather use {@linkcode ReadableStream} and - * {@linkcode https://jsr.io/@std/streams/doc/to-array-buffer/~/toArrayBuffer | toArrayBuffer} - * instead. - * - * **It is not guaranteed that the full buffer will be read in a single - * call.** - * - * ```ts - * // if "/foo/bar.txt" contains the text "hello world": - * using file = Deno.openSync("/foo/bar.txt"); - * const buf = new Uint8Array(100); - * const numberOfBytesRead = Deno.readSync(file.rid, buf); // 11 bytes - * const text = new TextDecoder().decode(buf); // "hello world" - * ``` - * - * @deprecated This will be removed in Deno 2.0. See the - * {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide} - * for migration instructions. - * - * @category I/O - */ - export function readSync(rid: number, buffer: Uint8Array): number | null; - - /** Write to the resource ID (`rid`) the contents of the array buffer (`data`). - * - * Resolves to the number of bytes written. This function is one of the lowest - * level APIs and most users should not work with this directly, but rather - * use {@linkcode WritableStream}, {@linkcode ReadableStream.from} and - * {@linkcode ReadableStream.pipeTo}. - * - * **It is not guaranteed that the full buffer will be written in a single - * call.** - * - * ```ts - * const encoder = new TextEncoder(); - * const data = encoder.encode("Hello world"); - * using file = await Deno.open("/foo/bar.txt", { write: true }); - * const bytesWritten = await Deno.write(file.rid, data); // 11 - * ``` - * - * @deprecated This will be removed in Deno 2.0. See the - * {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide} - * for migration instructions. - * - * @category I/O - */ - export function write(rid: number, data: Uint8Array): Promise; - - /** Synchronously write to the resource ID (`rid`) the contents of the array - * buffer (`data`). - * - * Returns the number of bytes written. This function is one of the lowest - * level APIs and most users should not work with this directly, but rather - * use {@linkcode WritableStream}, {@linkcode ReadableStream.from} and - * {@linkcode ReadableStream.pipeTo}. - * - * **It is not guaranteed that the full buffer will be written in a single - * call.** - * - * ```ts - * const encoder = new TextEncoder(); - * const data = encoder.encode("Hello world"); - * using file = Deno.openSync("/foo/bar.txt", { write: true }); - * const bytesWritten = Deno.writeSync(file.rid, data); // 11 - * ``` - * - * @deprecated This will be removed in Deno 2.0. See the - * {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide} - * for migration instructions. - * - * @category I/O - */ - export function writeSync(rid: number, data: Uint8Array): number; - /** Seek a resource ID (`rid`) to the given `offset` under mode given by `whence`. * The call resolves to the new position within the resource (bytes from the start). * @@ -2666,17 +2530,6 @@ declare namespace Deno { [Symbol.dispose](): void; } - /** - * The Deno abstraction for reading and writing files. - * - * @deprecated This will be removed in Deno 2.0. See the - * {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide} - * for migration instructions. - * - * @category File System - */ - export const File: typeof FsFile; - /** Gets the size of the console as columns/rows. * * ```ts @@ -2896,25 +2749,6 @@ declare namespace Deno { signal?: AbortSignal; } - /** - * Check if a given resource id (`rid`) is a TTY (a terminal). - * - * ```ts - * // This example is system and context specific - * const nonTTYRid = Deno.openSync("my_file.txt").rid; - * const ttyRid = Deno.openSync("/dev/tty6").rid; - * console.log(Deno.isatty(nonTTYRid)); // false - * console.log(Deno.isatty(ttyRid)); // true - * ``` - * - * @deprecated This will be soft-removed in Deno 2.0. See the - * {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide} - * for migration instructions. - * - * @category I/O - */ - export function isatty(rid: number): boolean; - /** * A variable-sized buffer of bytes with `read()` and `write()` methods. * @@ -3014,29 +2848,6 @@ declare namespace Deno { */ export function readAllSync(r: ReaderSync): Uint8Array; - /** - * Write all the content of the array buffer (`arr`) to the writer (`w`). - * - * @deprecated This will be removed in Deno 2.0. See the - * {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide} - * for migration instructions. - * - * @category I/O - */ - export function writeAll(w: Writer, arr: Uint8Array): Promise; - - /** - * Synchronously write all the content of the array buffer (`arr`) to the - * writer (`w`). - * - * @deprecated This will be removed in Deno 2.0. See the - * {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide} - * for migration instructions. - * - * @category I/O - */ - export function writeAllSync(w: WriterSync, arr: Uint8Array): void; - /** * Options which can be set when using {@linkcode Deno.mkdir} and * {@linkcode Deno.mkdirSync}. @@ -4038,14 +3849,6 @@ declare namespace Deno { * @category File System */ export interface FsWatcher extends AsyncIterable, Disposable { - /** - * The resource id. - * - * @deprecated This will be removed in Deno 2.0. See the - * {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide} - * for migration instructions. - */ - readonly rid: number; /** Stops watching the file system and closes the watcher resource. */ close(): void; /** @@ -4103,175 +3906,6 @@ declare namespace Deno { options?: { recursive: boolean }, ): FsWatcher; - /** - * Options which can be used with {@linkcode Deno.run}. - * - * @deprecated This will be removed in Deno 2.0. See the - * {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide} - * for migration instructions. - * - * @category Subprocess */ - export interface RunOptions { - /** Arguments to pass. - * - * _Note_: the first element needs to be a path to the executable that is - * being run. */ - cmd: readonly string[] | [string | URL, ...string[]]; - /** The current working directory that should be used when running the - * sub-process. */ - cwd?: string; - /** Any environment variables to be set when running the sub-process. */ - env?: Record; - /** By default subprocess inherits `stdout` of parent process. To change - * this this option can be set to a resource ID (_rid_) of an open file, - * `"inherit"`, `"piped"`, or `"null"`: - * - * - _number_: the resource ID of an open file/resource. This allows you to - * write to a file. - * - `"inherit"`: The default if unspecified. The subprocess inherits from the - * parent. - * - `"piped"`: A new pipe should be arranged to connect the parent and child - * sub-process. - * - `"null"`: This stream will be ignored. This is the equivalent of attaching - * the stream to `/dev/null`. - */ - stdout?: "inherit" | "piped" | "null" | number; - /** By default subprocess inherits `stderr` of parent process. To change - * this this option can be set to a resource ID (_rid_) of an open file, - * `"inherit"`, `"piped"`, or `"null"`: - * - * - _number_: the resource ID of an open file/resource. This allows you to - * write to a file. - * - `"inherit"`: The default if unspecified. The subprocess inherits from the - * parent. - * - `"piped"`: A new pipe should be arranged to connect the parent and child - * sub-process. - * - `"null"`: This stream will be ignored. This is the equivalent of attaching - * the stream to `/dev/null`. - */ - stderr?: "inherit" | "piped" | "null" | number; - /** By default subprocess inherits `stdin` of parent process. To change - * this this option can be set to a resource ID (_rid_) of an open file, - * `"inherit"`, `"piped"`, or `"null"`: - * - * - _number_: the resource ID of an open file/resource. This allows you to - * read from a file. - * - `"inherit"`: The default if unspecified. The subprocess inherits from the - * parent. - * - `"piped"`: A new pipe should be arranged to connect the parent and child - * sub-process. - * - `"null"`: This stream will be ignored. This is the equivalent of attaching - * the stream to `/dev/null`. - */ - stdin?: "inherit" | "piped" | "null" | number; - } - - /** - * The status resolved from the `.status()` method of a - * {@linkcode Deno.Process} instance. - * - * If `success` is `true`, then `code` will be `0`, but if `success` is - * `false`, the sub-process exit code will be set in `code`. - * - * @deprecated This will be removed in Deno 2.0. See the - * {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide} - * for migration instructions. - * - * @category Subprocess */ - export type ProcessStatus = - | { - success: true; - code: 0; - signal?: undefined; - } - | { - success: false; - code: number; - signal?: number; - }; - - /** - * Represents an instance of a sub process that is returned from - * {@linkcode Deno.run} which can be used to manage the sub-process. - * - * @deprecated This will be removed in Deno 2.0. See the - * {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide} - * for migration instructions. - * - * @category Subprocess */ - export class Process { - /** The resource ID of the sub-process. */ - readonly rid: number; - /** The operating system's process ID for the sub-process. */ - readonly pid: number; - /** A reference to the sub-processes `stdin`, which allows interacting with - * the sub-process at a low level. */ - readonly stdin: T["stdin"] extends "piped" ? Writer & Closer & { - writable: WritableStream; - } - : (Writer & Closer & { writable: WritableStream }) | null; - /** A reference to the sub-processes `stdout`, which allows interacting with - * the sub-process at a low level. */ - readonly stdout: T["stdout"] extends "piped" ? Reader & Closer & { - readable: ReadableStream; - } - : (Reader & Closer & { readable: ReadableStream }) | null; - /** A reference to the sub-processes `stderr`, which allows interacting with - * the sub-process at a low level. */ - readonly stderr: T["stderr"] extends "piped" ? Reader & Closer & { - readable: ReadableStream; - } - : (Reader & Closer & { readable: ReadableStream }) | null; - /** Wait for the process to exit and return its exit status. - * - * Calling this function multiple times will return the same status. - * - * The `stdin` reference to the process will be closed before waiting to - * avoid a deadlock. - * - * If `stdout` and/or `stderr` were set to `"piped"`, they must be closed - * manually before the process can exit. - * - * To run process to completion and collect output from both `stdout` and - * `stderr` use: - * - * ```ts - * const p = Deno.run({ cmd: [ "echo", "hello world" ], stderr: 'piped', stdout: 'piped' }); - * const [status, stdout, stderr] = await Promise.all([ - * p.status(), - * p.output(), - * p.stderrOutput() - * ]); - * p.close(); - * ``` - */ - status(): Promise; - /** Buffer the stdout until EOF and return it as `Uint8Array`. - * - * You must set `stdout` to `"piped"` when creating the process. - * - * This calls `close()` on stdout after its done. */ - output(): Promise; - /** Buffer the stderr until EOF and return it as `Uint8Array`. - * - * You must set `stderr` to `"piped"` when creating the process. - * - * This calls `close()` on stderr after its done. */ - stderrOutput(): Promise; - /** Clean up resources associated with the sub-process instance. */ - close(): void; - /** Send a signal to process. - * Default signal is `"SIGTERM"`. - * - * ```ts - * const p = Deno.run({ cmd: [ "sleep", "20" ]}); - * p.kill("SIGTERM"); - * p.close(); - * ``` - */ - kill(signo?: Signal): void; - } - /** Operating signals which can be listened for or sent to sub-processes. What * signals and what their standard behaviors are OS dependent. * @@ -4353,61 +3987,6 @@ declare namespace Deno { handler: () => void, ): void; - /** - * Spawns new subprocess. RunOptions must contain at a minimum the `opt.cmd`, - * an array of program arguments, the first of which is the binary. - * - * ```ts - * const p = Deno.run({ - * cmd: ["curl", "https://example.com"], - * }); - * const status = await p.status(); - * ``` - * - * Subprocess uses same working directory as parent process unless `opt.cwd` - * is specified. - * - * Environmental variables from parent process can be cleared using `opt.clearEnv`. - * Doesn't guarantee that only `opt.env` variables are present, - * as the OS may set environmental variables for processes. - * - * Environmental variables for subprocess can be specified using `opt.env` - * mapping. - * - * `opt.uid` sets the child process’s user ID. This translates to a setuid call - * in the child process. Failure in the setuid call will cause the spawn to fail. - * - * `opt.gid` is similar to `opt.uid`, but sets the group ID of the child process. - * This has the same semantics as the uid field. - * - * By default subprocess inherits stdio of parent process. To change - * this this, `opt.stdin`, `opt.stdout`, and `opt.stderr` can be set - * independently to a resource ID (_rid_) of an open file, `"inherit"`, - * `"piped"`, or `"null"`: - * - * - _number_: the resource ID of an open file/resource. This allows you to - * read or write to a file. - * - `"inherit"`: The default if unspecified. The subprocess inherits from the - * parent. - * - `"piped"`: A new pipe should be arranged to connect the parent and child - * sub-process. - * - `"null"`: This stream will be ignored. This is the equivalent of attaching - * the stream to `/dev/null`. - * - * Details of the spawned process are returned as an instance of - * {@linkcode Deno.Process}. - * - * Requires `allow-run` permission. - * - * @deprecated This will be soft-removed in Deno 2.0. See the - * {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide} - * for migration instructions. - * - * @tags allow-run - * @category Subprocess - */ - export function run(opt: T): Process; - /** Create a child process. * * If any stdio options are not set to `"piped"`, accessing the corresponding @@ -5256,136 +4835,6 @@ declare namespace Deno { options?: SymlinkOptions, ): void; - /** - * Truncates or extends the specified file stream, to reach the specified - * `len`. - * - * If `len` is not specified then the entire file contents are truncated as if - * `len` was set to `0`. - * - * If the file previously was larger than this new length, the extra data is - * lost. - * - * If the file previously was shorter, it is extended, and the extended part - * reads as null bytes ('\0'). - * - * ### Truncate the entire file - * - * ```ts - * const file = await Deno.open( - * "my_file.txt", - * { read: true, write: true, create: true } - * ); - * await Deno.ftruncate(file.rid); - * ``` - * - * ### Truncate part of the file - * - * ```ts - * const file = await Deno.open( - * "my_file.txt", - * { read: true, write: true, create: true } - * ); - * await file.write(new TextEncoder().encode("Hello World")); - * await Deno.ftruncate(file.rid, 7); - * const data = new Uint8Array(32); - * await Deno.read(file.rid, data); - * console.log(new TextDecoder().decode(data)); // Hello W - * ``` - * - * @deprecated This will be removed in Deno 2.0. See the - * {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide} - * for migration instructions. - * - * @category File System - */ - export function ftruncate(rid: number, len?: number): Promise; - - /** - * Synchronously truncates or extends the specified file stream, to reach the - * specified `len`. - * - * If `len` is not specified then the entire file contents are truncated as if - * `len` was set to `0`. - * - * If the file previously was larger than this new length, the extra data is - * lost. - * - * If the file previously was shorter, it is extended, and the extended part - * reads as null bytes ('\0'). - * - * ### Truncate the entire file - * - * ```ts - * const file = Deno.openSync( - * "my_file.txt", - * { read: true, write: true, truncate: true, create: true } - * ); - * Deno.ftruncateSync(file.rid); - * ``` - * - * ### Truncate part of the file - * - * ```ts - * const file = Deno.openSync( - * "my_file.txt", - * { read: true, write: true, create: true } - * ); - * file.writeSync(new TextEncoder().encode("Hello World")); - * Deno.ftruncateSync(file.rid, 7); - * Deno.seekSync(file.rid, 0, Deno.SeekMode.Start); - * const data = new Uint8Array(32); - * Deno.readSync(file.rid, data); - * console.log(new TextDecoder().decode(data)); // Hello W - * ``` - * - * @deprecated This will be removed in Deno 2.0. See the - * {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide} - * for migration instructions. - * - * @category File System - */ - export function ftruncateSync(rid: number, len?: number): void; - - /** - * Returns a `Deno.FileInfo` for the given file stream. - * - * ```ts - * import { assert } from "jsr:@std/assert"; - * - * const file = await Deno.open("file.txt", { read: true }); - * const fileInfo = await Deno.fstat(file.rid); - * assert(fileInfo.isFile); - * ``` - * - * @deprecated This will be removed in Deno 2.0. See the - * {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide} - * for migration instructions. - * - * @category File System - */ - export function fstat(rid: number): Promise; - - /** - * Synchronously returns a {@linkcode Deno.FileInfo} for the given file - * stream. - * - * ```ts - * import { assert } from "jsr:@std/assert"; - * - * const file = Deno.openSync("file.txt", { read: true }); - * const fileInfo = Deno.fstatSync(file.rid); - * assert(fileInfo.isFile); - * ``` - * - * @deprecated This will be removed in Deno 2.0. See the - * {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide} - * for migration instructions. - * - * @category File System - */ - export function fstatSync(rid: number): FileInfo; - /** * Synchronously changes the access (`atime`) and modification (`mtime`) times * of a file system object referenced by `path`. Given times are either in @@ -5616,11 +5065,10 @@ declare namespace Deno { * Windows. * * ```ts - * const p = Deno.run({ - * cmd: ["sleep", "10000"] - * }); + * const command = new Deno.Command("sleep", { args: ["10000"] }); + * const child = command.spawn(); * - * Deno.kill(p.pid, "SIGINT"); + * Deno.kill(child.pid, "SIGINT"); * ``` * * Requires `allow-run` permission. @@ -6255,14 +5703,14 @@ declare namespace Deno { /** Serves HTTP requests with the given option bag and handler. * * You can specify an object with a port and hostname option, which is the - * address to listen on. The default is port `8000` on hostname `"127.0.0.1"`. + * address to listen on. The default is port `8000` on hostname `"0.0.0.0"`. * * You can change the address to listen on using the `hostname` and `port` - * options. The below example serves on port `3000` and hostname `"0.0.0.0"`. + * options. The below example serves on port `3000` and hostname `"127.0.0.1"`. * * ```ts * Deno.serve( - * { port: 3000, hostname: "0.0.0.0" }, + * { port: 3000, hostname: "127.0.0.1" }, * (_req) => new Response("Hello, world") * ); * ``` @@ -6344,14 +5792,14 @@ declare namespace Deno { /** Serves HTTP requests with the given option bag. * * You can specify an object with a port and hostname option, which is the - * address to listen on. The default is port `8000` on hostname `"127.0.0.1"`. + * address to listen on. The default is port `8000` on hostname `"0.0.0.0"`. * * ```ts * const ac = new AbortController(); * * const server = Deno.serve({ * port: 3000, - * hostname: "0.0.0.0", + * hostname: "127.0.0.1", * handler: (_req) => new Response("Hello, world"), * signal: ac.signal, * onListen({ port, hostname }) { diff --git a/cli/tsc/dts/lib.deno.unstable.d.ts b/cli/tsc/dts/lib.deno.unstable.d.ts index 413abe42d3..9dee14f7fe 100644 --- a/cli/tsc/dts/lib.deno.unstable.d.ts +++ b/cli/tsc/dts/lib.deno.unstable.d.ts @@ -840,80 +840,6 @@ declare namespace Deno { present(): void; } - /** **UNSTABLE**: New API, yet to be vetted. - * - * These are unstable options which can be used with {@linkcode Deno.run}. - * - * @category Subprocess - * @experimental - */ - export interface UnstableRunOptions extends RunOptions { - /** If `true`, clears the environment variables before executing the - * sub-process. - * - * @default {false} */ - clearEnv?: boolean; - /** For POSIX systems, sets the group ID for the sub process. */ - gid?: number; - /** For POSIX systems, sets the user ID for the sub process. */ - uid?: number; - } - - /** **UNSTABLE**: New API, yet to be vetted. - * - * Spawns new subprocess. RunOptions must contain at a minimum the `opt.cmd`, - * an array of program arguments, the first of which is the binary. - * - * ```ts - * const p = Deno.run({ - * cmd: ["curl", "https://example.com"], - * }); - * const status = await p.status(); - * ``` - * - * Subprocess uses same working directory as parent process unless `opt.cwd` - * is specified. - * - * Environmental variables from parent process can be cleared using `opt.clearEnv`. - * Doesn't guarantee that only `opt.env` variables are present, - * as the OS may set environmental variables for processes. - * - * Environmental variables for subprocess can be specified using `opt.env` - * mapping. - * - * `opt.uid` sets the child process’s user ID. This translates to a setuid call - * in the child process. Failure in the setuid call will cause the spawn to fail. - * - * `opt.gid` is similar to `opt.uid`, but sets the group ID of the child process. - * This has the same semantics as the uid field. - * - * By default subprocess inherits stdio of parent process. To change - * this this, `opt.stdin`, `opt.stdout`, and `opt.stderr` can be set - * independently to a resource ID (_rid_) of an open file, `"inherit"`, - * `"piped"`, or `"null"`: - * - * - _number_: the resource ID of an open file/resource. This allows you to - * read or write to a file. - * - `"inherit"`: The default if unspecified. The subprocess inherits from the - * parent. - * - `"piped"`: A new pipe should be arranged to connect the parent and child - * sub-process. - * - `"null"`: This stream will be ignored. This is the equivalent of attaching - * the stream to `/dev/null`. - * - * Details of the spawned process are returned as an instance of - * {@linkcode Deno.Process}. - * - * Requires `allow-run` permission. - * - * @tags allow-run - * @category Subprocess - * @experimental - */ - export function run( - opt: T, - ): Process; - /** **UNSTABLE**: New API, yet to be vetted. * * A custom `HttpClient` for use with {@linkcode fetch} function. This is diff --git a/cli/tsc/mod.rs b/cli/tsc/mod.rs index cf7a55d8c8..1b443cafd3 100644 --- a/cli/tsc/mod.rs +++ b/cli/tsc/mod.rs @@ -795,7 +795,7 @@ fn resolve_graph_specifier_types( } fn resolve_non_graph_specifier_types( - specifier: &str, + raw_specifier: &str, referrer: &ModuleSpecifier, referrer_kind: NodeModuleKind, state: &State, @@ -810,14 +810,16 @@ fn resolve_non_graph_specifier_types( Ok(Some(NodeResolution::into_specifier_and_media_type( node_resolver .resolve( - specifier, + raw_specifier, referrer, referrer_kind, NodeResolutionMode::Types, ) .ok(), ))) - } else if let Ok(npm_req_ref) = NpmPackageReqReference::from_str(specifier) { + } else if let Ok(npm_req_ref) = + NpmPackageReqReference::from_str(raw_specifier) + { debug_assert_eq!(referrer_kind, NodeModuleKind::Esm); // todo(dsherret): add support for injecting this in the graph so // we don't need this special code here. diff --git a/cli/util/fs.rs b/cli/util/fs.rs index d723d24e1f..fdf6035ecd 100644 --- a/cli/util/fs.rs +++ b/cli/util/fs.rs @@ -496,9 +496,9 @@ pub fn hard_link_dir_recursive(from: &Path, to: &Path) -> Result<(), AnyError> { } pub fn symlink_dir(oldpath: &Path, newpath: &Path) -> Result<(), Error> { - let err_mapper = |err: Error| { + let err_mapper = |err: Error, kind: Option| { Error::new( - err.kind(), + kind.unwrap_or_else(|| err.kind()), format!( "{}, symlink '{}' -> '{}'", err, @@ -510,12 +510,19 @@ pub fn symlink_dir(oldpath: &Path, newpath: &Path) -> Result<(), Error> { #[cfg(unix)] { use std::os::unix::fs::symlink; - symlink(oldpath, newpath).map_err(err_mapper)?; + symlink(oldpath, newpath).map_err(|e| err_mapper(e, None))?; } #[cfg(not(unix))] { use std::os::windows::fs::symlink_dir; - symlink_dir(oldpath, newpath).map_err(err_mapper)?; + symlink_dir(oldpath, newpath).map_err(|err| { + if let Some(code) = err.raw_os_error() { + if code as u32 == winapi::shared::winerror::ERROR_PRIVILEGE_NOT_HELD { + return err_mapper(err, Some(ErrorKind::PermissionDenied)); + } + } + err_mapper(err, None) + })?; } Ok(()) } diff --git a/cli/worker.rs b/cli/worker.rs index 7000fd2040..64400af205 100644 --- a/cli/worker.rs +++ b/cli/worker.rs @@ -138,7 +138,6 @@ struct SharedWorkerState { maybe_inspector_server: Option>, maybe_lockfile: Option>, feature_checker: Arc, - enable_future_features: bool, code_cache: Option>, } @@ -453,8 +452,6 @@ impl CliMainWorkerFactory { maybe_inspector_server, maybe_lockfile, feature_checker, - // TODO(2.0): remove? - enable_future_features: true, code_cache, }), } @@ -591,7 +588,6 @@ impl CliMainWorkerFactory { argv0: shared.options.argv0.clone(), node_debug: shared.options.node_debug.clone(), node_ipc_fd: shared.options.node_ipc, - future: shared.enable_future_features, mode, serve_port: shared.options.serve_port, serve_host: shared.options.serve_host.clone(), @@ -787,7 +783,6 @@ fn create_web_worker_callback( argv0: shared.options.argv0.clone(), node_debug: shared.options.node_debug.clone(), node_ipc_fd: None, - future: shared.enable_future_features, mode: WorkerExecutionMode::Worker, serve_port: shared.options.serve_port, serve_host: shared.options.serve_host.clone(), diff --git a/ext/broadcast_channel/Cargo.toml b/ext/broadcast_channel/Cargo.toml index fc12fda6d7..8b8c9a1883 100644 --- a/ext/broadcast_channel/Cargo.toml +++ b/ext/broadcast_channel/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_broadcast_channel" -version = "0.161.0" +version = "0.162.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/cache/01_cache.js b/ext/cache/01_cache.js index a5bcde598f..269261f401 100644 --- a/ext/cache/01_cache.js +++ b/ext/cache/01_cache.js @@ -105,7 +105,7 @@ class Cache { const reqUrl = new URL(innerRequest.url()); if (reqUrl.protocol !== "http:" && reqUrl.protocol !== "https:") { throw new TypeError( - "Request url protocol must be 'http:' or 'https:'", + `Request url protocol must be 'http:' or 'https:': received '${reqUrl.protocol}'`, ); } if (innerRequest.method !== "GET") { diff --git a/ext/cache/Cargo.toml b/ext/cache/Cargo.toml index 12491f2806..5c6f162f17 100644 --- a/ext/cache/Cargo.toml +++ b/ext/cache/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_cache" -version = "0.99.0" +version = "0.100.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/cache/lib.rs b/ext/cache/lib.rs index e399b08e07..f6d758b95c 100644 --- a/ext/cache/lib.rs +++ b/ext/cache/lib.rs @@ -211,7 +211,7 @@ where state.put(cache); Ok(state.borrow::().clone()) } else { - Err(type_error("CacheStorage is not available in this context.")) + Err(type_error("CacheStorage is not available in this context")) } } diff --git a/ext/canvas/01_image.js b/ext/canvas/01_image.js index 6fb1ee62fc..3ea72db6ac 100644 --- a/ext/canvas/01_image.js +++ b/ext/canvas/01_image.js @@ -307,7 +307,9 @@ function processImage(input, width, height, sx, sy, sw, sh, options) { } if (options.colorSpaceConversion === "none") { - throw new TypeError("options.colorSpaceConversion 'none' is not supported"); + throw new TypeError( + "Cannot create image: invalid colorSpaceConversion option, 'none' is not supported", + ); } /* diff --git a/ext/canvas/Cargo.toml b/ext/canvas/Cargo.toml index 9b2fd1008f..96881682a4 100644 --- a/ext/canvas/Cargo.toml +++ b/ext/canvas/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_canvas" -version = "0.36.0" +version = "0.37.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/console/Cargo.toml b/ext/console/Cargo.toml index 4d1f1aef61..ef64398584 100644 --- a/ext/console/Cargo.toml +++ b/ext/console/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_console" -version = "0.167.0" +version = "0.168.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/cron/01_cron.ts b/ext/cron/01_cron.ts index 017da8ae2f..b5c556a677 100644 --- a/ext/cron/01_cron.ts +++ b/ext/cron/01_cron.ts @@ -41,7 +41,9 @@ export function formatToCronSchedule( } else if (end === undefined && every !== undefined) { return "*/" + every; } else { - throw new TypeError("Invalid cron schedule"); + throw new TypeError( + `Invalid cron schedule: start=${start}, end=${end}, every=${every}`, + ); } } else { if (typeof exact === "number") { @@ -103,10 +105,14 @@ function cron( handler2?: () => Promise | void, ) { if (name === undefined) { - throw new TypeError("Deno.cron requires a unique name"); + throw new TypeError( + "Cannot create cron job, a unique name is required: received 'undefined'", + ); } if (schedule === undefined) { - throw new TypeError("Deno.cron requires a valid schedule"); + throw new TypeError( + "Cannot create cron job, a schedule is required: received 'undefined'", + ); } schedule = parseScheduleToString(schedule); @@ -119,13 +125,15 @@ function cron( if (typeof handlerOrOptions1 === "function") { handler = handlerOrOptions1; if (handler2 !== undefined) { - throw new TypeError("Deno.cron requires a single handler"); + throw new TypeError( + "Cannot create cron job, a single handler is required: two handlers were specified", + ); } } else if (typeof handler2 === "function") { handler = handler2; options = handlerOrOptions1; } else { - throw new TypeError("Deno.cron requires a handler"); + throw new TypeError("Cannot create cron job: a handler is required"); } const rid = op_cron_create( diff --git a/ext/cron/Cargo.toml b/ext/cron/Cargo.toml index 19aef63b2c..966ac450e9 100644 --- a/ext/cron/Cargo.toml +++ b/ext/cron/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_cron" -version = "0.47.0" +version = "0.48.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/cron/lib.rs b/ext/cron/lib.rs index ede01ba45f..95e38179db 100644 --- a/ext/cron/lib.rs +++ b/ext/cron/lib.rs @@ -116,12 +116,15 @@ where fn validate_cron_name(name: &str) -> Result<(), AnyError> { if name.len() > 64 { - return Err(type_error("Cron name is too long")); + return Err(type_error(format!( + "Cron name cannot exceed 64 characters: current length {}", + name.len() + ))); } if !name.chars().all(|c| { c.is_ascii_whitespace() || c.is_ascii_alphanumeric() || c == '_' || c == '-' }) { - return Err(type_error("Invalid cron name. Only alphanumeric characters, whitespace, hyphens, and underscores are allowed")); + return Err(type_error("Invalid cron name: only alphanumeric characters, whitespace, hyphens, and underscores are allowed")); } Ok(()) } diff --git a/ext/crypto/00_crypto.js b/ext/crypto/00_crypto.js index 80a2e11c7c..f7dfe488fd 100644 --- a/ext/crypto/00_crypto.js +++ b/ext/crypto/00_crypto.js @@ -292,7 +292,7 @@ function normalizeAlgorithm(algorithm, op) { normalizedAlgorithm[member] = normalizeAlgorithm(idlValue, "digest"); } else if (idlType === "AlgorithmIdentifier") { // TODO(lucacasonato): implement - throw new TypeError("unimplemented"); + throw new TypeError("Unimplemented"); } } @@ -443,7 +443,7 @@ function getKeyLength(algorithm) { // 1. if (!ArrayPrototypeIncludes([128, 192, 256], algorithm.length)) { throw new DOMException( - "length must be 128, 192, or 256", + `Length must be 128, 192, or 256: received ${algorithm.length}`, "OperationError", ); } @@ -470,14 +470,14 @@ function getKeyLength(algorithm) { break; default: throw new DOMException( - "Unrecognized hash algorithm", + `Unrecognized hash algorithm: ${algorithm.hash.name}`, "NotSupportedError", ); } } else if (algorithm.length !== 0) { length = algorithm.length; } else { - throw new TypeError("Invalid length."); + throw new TypeError(`Invalid length: ${algorithm.length}`); } // 2. @@ -492,7 +492,7 @@ function getKeyLength(algorithm) { return null; } default: - throw new TypeError("unreachable"); + throw new TypeError("Unreachable"); } } @@ -556,7 +556,7 @@ class SubtleCrypto { // 8. if (normalizedAlgorithm.name !== key[_algorithm].name) { throw new DOMException( - "Encryption algorithm doesn't match key algorithm.", + `Encryption algorithm '${normalizedAlgorithm.name}' does not match key algorithm`, "InvalidAccessError", ); } @@ -564,7 +564,7 @@ class SubtleCrypto { // 9. if (!ArrayPrototypeIncludes(key[_usages], "encrypt")) { throw new DOMException( - "Key does not support the 'encrypt' operation.", + "Key does not support the 'encrypt' operation", "InvalidAccessError", ); } @@ -599,7 +599,7 @@ class SubtleCrypto { // 8. if (normalizedAlgorithm.name !== key[_algorithm].name) { throw new DOMException( - "Decryption algorithm doesn't match key algorithm.", + `Decryption algorithm "${normalizedAlgorithm.name}" does not match key algorithm`, "OperationError", ); } @@ -607,7 +607,7 @@ class SubtleCrypto { // 9. if (!ArrayPrototypeIncludes(key[_usages], "decrypt")) { throw new DOMException( - "Key does not support the 'decrypt' operation.", + "Key does not support the 'decrypt' operation", "InvalidAccessError", ); } @@ -683,7 +683,7 @@ class SubtleCrypto { normalizedAlgorithm.length === 0 || normalizedAlgorithm.length > 128 ) { throw new DOMException( - "Counter length must not be 0 or greater than 128", + `Counter length must not be 0 or greater than 128: received ${normalizedAlgorithm.length}`, "OperationError", ); } @@ -713,7 +713,7 @@ class SubtleCrypto { ) ) { throw new DOMException( - "Invalid tag length", + `Invalid tag length: ${normalizedAlgorithm.tagLength}`, "OperationError", ); } @@ -805,7 +805,7 @@ class SubtleCrypto { // 8. if (normalizedAlgorithm.name !== key[_algorithm].name) { throw new DOMException( - "Signing algorithm doesn't match key algorithm.", + "Signing algorithm does not match key algorithm", "InvalidAccessError", ); } @@ -813,7 +813,7 @@ class SubtleCrypto { // 9. if (!ArrayPrototypeIncludes(key[_usages], "sign")) { throw new DOMException( - "Key does not support the 'sign' operation.", + "Key does not support the 'sign' operation", "InvalidAccessError", ); } @@ -928,7 +928,7 @@ class SubtleCrypto { } } - throw new TypeError("unreachable"); + throw new TypeError("Unreachable"); } /** @@ -967,11 +967,11 @@ class SubtleCrypto { if (ArrayBufferIsView(keyData) || isArrayBuffer(keyData)) { keyData = copyBuffer(keyData); } else { - throw new TypeError("keyData is a JsonWebKey"); + throw new TypeError("Cannot import key: 'keyData' is a JsonWebKey"); } } else { if (ArrayBufferIsView(keyData) || isArrayBuffer(keyData)) { - throw new TypeError("keyData is not a JsonWebKey"); + throw new TypeError("Cannot import key: 'keyData' is not a JsonWebKey"); } } @@ -1156,7 +1156,7 @@ class SubtleCrypto { // 8. if (!ArrayPrototypeIncludes(baseKey[_usages], "deriveBits")) { throw new DOMException( - "baseKey usages does not contain `deriveBits`", + "'baseKey' usages does not contain 'deriveBits'", "InvalidAccessError", ); } @@ -1222,7 +1222,7 @@ class SubtleCrypto { // 11. if (normalizedAlgorithm.name !== baseKey[_algorithm].name) { throw new DOMException( - "Invalid algorithm name", + `Invalid algorithm name: ${normalizedAlgorithm.name}`, "InvalidAccessError", ); } @@ -1230,7 +1230,7 @@ class SubtleCrypto { // 12. if (!ArrayPrototypeIncludes(baseKey[_usages], "deriveKey")) { throw new DOMException( - "baseKey usages does not contain `deriveKey`", + "'baseKey' usages does not contain 'deriveKey'", "InvalidAccessError", ); } @@ -1259,7 +1259,7 @@ class SubtleCrypto { ArrayPrototypeIncludes(["private", "secret"], result[_type]) && keyUsages.length == 0 ) { - throw new SyntaxError("Invalid key usages"); + throw new SyntaxError("Invalid key usage"); } // 17. return result; @@ -1298,14 +1298,14 @@ class SubtleCrypto { if (normalizedAlgorithm.name !== key[_algorithm].name) { throw new DOMException( - "Verifying algorithm doesn't match key algorithm.", + "Verifying algorithm does not match key algorithm", "InvalidAccessError", ); } if (!ArrayPrototypeIncludes(key[_usages], "verify")) { throw new DOMException( - "Key does not support the 'verify' operation.", + "Key does not support the 'verify' operation", "InvalidAccessError", ); } @@ -1396,7 +1396,7 @@ class SubtleCrypto { } } - throw new TypeError("unreachable"); + throw new TypeError("Unreachable"); } /** @@ -1435,7 +1435,7 @@ class SubtleCrypto { // 8. if (normalizedAlgorithm.name !== wrappingKey[_algorithm].name) { throw new DOMException( - "Wrapping algorithm doesn't match key algorithm.", + "Wrapping algorithm does not match key algorithm", "InvalidAccessError", ); } @@ -1443,7 +1443,7 @@ class SubtleCrypto { // 9. if (!ArrayPrototypeIncludes(wrappingKey[_usages], "wrapKey")) { throw new DOMException( - "Key does not support the 'wrapKey' operation.", + "Key does not support the 'wrapKey' operation", "InvalidAccessError", ); } @@ -1591,7 +1591,7 @@ class SubtleCrypto { // 11. if (normalizedAlgorithm.name !== unwrappingKey[_algorithm].name) { throw new DOMException( - "Unwrapping algorithm doesn't match key algorithm.", + "Unwrapping algorithm does not match key algorithm", "InvalidAccessError", ); } @@ -1599,7 +1599,7 @@ class SubtleCrypto { // 12. if (!ArrayPrototypeIncludes(unwrappingKey[_usages], "unwrapKey")) { throw new DOMException( - "Key does not support the 'unwrapKey' operation.", + "Key does not support the 'unwrapKey' operation", "InvalidAccessError", ); } @@ -1678,7 +1678,7 @@ class SubtleCrypto { (result[_type] == "secret" || result[_type] == "private") && keyUsages.length == 0 ) { - throw new SyntaxError("Invalid key type."); + throw new SyntaxError("Invalid key type"); } // 17. result[_extractable] = extractable; @@ -1726,13 +1726,13 @@ class SubtleCrypto { if (ObjectPrototypeIsPrototypeOf(CryptoKeyPrototype, result)) { const type = result[_type]; if ((type === "secret" || type === "private") && usages.length === 0) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } } else if ( ObjectPrototypeIsPrototypeOf(CryptoKeyPrototype, result.privateKey) ) { if (result.privateKey[_usages].length === 0) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } } @@ -1758,7 +1758,7 @@ async function generateKey(normalizedAlgorithm, extractable, usages) { (u) => !ArrayPrototypeIncludes(["sign", "verify"], u), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } // 2. @@ -1817,7 +1817,7 @@ async function generateKey(normalizedAlgorithm, extractable, usages) { ], u), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } // 2. @@ -1873,7 +1873,7 @@ async function generateKey(normalizedAlgorithm, extractable, usages) { (u) => !ArrayPrototypeIncludes(["sign", "verify"], u), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } // 2-3. @@ -1933,7 +1933,7 @@ async function generateKey(normalizedAlgorithm, extractable, usages) { (u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } // 2-3. @@ -1999,7 +1999,7 @@ async function generateKey(normalizedAlgorithm, extractable, usages) { ], u), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } return generateKeyAES(normalizedAlgorithm, extractable, usages); @@ -2012,7 +2012,7 @@ async function generateKey(normalizedAlgorithm, extractable, usages) { (u) => !ArrayPrototypeIncludes(["wrapKey", "unwrapKey"], u), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } return generateKeyAES(normalizedAlgorithm, extractable, usages); @@ -2024,7 +2024,7 @@ async function generateKey(normalizedAlgorithm, extractable, usages) { (u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } const privateKeyData = new Uint8Array(32); const publicKeyData = new Uint8Array(32); @@ -2065,7 +2065,7 @@ async function generateKey(normalizedAlgorithm, extractable, usages) { (u) => !ArrayPrototypeIncludes(["sign", "verify"], u), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } const ED25519_SEED_LEN = 32; @@ -2114,7 +2114,7 @@ async function generateKey(normalizedAlgorithm, extractable, usages) { (u) => !ArrayPrototypeIncludes(["sign", "verify"], u), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } // 2. @@ -2178,7 +2178,7 @@ function importKeyEd25519( (u) => !ArrayPrototypeIncludes(["verify"], u), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } const handle = {}; @@ -2206,7 +2206,7 @@ function importKeyEd25519( (u) => !ArrayPrototypeIncludes(["verify"], u), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } const publicKeyData = new Uint8Array(32); @@ -2237,7 +2237,7 @@ function importKeyEd25519( (u) => !ArrayPrototypeIncludes(["sign"], u), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } const privateKeyData = new Uint8Array(32); @@ -2276,7 +2276,7 @@ function importKeyEd25519( ), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } } else { if ( @@ -2289,7 +2289,7 @@ function importKeyEd25519( ), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } } @@ -2349,7 +2349,7 @@ function importKeyEd25519( try { privateKeyData = op_crypto_base64url_decode(jwk.d); } catch (_) { - throw new DOMException("invalid private key data", "DataError"); + throw new DOMException("Invalid private key data", "DataError"); } const handle = {}; @@ -2372,7 +2372,7 @@ function importKeyEd25519( try { publicKeyData = op_crypto_base64url_decode(jwk.x); } catch (_) { - throw new DOMException("invalid public key data", "DataError"); + throw new DOMException("Invalid public key data", "DataError"); } const handle = {}; @@ -2406,7 +2406,7 @@ function importKeyX25519( case "raw": { // 1. if (keyUsages.length > 0) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } const handle = {}; @@ -2429,7 +2429,7 @@ function importKeyX25519( case "spki": { // 1. if (keyUsages.length > 0) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } const publicKeyData = new Uint8Array(32); @@ -2460,7 +2460,7 @@ function importKeyX25519( (u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } const privateKeyData = new Uint8Array(32); @@ -2499,13 +2499,13 @@ function importKeyX25519( ), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } } // 3. if (jwk.d === undefined && keyUsages.length > 0) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } // 4. @@ -2641,7 +2641,7 @@ function exportKeyAES( break; default: throw new DOMException( - "Invalid key length", + `Invalid key length: ${algorithm.length}`, "NotSupportedError", ); } @@ -2675,7 +2675,7 @@ function importKeyAES( (u) => !ArrayPrototypeIncludes(supportedKeyUsages, u), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } const algorithmName = normalizedAlgorithm.name; @@ -2731,7 +2731,10 @@ function importKeyAES( jwk.alg !== undefined && jwk.alg !== aesJwkAlg[algorithmName][128] ) { - throw new DOMException("Invalid algorithm", "DataError"); + throw new DOMException( + `Invalid algorithm: ${jwk.alg}`, + "DataError", + ); } break; case 192: @@ -2739,7 +2742,10 @@ function importKeyAES( jwk.alg !== undefined && jwk.alg !== aesJwkAlg[algorithmName][192] ) { - throw new DOMException("Invalid algorithm", "DataError"); + throw new DOMException( + `Invalid algorithm: ${jwk.alg}`, + "DataError", + ); } break; case 256: @@ -2747,7 +2753,10 @@ function importKeyAES( jwk.alg !== undefined && jwk.alg !== aesJwkAlg[algorithmName][256] ) { - throw new DOMException("Invalid algorithm", "DataError"); + throw new DOMException( + `Invalid algorithm: ${jwk.alg}`, + "DataError", + ); } break; default: @@ -2761,7 +2770,7 @@ function importKeyAES( if ( keyUsages.length > 0 && jwk.use !== undefined && jwk.use !== "enc" ) { - throw new DOMException("Invalid key usages", "DataError"); + throw new DOMException("Invalid key usage", "DataError"); } // 7. @@ -2844,7 +2853,7 @@ function importKeyHMAC( (u) => !ArrayPrototypeIncludes(["sign", "verify"], u), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } // 3. @@ -2926,7 +2935,7 @@ function importKeyHMAC( break; } default: - throw new TypeError("unreachable"); + throw new TypeError("Unreachable"); } // 7. @@ -3059,7 +3068,7 @@ function importKeyEC( ), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } // 3. @@ -3100,7 +3109,7 @@ function importKeyEC( ), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } // 2-9. @@ -3140,7 +3149,7 @@ function importKeyEC( ), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } } else if (keyUsages.length != 0) { throw new DOMException("Key usage must be empty", "SyntaxError"); @@ -3183,7 +3192,7 @@ function importKeyEC( (u) => !ArrayPrototypeIncludes(supportedUsages[keyType], u), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } // 3. @@ -3391,7 +3400,7 @@ function importKeyRSA( ), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } // 2-9. @@ -3436,7 +3445,7 @@ function importKeyRSA( ), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } // 2-9. @@ -3485,7 +3494,7 @@ function importKeyRSA( ), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } } else if ( ArrayPrototypeFind( @@ -3497,7 +3506,7 @@ function importKeyRSA( ), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } // 3. @@ -3579,7 +3588,7 @@ function importKeyRSA( break; default: throw new DOMException( - `'alg' property of JsonWebKey must be one of 'RS1', 'RS256', 'RS384', 'RS512'`, + `'alg' property of JsonWebKey must be one of 'RS1', 'RS256', 'RS384', 'RS512': received ${jwk.alg}`, "DataError", ); } @@ -3602,7 +3611,7 @@ function importKeyRSA( break; default: throw new DOMException( - `'alg' property of JsonWebKey must be one of 'PS1', 'PS256', 'PS384', 'PS512'`, + `'alg' property of JsonWebKey must be one of 'PS1', 'PS256', 'PS384', 'PS512': received ${jwk.alg}`, "DataError", ); } @@ -3625,7 +3634,7 @@ function importKeyRSA( break; default: throw new DOMException( - `'alg' property of JsonWebKey must be one of 'RSA-OAEP', 'RSA-OAEP-256', 'RSA-OAEP-384', or 'RSA-OAEP-512'`, + `'alg' property of JsonWebKey must be one of 'RSA-OAEP', 'RSA-OAEP-256', 'RSA-OAEP-384', or 'RSA-OAEP-512': received ${jwk.alg}`, "DataError", ); } @@ -3639,7 +3648,7 @@ function importKeyRSA( // 9.2. if (normalizedHash.name !== normalizedAlgorithm.hash.name) { throw new DOMException( - `'alg' property of JsonWebKey must be '${normalizedAlgorithm.name}'`, + `'alg' property of JsonWebKey must be '${normalizedAlgorithm.name}': received ${jwk.alg}`, "DataError", ); } @@ -3684,7 +3693,7 @@ function importKeyRSA( } } else { throw new DOMException( - "only optimized private keys are supported", + "Only optimized private keys are supported", "NotSupportedError", ); } @@ -3782,7 +3791,7 @@ function importKeyHKDF( (u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } // 2. @@ -3834,7 +3843,7 @@ function importKeyPBKDF2( (u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u), ) !== undefined ) { - throw new DOMException("Invalid key usages", "SyntaxError"); + throw new DOMException("Invalid key usage", "SyntaxError"); } // 3. @@ -3878,7 +3887,7 @@ function exportKeyHMAC(format, key, innerKey) { // 3. case "raw": { const bits = innerKey.data; - // TODO(petamoriken): Uint8Array doesn't have push method + // TODO(petamoriken): Uint8Array does not have push method // for (let _i = 7 & (8 - bits.length % 8); _i > 0; _i--) { // bits.push(0); // } @@ -4331,7 +4340,10 @@ async function generateKeyAES(normalizedAlgorithm, extractable, usages) { // 2. if (!ArrayPrototypeIncludes([128, 192, 256], normalizedAlgorithm.length)) { - throw new DOMException("Invalid key length", "OperationError"); + throw new DOMException( + `Invalid key length: ${normalizedAlgorithm.length}`, + "OperationError", + ); } // 3. @@ -4417,7 +4429,7 @@ async function deriveBits(normalizedAlgorithm, baseKey, length) { publicKey[_algorithm].namedCurve !== baseKey[_algorithm].namedCurve ) { throw new DOMException( - "namedCurve mismatch", + "'namedCurve' mismatch", "InvalidAccessError", ); } @@ -4670,7 +4682,7 @@ async function encrypt(normalizedAlgorithm, key, data) { ) ) { throw new DOMException( - "Invalid tag length", + `Invalid tag length: ${normalizedAlgorithm.tagLength}`, "OperationError", ); } diff --git a/ext/crypto/Cargo.toml b/ext/crypto/Cargo.toml index 88dfd43661..beea81d1e8 100644 --- a/ext/crypto/Cargo.toml +++ b/ext/crypto/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_crypto" -version = "0.181.0" +version = "0.182.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/fetch/20_headers.js b/ext/fetch/20_headers.js index 1690d9f7d6..e56a74c423 100644 --- a/ext/fetch/20_headers.js +++ b/ext/fetch/20_headers.js @@ -73,7 +73,7 @@ function fillHeaders(headers, object) { const header = object[i]; if (header.length !== 2) { throw new TypeError( - `Invalid header. Length must be 2, but is ${header.length}`, + `Invalid header: length must be 2, but is ${header.length}`, ); } appendHeader(headers, header[0], header[1]); @@ -133,15 +133,15 @@ function appendHeader(headers, name, value) { // 2. if (!checkHeaderNameForHttpTokenCodePoint(name)) { - throw new TypeError("Header name is not valid."); + throw new TypeError(`Invalid header name: "${name}"`); } if (!checkForInvalidValueChars(value)) { - throw new TypeError("Header value is not valid."); + throw new TypeError(`Invalid header value: "${value}"`); } // 3. if (headers[_guard] == "immutable") { - throw new TypeError("Headers are immutable."); + throw new TypeError("Cannot change header: headers are immutable"); } // 7. @@ -330,10 +330,10 @@ class Headers { name = webidl.converters["ByteString"](name, prefix, "Argument 1"); if (!checkHeaderNameForHttpTokenCodePoint(name)) { - throw new TypeError("Header name is not valid."); + throw new TypeError(`Invalid header name: "${name}"`); } if (this[_guard] == "immutable") { - throw new TypeError("Headers are immutable."); + throw new TypeError("Cannot change headers: headers are immutable"); } const list = this[_headerList]; @@ -356,7 +356,7 @@ class Headers { name = webidl.converters["ByteString"](name, prefix, "Argument 1"); if (!checkHeaderNameForHttpTokenCodePoint(name)) { - throw new TypeError("Header name is not valid."); + throw new TypeError(`Invalid header name: "${name}"`); } const list = this[_headerList]; @@ -387,7 +387,7 @@ class Headers { name = webidl.converters["ByteString"](name, prefix, "Argument 1"); if (!checkHeaderNameForHttpTokenCodePoint(name)) { - throw new TypeError("Header name is not valid."); + throw new TypeError(`Invalid header name: "${name}"`); } const list = this[_headerList]; @@ -415,14 +415,14 @@ class Headers { // 2. if (!checkHeaderNameForHttpTokenCodePoint(name)) { - throw new TypeError("Header name is not valid."); + throw new TypeError(`Invalid header name: "${name}"`); } if (!checkForInvalidValueChars(value)) { - throw new TypeError("Header value is not valid."); + throw new TypeError(`Invalid header value: "${value}"`); } if (this[_guard] == "immutable") { - throw new TypeError("Headers are immutable."); + throw new TypeError("Cannot change headers: headers are immutable"); } const list = this[_headerList]; diff --git a/ext/fetch/21_formdata.js b/ext/fetch/21_formdata.js index bb33ea2d47..7d466b8e25 100644 --- a/ext/fetch/21_formdata.js +++ b/ext/fetch/21_formdata.js @@ -396,7 +396,9 @@ class MultipartParser { */ constructor(body, boundary) { if (!boundary) { - throw new TypeError("multipart/form-data must provide a boundary"); + throw new TypeError( + "Cannot construct MultipartParser: multipart/form-data must provide a boundary", + ); } this.boundary = `--${boundary}`; @@ -445,7 +447,7 @@ class MultipartParser { ) { return new FormData(); } - throw new TypeError("Unable to parse body as form data."); + throw new TypeError("Unable to parse body as form data"); } const formData = new FormData(); diff --git a/ext/fetch/22_body.js b/ext/fetch/22_body.js index 82f41411d8..a8f5deac9c 100644 --- a/ext/fetch/22_body.js +++ b/ext/fetch/22_body.js @@ -151,7 +151,7 @@ class InnerBody { * @returns {Promise} */ consume() { - if (this.unusable()) throw new TypeError("Body already consumed."); + if (this.unusable()) throw new TypeError("Body already consumed"); if ( ObjectPrototypeIsPrototypeOf( ReadableStreamPrototype, @@ -372,7 +372,7 @@ function packageData(bytes, type, mimeType) { const boundary = mimeType.parameters.get("boundary"); if (boundary === null) { throw new TypeError( - "Missing boundary parameter in mime type of multipart formdata.", + "Cannot turn into form data: missing boundary parameter in mime type of multipart form data", ); } return parseFormData(chunkToU8(bytes), boundary); diff --git a/ext/fetch/23_response.js b/ext/fetch/23_response.js index 94fc69a986..7dad8c0472 100644 --- a/ext/fetch/23_response.js +++ b/ext/fetch/23_response.js @@ -172,7 +172,7 @@ function initializeAResponse(response, init, bodyWithType) { // 1. if ((init.status < 200 || init.status > 599) && init.status != 101) { throw new RangeError( - `The status provided (${init.status}) is not equal to 101 and outside the range [200, 599].`, + `The status provided (${init.status}) is not equal to 101 and outside the range [200, 599]`, ); } @@ -181,7 +181,9 @@ function initializeAResponse(response, init, bodyWithType) { init.statusText && RegExpPrototypeExec(REASON_PHRASE_RE, init.statusText) === null ) { - throw new TypeError("Status text is not valid."); + throw new TypeError( + `Invalid status text: "${init.statusText}"`, + ); } // 3. @@ -263,7 +265,7 @@ class Response { const baseURL = getLocationHref(); const parsedURL = new URL(url, baseURL); if (!redirectStatus(status)) { - throw new RangeError("Invalid redirect status code."); + throw new RangeError(`Invalid redirect status code: ${status}`); } const inner = newInnerResponse(status); inner.type = "default"; @@ -395,7 +397,7 @@ class Response { clone() { webidl.assertBranded(this, ResponsePrototype); if (this[_body] && this[_body].unusable()) { - throw new TypeError("Body is unusable."); + throw new TypeError("Body is unusable"); } const second = webidl.createBranded(Response); const newRes = cloneInnerResponse(this[_response]); diff --git a/ext/fetch/26_fetch.js b/ext/fetch/26_fetch.js index 47186fb2dd..8ac364a931 100644 --- a/ext/fetch/26_fetch.js +++ b/ext/fetch/26_fetch.js @@ -99,7 +99,7 @@ function createResponseBodyStream(responseBodyRid, terminator) { async function mainFetch(req, recursive, terminator) { if (req.blobUrlEntry !== null) { if (req.method !== "GET") { - throw new TypeError("Blob URL fetch only supports GET method."); + throw new TypeError("Blob URL fetch only supports GET method"); } const body = new InnerBody(req.blobUrlEntry.stream()); @@ -145,7 +145,7 @@ async function mainFetch(req, recursive, terminator) { reqRid = resourceForReadableStream(stream, req.body.length); } } else { - throw new TypeError("invalid body"); + throw new TypeError("Invalid body"); } } @@ -441,13 +441,15 @@ function handleWasmStreaming(source, rid) { typeof contentType !== "string" || StringPrototypeToLowerCase(contentType) !== "application/wasm" ) { - throw new TypeError("Invalid WebAssembly content type."); + throw new TypeError("Invalid WebAssembly content type"); } } // 2.5. if (!res.ok) { - throw new TypeError(`HTTP status code ${res.status}`); + throw new TypeError( + `Failed to receive WebAssembly content: HTTP status code ${res.status}`, + ); } // Pass the resolved URL to v8. diff --git a/ext/fetch/Cargo.toml b/ext/fetch/Cargo.toml index 0b74f7847a..2ec1c25f0c 100644 --- a/ext/fetch/Cargo.toml +++ b/ext/fetch/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_fetch" -version = "0.191.0" +version = "0.192.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/fetch/README.md b/ext/fetch/README.md index d088a6147c..3af8110a6f 100644 --- a/ext/fetch/README.md +++ b/ext/fetch/README.md @@ -78,6 +78,5 @@ Following ops are provided, which can be accessed through `Deno.ops`: - op_fetch - op_fetch_send -- op_fetch_response_upgrade - op_utf8_to_byte_string - op_fetch_custom_client diff --git a/ext/fetch/fs_fetch_handler.rs b/ext/fetch/fs_fetch_handler.rs index 6f45ee664e..4c2b81f356 100644 --- a/ext/fetch/fs_fetch_handler.rs +++ b/ext/fetch/fs_fetch_handler.rs @@ -43,7 +43,7 @@ impl FetchHandler for FsFetchHandler { Ok::<_, ()>(response) } .map_err(move |_| { - type_error("NetworkError when attempting to fetch resource.") + type_error("NetworkError when attempting to fetch resource") }) .or_cancel(&cancel_handle) .boxed_local(); diff --git a/ext/fetch/lib.rs b/ext/fetch/lib.rs index fa85824f44..79659771e6 100644 --- a/ext/fetch/lib.rs +++ b/ext/fetch/lib.rs @@ -28,7 +28,6 @@ use deno_core::futures::Stream; use deno_core::futures::StreamExt; use deno_core::futures::TryFutureExt; use deno_core::op2; -use deno_core::unsync::spawn; use deno_core::url::Url; use deno_core::AsyncRefCell; use deno_core::AsyncResult; @@ -70,12 +69,9 @@ use hyper::body::Frame; use hyper_util::client::legacy::connect::HttpConnector; use hyper_util::client::legacy::connect::HttpInfo; use hyper_util::rt::TokioExecutor; -use hyper_util::rt::TokioIo; use hyper_util::rt::TokioTimer; use serde::Deserialize; use serde::Serialize; -use tokio::io::AsyncReadExt; -use tokio::io::AsyncWriteExt; use tower::ServiceExt; use tower_http::decompression::Decompression; @@ -127,7 +123,6 @@ deno_core::extension!(deno_fetch, ops = [ op_fetch, op_fetch_send, - op_fetch_response_upgrade, op_utf8_to_byte_string, op_fetch_custom_client, ], @@ -177,7 +172,7 @@ impl FetchHandler for DefaultFileFetchHandler { ) -> (CancelableResponseFuture, Option>) { let fut = async move { Ok(Err(type_error( - "NetworkError when attempting to fetch resource.", + "NetworkError when attempting to fetch resource", ))) }; (Box::pin(fut), None) @@ -361,14 +356,14 @@ where let (request_rid, cancel_handle_rid) = match scheme { "file" => { let path = url.to_file_path().map_err(|_| { - type_error("NetworkError when attempting to fetch resource.") + type_error("NetworkError when attempting to fetch resource") })?; let permissions = state.borrow_mut::(); permissions.check_read(&path, "fetch()")?; if method != Method::GET { return Err(type_error(format!( - "Fetching files only supports the GET method. Received {method}." + "Fetching files only supports the GET method: received {method}" ))); } @@ -394,7 +389,7 @@ where let uri = url .as_str() .parse::() - .map_err(|_| type_error("Invalid URL"))?; + .map_err(|_| type_error(format!("Invalid URL {url}")))?; let mut con_len = None; let body = if has_body { @@ -522,7 +517,9 @@ where // because the URL isn't an object URL. return Err(type_error("Blob for the given URL not found.")); } - _ => return Err(type_error(format!("scheme '{scheme}' not supported"))), + _ => { + return Err(type_error(format!("Url scheme '{scheme}' not supported"))) + } }; Ok(FetchReturn { @@ -586,7 +583,7 @@ pub async fn op_fetch_send( return Err(type_error(err.to_string())); } - Err(_) => return Err(type_error("request was cancelled")), + Err(_) => return Err(type_error("Request was cancelled")), }; let status = res.status(); @@ -625,114 +622,6 @@ pub async fn op_fetch_send( }) } -#[op2(async)] -#[smi] -pub async fn op_fetch_response_upgrade( - state: Rc>, - #[smi] rid: ResourceId, -) -> Result { - let raw_response = state - .borrow_mut() - .resource_table - .take::(rid)?; - let raw_response = Rc::try_unwrap(raw_response) - .expect("Someone is holding onto FetchResponseResource"); - - let (read, write) = tokio::io::duplex(1024); - let (read_rx, write_tx) = tokio::io::split(read); - let (mut write_rx, mut read_tx) = tokio::io::split(write); - let upgraded = raw_response.upgrade().await?; - { - // Stage 3: Pump the data - let (mut upgraded_rx, mut upgraded_tx) = - tokio::io::split(TokioIo::new(upgraded)); - - spawn(async move { - let mut buf = [0; 1024]; - loop { - let read = upgraded_rx.read(&mut buf).await?; - if read == 0 { - break; - } - read_tx.write_all(&buf[..read]).await?; - } - Ok::<_, AnyError>(()) - }); - spawn(async move { - let mut buf = [0; 1024]; - loop { - let read = write_rx.read(&mut buf).await?; - if read == 0 { - break; - } - upgraded_tx.write_all(&buf[..read]).await?; - } - Ok::<_, AnyError>(()) - }); - } - - Ok( - state - .borrow_mut() - .resource_table - .add(UpgradeStream::new(read_rx, write_tx)), - ) -} - -struct UpgradeStream { - read: AsyncRefCell>, - write: AsyncRefCell>, - cancel_handle: CancelHandle, -} - -impl UpgradeStream { - pub fn new( - read: tokio::io::ReadHalf, - write: tokio::io::WriteHalf, - ) -> Self { - Self { - read: AsyncRefCell::new(read), - write: AsyncRefCell::new(write), - cancel_handle: CancelHandle::new(), - } - } - - async fn read(self: Rc, buf: &mut [u8]) -> Result { - let cancel_handle = RcRef::map(self.clone(), |this| &this.cancel_handle); - async { - let read = RcRef::map(self, |this| &this.read); - let mut read = read.borrow_mut().await; - Ok(Pin::new(&mut *read).read(buf).await?) - } - .try_or_cancel(cancel_handle) - .await - } - - async fn write(self: Rc, buf: &[u8]) -> Result { - let cancel_handle = RcRef::map(self.clone(), |this| &this.cancel_handle); - async { - let write = RcRef::map(self, |this| &this.write); - let mut write = write.borrow_mut().await; - Ok(Pin::new(&mut *write).write(buf).await?) - } - .try_or_cancel(cancel_handle) - .await - } -} - -impl Resource for UpgradeStream { - fn name(&self) -> Cow { - "fetchUpgradedStream".into() - } - - deno_core::impl_readable_byob!(); - deno_core::impl_writable!(); - - fn close(self: Rc) { - self.cancel_handle.cancel(); - } -} - type CancelableResponseResult = Result, AnyError>, Canceled>; @@ -1016,9 +905,11 @@ pub fn create_http_client( let mut http_connector = HttpConnector::new(); http_connector.enforce_http(false); - let user_agent = user_agent - .parse::() - .map_err(|_| type_error("illegal characters in User-Agent"))?; + let user_agent = user_agent.parse::().map_err(|_| { + type_error(format!( + "Illegal characters in User-Agent: received {user_agent}" + )) + })?; let mut builder = hyper_util::client::legacy::Builder::new(TokioExecutor::new()); @@ -1060,7 +951,7 @@ pub fn create_http_client( } (true, true) => {} (false, false) => { - return Err(type_error("Either `http1` or `http2` needs to be true")) + return Err(type_error("Cannot create Http Client: either `http1` or `http2` needs to be set to true")) } } diff --git a/ext/ffi/00_ffi.js b/ext/ffi/00_ffi.js index 06caf7c6cc..1475f8d3fc 100644 --- a/ext/ffi/00_ffi.js +++ b/ext/ffi/00_ffi.js @@ -250,7 +250,7 @@ class UnsafePointer { } } else { throw new TypeError( - "Expected ArrayBuffer, ArrayBufferView or UnsafeCallbackPrototype", + `Cannot access pointer: expected 'ArrayBuffer', 'ArrayBufferView' or 'UnsafeCallbackPrototype', received ${typeof value}`, ); } if (pointer) { @@ -335,7 +335,9 @@ function getTypeSizeAndAlignment(type, cache = new SafeMap()) { const cached = cache.get(type); if (cached !== undefined) { if (cached === null) { - throw new TypeError("Recursive struct definition"); + throw new TypeError( + "Cannot get pointer size: found recursive struct", + ); } return cached; } @@ -379,7 +381,7 @@ function getTypeSizeAndAlignment(type, cache = new SafeMap()) { case "isize": return [8, 8]; default: - throw new TypeError(`Unsupported type: ${type}`); + throw new TypeError(`Cannot get pointer size, unsupported type: ${type}`); } } @@ -395,7 +397,7 @@ class UnsafeCallback { constructor(definition, callback) { if (definition.nonblocking) { throw new TypeError( - "Invalid UnsafeCallback, cannot be nonblocking", + "Cannot construct UnsafeCallback: cannot be nonblocking", ); } const { 0: rid, 1: pointer } = op_ffi_unsafe_callback_create( @@ -467,7 +469,7 @@ class DynamicLibrary { const type = symbols[symbol].type; if (type === "void") { throw new TypeError( - "Foreign symbol of type 'void' is not supported.", + "Foreign symbol of type 'void' is not supported", ); } diff --git a/ext/ffi/Cargo.toml b/ext/ffi/Cargo.toml index 69dc80bf1b..8c4ccdc9ba 100644 --- a/ext/ffi/Cargo.toml +++ b/ext/ffi/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_ffi" -version = "0.154.0" +version = "0.155.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/ffi/call.rs b/ext/ffi/call.rs index 726f17fad0..9165972935 100644 --- a/ext/ffi/call.rs +++ b/ext/ffi/call.rs @@ -334,7 +334,9 @@ pub fn op_ffi_call_nonblocking( let symbols = &resource.symbols; *symbols .get(&symbol) - .ok_or_else(|| type_error("Invalid FFI symbol name"))? + .ok_or_else(|| { + type_error(format!("Invalid FFI symbol name: '{symbol}'")) + })? .clone() }; diff --git a/ext/ffi/callback.rs b/ext/ffi/callback.rs index 39321aa846..281208322b 100644 --- a/ext/ffi/callback.rs +++ b/ext/ffi/callback.rs @@ -174,7 +174,7 @@ unsafe extern "C" fn deno_ffi_callback( let tc_scope = &mut TryCatch::new(scope); args.run(tc_scope); if tc_scope.exception().is_some() { - log::error!("Illegal unhandled exception in nonblocking callback."); + log::error!("Illegal unhandled exception in nonblocking callback"); } }); } diff --git a/ext/fs/30_fs.js b/ext/fs/30_fs.js index b95fe623ae..f979badb97 100644 --- a/ext/fs/30_fs.js +++ b/ext/fs/30_fs.js @@ -19,11 +19,11 @@ import { op_fs_fdatasync_sync, op_fs_file_stat_async, op_fs_file_stat_sync, + op_fs_file_truncate_async, op_fs_flock_async, op_fs_flock_sync, op_fs_fsync_async, op_fs_fsync_sync, - op_fs_ftruncate_async, op_fs_ftruncate_sync, op_fs_funlock_async, op_fs_funlock_async_unstable, @@ -395,15 +395,6 @@ function parseFileInfo(response) { }; } -function fstatSync(rid) { - op_fs_file_stat_sync(rid, statBuf); - return statStruct(statBuf); -} - -async function fstat(rid) { - return parseFileInfo(await op_fs_file_stat_async(rid)); -} - async function lstat(path) { const res = await op_fs_lstat_async(pathFromURL(path)); return parseFileInfo(res); @@ -431,14 +422,6 @@ function coerceLen(len) { return len; } -function ftruncateSync(rid, len) { - op_fs_ftruncate_sync(rid, coerceLen(len)); -} - -async function ftruncate(rid, len) { - await op_fs_ftruncate_async(rid, coerceLen(len)); -} - function truncateSync(path, len) { op_fs_truncate_sync(path, coerceLen(len)); } @@ -664,11 +647,11 @@ class FsFile { } truncate(len) { - return ftruncate(this.#rid, len); + return op_fs_file_truncate_async(this.#rid, coerceLen(len)); } truncateSync(len) { - return ftruncateSync(this.#rid, len); + return op_fs_ftruncate_sync(this.#rid, coerceLen(len)); } read(p) { @@ -687,12 +670,13 @@ class FsFile { return seekSync(this.#rid, offset, whence); } - stat() { - return fstat(this.#rid); + async stat() { + return parseFileInfo(await op_fs_file_stat_async(this.#rid)); } statSync() { - return fstatSync(this.#rid); + op_fs_file_stat_sync(this.#rid, statBuf); + return statStruct(statBuf); } async syncData() { @@ -802,8 +786,6 @@ function checkOpenOptions(options) { } } -const File = FsFile; - function readFileSync(path) { return op_fs_read_file_sync(pathFromURL(path)); } @@ -966,14 +948,9 @@ export { cwd, fdatasync, fdatasyncSync, - File, FsFile, - fstat, - fstatSync, fsync, fsyncSync, - ftruncate, - ftruncateSync, funlock, funlockSync, link, diff --git a/ext/fs/Cargo.toml b/ext/fs/Cargo.toml index 62454de968..894b307efa 100644 --- a/ext/fs/Cargo.toml +++ b/ext/fs/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_fs" -version = "0.77.0" +version = "0.78.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/fs/lib.rs b/ext/fs/lib.rs index be43c81d9e..7cf5f6cb31 100644 --- a/ext/fs/lib.rs +++ b/ext/fs/lib.rs @@ -242,7 +242,7 @@ deno_core::extension!(deno_fs, op_fs_funlock_async, op_fs_funlock_sync, op_fs_ftruncate_sync, - op_fs_ftruncate_async, + op_fs_file_truncate_async, op_fs_futime_sync, op_fs_futime_async, diff --git a/ext/fs/ops.rs b/ext/fs/ops.rs index 7d28b56b02..acf2c216fc 100644 --- a/ext/fs/ops.rs +++ b/ext/fs/ops.rs @@ -1569,7 +1569,7 @@ pub fn op_fs_ftruncate_sync( } #[op2(async)] -pub async fn op_fs_ftruncate_async( +pub async fn op_fs_file_truncate_async( state: Rc>, #[smi] rid: ResourceId, #[number] len: u64, diff --git a/ext/http/00_serve.ts b/ext/http/00_serve.ts index c8f4e0604b..c8ddaa64be 100644 --- a/ext/http/00_serve.ts +++ b/ext/http/00_serve.ts @@ -583,6 +583,19 @@ type RawServeOptions = { const kLoadBalanced = Symbol("kLoadBalanced"); +function mapAnyAddrToLocalhostForWindows(hostname: string) { + // If the hostname is "0.0.0.0", we display "localhost" in console + // because browsers in Windows don't resolve "0.0.0.0". + // See the discussion in https://github.com/denoland/deno_std/issues/1165 + if ( + (Deno.build.os === "windows") && + (hostname == "0.0.0.0" || hostname == "::") + ) { + return "localhost"; + } + return hostname; +} + function serve(arg1, arg2) { let options: RawServeOptions | undefined; let handler: RawHandler | undefined; @@ -672,22 +685,15 @@ function serve(arg1, arg2) { } const addr = listener.addr; - // If the hostname is "0.0.0.0", we display "localhost" in console - // because browsers in Windows don't resolve "0.0.0.0". - // See the discussion in https://github.com/denoland/deno_std/issues/1165 - const hostname = (addr.hostname == "0.0.0.0" || addr.hostname == "::") && - (Deno.build.os === "windows") - ? "localhost" - : addr.hostname; - addr.hostname = hostname; const onListen = (scheme) => { if (options.onListen) { options.onListen(addr); } else { - const host = StringPrototypeIncludes(addr.hostname, ":") - ? `[${addr.hostname}]` - : addr.hostname; + const hostname = mapAnyAddrToLocalhostForWindows(addr.hostname); + const host = StringPrototypeIncludes(hostname, ":") + ? `[${hostname}]` + : hostname; // deno-lint-ignore no-console console.log(`Listening on ${scheme}${host}:${addr.port}/`); } @@ -862,9 +868,10 @@ function registerDeclarativeServer(exports) { const nThreads = serveWorkerCount > 1 ? ` with ${serveWorkerCount} threads` : ""; + const hostname_ = mapAnyAddrToLocalhostForWindows(hostname); // deno-lint-ignore no-console console.debug( - `%cdeno serve%c: Listening on %chttp://${hostname}:${port}/%c${nThreads}`, + `%cdeno serve%c: Listening on %chttp://${hostname_}:${port}/%c${nThreads}`, "color: green", "color: inherit", "color: yellow", diff --git a/ext/http/Cargo.toml b/ext/http/Cargo.toml index 149bdaa5fe..ba21e3f30d 100644 --- a/ext/http/Cargo.toml +++ b/ext/http/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_http" -version = "0.165.0" +version = "0.166.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/io/12_io.js b/ext/io/12_io.js index 6e95a9bca5..1caf6fe06f 100644 --- a/ext/io/12_io.js +++ b/ext/io/12_io.js @@ -20,7 +20,6 @@ import { writableStreamForRid, } from "ext:deno_web/06_streams.js"; -const DEFAULT_BUFFER_SIZE = 32 * 1024; // Seek whence values. // https://golang.org/pkg/io/#pkg-constants const SeekMode = { @@ -33,37 +32,6 @@ const SeekMode = { End: 2, }; -async function copy( - src, - dst, - options, -) { - internals.warnOnDeprecatedApi( - "Deno.copy()", - new Error().stack, - "Use `copy()` from `https://jsr.io/@std/io/doc/copy/~` instead.", - ); - let n = 0; - const bufSize = options?.bufSize ?? DEFAULT_BUFFER_SIZE; - const b = new Uint8Array(bufSize); - let gotEOF = false; - while (gotEOF === false) { - const result = await src.read(b); - if (result === null) { - gotEOF = true; - } else { - let nwritten = 0; - while (nwritten < result) { - nwritten += await dst.write( - TypedArrayPrototypeSubarray(b, nwritten, result), - ); - } - n += nwritten; - } - } - return n; -} - function readSync(rid, buffer) { if (buffer.length === 0) return 0; const nread = core.readSync(rid, buffer); @@ -295,7 +263,6 @@ const stdout = new Stdout(); const stderr = new Stderr(); export { - copy, read, readAll, readAllSync, diff --git a/ext/io/Cargo.toml b/ext/io/Cargo.toml index f2b6b4e235..22c346764b 100644 --- a/ext/io/Cargo.toml +++ b/ext/io/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_io" -version = "0.77.0" +version = "0.78.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/kv/Cargo.toml b/ext/kv/Cargo.toml index d7779ee65d..eee4762eb4 100644 --- a/ext/kv/Cargo.toml +++ b/ext/kv/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_kv" -version = "0.75.0" +version = "0.76.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/napi/Cargo.toml b/ext/napi/Cargo.toml index 3b54594735..aabf6d31f5 100644 --- a/ext/napi/Cargo.toml +++ b/ext/napi/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_napi" -version = "0.98.0" +version = "0.99.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/net/Cargo.toml b/ext/net/Cargo.toml index 8f952dc8f7..02e7a16818 100644 --- a/ext/net/Cargo.toml +++ b/ext/net/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_net" -version = "0.159.0" +version = "0.160.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/node/Cargo.toml b/ext/node/Cargo.toml index 783ad45c4b..d539d48516 100644 --- a/ext/node/Cargo.toml +++ b/ext/node/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_node" -version = "0.104.0" +version = "0.105.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/node/global.rs b/ext/node/global.rs index 61bcc33434..4d6695431d 100644 --- a/ext/node/global.rs +++ b/ext/node/global.rs @@ -54,7 +54,6 @@ const fn str_to_utf16(s: &str) -> [u16; N] { // - clearTimeout (both, but different implementation) // - global (node only) // - performance (both, but different implementation) -// - process (node only) // - setImmediate (node only) // - setInterval (both, but different implementation) // - setTimeout (both, but different implementation) @@ -62,7 +61,7 @@ const fn str_to_utf16(s: &str) -> [u16; N] { // UTF-16 encodings of the managed globals. THIS LIST MUST BE SORTED. #[rustfmt::skip] -const MANAGED_GLOBALS: [&[u16]; 13] = [ +const MANAGED_GLOBALS: [&[u16]; 12] = [ &str_to_utf16::<6>("Buffer"), &str_to_utf16::<17>("WorkerGlobalScope"), &str_to_utf16::<14>("clearImmediate"), @@ -70,7 +69,6 @@ const MANAGED_GLOBALS: [&[u16]; 13] = [ &str_to_utf16::<12>("clearTimeout"), &str_to_utf16::<6>("global"), &str_to_utf16::<11>("performance"), - &str_to_utf16::<7>("process"), &str_to_utf16::<4>("self"), &str_to_utf16::<12>("setImmediate"), &str_to_utf16::<11>("setInterval"), diff --git a/ext/node/lib.rs b/ext/node/lib.rs index 17fd7ab5a6..39b06e9fdd 100644 --- a/ext/node/lib.rs +++ b/ext/node/lib.rs @@ -502,6 +502,7 @@ deno_core::extension!(deno_node, "internal/error_codes.ts", "internal/errors.ts", "internal/event_target.mjs", + "internal/events/abort_listener.mjs", "internal/fixed_queue.ts", "internal/fs/streams.mjs", "internal/fs/utils.mjs", diff --git a/ext/node/ops/http.rs b/ext/node/ops/http.rs index 4b1f99ec04..773902dedf 100644 --- a/ext/node/ops/http.rs +++ b/ext/node/ops/http.rs @@ -272,6 +272,7 @@ pub async fn op_node_http_fetch_response_upgrade( loop { let read = upgraded_rx.read(&mut buf).await?; if read == 0 { + read_tx.shutdown().await?; break; } read_tx.write_all(&buf[..read]).await?; diff --git a/ext/node/polyfills/01_require.js b/ext/node/polyfills/01_require.js index d666b39274..e4a781cc44 100644 --- a/ext/node/polyfills/01_require.js +++ b/ext/node/polyfills/01_require.js @@ -940,12 +940,11 @@ Module.prototype.require = function (id) { // The module wrapper looks slightly different to Node. Instead of using one // wrapper function, we use two. The first one exists to performance optimize -// access to magic node globals, like `Buffer` or `process`. The second one -// is the actual wrapper function we run the users code in. -// The only observable difference is that in Deno `arguments.callee` is not -// null. +// access to magic node globals, like `Buffer`. The second one is the actual +// wrapper function we run the users code in. The only observable difference is +// that in Deno `arguments.callee` is not null. Module.wrapper = [ - "(function (exports, require, module, __filename, __dirname, Buffer, clearImmediate, clearInterval, clearTimeout, global, process, setImmediate, setInterval, setTimeout, performance) { (function (exports, require, module, __filename, __dirname) {", + "(function (exports, require, module, __filename, __dirname, Buffer, clearImmediate, clearInterval, clearTimeout, global, setImmediate, setInterval, setTimeout, performance) { (function (exports, require, module, __filename, __dirname) {", "\n}).call(this, exports, require, module, __filename, __dirname); })", ]; Module.wrap = function (script) { @@ -1030,7 +1029,6 @@ Module.prototype._compile = function (content, filename, format) { clearInterval, clearTimeout, global, - process, setImmediate, setInterval, setTimeout, @@ -1049,7 +1047,6 @@ Module.prototype._compile = function (content, filename, format) { clearInterval, clearTimeout, global, - process, setImmediate, setInterval, setTimeout, diff --git a/ext/node/polyfills/_events.mjs b/ext/node/polyfills/_events.mjs index bb34985940..ce7a8ebf24 100644 --- a/ext/node/polyfills/_events.mjs +++ b/ext/node/polyfills/_events.mjs @@ -46,7 +46,8 @@ import { } from "ext:deno_node/internal/validators.mjs"; import { spliceOne } from "ext:deno_node/_utils.ts"; import { nextTick } from "ext:deno_node/_process/process.ts"; -import { nodeGlobals } from "ext:deno_node/00_globals.js"; + +export { addAbortListener } from "./internal/events/abort_listener.mjs"; const kCapture = Symbol("kCapture"); const kErrorMonitor = Symbol("events.errorMonitor"); @@ -55,6 +56,11 @@ const kMaxEventTargetListenersWarned = Symbol( "events.maxEventTargetListenersWarned", ); +let process; +export function setProcess(p) { + process = p; +} + /** * Creates a new `EventEmitter` instance. * @param {{ captureRejections?: boolean; }} [opts] @@ -469,7 +475,7 @@ function _addListener(target, type, listener, prepend) { w.emitter = target; w.type = type; w.count = existing.length; - nodeGlobals.process.emitWarning(w); + process.emitWarning(w); } } diff --git a/ext/node/polyfills/events.ts b/ext/node/polyfills/events.ts index 3b73814109..78f3d8768c 100644 --- a/ext/node/polyfills/events.ts +++ b/ext/node/polyfills/events.ts @@ -1,6 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // @deno-types="./_events.d.ts" export { + addAbortListener, captureRejectionSymbol, default, defaultMaxListeners, diff --git a/ext/node/polyfills/internal/events/abort_listener.mjs b/ext/node/polyfills/internal/events/abort_listener.mjs new file mode 100644 index 0000000000..f1430489fa --- /dev/null +++ b/ext/node/polyfills/internal/events/abort_listener.mjs @@ -0,0 +1,44 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. + +import { primordials } from "ext:deno_node/internal/test/binding.ts"; +const { queueMicrotask } = primordials; +import { SymbolDispose } from "ext:deno_web/00_infra.js"; +import * as abortSignal from "ext:deno_web/03_abort_signal.js"; +import { validateAbortSignal, validateFunction } from "../validators.mjs"; +import { codes } from "../errors.ts"; +const { ERR_INVALID_ARG_TYPE } = codes; + +/** + * @param {AbortSignal} signal + * @param {EventListener} listener + * @returns {Disposable} + */ +function addAbortListener(signal, listener) { + if (signal === undefined) { + throw new ERR_INVALID_ARG_TYPE("signal", "AbortSignal", signal); + } + validateAbortSignal(signal, "signal"); + validateFunction(listener, "listener"); + + let removeEventListener; + if (signal.aborted) { + queueMicrotask(() => listener()); + } else { + signal[abortSignal.add](() => { + removeEventListener?.(); + listener(); + }); + removeEventListener = () => { + signal[abortSignal.remove](listener); + }; + } + return { + __proto__: null, + [SymbolDispose]() { + removeEventListener?.(); + }, + }; +} + +export { addAbortListener }; diff --git a/ext/node/polyfills/process.ts b/ext/node/polyfills/process.ts index 8d54429354..f09d7ceede 100644 --- a/ext/node/polyfills/process.ts +++ b/ext/node/polyfills/process.ts @@ -69,6 +69,7 @@ import * as constants from "ext:deno_node/internal_binding/constants.ts"; import * as uv from "ext:deno_node/internal_binding/uv.ts"; import type { BindingName } from "ext:deno_node/internal_binding/mod.ts"; import { buildAllowedFlags } from "ext:deno_node/internal/process/per_thread.mjs"; +import { setProcess } from "ext:deno_node/_events.mjs"; const notImplementedEvents = [ "multipleResolves", @@ -81,6 +82,8 @@ export const argv: string[] = ["", ""]; // And retains any value as long as it's nullish or number-ish. let ProcessExitCode: undefined | null | string | number; +export const execArgv: string[] = []; + /** https://nodejs.org/api/process.html#process_process_exit_code */ export const exit = (code?: number | string) => { if (code || code === 0) { @@ -336,7 +339,20 @@ function uncaughtExceptionHandler(err: any, origin: string) { process.emit("uncaughtException", err, origin); } -let execPath: string | null = null; +export let execPath: string = Object.freeze({ + __proto__: String.prototype, + toString() { + execPath = Deno.execPath(); + return execPath; + }, + get length() { + return this.toString().length; + }, + [Symbol.for("Deno.customInspect")](inspect, options) { + return inspect(this.toString(), options); + }, + // deno-lint-ignore no-explicit-any +}) as any as string; // The process class needs to be an ES5 class because it can be instantiated // in Node without the `new` keyword. It's not a true class in Node. Popular @@ -424,7 +440,7 @@ Process.prototype.cwd = cwd; Process.prototype.env = env; /** https://nodejs.org/api/process.html#process_process_execargv */ -Process.prototype.execArgv = []; +Process.prototype.execArgv = execArgv; /** https://nodejs.org/api/process.html#process_process_exit_code */ Process.prototype.exit = exit; @@ -703,11 +719,7 @@ Process.prototype._eval = undefined; Object.defineProperty(Process.prototype, "execPath", { get() { - if (execPath) { - return execPath; - } - execPath = Deno.execPath(); - return execPath; + return String(execPath); }, set(path: string) { execPath = path; @@ -960,4 +972,6 @@ internals.__bootstrapNodeProcess = function ( } }; +setProcess(process); + export default process; diff --git a/ext/node/polyfills/stream.ts b/ext/node/polyfills/stream.ts index 42f83fa289..618e5ba113 100644 --- a/ext/node/polyfills/stream.ts +++ b/ext/node/polyfills/stream.ts @@ -19,6 +19,9 @@ import { Transform, Writable, } from "ext:deno_node/_stream.mjs"; +import { + getDefaultHighWaterMark, +} from "ext:deno_node/internal/streams/state.mjs"; export { _isUint8Array, @@ -26,6 +29,7 @@ export { addAbortSignal, Duplex, finished, + getDefaultHighWaterMark, PassThrough, pipeline, Readable, diff --git a/ext/node/polyfills/util.ts b/ext/node/polyfills/util.ts index cb4e6498a4..c94d0f14b5 100644 --- a/ext/node/polyfills/util.ts +++ b/ext/node/polyfills/util.ts @@ -25,9 +25,13 @@ const { StringPrototypeIsWellFormed, StringPrototypePadStart, StringPrototypeToWellFormed, + PromiseResolve, } = primordials; -import { promisify } from "ext:deno_node/internal/util.mjs"; +import { + createDeferredPromise, + promisify, +} from "ext:deno_node/internal/util.mjs"; import { callbackify } from "ext:deno_node/_util/_util_callbackify.js"; import { debuglog } from "ext:deno_node/internal/util/debuglog.ts"; import { @@ -41,8 +45,13 @@ import types from "node:util/types"; import { Buffer } from "node:buffer"; import { isDeepStrictEqual } from "ext:deno_node/internal/util/comparisons.ts"; import process from "node:process"; -import { validateString } from "ext:deno_node/internal/validators.mjs"; +import { + validateAbortSignal, + validateString, +} from "ext:deno_node/internal/validators.mjs"; import { parseArgs } from "ext:deno_node/internal/util/parse_args/parse_args.js"; +import * as abortSignal from "ext:deno_web/03_abort_signal.js"; +import { ERR_INVALID_ARG_TYPE } from "ext:deno_node/internal/errors.ts"; export { callbackify, @@ -288,6 +297,24 @@ export function deprecate(fn: any, msg: string, code?: any) { return deprecated; } +// deno-lint-ignore require-await +export async function aborted( + signal: AbortSignal, + // deno-lint-ignore no-explicit-any + _resource: any, +): Promise { + if (signal === undefined) { + throw new ERR_INVALID_ARG_TYPE("signal", "AbortSignal", signal); + } + validateAbortSignal(signal, "signal"); + if (signal.aborted) { + return PromiseResolve(); + } + const abortPromise = createDeferredPromise(); + signal[abortSignal.add](abortPromise.resolve); + return abortPromise.promise; +} + export { getSystemErrorName, isDeepStrictEqual }; export default { @@ -311,6 +338,7 @@ export default { isBuffer, _extend, getSystemErrorName, + aborted, deprecate, callbackify, parseArgs, diff --git a/ext/node_resolver/Cargo.toml b/ext/node_resolver/Cargo.toml index 704a5af843..1042045692 100644 --- a/ext/node_resolver/Cargo.toml +++ b/ext/node_resolver/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "node_resolver" -version = "0.6.0" +version = "0.7.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/node_resolver/lib.rs b/ext/node_resolver/lib.rs index 1ab972ccfd..f03f770486 100644 --- a/ext/node_resolver/lib.rs +++ b/ext/node_resolver/lib.rs @@ -18,6 +18,7 @@ pub use npm::NpmResolverRc; pub use package_json::load_pkg_json; pub use package_json::PackageJsonThreadLocalCache; pub use path::PathClean; +pub use resolution::parse_npm_pkg_name; pub use resolution::NodeModuleKind; pub use resolution::NodeResolution; pub use resolution::NodeResolutionMode; diff --git a/ext/node_resolver/resolution.rs b/ext/node_resolver/resolution.rs index ae791e312b..ad9dbb7100 100644 --- a/ext/node_resolver/resolution.rs +++ b/ext/node_resolver/resolution.rs @@ -367,6 +367,7 @@ impl NodeResolver { pkg_json_path, }); }; + let name = name.split("/").last().unwrap(); vec![name.to_string()] } Some(Value::Object(o)) => { diff --git a/ext/tls/Cargo.toml b/ext/tls/Cargo.toml index 7fbfeffd12..08a9802df5 100644 --- a/ext/tls/Cargo.toml +++ b/ext/tls/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_tls" -version = "0.154.0" +version = "0.155.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/url/Cargo.toml b/ext/url/Cargo.toml index 991a28ce42..7f86e14456 100644 --- a/ext/url/Cargo.toml +++ b/ext/url/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_url" -version = "0.167.0" +version = "0.168.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/web/03_abort_signal.js b/ext/web/03_abort_signal.js index 81844d53fc..ae0701451b 100644 --- a/ext/web/03_abort_signal.js +++ b/ext/web/03_abort_signal.js @@ -71,6 +71,7 @@ class WeakRefSet { const add = Symbol("[[add]]"); const signalAbort = Symbol("[[signalAbort]]"); const remove = Symbol("[[remove]]"); +const runAbortSteps = Symbol("[[runAbortSteps]]"); const abortReason = Symbol("[[abortReason]]"); const abortAlgos = Symbol("[[abortAlgos]]"); const dependent = Symbol("[[dependent]]"); @@ -149,26 +150,43 @@ class AbortSignal extends EventTarget { return; } this[abortReason] = reason; + + const dependentSignalsToAbort = []; + if (this[dependentSignals] !== null) { + const dependentSignalArray = this[dependentSignals].toArray(); + for (let i = 0; i < dependentSignalArray.length; ++i) { + const dependentSignal = dependentSignalArray[i]; + if (dependentSignal[abortReason] === undefined) { + dependentSignal[abortReason] = this[abortReason]; + ArrayPrototypePush(dependentSignalsToAbort, dependentSignal); + } + } + } + + this[runAbortSteps](); + + if (dependentSignalsToAbort.length !== 0) { + for (let i = 0; i < dependentSignalsToAbort.length; ++i) { + const dependentSignal = dependentSignalsToAbort[i]; + dependentSignal[runAbortSteps](); + } + } + } + + [runAbortSteps]() { const algos = this[abortAlgos]; this[abortAlgos] = null; - if (listenerCount(this, "abort") > 0) { - const event = new Event("abort"); - setIsTrusted(event, true); - super.dispatchEvent(event); - } if (algos !== null) { for (const algorithm of new SafeSetIterator(algos)) { algorithm(); } } - if (this[dependentSignals] !== null) { - const dependentSignalArray = this[dependentSignals].toArray(); - for (let i = 0; i < dependentSignalArray.length; ++i) { - const dependentSignal = dependentSignalArray[i]; - dependentSignal[signalAbort](reason); - } + if (listenerCount(this, "abort") > 0) { + const event = new Event("abort"); + setIsTrusted(event, true); + super.dispatchEvent(event); } } diff --git a/ext/web/Cargo.toml b/ext/web/Cargo.toml index 717a4a7587..7fd12632d7 100644 --- a/ext/web/Cargo.toml +++ b/ext/web/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_web" -version = "0.198.0" +version = "0.199.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/webgpu/Cargo.toml b/ext/webgpu/Cargo.toml index 22c9d00334..b5cff59855 100644 --- a/ext/webgpu/Cargo.toml +++ b/ext/webgpu/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_webgpu" -version = "0.134.0" +version = "0.135.0" authors = ["the Deno authors"] edition.workspace = true license = "MIT" diff --git a/ext/webidl/Cargo.toml b/ext/webidl/Cargo.toml index 1c259690ad..2f87dc2197 100644 --- a/ext/webidl/Cargo.toml +++ b/ext/webidl/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_webidl" -version = "0.167.0" +version = "0.168.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/websocket/Cargo.toml b/ext/websocket/Cargo.toml index 932451b127..3fc9025466 100644 --- a/ext/websocket/Cargo.toml +++ b/ext/websocket/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_websocket" -version = "0.172.0" +version = "0.173.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/webstorage/Cargo.toml b/ext/webstorage/Cargo.toml index 6cf152cc84..fbcd17edf9 100644 --- a/ext/webstorage/Cargo.toml +++ b/ext/webstorage/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_webstorage" -version = "0.162.0" +version = "0.163.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 1299257e80..6d24781cfa 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_runtime" -version = "0.176.0" +version = "0.177.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/runtime/js/13_buffer.js b/runtime/js/13_buffer.js index ae57fcb163..4d3f08d4da 100644 --- a/runtime/js/13_buffer.js +++ b/runtime/js/13_buffer.js @@ -234,50 +234,4 @@ class Buffer { } } -async function readAll(r) { - internals.warnOnDeprecatedApi( - "Deno.readAll()", - new Error().stack, - "Use `readAll()` from `https://jsr.io/@std/io/doc/read-all/~` instead.", - ); - const buf = new Buffer(); - await buf.readFrom(r); - return buf.bytes(); -} - -function readAllSync(r) { - internals.warnOnDeprecatedApi( - "Deno.readAllSync()", - new Error().stack, - "Use `readAllSync()` from `https://jsr.io/@std/io/doc/read-all/~` instead.", - ); - const buf = new Buffer(); - buf.readFromSync(r); - return buf.bytes(); -} - -async function writeAll(w, arr) { - internals.warnOnDeprecatedApi( - "Deno.writeAll()", - new Error().stack, - "Use `writeAll()` from `https://jsr.io/@std/io/doc/write-all/~` instead.", - ); - let nwritten = 0; - while (nwritten < arr.length) { - nwritten += await w.write(TypedArrayPrototypeSubarray(arr, nwritten)); - } -} - -function writeAllSync(w, arr) { - internals.warnOnDeprecatedApi( - "Deno.writeAllSync()", - new Error().stack, - "Use `writeAllSync()` from `https://jsr.io/@std/io/doc/write-all/~` instead.", - ); - let nwritten = 0; - while (nwritten < arr.length) { - nwritten += w.writeSync(TypedArrayPrototypeSubarray(arr, nwritten)); - } -} - -export { Buffer, readAll, readAllSync, writeAll, writeAllSync }; +export { Buffer }; diff --git a/runtime/js/40_fs_events.js b/runtime/js/40_fs_events.js index d7aa5de05c..a0495540c6 100644 --- a/runtime/js/40_fs_events.js +++ b/runtime/js/40_fs_events.js @@ -31,15 +31,6 @@ class FsWatcher { this.#rid = op_fs_events_open({ recursive, paths }); } - get rid() { - internals.warnOnDeprecatedApi( - "Deno.FsWatcher.rid", - new Error().stack, - "Use `Deno.FsWatcher` instance methods instead.", - ); - return this.#rid; - } - unref() { core.unrefOpPromise(this.#promise); } diff --git a/runtime/js/40_process.js b/runtime/js/40_process.js index b2269ffd68..954d8d00b3 100644 --- a/runtime/js/40_process.js +++ b/runtime/js/40_process.js @@ -130,6 +130,8 @@ class Process { } } +// Note: This function was soft-removed in Deno 2. Its types have been removed, +// but its implementation has been kept to avoid breaking changes. function run({ cmd, cwd = undefined, @@ -144,11 +146,6 @@ function run({ ...new SafeArrayIterator(ArrayPrototypeSlice(cmd, 1)), ]; } - internals.warnOnDeprecatedApi( - "Deno.run()", - (new Error()).stack, - `Use "Deno.Command()" API instead.`, - ); const res = opRun({ cmd: ArrayPrototypeMap(cmd, String), cwd, diff --git a/runtime/js/40_tty.js b/runtime/js/40_tty.js index 7cf1e4f5d9..72e7b68846 100644 --- a/runtime/js/40_tty.js +++ b/runtime/js/40_tty.js @@ -1,5 +1,5 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import { core, internals, primordials } from "ext:core/mod.js"; +import { core, primordials } from "ext:core/mod.js"; import { op_console_size } from "ext:core/ops"; const { Uint32Array, @@ -15,12 +15,9 @@ function consoleSize() { return { columns: size[0], rows: size[1] }; } +// Note: This function was soft-removed in Deno 2. Its types have been removed, +// but its implementation has been kept to avoid breaking changes. function isatty(rid) { - internals.warnOnDeprecatedApi( - "Deno.isatty()", - new Error().stack, - "Use `Deno.stdin.isTerminal()`, `Deno.stdout.isTerminal()`, `Deno.stderr.isTerminal()` or `Deno.FsFile.isTerminal()` instead.", - ); return isTerminal(rid); } diff --git a/runtime/js/90_deno_ns.js b/runtime/js/90_deno_ns.js index 7c805e6476..6f5d85da2c 100644 --- a/runtime/js/90_deno_ns.js +++ b/runtime/js/90_deno_ns.js @@ -77,22 +77,6 @@ const denoNs = { lstat: fs.lstat, truncateSync: fs.truncateSync, truncate: fs.truncate, - ftruncateSync(rid, len) { - internals.warnOnDeprecatedApi( - "Deno.ftruncateSync()", - new Error().stack, - "Use `Deno.FsFile.truncateSync()` instead.", - ); - return fs.ftruncateSync(rid, len); - }, - ftruncate(rid, len) { - internals.warnOnDeprecatedApi( - "Deno.ftruncate()", - new Error().stack, - "Use `Deno.FsFile.truncate()` instead.", - ); - return fs.ftruncate(rid, len); - }, errors: errors.errors, inspect: console.inspect, env: os.env, @@ -101,42 +85,8 @@ const denoNs = { Buffer: buffer.Buffer, readAll: buffer.readAll, readAllSync: buffer.readAllSync, - writeAll: buffer.writeAll, - writeAllSync: buffer.writeAllSync, copy: io.copy, SeekMode: io.SeekMode, - read(rid, buffer) { - internals.warnOnDeprecatedApi( - "Deno.read()", - new Error().stack, - "Use `reader.read()` instead.", - ); - return io.read(rid, buffer); - }, - readSync(rid, buffer) { - internals.warnOnDeprecatedApi( - "Deno.readSync()", - new Error().stack, - "Use `reader.readSync()` instead.", - ); - return io.readSync(rid, buffer); - }, - write(rid, data) { - internals.warnOnDeprecatedApi( - "Deno.write()", - new Error().stack, - "Use `writer.write()` instead.", - ); - return io.write(rid, data); - }, - writeSync(rid, data) { - internals.warnOnDeprecatedApi( - "Deno.writeSync()", - new Error().stack, - "Use `writer.writeSync()` instead.", - ); - return io.writeSync(rid, data); - }, File: fs.File, FsFile: fs.FsFile, open: fs.open, @@ -168,22 +118,6 @@ const denoNs = { connectTls: tls.connectTls, listenTls: tls.listenTls, startTls: tls.startTls, - fstatSync(rid) { - internals.warnOnDeprecatedApi( - "Deno.fstatSync()", - new Error().stack, - "Use `Deno.FsFile.statSync()` instead.", - ); - return fs.fstatSync(rid); - }, - fstat(rid) { - internals.warnOnDeprecatedApi( - "Deno.fstat()", - new Error().stack, - "Use `Deno.FsFile.stat()` instead.", - ); - return fs.fstat(rid); - }, fsyncSync: fs.fsyncSync, fsync: fs.fsync, fdatasyncSync: fs.fdatasyncSync, diff --git a/runtime/js/98_global_scope_shared.js b/runtime/js/98_global_scope_shared.js index b6e4802163..41df35c609 100644 --- a/runtime/js/98_global_scope_shared.js +++ b/runtime/js/98_global_scope_shared.js @@ -31,6 +31,7 @@ import * as webidl from "ext:deno_webidl/00_webidl.js"; import { DOMException } from "ext:deno_web/01_dom_exception.js"; import * as abortSignal from "ext:deno_web/03_abort_signal.js"; import * as imageData from "ext:deno_web/16_image_data.js"; +import process from "node:process"; import { loadWebGPU } from "ext:deno_webgpu/00_init.js"; import * as webgpuSurface from "ext:deno_webgpu/02_surface.js"; import { unstableIds } from "ext:runtime/90_deno_ns.js"; @@ -137,6 +138,7 @@ const windowOrWorkerGlobalScope = { fetch: core.propWritable(fetch.fetch), EventSource: core.propWritable(eventSource.EventSource), performance: core.propWritable(performance.performance), + process: core.propWritable(process), reportError: core.propWritable(event.reportError), setInterval: core.propWritable(timers.setInterval), setTimeout: core.propWritable(timers.setTimeout), diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js index 1854a73fad..913761f6a8 100644 --- a/runtime/js/99_main.js +++ b/runtime/js/99_main.js @@ -576,12 +576,11 @@ function bootstrapMainRuntime(runtimeOptions, warmup = false) { 6: hasNodeModulesDir, 7: argv0, 8: nodeDebug, - 9: future, - 10: mode, - 11: servePort, - 12: serveHost, - 13: serveIsMain, - 14: serveWorkerCount, + 9: mode, + 10: servePort, + 11: serveHost, + 12: serveIsMain, + 13: serveWorkerCount, } = runtimeOptions; if (mode === executionModes.serve) { @@ -668,7 +667,7 @@ function bootstrapMainRuntime(runtimeOptions, warmup = false) { // TODO(iuioiua): remove in Deno v2. This allows us to dynamically delete // class properties within constructors for classes that are not defined // within the Deno namespace. - internals.future = future; + internals.future = true; removeImportedOps(); @@ -723,26 +722,27 @@ function bootstrapMainRuntime(runtimeOptions, warmup = false) { target, ); + // TODO(bartlomieju): this is not ideal, but because we use `ObjectAssign` + // above any properties that are defined elsewhere using `Object.defineProperty` + // are lost. + let jupyterNs = undefined; + ObjectDefineProperty(finalDenoNs, "jupyter", { + get() { + if (jupyterNs) { + return jupyterNs; + } + throw new Error( + "Deno.jupyter is only available in `deno jupyter` subcommand.", + ); + }, + set(val) { + jupyterNs = val; + }, + }); + // TODO(bartlomieju): deprecate --unstable if (unstableFlag) { ObjectAssign(finalDenoNs, denoNsUnstable); - // TODO(bartlomieju): this is not ideal, but because we use `ObjectAssign` - // above any properties that are defined elsewhere using `Object.defineProperty` - // are lost. - let jupyterNs = undefined; - ObjectDefineProperty(finalDenoNs, "jupyter", { - get() { - if (jupyterNs) { - return jupyterNs; - } - throw new Error( - "Deno.jupyter is only available in `deno jupyter` subcommand.", - ); - }, - set(val) { - jupyterNs = val; - }, - }); } else { for (let i = 0; i <= unstableFeatures.length; i++) { const id = unstableFeatures[i]; @@ -798,28 +798,14 @@ function bootstrapMainRuntime(runtimeOptions, warmup = false) { nodeDebug, }); } - if (future) { + if (internals.future) { delete globalThis.window; delete Deno.Buffer; - delete Deno.copy; - delete Deno.File; - delete Deno.fstat; - delete Deno.fstatSync; - delete Deno.ftruncate; - delete Deno.ftruncateSync; delete Deno.FsFile.prototype.rid; delete Deno.funlock; delete Deno.funlockSync; - delete Deno.readAll; - delete Deno.readAllSync; - delete Deno.read; - delete Deno.readSync; delete Deno.seek; delete Deno.seekSync; - delete Deno.writeAll; - delete Deno.writeAllSync; - delete Deno.write; - delete Deno.writeSync; } } else { // Warmup @@ -848,13 +834,12 @@ function bootstrapWorkerRuntime( 6: hasNodeModulesDir, 7: argv0, 8: nodeDebug, - 9: future, } = runtimeOptions; // TODO(iuioiua): remove in Deno v2. This allows us to dynamically delete // class properties within constructors for classes that are not defined // within the Deno namespace. - internals.future = future; + internals.future = true; performance.setTimeOrigin(DateNow()); globalThis_ = globalThis; @@ -977,27 +962,13 @@ function bootstrapWorkerRuntime( }); } - if (future) { + if (internals.future) { delete Deno.Buffer; - delete Deno.copy; - delete Deno.File; - delete Deno.fstat; - delete Deno.fstatSync; - delete Deno.ftruncate; - delete Deno.ftruncateSync; delete Deno.FsFile.prototype.rid; delete Deno.funlock; delete Deno.funlockSync; - delete Deno.readAll; - delete Deno.readAllSync; - delete Deno.read; - delete Deno.readSync; delete Deno.seek; delete Deno.seekSync; - delete Deno.writeAll; - delete Deno.writeAllSync; - delete Deno.write; - delete Deno.writeSync; } } else { // Warmup diff --git a/runtime/lib.rs b/runtime/lib.rs index daa55f773f..c8ab099f18 100644 --- a/runtime/lib.rs +++ b/runtime/lib.rs @@ -44,7 +44,6 @@ pub use worker_bootstrap::WorkerExecutionMode; pub use worker_bootstrap::WorkerLogLevel; mod shared; -pub use shared::import_assertion_callback; pub use shared::runtime; pub struct UnstableGranularFlag { @@ -84,7 +83,7 @@ pub static UNSTABLE_GRANULAR_FLAGS: &[UnstableGranularFlag] = &[ UnstableGranularFlag { name: ops::http::UNSTABLE_FEATURE_NAME, help_text: "Enable unstable HTTP APIs", - show_in_help: false, + show_in_help: true, id: 5, }, UnstableGranularFlag { diff --git a/runtime/ops/process.rs b/runtime/ops/process.rs index 11e4390513..c2fa212d3a 100644 --- a/runtime/ops/process.rs +++ b/runtime/ops/process.rs @@ -17,10 +17,14 @@ use deno_io::ChildStderrResource; use deno_io::ChildStdinResource; use deno_io::ChildStdoutResource; use deno_permissions::PermissionsContainer; +use deno_permissions::RunPathQuery; use serde::Deserialize; use serde::Serialize; use std::borrow::Cow; use std::cell::RefCell; +use std::collections::HashMap; +use std::path::Path; +use std::path::PathBuf; use std::process::ExitStatus; use std::rc::Rc; use tokio::process::Command; @@ -228,63 +232,15 @@ fn create_command( mut args: SpawnArgs, api_name: &str, ) -> Result { - fn get_requires_allow_all_env_var(args: &SpawnArgs) -> Option> { - fn requires_allow_all(key: &str) -> bool { - let key = key.trim(); - // we could be more targted here, but there are quite a lot of - // LD_* and DYLD_* env variables - key.starts_with("LD_") || key.starts_with("DYLD_") - } - - /// Checks if the user set this env var to an empty - /// string in order to clear it. - fn args_has_empty_env_value(args: &SpawnArgs, key_name: &str) -> bool { - args - .env - .iter() - .find(|(k, _)| k == key_name) - .map(|(_, v)| v.trim().is_empty()) - .unwrap_or(false) - } - - if let Some((key, _)) = args - .env - .iter() - .find(|(k, v)| requires_allow_all(k) && !v.trim().is_empty()) - { - return Some(key.into()); - } - - if !args.clear_env { - if let Some((key, _)) = std::env::vars().find(|(k, v)| { - requires_allow_all(k) - && !v.trim().is_empty() - && !args_has_empty_env_value(args, k) - }) { - return Some(key.into()); - } - } - - None - } - - { - let permissions = state.borrow_mut::(); - permissions.check_run(&args.cmd, api_name)?; - if permissions.check_run_all(api_name).is_err() { - // error the same on all platforms - if let Some(name) = get_requires_allow_all_env_var(&args) { - // we don't allow users to launch subprocesses with any LD_ or DYLD_* - // env vars set because this allows executing code (ex. LD_PRELOAD) - return Err(deno_core::error::custom_error( - "PermissionDenied", - format!("Requires --allow-all permissions to spawn subprocess with {} environment variable.", name) - )); - } - } - } - - let mut command = std::process::Command::new(args.cmd); + let (cmd, run_env) = compute_run_cmd_and_check_permissions( + &args.cmd, + args.cwd.as_deref(), + &args.env, + args.clear_env, + state, + api_name, + )?; + let mut command = std::process::Command::new(cmd); #[cfg(windows)] if args.windows_raw_arguments { @@ -298,14 +254,9 @@ fn create_command( #[cfg(not(windows))] command.args(args.args); - if let Some(cwd) = args.cwd { - command.current_dir(cwd); - } - - if args.clear_env { - command.env_clear(); - } - command.envs(args.env); + command.current_dir(run_env.cwd); + command.env_clear(); + command.envs(run_env.envs); #[cfg(unix)] if let Some(gid) = args.gid { @@ -554,6 +505,141 @@ fn close_raw_handle(handle: deno_io::RawBiPipeHandle) { } } +fn compute_run_cmd_and_check_permissions( + arg_cmd: &str, + arg_cwd: Option<&str>, + arg_envs: &[(String, String)], + arg_clear_env: bool, + state: &mut OpState, + api_name: &str, +) -> Result<(PathBuf, RunEnv), AnyError> { + let run_env = compute_run_env(arg_cwd, arg_envs, arg_clear_env) + .with_context(|| format!("Failed to spawn '{}'", arg_cmd))?; + let cmd = resolve_cmd(arg_cmd, &run_env) + .with_context(|| format!("Failed to spawn '{}'", arg_cmd))?; + check_run_permission( + state, + RunPathQuery { + requested: arg_cmd, + resolved: &cmd, + }, + &run_env, + api_name, + )?; + Ok((cmd, run_env)) +} + +struct RunEnv { + envs: HashMap, + cwd: PathBuf, +} + +/// Computes the current environment, which will then be used to inform +/// permissions and finally spawning. This is very important to compute +/// ahead of time so that the environment used to verify permissions is +/// the same environment used to spawn the sub command. This protects against +/// someone doing timing attacks by changing the environment on a worker. +fn compute_run_env( + arg_cwd: Option<&str>, + arg_envs: &[(String, String)], + arg_clear_env: bool, +) -> Result { + #[allow(clippy::disallowed_methods)] + let cwd = std::env::current_dir().context("failed resolving cwd")?; + let cwd = arg_cwd + .map(|cwd_arg| resolve_path(cwd_arg, &cwd)) + .unwrap_or(cwd); + let envs = if arg_clear_env { + arg_envs.iter().cloned().collect() + } else { + let mut envs = std::env::vars().collect::>(); + for (key, value) in arg_envs { + envs.insert(key.clone(), value.clone()); + } + envs + }; + Ok(RunEnv { envs, cwd }) +} + +fn resolve_cmd(cmd: &str, env: &RunEnv) -> Result { + let is_path = cmd.contains('/'); + #[cfg(windows)] + let is_path = is_path || cmd.contains('\\') || Path::new(&cmd).is_absolute(); + if is_path { + Ok(resolve_path(cmd, &env.cwd)) + } else { + let path = env.envs.get("PATH").or_else(|| { + if cfg!(windows) { + env.envs.iter().find_map(|(k, v)| { + if k.to_uppercase() == "PATH" { + Some(v) + } else { + None + } + }) + } else { + None + } + }); + match which::which_in(cmd, path, &env.cwd) { + Ok(cmd) => Ok(cmd), + Err(which::Error::CannotFindBinaryPath) => { + Err(std::io::Error::from(std::io::ErrorKind::NotFound).into()) + } + Err(err) => Err(err.into()), + } + } +} + +fn resolve_path(path: &str, cwd: &Path) -> PathBuf { + deno_core::normalize_path(cwd.join(path)) +} + +fn check_run_permission( + state: &mut OpState, + cmd: RunPathQuery, + run_env: &RunEnv, + api_name: &str, +) -> Result<(), AnyError> { + let permissions = state.borrow_mut::(); + if !permissions.query_run_all(api_name) { + // error the same on all platforms + let env_var_names = get_requires_allow_all_env_vars(run_env); + if !env_var_names.is_empty() { + // we don't allow users to launch subprocesses with any LD_ or DYLD_* + // env vars set because this allows executing code (ex. LD_PRELOAD) + return Err(deno_core::error::custom_error( + "PermissionDenied", + format!( + "Requires --allow-all permissions to spawn subprocess with {} environment variable{}.", + env_var_names.join(", "), + if env_var_names.len() != 1 { "s" } else { "" } + ) + )); + } + permissions.check_run(cmd, api_name)?; + } + Ok(()) +} + +fn get_requires_allow_all_env_vars(env: &RunEnv) -> Vec<&str> { + fn requires_allow_all(key: &str) -> bool { + let key = key.trim(); + // we could be more targted here, but there are quite a lot of + // LD_* and DYLD_* env variables + key.starts_with("LD_") || key.starts_with("DYLD_") + } + + let mut found_envs = env + .envs + .iter() + .filter(|(k, v)| requires_allow_all(k) && !v.trim().is_empty()) + .map(|(k, _)| k.as_str()) + .collect::>(); + found_envs.sort(); + found_envs +} + #[op2] #[serde] fn op_spawn_child( @@ -634,6 +720,8 @@ fn op_spawn_kill( } mod deprecated { + use deno_core::anyhow; + use super::*; #[derive(Deserialize)] @@ -681,20 +769,24 @@ mod deprecated { #[serde] run_args: RunArgs, ) -> Result { let args = run_args.cmd; - state - .borrow_mut::() - .check_run(&args[0], "Deno.run()")?; - let env = run_args.env; - let cwd = run_args.cwd; + let cmd = args.first().ok_or_else(|| anyhow::anyhow!("Missing cmd"))?; + let (cmd, run_env) = compute_run_cmd_and_check_permissions( + cmd, + run_args.cwd.as_deref(), + &run_args.env, + /* clear env */ false, + state, + "Deno.run()", + )?; - let mut c = Command::new(args.first().unwrap()); - (1..args.len()).for_each(|i| { - let arg = args.get(i).unwrap(); + let mut c = Command::new(cmd); + for arg in args.iter().skip(1) { c.arg(arg); - }); - cwd.map(|d| c.current_dir(d)); + } + c.current_dir(run_env.cwd); - for (key, value) in &env { + c.env_clear(); + for (key, value) in run_env.envs { c.env(key, value); } diff --git a/runtime/permissions/Cargo.toml b/runtime/permissions/Cargo.toml index 5ed58287c2..b435748965 100644 --- a/runtime/permissions/Cargo.toml +++ b/runtime/permissions/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_permissions" -version = "0.27.0" +version = "0.28.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/runtime/permissions/lib.rs b/runtime/permissions/lib.rs index d50258fd6e..f2d4e909ff 100644 --- a/runtime/permissions/lib.rs +++ b/runtime/permissions/lib.rs @@ -32,7 +32,6 @@ use std::path::PathBuf; use std::str::FromStr; use std::string::ToString; use std::sync::Arc; -use which::which; pub mod prompter; use prompter::permission_prompt; @@ -317,7 +316,7 @@ pub trait Descriptor: Eq + Clone + Hash { /// Parse this descriptor from a list of Self::Arg, which may have been converted from /// command-line strings. - fn parse(list: &Option>) -> Result, AnyError>; + fn parse(list: Option<&[Self::Arg]>) -> Result, AnyError>; /// Generic check function to check this descriptor against a `UnaryPermission`. fn check_in_permission( @@ -333,9 +332,6 @@ pub trait Descriptor: Eq + Clone + Hash { fn stronger_than(&self, other: &Self) -> bool { self == other } - fn aliases(&self) -> Vec { - vec![] - } } #[derive(Clone, Debug, Eq, PartialEq)] @@ -423,43 +419,33 @@ impl UnaryPermission { desc: Option<&T>, allow_partial: AllowPartial, ) -> PermissionState { - let aliases = desc.map_or(vec![], T::aliases); - for desc in [desc] - .into_iter() - .chain(aliases.iter().map(Some).collect::>()) - { - let state = if self.is_flag_denied(desc) || self.is_prompt_denied(desc) { - PermissionState::Denied - } else if self.is_granted(desc) { - match allow_partial { - AllowPartial::TreatAsGranted => PermissionState::Granted, - AllowPartial::TreatAsDenied => { - if self.is_partial_flag_denied(desc) { - PermissionState::Denied - } else { - PermissionState::Granted - } - } - AllowPartial::TreatAsPartialGranted => { - if self.is_partial_flag_denied(desc) { - PermissionState::GrantedPartial - } else { - PermissionState::Granted - } + if self.is_flag_denied(desc) || self.is_prompt_denied(desc) { + PermissionState::Denied + } else if self.is_granted(desc) { + match allow_partial { + AllowPartial::TreatAsGranted => PermissionState::Granted, + AllowPartial::TreatAsDenied => { + if self.is_partial_flag_denied(desc) { + PermissionState::Denied + } else { + PermissionState::Granted + } + } + AllowPartial::TreatAsPartialGranted => { + if self.is_partial_flag_denied(desc) { + PermissionState::GrantedPartial + } else { + PermissionState::Granted } } - } else if matches!(allow_partial, AllowPartial::TreatAsDenied) - && self.is_partial_flag_denied(desc) - { - PermissionState::Denied - } else { - PermissionState::Prompt - }; - if state != PermissionState::Prompt { - return state; } + } else if matches!(allow_partial, AllowPartial::TreatAsDenied) + && self.is_partial_flag_denied(desc) + { + PermissionState::Denied + } else { + PermissionState::Prompt } - PermissionState::Prompt } fn request_desc( @@ -512,9 +498,6 @@ impl UnaryPermission { match desc { Some(desc) => { self.granted_list.retain(|v| !v.stronger_than(desc)); - for alias in desc.aliases() { - self.granted_list.retain(|v| !v.stronger_than(&alias)); - } } None => { self.granted_global = false; @@ -582,11 +565,7 @@ impl UnaryPermission { ) { match desc { Some(desc) => { - let aliases = desc.aliases(); list.insert(desc); - for alias in aliases { - list.insert(alias); - } } None => *list_global = true, } @@ -612,7 +591,7 @@ impl UnaryPermission { ChildUnaryPermissionArg::GrantedList(granted_list) => { let granted: Vec = granted_list.into_iter().map(From::from).collect(); - perms.granted_list = T::parse(&Some(granted))?; + perms.granted_list = T::parse(Some(&granted))?; if !perms .granted_list .iter() @@ -649,7 +628,7 @@ impl Descriptor for ReadDescriptor { perm.check_desc(Some(self), true, api_name, || None) } - fn parse(args: &Option>) -> Result, AnyError> { + fn parse(args: Option<&[Self::Arg]>) -> Result, AnyError> { parse_path_list(args, ReadDescriptor) } @@ -681,7 +660,7 @@ impl Descriptor for WriteDescriptor { perm.check_desc(Some(self), true, api_name, || None) } - fn parse(args: &Option>) -> Result, AnyError> { + fn parse(args: Option<&[Self::Arg]>) -> Result, AnyError> { parse_path_list(args, WriteDescriptor) } @@ -754,7 +733,7 @@ impl Descriptor for NetDescriptor { perm.check_desc(Some(self), false, api_name, || None) } - fn parse(args: &Option>) -> Result, AnyError> { + fn parse(args: Option<&[Self::Arg]>) -> Result, AnyError> { parse_net_list(args) } @@ -864,7 +843,7 @@ impl Descriptor for EnvDescriptor { perm.check_desc(Some(self), false, api_name, || None) } - fn parse(list: &Option>) -> Result, AnyError> { + fn parse(list: Option<&[Self::Arg]>) -> Result, AnyError> { parse_env_list(list) } @@ -883,6 +862,17 @@ impl AsRef for EnvDescriptor { } } +#[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)] +pub struct RunPathQuery<'a> { + pub requested: &'a str, + pub resolved: &'a Path, +} + +pub enum RunDescriptorArg { + Name(String), + Path(PathBuf), +} + #[derive(Clone, Eq, PartialEq, Hash, Debug)] pub enum RunDescriptor { /// Warning: You may want to construct with `RunDescriptor::from()` for case @@ -893,8 +883,26 @@ pub enum RunDescriptor { Path(PathBuf), } +impl From for RunDescriptorArg { + fn from(s: String) -> Self { + #[cfg(windows)] + let s = s.to_lowercase(); + let is_path = s.contains('/'); + #[cfg(windows)] + let is_path = is_path || s.contains('\\') || Path::new(&s).is_absolute(); + if is_path { + Self::Path(resolve_from_cwd(Path::new(&s)).unwrap()) + } else { + match which::which(&s) { + Ok(path) => Self::Path(path), + Err(_) => Self::Name(s), + } + } + } +} + impl Descriptor for RunDescriptor { - type Arg = String; + type Arg = RunDescriptorArg; fn check_in_permission( &self, @@ -905,7 +913,7 @@ impl Descriptor for RunDescriptor { perm.check_desc(Some(self), false, api_name, || None) } - fn parse(args: &Option>) -> Result, AnyError> { + fn parse(args: Option<&[Self::Arg]>) -> Result, AnyError> { parse_run_list(args) } @@ -916,16 +924,6 @@ impl Descriptor for RunDescriptor { fn name(&self) -> Cow { Cow::from(self.to_string()) } - - fn aliases(&self) -> Vec { - match self { - RunDescriptor::Name(name) => match which(name) { - Ok(path) => vec![RunDescriptor::Path(path)], - Err(_) => vec![], - }, - RunDescriptor::Path(_) => vec![], - } - } } impl From for RunDescriptor { @@ -938,7 +936,10 @@ impl From for RunDescriptor { if is_path { Self::Path(resolve_from_cwd(Path::new(&s)).unwrap()) } else { - Self::Name(s) + match which::which(&s) { + Ok(path) => Self::Path(path), + Err(_) => Self::Name(s), + } } } } @@ -947,11 +948,7 @@ impl From for RunDescriptor { fn from(p: PathBuf) -> Self { #[cfg(windows)] let p = PathBuf::from(p.to_string_lossy().to_string().to_lowercase()); - if p.is_absolute() { - Self::Path(p) - } else { - Self::Path(resolve_from_cwd(&p).unwrap()) - } + Self::Path(resolve_from_cwd(&p).unwrap()) } } @@ -988,7 +985,7 @@ impl Descriptor for SysDescriptor { perm.check_desc(Some(self), false, api_name, || None) } - fn parse(list: &Option>) -> Result, AnyError> { + fn parse(list: Option<&[Self::Arg]>) -> Result, AnyError> { parse_sys_list(list) } @@ -1025,7 +1022,7 @@ impl Descriptor for FfiDescriptor { perm.check_desc(Some(self), true, api_name, || None) } - fn parse(list: &Option>) -> Result, AnyError> { + fn parse(list: Option<&[Self::Arg]>) -> Result, AnyError> { parse_path_list(list, FfiDescriptor) } @@ -1330,15 +1327,16 @@ impl UnaryPermission { pub fn check( &mut self, - cmd: &str, + cmd: RunPathQuery, api_name: Option<&str>, ) -> Result<(), AnyError> { + debug_assert!(cmd.resolved.is_absolute()); skip_check_if_is_permission_fully_granted!(self); self.check_desc( - Some(&RunDescriptor::from(cmd.to_string())), + Some(&RunDescriptor::Path(cmd.resolved.to_path_buf())), false, api_name, - || Some(format!("\"{}\"", cmd)), + || Some(format!("\"{}\"", cmd.requested)), ) } @@ -1346,6 +1344,21 @@ impl UnaryPermission { skip_check_if_is_permission_fully_granted!(self); self.check_desc(None, false, api_name, || None) } + + /// Queries without prompting + pub fn query_all(&mut self, api_name: Option<&str>) -> bool { + if self.is_allow_all() { + return true; + } + let (result, _prompted, _is_allow_all) = + self.query_desc(None, AllowPartial::TreatAsDenied).check2( + RunDescriptor::flag_name(), + api_name, + || None, + /* prompt */ false, + ); + result.is_ok() + } } impl UnaryPermission { @@ -1429,7 +1442,7 @@ pub struct PermissionsOptions { pub deny_ffi: Option>, pub allow_read: Option>, pub deny_read: Option>, - pub allow_run: Option>, + pub allow_run: Option>, pub deny_run: Option>, pub allow_sys: Option>, pub deny_sys: Option>, @@ -1440,8 +1453,8 @@ pub struct PermissionsOptions { impl Permissions { pub fn new_unary( - allow_list: &Option>, - deny_list: &Option>, + allow_list: Option<&[T::Arg]>, + deny_list: Option<&[T::Arg]>, prompt: bool, ) -> Result, AnyError> where @@ -1470,38 +1483,54 @@ impl Permissions { pub fn from_options(opts: &PermissionsOptions) -> Result { Ok(Self { read: Permissions::new_unary( - &opts.allow_read, - &opts.deny_read, + opts.allow_read.as_deref(), + opts.deny_read.as_deref(), opts.prompt, )?, write: Permissions::new_unary( - &opts.allow_write, - &opts.deny_write, + opts.allow_write.as_deref(), + opts.deny_write.as_deref(), opts.prompt, )?, net: Permissions::new_unary( - &opts.allow_net, - &opts.deny_net, + opts.allow_net.as_deref(), + opts.deny_net.as_deref(), opts.prompt, )?, env: Permissions::new_unary( - &opts.allow_env, - &opts.deny_env, + opts.allow_env.as_deref(), + opts.deny_env.as_deref(), opts.prompt, )?, sys: Permissions::new_unary( - &opts.allow_sys, - &opts.deny_sys, + opts.allow_sys.as_deref(), + opts.deny_sys.as_deref(), opts.prompt, )?, run: Permissions::new_unary( - &opts.allow_run, - &opts.deny_run, + opts + .allow_run + .as_ref() + .map(|d| { + d.iter() + .map(|s| RunDescriptorArg::Path(s.clone())) + .collect::>() + }) + .as_deref(), + opts + .deny_run + .as_ref() + .map(|d| { + d.iter() + .map(|s| RunDescriptorArg::from(s.clone())) + .collect::>() + }) + .as_deref(), opts.prompt, )?, ffi: Permissions::new_unary( - &opts.allow_ffi, - &opts.deny_ffi, + opts.allow_ffi.as_deref(), + opts.deny_ffi.as_deref(), opts.prompt, )?, all: Permissions::new_all(opts.allow_all), @@ -1534,13 +1563,13 @@ impl Permissions { fn none(prompt: bool) -> Self { Self { - read: Permissions::new_unary(&None, &None, prompt).unwrap(), - write: Permissions::new_unary(&None, &None, prompt).unwrap(), - net: Permissions::new_unary(&None, &None, prompt).unwrap(), - env: Permissions::new_unary(&None, &None, prompt).unwrap(), - sys: Permissions::new_unary(&None, &None, prompt).unwrap(), - run: Permissions::new_unary(&None, &None, prompt).unwrap(), - ffi: Permissions::new_unary(&None, &None, prompt).unwrap(), + read: Permissions::new_unary(None, None, prompt).unwrap(), + write: Permissions::new_unary(None, None, prompt).unwrap(), + net: Permissions::new_unary(None, None, prompt).unwrap(), + env: Permissions::new_unary(None, None, prompt).unwrap(), + sys: Permissions::new_unary(None, None, prompt).unwrap(), + run: Permissions::new_unary(None, None, prompt).unwrap(), + ffi: Permissions::new_unary(None, None, prompt).unwrap(), all: Permissions::new_all(false), } } @@ -1669,7 +1698,7 @@ impl PermissionsContainer { #[inline(always)] pub fn check_run( &mut self, - cmd: &str, + cmd: RunPathQuery, api_name: &str, ) -> Result<(), AnyError> { self.0.lock().run.check(cmd, Some(api_name)) @@ -1680,6 +1709,11 @@ impl PermissionsContainer { self.0.lock().run.check_all(Some(api_name)) } + #[inline(always)] + pub fn query_run_all(&mut self, api_name: &str) -> bool { + self.0.lock().run.query_all(Some(api_name)) + } + #[inline(always)] pub fn check_sys(&self, kind: &str, api_name: &str) -> Result<(), AnyError> { self.0.lock().sys.check(kind, Some(api_name)) @@ -1879,12 +1913,12 @@ const fn unit_permission_from_flag_bools( } } -fn global_from_option(flag: &Option>) -> bool { +fn global_from_option(flag: Option<&[T]>) -> bool { matches!(flag, Some(v) if v.is_empty()) } fn parse_net_list( - list: &Option>, + list: Option<&[String]>, ) -> Result, AnyError> { if let Some(v) = list { v.iter() @@ -1896,7 +1930,7 @@ fn parse_net_list( } fn parse_env_list( - list: &Option>, + list: Option<&[String]>, ) -> Result, AnyError> { if let Some(v) = list { v.iter() @@ -1914,7 +1948,7 @@ fn parse_env_list( } fn parse_path_list( - list: &Option>, + list: Option<&[PathBuf]>, f: fn(PathBuf) -> T, ) -> Result, AnyError> { if let Some(v) = list { @@ -1933,7 +1967,7 @@ fn parse_path_list( } fn parse_sys_list( - list: &Option>, + list: Option<&[String]>, ) -> Result, AnyError> { if let Some(v) = list { v.iter() @@ -1951,22 +1985,19 @@ fn parse_sys_list( } fn parse_run_list( - list: &Option>, + list: Option<&[RunDescriptorArg]>, ) -> Result, AnyError> { - let mut result = HashSet::new(); - if let Some(v) = list { - for s in v { - if s.is_empty() { - return Err(AnyError::msg("Empty path is not allowed")); - } else { - let desc = RunDescriptor::from(s.to_string()); - let aliases = desc.aliases(); - result.insert(desc); - result.extend(aliases); - } - } - } - Ok(result) + let Some(v) = list else { + return Ok(HashSet::new()); + }; + Ok( + v.iter() + .map(|arg| match arg { + RunDescriptorArg::Name(s) => RunDescriptor::Name(s.clone()), + RunDescriptorArg::Path(l) => RunDescriptor::Path(l.clone()), + }) + .collect(), + ) } fn escalation_error() -> AnyError { @@ -2306,6 +2337,9 @@ mod tests { macro_rules! svec { ($($x:expr),*) => (vec![$($x.to_string()),*]); } + macro_rules! sarr { + ($($x:expr),*) => ([$($x.to_string()),*]); + } #[test] fn check_paths() { @@ -2686,94 +2720,88 @@ mod tests { set_prompter(Box::new(TestPrompter)); let perms1 = Permissions::allow_all(); let perms2 = Permissions { - read: Permissions::new_unary( - &Some(vec![PathBuf::from("/foo")]), - &None, - false, - ) - .unwrap(), + read: Permissions::new_unary(Some(&[PathBuf::from("/foo")]), None, false) + .unwrap(), write: Permissions::new_unary( - &Some(vec![PathBuf::from("/foo")]), - &None, + Some(&[PathBuf::from("/foo")]), + None, false, ) .unwrap(), - ffi: Permissions::new_unary( - &Some(vec![PathBuf::from("/foo")]), - &None, + ffi: Permissions::new_unary(Some(&[PathBuf::from("/foo")]), None, false) + .unwrap(), + net: Permissions::new_unary(Some(&sarr!["127.0.0.1:8000"]), None, false) + .unwrap(), + env: Permissions::new_unary(Some(&sarr!["HOME"]), None, false).unwrap(), + sys: Permissions::new_unary(Some(&sarr!["hostname"]), None, false) + .unwrap(), + run: Permissions::new_unary( + Some(&["deno".to_string().into()]), + None, false, ) .unwrap(), - net: Permissions::new_unary(&Some(svec!["127.0.0.1:8000"]), &None, false) - .unwrap(), - env: Permissions::new_unary(&Some(svec!["HOME"]), &None, false).unwrap(), - sys: Permissions::new_unary(&Some(svec!["hostname"]), &None, false) - .unwrap(), - run: Permissions::new_unary(&Some(svec!["deno"]), &None, false).unwrap(), all: Permissions::new_all(false), }; let perms3 = Permissions { - read: Permissions::new_unary( - &None, - &Some(vec![PathBuf::from("/foo")]), - false, - ) - .unwrap(), + read: Permissions::new_unary(None, Some(&[PathBuf::from("/foo")]), false) + .unwrap(), write: Permissions::new_unary( - &None, - &Some(vec![PathBuf::from("/foo")]), + None, + Some(&[PathBuf::from("/foo")]), false, ) .unwrap(), - ffi: Permissions::new_unary( - &None, - &Some(vec![PathBuf::from("/foo")]), + ffi: Permissions::new_unary(None, Some(&[PathBuf::from("/foo")]), false) + .unwrap(), + net: Permissions::new_unary(None, Some(&sarr!["127.0.0.1:8000"]), false) + .unwrap(), + env: Permissions::new_unary(None, Some(&sarr!["HOME"]), false).unwrap(), + sys: Permissions::new_unary(None, Some(&sarr!["hostname"]), false) + .unwrap(), + run: Permissions::new_unary( + None, + Some(&["deno".to_string().into()]), false, ) .unwrap(), - net: Permissions::new_unary(&None, &Some(svec!["127.0.0.1:8000"]), false) - .unwrap(), - env: Permissions::new_unary(&None, &Some(svec!["HOME"]), false).unwrap(), - sys: Permissions::new_unary(&None, &Some(svec!["hostname"]), false) - .unwrap(), - run: Permissions::new_unary(&None, &Some(svec!["deno"]), false).unwrap(), all: Permissions::new_all(false), }; let perms4 = Permissions { read: Permissions::new_unary( - &Some(vec![]), - &Some(vec![PathBuf::from("/foo")]), + Some(&[]), + Some(&[PathBuf::from("/foo")]), false, ) .unwrap(), write: Permissions::new_unary( - &Some(vec![]), - &Some(vec![PathBuf::from("/foo")]), + Some(&[]), + Some(&[PathBuf::from("/foo")]), false, ) .unwrap(), ffi: Permissions::new_unary( - &Some(vec![]), - &Some(vec![PathBuf::from("/foo")]), + Some(&[]), + Some(&[PathBuf::from("/foo")]), false, ) .unwrap(), net: Permissions::new_unary( - &Some(vec![]), - &Some(svec!["127.0.0.1:8000"]), + Some(&[]), + Some(&sarr!["127.0.0.1:8000"]), false, ) .unwrap(), - env: Permissions::new_unary(&Some(vec![]), &Some(svec!["HOME"]), false) + env: Permissions::new_unary(Some(&[]), Some(&sarr!["HOME"]), false) .unwrap(), - sys: Permissions::new_unary( - &Some(vec![]), - &Some(svec!["hostname"]), + sys: Permissions::new_unary(Some(&[]), Some(&sarr!["hostname"]), false) + .unwrap(), + run: Permissions::new_unary( + Some(&[]), + Some(&["deno".to_string().into()]), false, ) .unwrap(), - run: Permissions::new_unary(&Some(vec![]), &Some(svec!["deno"]), false) - .unwrap(), all: Permissions::new_all(false), }; #[rustfmt::skip] @@ -2902,33 +2930,38 @@ mod tests { set_prompter(Box::new(TestPrompter)); let mut perms = Permissions { read: Permissions::new_unary( - &Some(vec![PathBuf::from("/foo"), PathBuf::from("/foo/baz")]), - &None, + Some(&[PathBuf::from("/foo"), PathBuf::from("/foo/baz")]), + None, false, ) .unwrap(), write: Permissions::new_unary( - &Some(vec![PathBuf::from("/foo"), PathBuf::from("/foo/baz")]), - &None, + Some(&[PathBuf::from("/foo"), PathBuf::from("/foo/baz")]), + None, false, ) .unwrap(), ffi: Permissions::new_unary( - &Some(vec![PathBuf::from("/foo"), PathBuf::from("/foo/baz")]), - &None, + Some(&[PathBuf::from("/foo"), PathBuf::from("/foo/baz")]), + None, false, ) .unwrap(), net: Permissions::new_unary( - &Some(svec!["127.0.0.1", "127.0.0.1:8000"]), - &None, + Some(&sarr!["127.0.0.1", "127.0.0.1:8000"]), + None, false, ) .unwrap(), - env: Permissions::new_unary(&Some(svec!["HOME"]), &None, false).unwrap(), - sys: Permissions::new_unary(&Some(svec!["hostname"]), &None, false) + env: Permissions::new_unary(Some(&sarr!["HOME"]), None, false).unwrap(), + sys: Permissions::new_unary(Some(&sarr!["hostname"]), None, false) .unwrap(), - run: Permissions::new_unary(&Some(svec!["deno"]), &None, false).unwrap(), + run: Permissions::new_unary( + Some(&["deno".to_string().into()]), + None, + false, + ) + .unwrap(), all: Permissions::new_all(false), }; #[rustfmt::skip] @@ -3014,11 +3047,40 @@ mod tests { .check(&NetDescriptor("deno.land".parse().unwrap(), None), None) .is_err()); + #[allow(clippy::disallowed_methods)] + let cwd = std::env::current_dir().unwrap(); prompt_value.set(true); - assert!(perms.run.check("cat", None).is_ok()); + assert!(perms + .run + .check( + RunPathQuery { + requested: "cat", + resolved: &cwd.join("cat") + }, + None + ) + .is_ok()); prompt_value.set(false); - assert!(perms.run.check("cat", None).is_ok()); - assert!(perms.run.check("ls", None).is_err()); + assert!(perms + .run + .check( + RunPathQuery { + requested: "cat", + resolved: &cwd.join("cat") + }, + None + ) + .is_ok()); + assert!(perms + .run + .check( + RunPathQuery { + requested: "ls", + resolved: &cwd.join("ls") + }, + None + ) + .is_err()); prompt_value.set(true); assert!(perms.env.check("HOME", None).is_ok()); @@ -3110,12 +3172,50 @@ mod tests { .is_ok()); prompt_value.set(false); - assert!(perms.run.check("cat", None).is_err()); + #[allow(clippy::disallowed_methods)] + let cwd = std::env::current_dir().unwrap(); + assert!(perms + .run + .check( + RunPathQuery { + requested: "cat", + resolved: &cwd.join("cat") + }, + None + ) + .is_err()); prompt_value.set(true); - assert!(perms.run.check("cat", None).is_err()); - assert!(perms.run.check("ls", None).is_ok()); + assert!(perms + .run + .check( + RunPathQuery { + requested: "cat", + resolved: &cwd.join("cat") + }, + None + ) + .is_err()); + assert!(perms + .run + .check( + RunPathQuery { + requested: "ls", + resolved: &cwd.join("ls") + }, + None + ) + .is_ok()); prompt_value.set(false); - assert!(perms.run.check("ls", None).is_ok()); + assert!(perms + .run + .check( + RunPathQuery { + requested: "ls", + resolved: &cwd.join("ls") + }, + None + ) + .is_ok()); prompt_value.set(false); assert!(perms.env.check("HOME", None).is_err()); @@ -3142,7 +3242,7 @@ mod tests { let mut perms = Permissions::allow_all(); perms.env = UnaryPermission { granted_global: false, - ..Permissions::new_unary(&Some(svec!["HOME"]), &None, false).unwrap() + ..Permissions::new_unary(Some(&sarr!["HOME"]), None, false).unwrap() }; prompt_value.set(true); @@ -3158,14 +3258,14 @@ mod tests { fn test_check_partial_denied() { let mut perms = Permissions { read: Permissions::new_unary( - &Some(vec![]), - &Some(vec![PathBuf::from("/foo/bar")]), + Some(&[]), + Some(&[PathBuf::from("/foo/bar")]), false, ) .unwrap(), write: Permissions::new_unary( - &Some(vec![]), - &Some(vec![PathBuf::from("/foo/bar")]), + Some(&[]), + Some(&[PathBuf::from("/foo/bar")]), false, ) .unwrap(), @@ -3183,8 +3283,8 @@ mod tests { fn test_net_fully_qualified_domain_name() { let mut perms = Permissions { net: Permissions::new_unary( - &Some(vec!["allowed.domain".to_string(), "1.1.1.1".to_string()]), - &Some(vec!["denied.domain".to_string(), "2.2.2.2".to_string()]), + Some(&["allowed.domain".to_string(), "1.1.1.1".to_string()]), + Some(&["denied.domain".to_string(), "2.2.2.2".to_string()]), false, ) .unwrap(), @@ -3349,8 +3449,8 @@ mod tests { fn test_create_child_permissions() { set_prompter(Box::new(TestPrompter)); let mut main_perms = Permissions { - env: Permissions::new_unary(&Some(vec![]), &None, false).unwrap(), - net: Permissions::new_unary(&Some(svec!["foo", "bar"]), &None, false) + env: Permissions::new_unary(Some(&[]), None, false).unwrap(), + net: Permissions::new_unary(Some(&sarr!["foo", "bar"]), None, false) .unwrap(), ..Permissions::none_without_prompt() }; @@ -3366,8 +3466,8 @@ mod tests { ) .unwrap(), Permissions { - env: Permissions::new_unary(&Some(vec![]), &None, false).unwrap(), - net: Permissions::new_unary(&Some(svec!["foo"]), &None, false).unwrap(), + env: Permissions::new_unary(Some(&[]), None, false).unwrap(), + net: Permissions::new_unary(Some(&sarr!["foo"]), None, false).unwrap(), ..Permissions::none_without_prompt() } ); @@ -3453,20 +3553,20 @@ mod tests { set_prompter(Box::new(TestPrompter)); assert!(Permissions::new_unary::( - &Some(vec![Default::default()]), - &None, + Some(&[Default::default()]), + None, false ) .is_err()); assert!(Permissions::new_unary::( - &Some(vec![Default::default()]), - &None, + Some(&[Default::default()]), + None, false ) .is_err()); assert!(Permissions::new_unary::( - &Some(vec![Default::default()]), - &None, + Some(&[Default::default()]), + None, false ) .is_err()); diff --git a/runtime/shared.rs b/runtime/shared.rs index c52521690c..1b2136c638 100644 --- a/runtime/shared.rs +++ b/runtime/shared.rs @@ -116,26 +116,3 @@ pub fn maybe_transpile_source( Ok((source_text.into(), maybe_source_map)) } - -pub fn import_assertion_callback( - args: deno_core::ImportAssertionsSupportCustomCallbackArgs, -) { - let mut msg = deno_terminal::colors::yellow("⚠️ Import assertions are deprecated. Use `with` keyword, instead of 'assert' keyword.").to_string(); - if let Some(specifier) = args.maybe_specifier { - if let Some(source_line) = args.maybe_source_line { - msg.push_str("\n\n"); - msg.push_str(&source_line); - msg.push_str("\n\n"); - } - msg.push_str(&format!( - " at {}:{}:{}\n", - specifier, - args.maybe_line_number.unwrap(), - args.column_number - )); - #[allow(clippy::print_stderr)] - { - eprintln!("{}", msg); - } - } -} diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs index ad0ac5a3f2..e143288618 100644 --- a/runtime/web_worker.rs +++ b/runtime/web_worker.rs @@ -545,13 +545,6 @@ impl WebWorker { options.bootstrap.enable_op_summary_metrics, options.strace_ops, ); - let import_assertions_support = if options.bootstrap.future { - deno_core::ImportAssertionsSupport::Error - } else { - deno_core::ImportAssertionsSupport::CustomCallback(Box::new( - crate::shared::import_assertion_callback, - )) - }; let mut js_runtime = JsRuntime::new(RuntimeOptions { module_loader: Some(options.module_loader.clone()), @@ -572,7 +565,7 @@ impl WebWorker { validate_import_attributes_cb: Some(Box::new( validate_import_attributes_callback, )), - import_assertions_support, + import_assertions_support: deno_core::ImportAssertionsSupport::Error, ..Default::default() }); diff --git a/runtime/worker.rs b/runtime/worker.rs index c0d8391667..02749e7c18 100644 --- a/runtime/worker.rs +++ b/runtime/worker.rs @@ -477,14 +477,6 @@ impl MainWorker { } }); - let import_assertions_support = if options.bootstrap.future { - deno_core::ImportAssertionsSupport::Error - } else { - deno_core::ImportAssertionsSupport::CustomCallback(Box::new( - crate::shared::import_assertion_callback, - )) - }; - let mut js_runtime = JsRuntime::new(RuntimeOptions { module_loader: Some(options.module_loader.clone()), startup_snapshot: options.startup_snapshot, @@ -510,7 +502,7 @@ impl MainWorker { validate_import_attributes_cb: Some(Box::new( validate_import_attributes_callback, )), - import_assertions_support, + import_assertions_support: deno_core::ImportAssertionsSupport::Error, eval_context_code_cache_cbs: options.v8_code_cache.map(|cache| { let cache_clone = cache.clone(); ( diff --git a/runtime/worker_bootstrap.rs b/runtime/worker_bootstrap.rs index b6ede466e1..b137efae22 100644 --- a/runtime/worker_bootstrap.rs +++ b/runtime/worker_bootstrap.rs @@ -116,7 +116,6 @@ pub struct BootstrapOptions { pub argv0: Option, pub node_debug: Option, pub node_ipc_fd: Option, - pub future: bool, pub mode: WorkerExecutionMode, // Used by `deno serve` pub serve_port: Option, @@ -153,7 +152,6 @@ impl Default for BootstrapOptions { argv0: None, node_debug: None, node_ipc_fd: None, - future: false, mode: WorkerExecutionMode::None, serve_port: Default::default(), serve_host: Default::default(), @@ -190,8 +188,6 @@ struct BootstrapV8<'a>( Option<&'a str>, // node_debug Option<&'a str>, - // future - bool, // mode i32, // serve port @@ -224,7 +220,6 @@ impl BootstrapOptions { self.has_node_modules_dir, self.argv0.as_deref(), self.node_debug.as_deref(), - self.future, self.mode.discriminant() as _, self.serve_port.unwrap_or_default(), self.serve_host.as_deref(), diff --git a/tests/ffi/tests/integration_tests.rs b/tests/ffi/tests/integration_tests.rs index 2235405a8a..c84a1b820d 100644 --- a/tests/ffi/tests/integration_tests.rs +++ b/tests/ffi/tests/integration_tests.rs @@ -300,6 +300,6 @@ fn ffi_callback_errors_test() { assert_eq!(stdout, expected); assert_eq!( stderr, - "Illegal unhandled exception in nonblocking callback.\n".repeat(3) + "Illegal unhandled exception in nonblocking callback\n".repeat(3) ); } diff --git a/tests/integration/eval_tests.rs b/tests/integration/eval_tests.rs index 3f4c6a3a6d..198be3a4e8 100644 --- a/tests/integration/eval_tests.rs +++ b/tests/integration/eval_tests.rs @@ -1,24 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. use test_util as util; -use test_util::itest; - -#[test] -fn eval_p() { - let output = util::deno_cmd() - .arg("eval") - .arg("-p") - .arg("1+2") - .stdout_piped() - .spawn() - .unwrap() - .wait_with_output() - .unwrap(); - assert!(output.status.success()); - let stdout_str = - util::strip_ansi_codes(std::str::from_utf8(&output.stdout).unwrap().trim()); - assert_eq!("3", stdout_str); -} // Make sure that snapshot flags don't affect runtime. #[test] @@ -43,48 +25,3 @@ fn eval_randomness() { numbers.dedup(); assert!(numbers.len() > 1); } - -itest!(eval_basic { - args: "eval console.log(\"hello\")", - output_str: Some("hello\n"), -}); - -// Ugly parentheses due to whitespace delimiting problem. -itest!(eval_ts { - args: "eval --quiet --ext=ts console.log((123)as(number))", // 'as' is a TS keyword only - output_str: Some("123\n"), -}); - -itest!(dyn_import_eval { - args: "eval import('./subdir/mod4.js').then(console.log)", - output: "eval/dyn_import_eval.out", -}); - -// Cannot write the expression to evaluate as "console.log(typeof gc)" -// because itest! splits args on whitespace. -itest!(v8_flags_eval { - args: "eval --v8-flags=--expose-gc console.log(typeof(gc))", - output: "run/v8_flags.js.out", -}); - -itest!(check_local_by_default { - args: "eval --quiet import('http://localhost:4545/subdir/type_error.ts').then(console.log);", - output: "eval/check_local_by_default.out", - http_server: true, -}); - -itest!(check_local_by_default2 { - args: "eval --quiet import('./eval/check_local_by_default2.ts').then(console.log);", - output: "eval/check_local_by_default2.out", - http_server: true, -}); - -itest!(env_file { - args: "eval --env=env console.log(Deno.env.get(\"ANOTHER_FOO\"))", - output_str: Some("ANOTHER_BAR\n"), -}); - -itest!(env_file_missing { - args: "eval --env=missing console.log(Deno.env.get(\"ANOTHER_FOO\"))", - output: "eval/env_file_missing.out", -}); diff --git a/tests/integration/js_unit_tests.rs b/tests/integration/js_unit_tests.rs index 9f1ee7394a..b6a204157b 100644 --- a/tests/integration/js_unit_tests.rs +++ b/tests/integration/js_unit_tests.rs @@ -47,7 +47,6 @@ util::unit_test_factory!( image_data_test, internals_test, intl_test, - io_test, jupyter_test, kv_test, kv_queue_test_no_db_close, @@ -117,22 +116,40 @@ util::unit_test_factory!( fn js_unit_test(test: String) { let _g = util::http_server(); - let deno = util::deno_cmd() + let mut deno = util::deno_cmd() .current_dir(util::root_path()) .arg("test") .arg("--config") .arg(util::deno_config_path()) .arg("--no-lock") - .arg("--unstable") + // TODO(bartlomieju): would be better if we could apply this unstable + // flag to particular files, but there's many of them that rely on unstable + // net APIs (`reusePort` in `listen` and `listenTls`; `listenDatagram`, `createHttpClient`) + .arg("--unstable-net") + .arg("--unstable-http") .arg("--location=http://127.0.0.1:4545/") .arg("--no-prompt"); + if test == "broadcast_channel_test" { + deno = deno.arg("--unstable-broadcast-channel"); + } + + if test == "cron_test" { + deno = deno.arg("--unstable-cron"); + } + + if test.contains("kv_") { + deno = deno.arg("--unstable-kv"); + } + + if test == "worker_permissions_test" || test == "worker_test" { + deno = deno.arg("--unstable-worker-options"); + } + // TODO(mmastrac): it would be better to just load a test CA for all tests - let deno = if test == "websocket_test" || test == "tls_sni_test" { - deno.arg("--unsafely-ignore-certificate-errors") - } else { - deno - }; + if test == "websocket_test" || test == "tls_sni_test" { + deno = deno.arg("--unsafely-ignore-certificate-errors"); + } let mut deno = deno .arg("-A") diff --git a/tests/integration/lsp_tests.rs b/tests/integration/lsp_tests.rs index 7c7e9315ce..78e5260851 100644 --- a/tests/integration/lsp_tests.rs +++ b/tests/integration/lsp_tests.rs @@ -8905,7 +8905,7 @@ fn lsp_completions_node_builtin() { "severity": 1, "code": "import-node-prefix-missing", "source": "deno", - "message": "Relative import path \"fs\" not prefixed with / or ./ or ../\nIf you want to use a built-in Node module, add a \"node:\" prefix (ex. \"node:fs\").", + "message": "Relative import path \"fs\" not prefixed with / or ./ or ../\n \u{1b}[0m\u{1b}[36mhint:\u{1b}[0m If you want to use a built-in Node module, add a \"node:\" prefix (ex. \"node:fs\").", "data": { "specifier": "fs" }, @@ -14767,7 +14767,6 @@ fn lsp_byonm() { "@denotest/esm-basic": "*", }, })); - context.run_npm("install"); let mut client = context.new_lsp_command().build(); client.initialize_default(); let diagnostics = client.did_open(json!({ @@ -14798,7 +14797,52 @@ fn lsp_byonm() { "severity": 1, "code": "resolver-error", "source": "deno", - "message": "Could not find a matching package for 'npm:chalk' in a package.json file. You must specify this as a package.json dependency when the node_modules folder is not managed by Deno.", + "message": "Could not find a matching package for 'npm:chalk' in the node_modules directory. Ensure you have all your JSR and npm dependencies listed in your deno.json or package.json, then run `deno install`. Alternatively, turn on auto-install by specifying `\"nodeModulesDir\": \"auto\"` in your deno.json file.", + }, + { + "range": { + "start": { + "line": 2, + "character": 15, + }, + "end": { + "line": 2, + "character": 36, + }, + }, + "severity": 1, + "code": "resolver-error", + "source": "deno", + "message": "Could not resolve \"@denotest/esm-basic\", but found it in a package.json. Deno expects the node_modules/ directory to be up to date. Did you forget to run `deno install`?", + }, + ]) + ); + context.run_npm("install"); + client.did_change_watched_files(json!({ + "changes": [{ + "uri": temp_dir.url().join("node_modules/.package-lock.json").unwrap(), + "type": 1, + }], + })); + let diagnostics = client.read_diagnostics(); + assert_eq!( + json!(diagnostics.all()), + json!([ + { + "range": { + "start": { + "line": 1, + "character": 15, + }, + "end": { + "line": 1, + "character": 26, + }, + }, + "severity": 1, + "code": "resolver-error", + "source": "deno", + "message": "Could not find a matching package for 'npm:chalk' in the node_modules directory. Ensure you have all your JSR and npm dependencies listed in your deno.json or package.json, then run `deno install`. Alternatively, turn on auto-install by specifying `\"nodeModulesDir\": \"auto\"` in your deno.json file.", }, ]) ); diff --git a/tests/integration/npm_tests.rs b/tests/integration/npm_tests.rs index db63d4533f..61ef0b22d3 100644 --- a/tests/integration/npm_tests.rs +++ b/tests/integration/npm_tests.rs @@ -2195,7 +2195,7 @@ console.log(getKind()); .args("run --allow-read chalk.ts") .run(); output.assert_matches_text( - r#"error: Could not find a matching package for 'npm:chalk@5' in a package.json file. You must specify this as a package.json dependency when the node_modules folder is not managed by Deno. + r#"error: Could not find a matching package for 'npm:chalk@5' in the node_modules directory. Ensure you have all your JSR and npm dependencies listed in your deno.json or package.json, then run `deno install`. Alternatively, turn on auto-install by specifying `"nodeModulesDir": "auto"` in your deno.json file. at file:///[WILDCARD]chalk.ts:1:19 "#); output.assert_exit_code(1); @@ -2277,7 +2277,7 @@ console.log(getKind()); .args("run --allow-read chalk.ts") .run(); output.assert_matches_text( - r#"error: Could not find a matching package for 'npm:chalk@5' in a package.json file. You must specify this as a package.json dependency when the node_modules folder is not managed by Deno. + r#"error: Could not find a matching package for 'npm:chalk@5' in the node_modules directory. Ensure you have all your JSR and npm dependencies listed in your deno.json or package.json, then run `deno install`. Alternatively, turn on auto-install by specifying `"nodeModulesDir": "auto"` in your deno.json file. at file:///[WILDCARD]chalk.ts:1:19 "#); output.assert_exit_code(1); diff --git a/tests/integration/run_tests.rs b/tests/integration/run_tests.rs index 841ef2d182..117e5709e4 100644 --- a/tests/integration/run_tests.rs +++ b/tests/integration/run_tests.rs @@ -483,11 +483,6 @@ itest!(dynamic_import_concurrent_non_statically_analyzable { http_server: true, }); -itest!(no_check_imports_not_used_as_values { - args: "run --config run/no_check_imports_not_used_as_values/preserve_imports.tsconfig.json --no-check run/no_check_imports_not_used_as_values/main.ts", - output: "run/no_check_imports_not_used_as_values/main.out", - }); - itest!(_088_dynamic_import_already_evaluating { args: "run --allow-read run/088_dynamic_import_already_evaluating.ts", output: "run/088_dynamic_import_already_evaluating.ts.out", @@ -3683,11 +3678,6 @@ itest!(followup_dyn_import_resolved { output: "run/followup_dyn_import_resolves/main.ts.out", }); -itest!(allow_run_allowlist_resolution { - args: "run --quiet -A allow_run_allowlist_resolution.ts", - output: "allow_run_allowlist_resolution.ts.out", -}); - itest!(unhandled_rejection { args: "run --check run/unhandled_rejection.ts", output: "run/unhandled_rejection.ts.out", @@ -4592,16 +4582,32 @@ fn permission_prompt_escapes_ansi_codes_and_control_chars() { )) }); - util::with_pty(&["repl"], |mut console| { - console.write_line_raw(r#"const boldANSI = "\u001b[1m";"#); - console.expect("undefined"); - console.write_line_raw(r#"const unboldANSI = "\u001b[22m";"#); - console.expect("undefined"); - console.write_line_raw( - r#"new Deno.Command(`${boldANSI}cat${unboldANSI}`).spawn();"#, - ); - console.expect("\u{250f} \u{26a0}\u{fe0f} Deno requests run access to \"\\u{1b}[1mcat\\u{1b}[22m\"."); - }); + // windows doesn't support backslashes in paths, so just try this on unix + if cfg!(unix) { + let context = TestContextBuilder::default().use_temp_cwd().build(); + context + .new_command() + .env("PATH", context.temp_dir().path()) + .env("DYLD_FALLBACK_LIBRARY_PATH", "") + .env("LD_LIBRARY_PATH", "") + .args_vec(["repl", "--allow-write=."]) + .with_pty(|mut console| { + console.write_line_raw(r#"const boldANSI = "\u001b[1m";"#); + console.expect("undefined"); + console.write_line_raw(r#"const unboldANSI = "\u001b[22m";"#); + console.expect("undefined"); + console.write_line_raw( + r#"Deno.writeTextFileSync(`${boldANSI}cat${unboldANSI}`, "");"#, + ); + console.expect("undefined"); + console.write_line_raw( + r#"new Deno.Command(`./${boldANSI}cat${unboldANSI}`).spawn();"#, + ); + console + .expect("\u{250f} \u{26a0}\u{fe0f} Deno requests run access to \""); + console.expect("\\u{1b}[1mcat\\u{1b}[22m\"."); // ensure escaped + }); + } } itest!(node_builtin_modules_ts { diff --git a/tests/node_compat/polyfill_globals.js b/tests/node_compat/polyfill_globals.js index 93246d2ef2..79e1cc3f9b 100644 --- a/tests/node_compat/polyfill_globals.js +++ b/tests/node_compat/polyfill_globals.js @@ -1,5 +1,4 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import process from "node:process"; import { Buffer } from "node:buffer"; import { clearImmediate, @@ -10,15 +9,12 @@ import { setTimeout, } from "node:timers"; import { performance } from "node:perf_hooks"; -import console from "node:console"; globalThis.Buffer = Buffer; globalThis.clearImmediate = clearImmediate; globalThis.clearInterval = clearInterval; globalThis.clearTimeout = clearTimeout; -globalThis.console = console; globalThis.global = globalThis; globalThis.performance = performance; -globalThis.process = process; globalThis.setImmediate = setImmediate; globalThis.setInterval = setInterval; globalThis.setTimeout = setTimeout; diff --git a/tests/registry/jsr/@denotest/npm-add/0.5.0/mod.ts b/tests/registry/jsr/@denotest/npm-add/0.5.0/mod.ts new file mode 100644 index 0000000000..733997e7be --- /dev/null +++ b/tests/registry/jsr/@denotest/npm-add/0.5.0/mod.ts @@ -0,0 +1,5 @@ +import * as npmAdd from "npm:@denotest/add@0.5"; + +export function sum(a: number, b: number): number { + return npmAdd.sum(a, b); +} diff --git a/tests/registry/jsr/@denotest/npm-add/0.5.0_meta.json b/tests/registry/jsr/@denotest/npm-add/0.5.0_meta.json new file mode 100644 index 0000000000..631a18d0e5 --- /dev/null +++ b/tests/registry/jsr/@denotest/npm-add/0.5.0_meta.json @@ -0,0 +1,5 @@ +{ + "exports": { + ".": "./mod.ts" + } +} diff --git a/tests/registry/jsr/@denotest/npm-add/1.0.0/mod.ts b/tests/registry/jsr/@denotest/npm-add/1.0.0/mod.ts new file mode 100644 index 0000000000..16663bab61 --- /dev/null +++ b/tests/registry/jsr/@denotest/npm-add/1.0.0/mod.ts @@ -0,0 +1,5 @@ +import * as npmAdd from "npm:@denotest/add@1"; + +export function add(a: number, b: number): number { + return npmAdd.add(a, b); +} diff --git a/tests/registry/jsr/@denotest/npm-add/1.0.0_meta.json b/tests/registry/jsr/@denotest/npm-add/1.0.0_meta.json new file mode 100644 index 0000000000..631a18d0e5 --- /dev/null +++ b/tests/registry/jsr/@denotest/npm-add/1.0.0_meta.json @@ -0,0 +1,5 @@ +{ + "exports": { + ".": "./mod.ts" + } +} diff --git a/tests/registry/jsr/@denotest/npm-add/meta.json b/tests/registry/jsr/@denotest/npm-add/meta.json new file mode 100644 index 0000000000..1f9cb61845 --- /dev/null +++ b/tests/registry/jsr/@denotest/npm-add/meta.json @@ -0,0 +1,6 @@ +{ + "versions": { + "0.5.0": {}, + "1.0.0": {} + } +} diff --git a/tests/registry/npm/@denotest/globals/1.0.0/index.d.ts b/tests/registry/npm/@denotest/globals/1.0.0/index.d.ts index 76dd781db6..548633db12 100644 --- a/tests/registry/npm/@denotest/globals/1.0.0/index.d.ts +++ b/tests/registry/npm/@denotest/globals/1.0.0/index.d.ts @@ -15,7 +15,6 @@ type _TestHasProcessGlobal = AssertTrue< export function deleteSetTimeout(): void; export function getSetTimeout(): typeof setTimeout; -export function checkProcessGlobal(): void; export function checkWindowGlobal(): void; export function checkSelfGlobal(): void; diff --git a/tests/registry/npm/@denotest/globals/1.0.0/index.js b/tests/registry/npm/@denotest/globals/1.0.0/index.js index 64f913b37a..542cb63d2b 100644 --- a/tests/registry/npm/@denotest/globals/1.0.0/index.js +++ b/tests/registry/npm/@denotest/globals/1.0.0/index.js @@ -10,11 +10,6 @@ exports.getSetTimeout = function () { return globalThis.setTimeout; }; -exports.checkProcessGlobal = function () { - console.log("process" in globalThis); - console.log(Object.getOwnPropertyDescriptor(globalThis, "process") !== undefined); -}; - exports.checkWindowGlobal = function () { console.log("window" in globalThis); console.log(Object.getOwnPropertyDescriptor(globalThis, "window") !== undefined); diff --git a/tests/specs/add/add_with_subpath/__test__.jsonc b/tests/specs/add/add_with_subpath/__test__.jsonc new file mode 100644 index 0000000000..b051bd2654 --- /dev/null +++ b/tests/specs/add/add_with_subpath/__test__.jsonc @@ -0,0 +1,19 @@ +{ + "tempDir": true, + "steps": [ + { + "args": "add @std/testing/bdd npm:preact/hooks", + "output": "add.out" + }, + { + "args": "add @std/testing/bdd@1 npm:preact/hooks@10", + "output": "wrong_constraint_jsr.out", + "exitCode": 1 + }, + { + "args": "add npm:preact/hooks@10", + "output": "wrong_constraint_npm.out", + "exitCode": 1 + } + ] +} diff --git a/tests/specs/add/add_with_subpath/add.out b/tests/specs/add/add_with_subpath/add.out new file mode 100644 index 0000000000..02b286ba38 --- /dev/null +++ b/tests/specs/add/add_with_subpath/add.out @@ -0,0 +1,8 @@ +[UNORDERED_START] +Add jsr:@std/testing@1.0.0 +Add npm:preact@10.19.6 +Download http://127.0.0.1:4250/@std/testing/1.0.0/bdd.ts +Download http://127.0.0.1:4250/@std/testing/1.0.0/types.ts +Download http://localhost:4260/preact +Download http://localhost:4260/preact/preact-10.19.6.tgz +[UNORDERED_END] diff --git a/tests/specs/add/add_with_subpath/deno.json b/tests/specs/add/add_with_subpath/deno.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/specs/add/add_with_subpath/wrong_constraint_jsr.out b/tests/specs/add/add_with_subpath/wrong_constraint_jsr.out new file mode 100644 index 0000000000..2b218407d2 --- /dev/null +++ b/tests/specs/add/add_with_subpath/wrong_constraint_jsr.out @@ -0,0 +1,4 @@ +error: Failed to parse package required: @std/testing/bdd@1 + +Caused by: + Invalid package specifier 'jsr:@std/testing/bdd@1'. Did you mean to write 'jsr:@std/testing@1/bdd'? diff --git a/tests/specs/add/add_with_subpath/wrong_constraint_npm.out b/tests/specs/add/add_with_subpath/wrong_constraint_npm.out new file mode 100644 index 0000000000..4adcf9ef6a --- /dev/null +++ b/tests/specs/add/add_with_subpath/wrong_constraint_npm.out @@ -0,0 +1,4 @@ +error: Failed to parse package required: npm:preact/hooks@10 + +Caused by: + Invalid package specifier 'npm:preact/hooks@10'. Did you mean to write 'npm:preact@10/hooks'? diff --git a/tests/specs/bench/bench_explicit_start_end/explicit_start_and_end.out b/tests/specs/bench/bench_explicit_start_end/explicit_start_and_end.out index 4dc2b6179f..ae1b058475 100644 --- a/tests/specs/bench/bench_explicit_start_end/explicit_start_and_end.out +++ b/tests/specs/bench/bench_explicit_start_end/explicit_start_and_end.out @@ -8,17 +8,17 @@ benchmark time/iter (avg) iter/s (min … max) p75 start and end [WILDCARD] [WILDCARD] [WILDCARD] ([WILDCARD] … [WILDCARD]) [WILDCARD] start only [WILDCARD] [WILDCARD] [WILDCARD] ([WILDCARD] … [WILDCARD]) [WILDCARD] end only [WILDCARD] [WILDCARD] [WILDCARD] ([WILDCARD] … [WILDCARD]) [WILDCARD] -double start error: TypeError: BenchContext::start() has already been invoked. +double start error: TypeError: BenchContext::start() has already been invoked t.start(); ^ at BenchContext.start ([WILDCARD]) at [WILDCARD]/explicit_start_and_end.ts:[WILDCARD] -double end error: TypeError: BenchContext::end() has already been invoked. +double end error: TypeError: BenchContext::end() has already been invoked t.end(); ^ at BenchContext.end ([WILDCARD]) at [WILDCARD]/explicit_start_and_end.ts:[WILDCARD] -captured error: TypeError: The benchmark which this context belongs to is not being executed. +captured error: TypeError: The benchmark which this context belongs to is not being executed captured!.start(); ^ at BenchContext.start ([WILDCARD]) diff --git a/tests/specs/cache/with_bare_import/095_cache_with_bare_import.ts.out b/tests/specs/cache/with_bare_import/095_cache_with_bare_import.ts.out index 2668a6e083..50daf80419 100644 --- a/tests/specs/cache/with_bare_import/095_cache_with_bare_import.ts.out +++ b/tests/specs/cache/with_bare_import/095_cache_with_bare_import.ts.out @@ -1,2 +1,3 @@ [WILDCARD]error: Relative import path "foo" not prefixed with / or ./ or ../ + hint: If you want to use a JSR or npm package, try running `deno add foo` at file:///[WILDCARD]/095_cache_with_bare_import.ts:[WILDCARD] diff --git a/tests/specs/check/with_bare_import/095_cache_with_bare_import.ts.out b/tests/specs/check/with_bare_import/095_cache_with_bare_import.ts.out index 2668a6e083..50daf80419 100644 --- a/tests/specs/check/with_bare_import/095_cache_with_bare_import.ts.out +++ b/tests/specs/check/with_bare_import/095_cache_with_bare_import.ts.out @@ -1,2 +1,3 @@ [WILDCARD]error: Relative import path "foo" not prefixed with / or ./ or ../ + hint: If you want to use a JSR or npm package, try running `deno add foo` at file:///[WILDCARD]/095_cache_with_bare_import.ts:[WILDCARD] diff --git a/tests/specs/compile/permissions_denied/__test__.jsonc b/tests/specs/compile/permissions_denied/__test__.jsonc index 8f85901628..ec683ea62e 100644 --- a/tests/specs/compile/permissions_denied/__test__.jsonc +++ b/tests/specs/compile/permissions_denied/__test__.jsonc @@ -1,5 +1,9 @@ { "tempDir": true, + "envs": { + "DYLD_FALLBACK_LIBRARY_PATH": "", + "LD_LIBRARY_PATH": "" + }, "steps": [{ "if": "unix", "args": "compile --output main main.ts", diff --git a/tests/specs/eval/check_local/__test__.jsonc b/tests/specs/eval/check_local/__test__.jsonc new file mode 100644 index 0000000000..e9253803c0 --- /dev/null +++ b/tests/specs/eval/check_local/__test__.jsonc @@ -0,0 +1,4 @@ +{ + "args": "eval --quiet import('http://localhost:4545/subdir/type_error.ts').then(console.log);", + "output": "main.out" +} diff --git a/tests/testdata/eval/check_local_by_default.out b/tests/specs/eval/check_local/main.out similarity index 100% rename from tests/testdata/eval/check_local_by_default.out rename to tests/specs/eval/check_local/main.out diff --git a/tests/specs/eval/check_local_by_default2/__test__.jsonc b/tests/specs/eval/check_local_by_default2/__test__.jsonc new file mode 100644 index 0000000000..b6188b8cee --- /dev/null +++ b/tests/specs/eval/check_local_by_default2/__test__.jsonc @@ -0,0 +1,4 @@ +{ + "args": "eval --quiet import('./check_local_by_default2.ts').then(console.log);", + "output": "main.out" +} diff --git a/tests/testdata/eval/check_local_by_default2.ts b/tests/specs/eval/check_local_by_default2/check_local_by_default2.ts similarity index 100% rename from tests/testdata/eval/check_local_by_default2.ts rename to tests/specs/eval/check_local_by_default2/check_local_by_default2.ts diff --git a/tests/testdata/eval/check_local_by_default2.out b/tests/specs/eval/check_local_by_default2/main.out similarity index 100% rename from tests/testdata/eval/check_local_by_default2.out rename to tests/specs/eval/check_local_by_default2/main.out diff --git a/tests/specs/eval/dyn_import_eval/__test__.jsonc b/tests/specs/eval/dyn_import_eval/__test__.jsonc new file mode 100644 index 0000000000..34e5734936 --- /dev/null +++ b/tests/specs/eval/dyn_import_eval/__test__.jsonc @@ -0,0 +1,4 @@ +{ + "args": "eval import('./mod4.js').then(console.log)", + "output": "main.out" +} diff --git a/tests/testdata/eval/dyn_import_eval.out b/tests/specs/eval/dyn_import_eval/main.out similarity index 100% rename from tests/testdata/eval/dyn_import_eval.out rename to tests/specs/eval/dyn_import_eval/main.out diff --git a/tests/specs/eval/dyn_import_eval/mod4.js b/tests/specs/eval/dyn_import_eval/mod4.js new file mode 100644 index 0000000000..71332dbc42 --- /dev/null +++ b/tests/specs/eval/dyn_import_eval/mod4.js @@ -0,0 +1 @@ +export const isMod4 = true; diff --git a/tests/specs/eval/env_file/__test__.jsonc b/tests/specs/eval/env_file/__test__.jsonc new file mode 100644 index 0000000000..b2e8f87b8a --- /dev/null +++ b/tests/specs/eval/env_file/__test__.jsonc @@ -0,0 +1,4 @@ +{ + "args": "eval --env-file=env_file console.log(Deno.env.get(\"ANOTHER_FOO\"));", + "output": "main.out" +} diff --git a/tests/specs/eval/env_file/env_file b/tests/specs/eval/env_file/env_file new file mode 100644 index 0000000000..c41732d30b --- /dev/null +++ b/tests/specs/eval/env_file/env_file @@ -0,0 +1,4 @@ +FOO=BAR +ANOTHER_FOO=ANOTHER_${FOO} +MULTILINE="First Line +Second Line" \ No newline at end of file diff --git a/tests/specs/eval/env_file/main.out b/tests/specs/eval/env_file/main.out new file mode 100644 index 0000000000..01fcfbd290 --- /dev/null +++ b/tests/specs/eval/env_file/main.out @@ -0,0 +1 @@ +ANOTHER_BAR diff --git a/tests/specs/eval/env_file_missing/__test__.jsonc b/tests/specs/eval/env_file_missing/__test__.jsonc new file mode 100644 index 0000000000..fc4e463807 --- /dev/null +++ b/tests/specs/eval/env_file_missing/__test__.jsonc @@ -0,0 +1,4 @@ +{ + "args": "eval --env-file=missing console.log(Deno.env.get(\"ANOTHER_FOO\"));", + "output": "main.out" +} diff --git a/tests/testdata/eval/env_file_missing.out b/tests/specs/eval/env_file_missing/main.out similarity index 100% rename from tests/testdata/eval/env_file_missing.out rename to tests/specs/eval/env_file_missing/main.out diff --git a/tests/specs/eval/env_unparsable_file/__test__.jsonc b/tests/specs/eval/env_unparsable_file/__test__.jsonc index cf5e9a99b2..8c8dbf5a94 100644 --- a/tests/specs/eval/env_unparsable_file/__test__.jsonc +++ b/tests/specs/eval/env_unparsable_file/__test__.jsonc @@ -1,4 +1,4 @@ { - "args": "eval --env=../../../testdata/env_unparsable console.log(Deno.env.get(\"Another_FOO\"))", + "args": "eval --env-file=env_unparsable console.log(Deno.env.get(\"ANOTHER_FOO\"));", "output": "main.out" } diff --git a/tests/specs/eval/env_unparsable_file/env_unparsable b/tests/specs/eval/env_unparsable_file/env_unparsable new file mode 100644 index 0000000000..5542b80bc3 --- /dev/null +++ b/tests/specs/eval/env_unparsable_file/env_unparsable @@ -0,0 +1,4 @@ +FOO=valid +ANOTHER_FOO=c:\path +MULTILINE="First Line +Second Line" \ No newline at end of file diff --git a/tests/specs/eval/env_unparsable_file/main.out b/tests/specs/eval/env_unparsable_file/main.out index 18d7856b45..1b3f7047a7 100644 --- a/tests/specs/eval/env_unparsable_file/main.out +++ b/tests/specs/eval/env_unparsable_file/main.out @@ -1,2 +1,2 @@ -Warning Parsing failed within the specified environment file: ../../../testdata/env_unparsable at index: 3 of the value: c:\path +Warning Parsing failed within the specified environment file: env_unparsable at index: 3 of the value: c:\path undefined diff --git a/tests/specs/eval/eval_basic/__test__.jsonc b/tests/specs/eval/eval_basic/__test__.jsonc new file mode 100644 index 0000000000..ebc9732361 --- /dev/null +++ b/tests/specs/eval/eval_basic/__test__.jsonc @@ -0,0 +1,4 @@ +{ + "args": "eval console.log(\"hello\")", + "output": "main.out" +} diff --git a/tests/specs/eval/eval_basic/main.out b/tests/specs/eval/eval_basic/main.out new file mode 100644 index 0000000000..ce01362503 --- /dev/null +++ b/tests/specs/eval/eval_basic/main.out @@ -0,0 +1 @@ +hello diff --git a/tests/specs/eval/eval_p/__test__.jsonc b/tests/specs/eval/eval_p/__test__.jsonc new file mode 100644 index 0000000000..bd34d67e3c --- /dev/null +++ b/tests/specs/eval/eval_p/__test__.jsonc @@ -0,0 +1,4 @@ +{ + "args": "eval -p 1+2", + "output": "main.out" +} diff --git a/tests/specs/eval/eval_p/main.out b/tests/specs/eval/eval_p/main.out new file mode 100644 index 0000000000..00750edc07 --- /dev/null +++ b/tests/specs/eval/eval_p/main.out @@ -0,0 +1 @@ +3 diff --git a/tests/specs/eval/eval_ts/__test__.jsonc b/tests/specs/eval/eval_ts/__test__.jsonc new file mode 100644 index 0000000000..4e8b9c2ae2 --- /dev/null +++ b/tests/specs/eval/eval_ts/__test__.jsonc @@ -0,0 +1,4 @@ +{ + "args": "eval --quiet --ext=ts console.log((123)as(number))", + "output": "main.out" +} diff --git a/tests/specs/eval/eval_ts/main.out b/tests/specs/eval/eval_ts/main.out new file mode 100644 index 0000000000..190a18037c --- /dev/null +++ b/tests/specs/eval/eval_ts/main.out @@ -0,0 +1 @@ +123 diff --git a/tests/specs/eval/v8_flags_eval/__test__.jsonc b/tests/specs/eval/v8_flags_eval/__test__.jsonc new file mode 100644 index 0000000000..23b59d482d --- /dev/null +++ b/tests/specs/eval/v8_flags_eval/__test__.jsonc @@ -0,0 +1,4 @@ +{ + "args": "eval --v8-flags=--expose-gc console.log(typeof(gc))", + "output": "main.out" +} diff --git a/tests/specs/eval/v8_flags_eval/main.out b/tests/specs/eval/v8_flags_eval/main.out new file mode 100644 index 0000000000..e2dbde096f --- /dev/null +++ b/tests/specs/eval/v8_flags_eval/main.out @@ -0,0 +1 @@ +function diff --git a/tests/specs/future/runtime_api/main.js b/tests/specs/future/runtime_api/main.js index a12b2f1fcf..95b10eecd0 100644 --- a/tests/specs/future/runtime_api/main.js +++ b/tests/specs/future/runtime_api/main.js @@ -1,27 +1,13 @@ console.log("window is", globalThis.window); console.log("Deno.Buffer is", Deno.Buffer); -console.log("Deno.copy is", Deno.copy); -console.log("Deno.File is", Deno.File); -console.log("Deno.fstat is", Deno.fstat); -console.log("Deno.fstatSync is", Deno.fstatSync); -console.log("Deno.ftruncate is", Deno.ftruncate); -console.log("Deno.ftruncateSync is", Deno.ftruncateSync); console.log( "Deno.FsFile.prototype.rid is", Deno.openSync(import.meta.filename).rid, ); console.log("Deno.funlock is", Deno.funlock); console.log("Deno.funlockSync is", Deno.funlockSync); -console.log("Deno.readAll is", Deno.readAll); -console.log("Deno.readAllSync is", Deno.readAllSync); -console.log("Deno.read is", Deno.read); -console.log("Deno.readSync is", Deno.readSync); console.log("Deno.seek is", Deno.seek); console.log("Deno.seekSync is", Deno.seekSync); -console.log("Deno.writeAll is", Deno.writeAll); -console.log("Deno.writeAllSync is", Deno.writeAllSync); -console.log("Deno.write is", Deno.write); -console.log("Deno.writeSync is", Deno.writeSync); // TCP // Since these tests may run in parallel, ensure this port is unique to this file @@ -67,10 +53,6 @@ console.log("Deno.TlsConn.prototype.rid is", tlsConn.rid); tlsConn.close(); -const watcher = Deno.watchFs("."); -console.log("Deno.FsWatcher.prototype.rid is", watcher.rid); -watcher.close(); - try { new Deno.FsFile(0); } catch (error) { diff --git a/tests/specs/future/runtime_api/main.out b/tests/specs/future/runtime_api/main.out index 398922749a..489dd4636b 100644 --- a/tests/specs/future/runtime_api/main.out +++ b/tests/specs/future/runtime_api/main.out @@ -1,30 +1,15 @@ window is undefined Deno.Buffer is undefined -Deno.copy is undefined -Deno.File is undefined -Deno.fstat is undefined -Deno.fstatSync is undefined -Deno.ftruncate is undefined -Deno.ftruncateSync is undefined Deno.FsFile.prototype.rid is undefined Deno.funlock is undefined Deno.funlockSync is undefined -Deno.readAll is undefined -Deno.readAllSync is undefined -Deno.read is undefined -Deno.readSync is undefined Deno.seek is undefined Deno.seekSync is undefined -Deno.writeAll is undefined -Deno.writeAllSync is undefined -Deno.write is undefined -Deno.writeSync is undefined Deno.Listener.prototype.rid is undefined Deno.Conn.prototype.rid is undefined Deno.UnixConn.prototype.rid is undefined Deno.TlsListener.prototype.rid is undefined Deno.TlsConn.prototype.rid is undefined -Deno.FsWatcher.prototype.rid is undefined Deno.FsFile constructor is illegal Deno.ConnectTlsOptions.(certFile|keyFile) do nothing Deno.ConnectTlsOptions.(certChain|privateKey) do nothing diff --git a/tests/specs/install/alias_deno_json/__test__.jsonc b/tests/specs/install/alias_deno_json/__test__.jsonc new file mode 100644 index 0000000000..0398e2eeb5 --- /dev/null +++ b/tests/specs/install/alias_deno_json/__test__.jsonc @@ -0,0 +1,10 @@ +{ + "tempDir": true, + "steps": [{ + "args": "install", + "output": "[WILDCARD]" + }, { + "args": "run --allow-read=. verify.ts", + "output": "true\n" + }] +} diff --git a/tests/specs/install/alias_deno_json/deno.json b/tests/specs/install/alias_deno_json/deno.json new file mode 100644 index 0000000000..a1adfb35e2 --- /dev/null +++ b/tests/specs/install/alias_deno_json/deno.json @@ -0,0 +1,5 @@ +{ + "imports": { + "alias": "npm:@denotest/add" + } +} diff --git a/tests/specs/install/alias_deno_json/package.json b/tests/specs/install/alias_deno_json/package.json new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/tests/specs/install/alias_deno_json/package.json @@ -0,0 +1,2 @@ +{ +} diff --git a/tests/specs/install/alias_deno_json/verify.ts b/tests/specs/install/alias_deno_json/verify.ts new file mode 100644 index 0000000000..ea6cadb709 --- /dev/null +++ b/tests/specs/install/alias_deno_json/verify.ts @@ -0,0 +1,2 @@ +const stat = Deno.statSync(new URL("./node_modules/alias", import.meta.url)); +console.log(stat.isDirectory); diff --git a/tests/specs/install/alias_invalid_path_char/__test__.jsonc b/tests/specs/install/alias_invalid_path_char/__test__.jsonc new file mode 100644 index 0000000000..4a30586350 --- /dev/null +++ b/tests/specs/install/alias_invalid_path_char/__test__.jsonc @@ -0,0 +1,10 @@ +{ + "tempDir": true, + "steps": [{ + "args": "install", + "output": "[WILDCARD]" + }, { + "args": "run --allow-read=. verify.ts", + "output": ".bin\n.deno\n@denotest\n" + }] +} diff --git a/tests/specs/install/alias_invalid_path_char/deno.jsonc b/tests/specs/install/alias_invalid_path_char/deno.jsonc new file mode 100644 index 0000000000..85befb55e8 --- /dev/null +++ b/tests/specs/install/alias_invalid_path_char/deno.jsonc @@ -0,0 +1,7 @@ +{ + "imports": { + // alias*test is an invalid path char on windows, so + // don't create an alias for this + "alias*test": "npm:@denotest/add" + } +} diff --git a/tests/specs/install/alias_invalid_path_char/package.json b/tests/specs/install/alias_invalid_path_char/package.json new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/tests/specs/install/alias_invalid_path_char/package.json @@ -0,0 +1,2 @@ +{ +} diff --git a/tests/specs/install/alias_invalid_path_char/verify.ts b/tests/specs/install/alias_invalid_path_char/verify.ts new file mode 100644 index 0000000000..497e1d8dd9 --- /dev/null +++ b/tests/specs/install/alias_invalid_path_char/verify.ts @@ -0,0 +1,10 @@ +const entries = Array.from( + Deno.readDirSync(new URL("./node_modules", import.meta.url)), +); +const names = entries.map((entry) => entry.name); +names.sort(); + +// won't have the invalid path alias +for (const name of names) { + console.log(name); +} diff --git a/tests/specs/install/alias_pkg_json_and_deno_json_jsr_pkg/__test__.jsonc b/tests/specs/install/alias_pkg_json_and_deno_json_jsr_pkg/__test__.jsonc new file mode 100644 index 0000000000..9a149219db --- /dev/null +++ b/tests/specs/install/alias_pkg_json_and_deno_json_jsr_pkg/__test__.jsonc @@ -0,0 +1,10 @@ +{ + "tempDir": true, + "steps": [{ + "args": "install", + "output": "[WILDCARD]" + }, { + "args": "run --allow-read=. verify.ts", + "output": "verify.out" + }] +} diff --git a/tests/specs/install/alias_pkg_json_and_deno_json_jsr_pkg/deno.json b/tests/specs/install/alias_pkg_json_and_deno_json_jsr_pkg/deno.json new file mode 100644 index 0000000000..bbd5b9946a --- /dev/null +++ b/tests/specs/install/alias_pkg_json_and_deno_json_jsr_pkg/deno.json @@ -0,0 +1,5 @@ +{ + "imports": { + "alias": "jsr:@denotest/add" + } +} diff --git a/tests/specs/install/alias_pkg_json_and_deno_json_jsr_pkg/package.json b/tests/specs/install/alias_pkg_json_and_deno_json_jsr_pkg/package.json new file mode 100644 index 0000000000..01835ee933 --- /dev/null +++ b/tests/specs/install/alias_pkg_json_and_deno_json_jsr_pkg/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "alias": "npm:@denotest/esm-basic" + } +} diff --git a/tests/specs/install/alias_pkg_json_and_deno_json_jsr_pkg/verify.out b/tests/specs/install/alias_pkg_json_and_deno_json_jsr_pkg/verify.out new file mode 100644 index 0000000000..dad0ca2d8f --- /dev/null +++ b/tests/specs/install/alias_pkg_json_and_deno_json_jsr_pkg/verify.out @@ -0,0 +1,2 @@ +@denotest/esm-basic +[Module: null prototype] { add: [Function: add] } diff --git a/tests/specs/install/alias_pkg_json_and_deno_json_jsr_pkg/verify.ts b/tests/specs/install/alias_pkg_json_and_deno_json_jsr_pkg/verify.ts new file mode 100644 index 0000000000..835442322e --- /dev/null +++ b/tests/specs/install/alias_pkg_json_and_deno_json_jsr_pkg/verify.ts @@ -0,0 +1,13 @@ +import * as mod from "alias"; + +const data = JSON.parse( + Deno.readTextFileSync( + new URL("./node_modules/alias/package.json", import.meta.url), + ), +); + +// this should just setup the npm package anyway, even though the alias +// will resolve to the jsr package +console.log(data.name); + +console.log(mod); diff --git a/tests/specs/install/alias_pkg_json_and_deno_json_npm_pkg/__test__.jsonc b/tests/specs/install/alias_pkg_json_and_deno_json_npm_pkg/__test__.jsonc new file mode 100644 index 0000000000..9a149219db --- /dev/null +++ b/tests/specs/install/alias_pkg_json_and_deno_json_npm_pkg/__test__.jsonc @@ -0,0 +1,10 @@ +{ + "tempDir": true, + "steps": [{ + "args": "install", + "output": "[WILDCARD]" + }, { + "args": "run --allow-read=. verify.ts", + "output": "verify.out" + }] +} diff --git a/tests/specs/install/alias_pkg_json_and_deno_json_npm_pkg/deno.json b/tests/specs/install/alias_pkg_json_and_deno_json_npm_pkg/deno.json new file mode 100644 index 0000000000..a1adfb35e2 --- /dev/null +++ b/tests/specs/install/alias_pkg_json_and_deno_json_npm_pkg/deno.json @@ -0,0 +1,5 @@ +{ + "imports": { + "alias": "npm:@denotest/add" + } +} diff --git a/tests/specs/install/alias_pkg_json_and_deno_json_npm_pkg/package.json b/tests/specs/install/alias_pkg_json_and_deno_json_npm_pkg/package.json new file mode 100644 index 0000000000..01835ee933 --- /dev/null +++ b/tests/specs/install/alias_pkg_json_and_deno_json_npm_pkg/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "alias": "npm:@denotest/esm-basic" + } +} diff --git a/tests/specs/install/alias_pkg_json_and_deno_json_npm_pkg/verify.out b/tests/specs/install/alias_pkg_json_and_deno_json_npm_pkg/verify.out new file mode 100644 index 0000000000..bc6cb31f7c --- /dev/null +++ b/tests/specs/install/alias_pkg_json_and_deno_json_npm_pkg/verify.out @@ -0,0 +1,5 @@ +@denotest/add +[Module: null prototype] { + add: [Function (anonymous)], + default: { add: [Function (anonymous)] } +} diff --git a/tests/specs/install/alias_pkg_json_and_deno_json_npm_pkg/verify.ts b/tests/specs/install/alias_pkg_json_and_deno_json_npm_pkg/verify.ts new file mode 100644 index 0000000000..bcc0a5d877 --- /dev/null +++ b/tests/specs/install/alias_pkg_json_and_deno_json_npm_pkg/verify.ts @@ -0,0 +1,10 @@ +import * as mod from "alias"; + +const data = JSON.parse( + Deno.readTextFileSync( + new URL("./node_modules/alias/package.json", import.meta.url), + ), +); + +console.log(data.name); +console.log(mod); diff --git a/tests/specs/install/byonm_jsr_npm_dep/__test__.jsonc b/tests/specs/install/byonm_jsr_npm_dep/__test__.jsonc new file mode 100644 index 0000000000..ca7064aaf3 --- /dev/null +++ b/tests/specs/install/byonm_jsr_npm_dep/__test__.jsonc @@ -0,0 +1,10 @@ +{ + "tempDir": true, + "steps": [{ + "args": "install", + "output": "[WILDCARD]" + }, { + "args": "run main.ts", + "output": "3\n4\n" + }] +} diff --git a/tests/specs/install/byonm_jsr_npm_dep/deno.json b/tests/specs/install/byonm_jsr_npm_dep/deno.json new file mode 100644 index 0000000000..2127bd2860 --- /dev/null +++ b/tests/specs/install/byonm_jsr_npm_dep/deno.json @@ -0,0 +1,6 @@ +{ + "imports": { + "@denotest/npm-add": "jsr:@denotest/npm-add@1", + "@denotest/npm-add-0-5": "jsr:@denotest/npm-add@0.5" + } +} diff --git a/tests/specs/install/byonm_jsr_npm_dep/main.ts b/tests/specs/install/byonm_jsr_npm_dep/main.ts new file mode 100644 index 0000000000..a75e65bd88 --- /dev/null +++ b/tests/specs/install/byonm_jsr_npm_dep/main.ts @@ -0,0 +1,5 @@ +import { add } from "@denotest/npm-add"; +import { sum } from "@denotest/npm-add-0-5"; + +console.log(add(1, 2)); +console.log(sum(2, 2)); diff --git a/tests/specs/install/byonm_jsr_npm_dep/package.json b/tests/specs/install/byonm_jsr_npm_dep/package.json new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/tests/specs/install/byonm_jsr_npm_dep/package.json @@ -0,0 +1,2 @@ +{ +} diff --git a/tests/specs/install/install_entrypoint/__test__.jsonc b/tests/specs/install/install_entrypoint/__test__.jsonc new file mode 100644 index 0000000000..1afe195e28 --- /dev/null +++ b/tests/specs/install/install_entrypoint/__test__.jsonc @@ -0,0 +1,21 @@ +{ + "tempDir": true, + "tests": { + "basic": { + "steps": [ + { + "args": "install --entrypoint main.ts second.ts", + "output": "install.out" + } + ] + }, + "allow_scripts": { + "steps": [ + { + "args": "install --allow-scripts --node-modules-dir=auto --entrypoint lifecycle.ts", + "output": "lifecycle.out" + } + ] + } + } +} diff --git a/tests/specs/install/install_entrypoint/install.out b/tests/specs/install/install_entrypoint/install.out new file mode 100644 index 0000000000..d702cf45ac --- /dev/null +++ b/tests/specs/install/install_entrypoint/install.out @@ -0,0 +1,7 @@ +[UNORDERED_START] +Download http://127.0.0.1:4250/@denotest/add/meta.json +Download http://localhost:4260/@denotest/esm-basic +Download http://127.0.0.1:4250/@denotest/add/1.0.0_meta.json +Download http://127.0.0.1:4250/@denotest/add/1.0.0/mod.ts +Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz +[UNORDERED_END] diff --git a/tests/specs/install/install_entrypoint/lifecycle.out b/tests/specs/install/install_entrypoint/lifecycle.out new file mode 100644 index 0000000000..8eae8ee120 --- /dev/null +++ b/tests/specs/install/install_entrypoint/lifecycle.out @@ -0,0 +1,22 @@ +[UNORDERED_START] +Download http://localhost:4260/@denotest/node-lifecycle-scripts +Download http://localhost:4260/@denotest/bin +Download http://localhost:4260/@denotest/node-lifecycle-scripts/1.0.0.tgz +Download http://localhost:4260/@denotest/bin/1.0.0.tgz +Initialize @denotest/node-lifecycle-scripts@1.0.0 +Initialize @denotest/bin@1.0.0 +[UNORDERED_END] +preinstall +deno preinstall.js +node preinstall.js +install +hello from install script +postinstall[WILDCARD] + _____________ +< postinstall > + ------------- + \ ^__^ + \ (oo)\_______ + (__)\ )\/\ + ||----w | + || || diff --git a/tests/specs/install/install_entrypoint/lifecycle.ts b/tests/specs/install/install_entrypoint/lifecycle.ts new file mode 100644 index 0000000000..e9fb2cf9cc --- /dev/null +++ b/tests/specs/install/install_entrypoint/lifecycle.ts @@ -0,0 +1,3 @@ +import { value } from "npm:@denotest/node-lifecycle-scripts"; + +console.log(`value is ${value}`); diff --git a/tests/specs/install/install_entrypoint/main.ts b/tests/specs/install/install_entrypoint/main.ts new file mode 100644 index 0000000000..aceb2b3c88 --- /dev/null +++ b/tests/specs/install/install_entrypoint/main.ts @@ -0,0 +1,4 @@ +import { getValue, setValue } from "npm:@denotest/esm-basic"; + +setValue(5); +console.log(getValue()); diff --git a/tests/specs/install/install_entrypoint/second.ts b/tests/specs/install/install_entrypoint/second.ts new file mode 100644 index 0000000000..2c781286f8 --- /dev/null +++ b/tests/specs/install/install_entrypoint/second.ts @@ -0,0 +1 @@ +import { add } from "jsr:@denotest/add@1.0.0"; diff --git a/tests/specs/install/install_single_http_url_without_global_flag/__test__.jsonc b/tests/specs/install/install_single_http_url_without_global_flag/__test__.jsonc new file mode 100644 index 0000000000..b906a846d0 --- /dev/null +++ b/tests/specs/install/install_single_http_url_without_global_flag/__test__.jsonc @@ -0,0 +1,14 @@ +{ + "steps": [ + { + "args": "install http://example.com", + "output": "install_http.out", + "exitCode": 1 + }, + { + "args": "install https://example.com", + "output": "install_https.out", + "exitCode": 1 + } + ] +} diff --git a/tests/specs/install/install_single_http_url_without_global_flag/install_http.out b/tests/specs/install/install_single_http_url_without_global_flag/install_http.out new file mode 100644 index 0000000000..17f4b286d0 --- /dev/null +++ b/tests/specs/install/install_single_http_url_without_global_flag/install_http.out @@ -0,0 +1,2 @@ +error: Failed to install "http" specifier. If you are trying to install http://example.com/ globally, run again with `-g` flag: + deno install -g http://example.com/ diff --git a/tests/specs/install/install_single_http_url_without_global_flag/install_https.out b/tests/specs/install/install_single_http_url_without_global_flag/install_https.out new file mode 100644 index 0000000000..87597de128 --- /dev/null +++ b/tests/specs/install/install_single_http_url_without_global_flag/install_https.out @@ -0,0 +1,2 @@ +error: Failed to install "https" specifier. If you are trying to install https://example.com/ globally, run again with `-g` flag: + deno install -g https://example.com/ diff --git a/tests/specs/lint/node_globals_no_duplicate_imports/__test__.jsonc b/tests/specs/lint/node_globals_no_duplicate_imports/__test__.jsonc index d8e00f47ad..a632e896ef 100644 --- a/tests/specs/lint/node_globals_no_duplicate_imports/__test__.jsonc +++ b/tests/specs/lint/node_globals_no_duplicate_imports/__test__.jsonc @@ -3,8 +3,7 @@ "steps": [ { "args": "run main.ts", - "output": "error.out", - "exitCode": 1 + "output": "" }, { "args": "lint main.ts", diff --git a/tests/specs/lint/node_globals_no_duplicate_imports/error.out b/tests/specs/lint/node_globals_no_duplicate_imports/error.out deleted file mode 100644 index 5671b17b46..0000000000 --- a/tests/specs/lint/node_globals_no_duplicate_imports/error.out +++ /dev/null @@ -1,4 +0,0 @@ -error: Uncaught (in promise) ReferenceError: process is not defined -const _foo = process.env.FOO; - ^ - at [WILDCARD]main.ts:3:14 diff --git a/tests/specs/lockfile/frozen_lockfile/__test__.jsonc b/tests/specs/lockfile/frozen_lockfile/__test__.jsonc index 52cb6321b1..36a1fc71ef 100644 --- a/tests/specs/lockfile/frozen_lockfile/__test__.jsonc +++ b/tests/specs/lockfile/frozen_lockfile/__test__.jsonc @@ -1,7 +1,5 @@ { "tempDir": true, - // TODO(2.0): re-enable after DENO_FUTURE=1 by default lands - "ignore": true, "tests": { "error_with_new_npm_dep": { "steps": [ @@ -64,7 +62,7 @@ { "args": [ "eval", - "Deno.writeTextFileSync('deno.json', `{ \"nodeModules\": \"local-auto\" }`)" + "Deno.writeTextFileSync('deno.json', `{ \"nodeModulesDir\": \"auto\" }`)" ], "output": "[WILDCARD]" }, diff --git a/tests/specs/lockfile/frozen_lockfile/deno.json b/tests/specs/lockfile/frozen_lockfile/deno.json index 176354f98f..fbd70ec480 100644 --- a/tests/specs/lockfile/frozen_lockfile/deno.json +++ b/tests/specs/lockfile/frozen_lockfile/deno.json @@ -1,3 +1,3 @@ { - "nodeModulesDir": true + "nodeModulesDir": "auto" } diff --git a/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_cache.out b/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_cache.out index 55ada3dc3e..9a25fd413f 100644 --- a/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_cache.out +++ b/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_cache.out @@ -1,4 +1,4 @@ -error: The lockfile is out of date. Run `deno cache --frozen=false` or rerun with `--frozen=false` to update it. +error: The lockfile is out of date. Run `deno cache --frozen=false`, `deno install --frozen=false`, or rerun with `--frozen=false` to update it. changes: 4 | - "npm:@denotest/add@1": "1.0.0" 4 | + "npm:@denotest/add@1": "1.0.0", diff --git a/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_dynamic_http.out b/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_dynamic_http.out index 3ec45581aa..2e10aaca54 100644 --- a/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_dynamic_http.out +++ b/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_dynamic_http.out @@ -1,5 +1,5 @@ Download http://localhost:4545/welcome.ts -error: Uncaught (in promise) TypeError: The lockfile is out of date. Run `deno cache --frozen=false` or rerun with `--frozen=false` to update it. +error: Uncaught (in promise) TypeError: The lockfile is out of date. Run `deno cache --frozen=false`, `deno install --frozen=false`, or rerun with `--frozen=false` to update it. changes: 10 | - } 10 | + }, diff --git a/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_dynamic_jsr.out b/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_dynamic_jsr.out index e2b29706c0..6a3dcf5c4b 100644 --- a/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_dynamic_jsr.out +++ b/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_dynamic_jsr.out @@ -1,7 +1,7 @@ Download http://127.0.0.1:4250/@denotest/add/meta.json Download http://127.0.0.1:4250/@denotest/add/1.0.0_meta.json Download http://127.0.0.1:4250/@denotest/add/1.0.0/mod.ts -error: Uncaught (in promise) TypeError: The lockfile is out of date. Run `deno cache --frozen=false` or rerun with `--frozen=false` to update it. +error: Uncaught (in promise) TypeError: The lockfile is out of date. Run `deno cache --frozen=false`, `deno install --frozen=false`, or rerun with `--frozen=false` to update it. changes: 4 | - "npm:@denotest/add@1": "1.0.0" 4 | + "jsr:@denotest/add@1": "1.0.0", diff --git a/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_dynamic_npm.out b/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_dynamic_npm.out index 368d8de5e1..1f866f24e8 100644 --- a/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_dynamic_npm.out +++ b/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_dynamic_npm.out @@ -1,5 +1,5 @@ Download http://localhost:4260/@denotest/subtract -error: Uncaught (in promise) TypeError: The lockfile is out of date. Run `deno cache --frozen=false` or rerun with `--frozen=false` to update it. +error: Uncaught (in promise) TypeError: The lockfile is out of date. Run `deno cache --frozen=false`, `deno install --frozen=false`, or rerun with `--frozen=false` to update it. changes: 4 | - "npm:@denotest/add@1": "1.0.0" 4 | + "npm:@denotest/add@1": "1.0.0", diff --git a/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_jsr_cache.out b/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_jsr_cache.out index 5265400ec3..0ed46a9491 100644 --- a/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_jsr_cache.out +++ b/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_jsr_cache.out @@ -1,4 +1,4 @@ -error: The lockfile is out of date. Run `deno cache --frozen=false` or rerun with `--frozen=false` to update it. +error: The lockfile is out of date. Run `deno cache --frozen=false`, `deno install --frozen=false`, or rerun with `--frozen=false` to update it. changes: 4 | - "jsr:@denotest/add@1": "1.0.0" 5 | - }, diff --git a/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_jsr_run.out b/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_jsr_run.out index 215427a0d0..6e7a1462f8 100644 --- a/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_jsr_run.out +++ b/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_jsr_run.out @@ -1,6 +1,6 @@ Download http://127.0.0.1:4250/@denotest/add/0.2.0_meta.json Download http://127.0.0.1:4250/@denotest/add/0.2.0/mod.ts -error: The lockfile is out of date. Run `deno cache --frozen=false` or rerun with `--frozen=false` to update it. +error: The lockfile is out of date. Run `deno cache --frozen=false`, `deno install --frozen=false`, or rerun with `--frozen=false` to update it. changes: 4 | - "jsr:@denotest/add@1": "1.0.0" 5 | - }, diff --git a/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_run.out b/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_run.out index 351afbae7c..6645c913e0 100644 --- a/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_run.out +++ b/tests/specs/lockfile/frozen_lockfile/frozen_new_dep_run.out @@ -1,5 +1,5 @@ Download http://localhost:4260/@denotest/subtract -error: The lockfile is out of date. Run `deno cache --frozen=false` or rerun with `--frozen=false` to update it. +error: The lockfile is out of date. Run `deno cache --frozen=false`, `deno install --frozen=false`, or rerun with `--frozen=false` to update it. changes: 4 | - "npm:@denotest/add@1": "1.0.0" 4 | + "npm:@denotest/add@1": "1.0.0", diff --git a/tests/specs/lockfile/frozen_lockfile/no_lockfile_run.out b/tests/specs/lockfile/frozen_lockfile/no_lockfile_run.out index f04aea55cb..ba63f475a6 100644 --- a/tests/specs/lockfile/frozen_lockfile/no_lockfile_run.out +++ b/tests/specs/lockfile/frozen_lockfile/no_lockfile_run.out @@ -1,5 +1,5 @@ Download http://localhost:4260/@denotest/add -error: The lockfile is out of date. Run `deno cache --frozen=false` or rerun with `--frozen=false` to update it. +error: The lockfile is out of date. Run `deno cache --frozen=false`, `deno install --frozen=false`, or rerun with `--frozen=false` to update it. changes: 1 | - 1 | +{ diff --git a/tests/specs/lockfile/only_package_json/__test__.jsonc b/tests/specs/lockfile/only_package_json/__test__.jsonc index 5d79d7a872..f53d68f7df 100644 --- a/tests/specs/lockfile/only_package_json/__test__.jsonc +++ b/tests/specs/lockfile/only_package_json/__test__.jsonc @@ -1,11 +1,9 @@ { "tempDir": true, - // TODO(2.0): re-enable after DENO_FUTURE=1 by default lands - "ignore": true, "steps": [ { - "args": "cache index.js", - "output": "cache.out" + "args": "install", + "output": "install.out" }, { "args": [ diff --git a/tests/specs/lockfile/only_package_json/cache.out b/tests/specs/lockfile/only_package_json/install.out similarity index 100% rename from tests/specs/lockfile/only_package_json/cache.out rename to tests/specs/lockfile/only_package_json/install.out diff --git a/tests/specs/npm/lifecycle_scripts/node_gyp_not_found.out b/tests/specs/npm/lifecycle_scripts/node_gyp_not_found.out index 65ea53d586..2f0ff11e28 100644 --- a/tests/specs/npm/lifecycle_scripts/node_gyp_not_found.out +++ b/tests/specs/npm/lifecycle_scripts/node_gyp_not_found.out @@ -3,6 +3,6 @@ Download http://localhost:4260/@denotest/node-addon-implicit-node-gyp Download http://localhost:4260/@denotest/node-addon-implicit-node-gyp/1.0.0.tgz Initialize @denotest/node-addon-implicit-node-gyp@1.0.0 [UNORDERED_END] -warning: node-gyp was used in a script, but was not listed as a dependency. Either add it as a dependency or install it globally (e.g. `npm install -g node-gyp`) +Warning node-gyp was used in a script, but was not listed as a dependency. Either add it as a dependency or install it globally (e.g. `npm install -g node-gyp`) [WILDCARD] error: script 'install' in '@denotest/node-addon-implicit-node-gyp@1.0.0' failed with exit code 1 diff --git a/tests/specs/npm/npmrc_not_next_to_package_json/__test__.jsonc b/tests/specs/npm/npmrc_not_next_to_package_json/__test__.jsonc index 68fa8fdf0d..1f4952ed9b 100644 --- a/tests/specs/npm/npmrc_not_next_to_package_json/__test__.jsonc +++ b/tests/specs/npm/npmrc_not_next_to_package_json/__test__.jsonc @@ -4,7 +4,7 @@ "HOME": "$DENO_DIR" }, "tempDir": true, - "args": "install -A -L debug", + "args": "install -L debug", "output": "main.out", "cwd": "subdir" } diff --git a/tests/specs/permission/path_not_permitted/__test__.jsonc b/tests/specs/permission/path_not_permitted/__test__.jsonc new file mode 100644 index 0000000000..f10e8b389e --- /dev/null +++ b/tests/specs/permission/path_not_permitted/__test__.jsonc @@ -0,0 +1,10 @@ +{ + "tempDir": true, + "envs": { + "LD_LIBRARY_PATH": "", + "LD_PRELOAD": "", + "DYLD_FALLBACK_LIBRARY_PATH": "" + }, + "args": "run -A main.ts", + "output": "main.out" +} diff --git a/tests/specs/permission/path_not_permitted/main.out b/tests/specs/permission/path_not_permitted/main.out new file mode 100644 index 0000000000..77f8001586 --- /dev/null +++ b/tests/specs/permission/path_not_permitted/main.out @@ -0,0 +1,11 @@ +Running... +PermissionDenied: Requires run access to "deno", run again with the --allow-run flag + [WILDCARD] + at file:///[WILDLINE]/sub.ts:15:5 { + name: "PermissionDenied" +} +PermissionDenied: Requires run access to "deno", run again with the --allow-run flag + [WILDCARD] + at file:///[WILDLINE]/sub.ts:23:22 { + name: "PermissionDenied" +} diff --git a/tests/specs/permission/path_not_permitted/main.ts b/tests/specs/permission/path_not_permitted/main.ts new file mode 100644 index 0000000000..0cc141e7ac --- /dev/null +++ b/tests/specs/permission/path_not_permitted/main.ts @@ -0,0 +1,18 @@ +const binaryName = Deno.build.os === "windows" ? "deno.exe" : "deno"; +Deno.copyFileSync(Deno.execPath(), binaryName); + +console.log("Running..."); +new Deno.Command( + Deno.execPath(), + { + args: [ + "run", + "--allow-write", + "--allow-read", + `--allow-run=deno`, + "sub.ts", + ], + stderr: "inherit", + stdout: "inherit", + }, +).outputSync(); diff --git a/tests/specs/permission/path_not_permitted/sub.ts b/tests/specs/permission/path_not_permitted/sub.ts new file mode 100644 index 0000000000..ea527a938b --- /dev/null +++ b/tests/specs/permission/path_not_permitted/sub.ts @@ -0,0 +1,34 @@ +const binaryName = Deno.build.os === "windows" ? "deno.exe" : "deno"; +const pathSep = Deno.build.os === "windows" ? "\\" : "/"; + +Deno.mkdirSync("subdir"); +Deno.copyFileSync(binaryName, "subdir/" + binaryName); + +try { + const commandResult = new Deno.Command( + "deno", + { + env: { "PATH": Deno.cwd() + pathSep + "subdir" }, + stdout: "inherit", + stderr: "inherit", + }, + ).outputSync(); + + console.log(commandResult.code); +} catch (err) { + console.log(err); +} + +try { + const child = Deno.run( + { + cmd: ["deno"], + env: { "PATH": Deno.cwd() + pathSep + "subdir" }, + stdout: "inherit", + stderr: "inherit", + }, + ); + console.log((await child.status()).code); +} catch (err) { + console.log(err); +} diff --git a/tests/specs/permission/write_allow_binary/__test__.jsonc b/tests/specs/permission/write_allow_binary/__test__.jsonc new file mode 100644 index 0000000000..a47fed572d --- /dev/null +++ b/tests/specs/permission/write_allow_binary/__test__.jsonc @@ -0,0 +1,5 @@ +{ + "tempDir": true, + "args": "run -A main.ts", + "output": "main.out" +} diff --git a/tests/specs/permission/write_allow_binary/main.out b/tests/specs/permission/write_allow_binary/main.out new file mode 100644 index 0000000000..e7c47f2883 --- /dev/null +++ b/tests/specs/permission/write_allow_binary/main.out @@ -0,0 +1,6 @@ +Running... +error: Uncaught (in promise) PermissionDenied: Requires write access to "binary[WILDLINE]", run again with the --allow-write flag +Deno.writeTextFileSync(binaryName, ""); + ^ + at [WILDCARD] + at file:///[WILDLINE]sub.ts:3:6 diff --git a/tests/specs/permission/write_allow_binary/main.ts b/tests/specs/permission/write_allow_binary/main.ts new file mode 100644 index 0000000000..73deeab9a7 --- /dev/null +++ b/tests/specs/permission/write_allow_binary/main.ts @@ -0,0 +1,14 @@ +const binaryName = Deno.build.os === "windows" ? "binary.exe" : "binary"; +Deno.copyFileSync(Deno.execPath(), binaryName); + +console.log("Running..."); +const result = new Deno.Command( + Deno.execPath(), + { + args: ["run", "--allow-write", `--allow-run=./${binaryName}`, "sub.ts"], + stderr: "inherit", + stdout: "inherit", + }, +).outputSync(); + +console.assert(result.code == 1, "Expected failure"); diff --git a/tests/specs/permission/write_allow_binary/sub.ts b/tests/specs/permission/write_allow_binary/sub.ts new file mode 100644 index 0000000000..e865597b15 --- /dev/null +++ b/tests/specs/permission/write_allow_binary/sub.ts @@ -0,0 +1,3 @@ +const binaryName = Deno.build.os === "windows" ? "binary.exe" : "binary"; + +Deno.writeTextFileSync(binaryName, ""); diff --git a/tests/specs/run/allow_run_allowlist_resolution/__test__.jsonc b/tests/specs/run/allow_run_allowlist_resolution/__test__.jsonc new file mode 100644 index 0000000000..173e13027f --- /dev/null +++ b/tests/specs/run/allow_run_allowlist_resolution/__test__.jsonc @@ -0,0 +1,8 @@ +{ + "args": "run --quiet -A main.ts", + "output": "main.out", + "envs": { + "DYLD_FALLBACK_LIBRARY_PATH": "", + "LD_LIBRARY_PATH": "" + } +} diff --git a/tests/testdata/allow_run_allowlist_resolution.ts.out b/tests/specs/run/allow_run_allowlist_resolution/main.out similarity index 67% rename from tests/testdata/allow_run_allowlist_resolution.ts.out rename to tests/specs/run/allow_run_allowlist_resolution/main.out index 16ba6754a9..f61f9b5503 100644 --- a/tests/testdata/allow_run_allowlist_resolution.ts.out +++ b/tests/specs/run/allow_run_allowlist_resolution/main.out @@ -1,15 +1,15 @@ -PermissionStatus { state: "granted", onchange: null } -PermissionStatus { state: "granted", onchange: null } -PermissionStatus { state: "granted", onchange: null } -PermissionStatus { state: "granted", onchange: null } - -PermissionStatus { state: "granted", onchange: null } -PermissionStatus { state: "prompt", onchange: null } -PermissionStatus { state: "granted", onchange: null } -PermissionStatus { state: "prompt", onchange: null } - PermissionStatus { state: "granted", onchange: null } PermissionStatus { state: "granted", onchange: null } PermissionStatus { state: "prompt", onchange: null } PermissionStatus { state: "granted", onchange: null } - +--- +Info Failed to resolve 'deno' for allow-run: cannot find binary path +PermissionStatus { state: "prompt", onchange: null } +PermissionStatus { state: "prompt", onchange: null } +PermissionStatus { state: "prompt", onchange: null } +PermissionStatus { state: "prompt", onchange: null } +--- +PermissionStatus { state: "granted", onchange: null } +PermissionStatus { state: "granted", onchange: null } +PermissionStatus { state: "prompt", onchange: null } +PermissionStatus { state: "granted", onchange: null } diff --git a/tests/testdata/allow_run_allowlist_resolution.ts b/tests/specs/run/allow_run_allowlist_resolution/main.ts similarity index 71% rename from tests/testdata/allow_run_allowlist_resolution.ts rename to tests/specs/run/allow_run_allowlist_resolution/main.ts index c7369d928a..bf33d8cbe1 100644 --- a/tests/testdata/allow_run_allowlist_resolution.ts +++ b/tests/specs/run/allow_run_allowlist_resolution/main.ts @@ -1,26 +1,26 @@ // Testing the following (but with `deno` instead of `echo`): // | `deno run --allow-run=echo` | `which path == "/usr/bin/echo"` at startup | `which path != "/usr/bin/echo"` at startup | // |-------------------------------------|--------------------------------------------|--------------------------------------------| -// | **`Deno.Command("echo")`** | ✅ | ✅ | -// | **`Deno.Command("/usr/bin/echo")`** | ✅ | ❌ | +// | **`Deno.Command("echo")`** | ✅ | ✅ | +// | **`Deno.Command("/usr/bin/echo")`** | ✅ | ❌ | // | `deno run --allow-run=/usr/bin/echo | `which path == "/usr/bin/echo"` at runtime | `which path != "/usr/bin/echo"` at runtime | // |-------------------------------------|--------------------------------------------|--------------------------------------------| -// | **`Deno.Command("echo")`** | ✅ | ❌ | -// | **`Deno.Command("/usr/bin/echo")`** | ✅ | ✅ | +// | **`Deno.Command("echo")`** | ✅ | ❌ | +// | **`Deno.Command("/usr/bin/echo")`** | ✅ | ✅ | const execPath = Deno.execPath(); const execPathParent = execPath.replace(/[/\\][^/\\]+$/, ""); const testUrl = `data:application/typescript;base64,${ btoa(` - console.log(await Deno.permissions.query({ name: "run", command: "deno" })); - console.log(await Deno.permissions.query({ name: "run", command: "${ + console.error(await Deno.permissions.query({ name: "run", command: "deno" })); + console.error(await Deno.permissions.query({ name: "run", command: "${ execPath.replaceAll("\\", "\\\\") }" })); Deno.env.set("PATH", ""); - console.log(await Deno.permissions.query({ name: "run", command: "deno" })); - console.log(await Deno.permissions.query({ name: "run", command: "${ + console.error(await Deno.permissions.query({ name: "run", command: "deno" })); + console.error(await Deno.permissions.query({ name: "run", command: "${ execPath.replaceAll("\\", "\\\\") }" })); `) @@ -29,38 +29,39 @@ const testUrl = `data:application/typescript;base64,${ const process1 = await new Deno.Command(Deno.execPath(), { args: [ "run", - "--quiet", "--allow-env", "--allow-run=deno", testUrl, ], - stderr: "null", + stdout: "inherit", + stderr: "inherit", env: { "PATH": execPathParent }, }).output(); -console.log(new TextDecoder().decode(process1.stdout)); -const process2 = await new Deno.Command(Deno.execPath(), { +console.error("---"); + +await new Deno.Command(Deno.execPath(), { args: [ "run", - "--quiet", "--allow-env", "--allow-run=deno", testUrl, ], - stderr: "null", + stderr: "inherit", + stdout: "inherit", env: { "PATH": "" }, }).output(); -console.log(new TextDecoder().decode(process2.stdout)); -const process3 = await new Deno.Command(Deno.execPath(), { +console.error("---"); + +await new Deno.Command(Deno.execPath(), { args: [ "run", - "--quiet", "--allow-env", `--allow-run=${execPath}`, testUrl, ], - stderr: "null", + stderr: "inherit", + stdout: "inherit", env: { "PATH": execPathParent }, }).output(); -console.log(new TextDecoder().decode(process3.stdout)); diff --git a/tests/specs/run/bare_specifier_without_import/__test__.jsonc b/tests/specs/run/bare_specifier_without_import/__test__.jsonc new file mode 100644 index 0000000000..7b5c5e1b67 --- /dev/null +++ b/tests/specs/run/bare_specifier_without_import/__test__.jsonc @@ -0,0 +1,5 @@ +{ + "args": "run main.ts", + "output": "main.out", + "exitCode": 1 +} diff --git a/tests/specs/run/bare_specifier_without_import/main.out b/tests/specs/run/bare_specifier_without_import/main.out new file mode 100644 index 0000000000..a873f2727c --- /dev/null +++ b/tests/specs/run/bare_specifier_without_import/main.out @@ -0,0 +1,3 @@ +error: Relative import path "@std/dotenv/load" not prefixed with / or ./ or ../ + hint: If you want to use a JSR or npm package, try running `deno add @std/dotenv/load` + at [WILDCARD]bare_specifier_without_import/main.ts:1:8 diff --git a/tests/specs/run/bare_specifier_without_import/main.ts b/tests/specs/run/bare_specifier_without_import/main.ts new file mode 100644 index 0000000000..67e57b26b3 --- /dev/null +++ b/tests/specs/run/bare_specifier_without_import/main.ts @@ -0,0 +1,3 @@ +import "@std/dotenv/load"; + +console.log(Deno.env.get("GREETING")); // hello world diff --git a/tests/specs/run/ld_preload/__test__.jsonc b/tests/specs/run/ld_preload/__test__.jsonc index 767e423d06..882f157e9e 100644 --- a/tests/specs/run/ld_preload/__test__.jsonc +++ b/tests/specs/run/ld_preload/__test__.jsonc @@ -7,13 +7,11 @@ "tests": { "env_arg": { "args": "run --allow-run=echo env_arg.ts", - "output": "env_arg.out", - "exitCode": 1 + "output": "env_arg.out" }, "set_with_allow_env": { "args": "run --allow-run=echo --allow-env set_with_allow_env.ts", - "output": "set_with_allow_env.out", - "exitCode": 1 + "output": "set_with_allow_env.out" } } } diff --git a/tests/specs/run/ld_preload/env_arg.out b/tests/specs/run/ld_preload/env_arg.out index fbf37014ae..3df781a8e6 100644 --- a/tests/specs/run/ld_preload/env_arg.out +++ b/tests/specs/run/ld_preload/env_arg.out @@ -1,4 +1,8 @@ -error: Uncaught (in promise) PermissionDenied: Requires --allow-all permissions to spawn subprocess with LD_PRELOAD environment variable. -}).spawn(); - ^ - at [WILDCARD] +PermissionDenied: Requires --allow-all permissions to spawn subprocess with LD_PRELOAD environment variable. + [WILDCARD] + name: "PermissionDenied" +} +PermissionDenied: Requires --allow-all permissions to spawn subprocess with LD_PRELOAD environment variable. + [WILDCARD] + name: "PermissionDenied" +} diff --git a/tests/specs/run/ld_preload/env_arg.ts b/tests/specs/run/ld_preload/env_arg.ts index 0b236619e1..d7ca1073df 100644 --- a/tests/specs/run/ld_preload/env_arg.ts +++ b/tests/specs/run/ld_preload/env_arg.ts @@ -1,5 +1,20 @@ -const output = new Deno.Command("echo", { - env: { - "LD_PRELOAD": "./libpreload.so", - }, -}).spawn(); +try { + new Deno.Command("echo", { + env: { + "LD_PRELOAD": "./libpreload.so", + }, + }).spawn(); +} catch (err) { + console.log(err); +} + +try { + Deno.run({ + cmd: ["echo"], + env: { + "LD_PRELOAD": "./libpreload.so", + }, + }); +} catch (err) { + console.log(err); +} diff --git a/tests/specs/run/ld_preload/set_with_allow_env.out b/tests/specs/run/ld_preload/set_with_allow_env.out index 2e92763dda..60dba7cff1 100644 --- a/tests/specs/run/ld_preload/set_with_allow_env.out +++ b/tests/specs/run/ld_preload/set_with_allow_env.out @@ -1,4 +1,8 @@ -error: Uncaught (in promise) PermissionDenied: Requires --allow-all permissions to spawn subprocess with LD_PRELOAD environment variable. -const output = new Deno.Command("echo").spawn(); - ^ - at [WILDCARD] +PermissionDenied: Requires --allow-all permissions to spawn subprocess with LD_PRELOAD environment variable. + [WILDCARD] + name: "PermissionDenied" +} +PermissionDenied: Requires --allow-all permissions to spawn subprocess with DYLD_FALLBACK_LIBRARY_PATH, LD_PRELOAD environment variables. + [WILDCARD] + name: "PermissionDenied" +} diff --git a/tests/specs/run/ld_preload/set_with_allow_env.ts b/tests/specs/run/ld_preload/set_with_allow_env.ts index 9530f4478c..79004aa165 100644 --- a/tests/specs/run/ld_preload/set_with_allow_env.ts +++ b/tests/specs/run/ld_preload/set_with_allow_env.ts @@ -1,3 +1,15 @@ Deno.env.set("LD_PRELOAD", "./libpreload.so"); -const output = new Deno.Command("echo").spawn(); +try { + new Deno.Command("echo").spawn(); +} catch (err) { + console.log(err); +} + +Deno.env.set("DYLD_FALLBACK_LIBRARY_PATH", "./libpreload.so"); + +try { + Deno.run({ cmd: ["echo"] }).spawnSync(); +} catch (err) { + console.log(err); +} diff --git a/tests/specs/task/bin_pkg_with_scope_auto/__test__.jsonc b/tests/specs/task/bin_pkg_with_scope_auto/__test__.jsonc new file mode 100644 index 0000000000..2e126f6b16 --- /dev/null +++ b/tests/specs/task/bin_pkg_with_scope_auto/__test__.jsonc @@ -0,0 +1,5 @@ +{ + "tempDir": true, + "args": "task bin extra", + "output": "bin_auto.out" +} diff --git a/tests/specs/task/bin_pkg_with_scope_auto/bin_auto.out b/tests/specs/task/bin_pkg_with_scope_auto/bin_auto.out new file mode 100644 index 0000000000..20865898e3 --- /dev/null +++ b/tests/specs/task/bin_pkg_with_scope_auto/bin_auto.out @@ -0,0 +1,14 @@ +Download http://localhost:4260/@denotest/bin +[UNORDERED_START] +Download http://localhost:4260/@denotest/bin/0.5.0.tgz +Initialize @denotest/bin@0.5.0 +Download http://localhost:4260/@denotest/bin/1.0.0.tgz +Initialize @denotest/bin@1.0.0 +[UNORDERED_END] +Task bin bin hi && cli-esm testing this out && npx cli-cjs test "extra" +hi +testing +this +out +test +extra diff --git a/tests/specs/task/bin_pkg_with_scope_auto/bin_none.out b/tests/specs/task/bin_pkg_with_scope_auto/bin_none.out new file mode 100644 index 0000000000..066c67bd8a --- /dev/null +++ b/tests/specs/task/bin_pkg_with_scope_auto/bin_none.out @@ -0,0 +1,12 @@ +Download http://localhost:4260/@denotest/bin +[UNORDERED_START] +Download http://localhost:4260/@denotest/bin/0.5.0.tgz +Download http://localhost:4260/@denotest/bin/1.0.0.tgz +[UNORDERED_END] +Task bin bin hi && cli-esm testing this out && npx cli-cjs test "extra" +hi +testing +this +out +test +extra diff --git a/tests/specs/task/bin_pkg_with_scope_auto/deno.json b/tests/specs/task/bin_pkg_with_scope_auto/deno.json new file mode 100644 index 0000000000..fbd70ec480 --- /dev/null +++ b/tests/specs/task/bin_pkg_with_scope_auto/deno.json @@ -0,0 +1,3 @@ +{ + "nodeModulesDir": "auto" +} diff --git a/tests/specs/task/bin_pkg_with_scope_auto/package.json b/tests/specs/task/bin_pkg_with_scope_auto/package.json new file mode 100644 index 0000000000..2ee4c2bbb1 --- /dev/null +++ b/tests/specs/task/bin_pkg_with_scope_auto/package.json @@ -0,0 +1,9 @@ +{ + "scripts": { + "bin": "bin hi && cli-esm testing this out && npx cli-cjs test" + }, + "dependencies": { + "@denotest/bin": "0.5", + "other": "npm:@denotest/bin@1.0" + } +} diff --git a/tests/specs/task/bin_pkg_with_scope_none/__test__.jsonc b/tests/specs/task/bin_pkg_with_scope_none/__test__.jsonc new file mode 100644 index 0000000000..9f88b275fd --- /dev/null +++ b/tests/specs/task/bin_pkg_with_scope_none/__test__.jsonc @@ -0,0 +1,5 @@ +{ + "tempDir": true, + "args": "task bin extra", + "output": "bin_none.out" +} diff --git a/tests/specs/task/bin_pkg_with_scope_none/bin_none.out b/tests/specs/task/bin_pkg_with_scope_none/bin_none.out new file mode 100644 index 0000000000..066c67bd8a --- /dev/null +++ b/tests/specs/task/bin_pkg_with_scope_none/bin_none.out @@ -0,0 +1,12 @@ +Download http://localhost:4260/@denotest/bin +[UNORDERED_START] +Download http://localhost:4260/@denotest/bin/0.5.0.tgz +Download http://localhost:4260/@denotest/bin/1.0.0.tgz +[UNORDERED_END] +Task bin bin hi && cli-esm testing this out && npx cli-cjs test "extra" +hi +testing +this +out +test +extra diff --git a/tests/specs/task/bin_pkg_with_scope_none/deno.json b/tests/specs/task/bin_pkg_with_scope_none/deno.json new file mode 100644 index 0000000000..38af4024b0 --- /dev/null +++ b/tests/specs/task/bin_pkg_with_scope_none/deno.json @@ -0,0 +1,3 @@ +{ + "nodeModulesDir": "none" +} diff --git a/tests/specs/task/bin_pkg_with_scope_none/package.json b/tests/specs/task/bin_pkg_with_scope_none/package.json new file mode 100644 index 0000000000..2ee4c2bbb1 --- /dev/null +++ b/tests/specs/task/bin_pkg_with_scope_none/package.json @@ -0,0 +1,9 @@ +{ + "scripts": { + "bin": "bin hi && cli-esm testing this out && npx cli-cjs test" + }, + "dependencies": { + "@denotest/bin": "0.5", + "other": "npm:@denotest/bin@1.0" + } +} diff --git a/tests/specs/test/exit_code/main.out b/tests/specs/test/exit_code/main.out index 2562695a02..d5fe6c4751 100644 --- a/tests/specs/test/exit_code/main.out +++ b/tests/specs/test/exit_code/main.out @@ -4,7 +4,7 @@ Deno.exitCode ... FAILED ([WILDCARD]) ERRORS Deno.exitCode => ./main.js:1:6 -error: Error: Test case finished with exit code set to 42. +error: Error: Test case finished with exit code set to 42 at exitSanitizer (ext:cli/40_test.js:113:15) at async outerWrapped (ext:cli/40_test.js:134:14) diff --git a/tests/specs/test/exit_code2/main.out b/tests/specs/test/exit_code2/main.out index adc9cb5775..4943846520 100644 --- a/tests/specs/test/exit_code2/main.out +++ b/tests/specs/test/exit_code2/main.out @@ -11,7 +11,7 @@ error: Error at [WILDCARD]/exit_code2/main.js:3:9 success => ./main.js:6:6 -error: Error: Test case finished with exit code set to 5. +error: Error: Test case finished with exit code set to 5 at exitSanitizer (ext:cli/40_test.js:113:15) at async outerWrapped (ext:cli/40_test.js:134:14) diff --git a/tests/specs/test/exit_code3/main.out b/tests/specs/test/exit_code3/main.out index 6e333bf425..a461db2f6f 100644 --- a/tests/specs/test/exit_code3/main.out +++ b/tests/specs/test/exit_code3/main.out @@ -5,7 +5,7 @@ success ... ok ([WILDCARD]) ERRORS Deno.exitCode => ./main.js:1:6 -error: Error: Test case finished with exit code set to 42. +error: Error: Test case finished with exit code set to 42 at exitSanitizer (ext:cli/40_test.js:113:15) at async outerWrapped (ext:cli/40_test.js:134:14) diff --git a/tests/specs/workspaces/nested_deno_pkg_npm_conflict/__test__.jsonc b/tests/specs/workspaces/nested_deno_pkg_npm_conflict/__test__.jsonc new file mode 100644 index 0000000000..1bad68fd4e --- /dev/null +++ b/tests/specs/workspaces/nested_deno_pkg_npm_conflict/__test__.jsonc @@ -0,0 +1,13 @@ +{ + "tempDir": true, + "steps": [{ + "args": "install", + "output": "[WILDCARD]" + }, { + "args": "run --allow-read main.js", + "output": "4\n0.5.0\n" + }, { + "args": "run --allow-read member/main.js", + "output": "3\n1.0.0\n" + }] +} diff --git a/tests/specs/workspaces/nested_deno_pkg_npm_conflict/deno.json b/tests/specs/workspaces/nested_deno_pkg_npm_conflict/deno.json new file mode 100644 index 0000000000..f03a591e23 --- /dev/null +++ b/tests/specs/workspaces/nested_deno_pkg_npm_conflict/deno.json @@ -0,0 +1,7 @@ +{ + "nodeModulesDir": "manual", + "workspace": ["./member"], + "imports": { + "@denotest/add": "npm:@denotest/add@0.5" + } +} diff --git a/tests/specs/workspaces/nested_deno_pkg_npm_conflict/main.js b/tests/specs/workspaces/nested_deno_pkg_npm_conflict/main.js new file mode 100644 index 0000000000..188da6f975 --- /dev/null +++ b/tests/specs/workspaces/nested_deno_pkg_npm_conflict/main.js @@ -0,0 +1,9 @@ +import { sum } from "@denotest/add"; + +console.log(sum(2, 2)); + +console.log( + JSON.parse(Deno.readTextFileSync( + new URL("node_modules/@denotest/add/package.json", import.meta.url), + )).version, +); diff --git a/tests/specs/workspaces/nested_deno_pkg_npm_conflict/member/deno.json b/tests/specs/workspaces/nested_deno_pkg_npm_conflict/member/deno.json new file mode 100644 index 0000000000..1d36d0aab7 --- /dev/null +++ b/tests/specs/workspaces/nested_deno_pkg_npm_conflict/member/deno.json @@ -0,0 +1,5 @@ +{ + "imports": { + "@denotest/add": "npm:@denotest/add@1" + } +} diff --git a/tests/specs/workspaces/nested_deno_pkg_npm_conflict/member/main.js b/tests/specs/workspaces/nested_deno_pkg_npm_conflict/member/main.js new file mode 100644 index 0000000000..0f64cf5532 --- /dev/null +++ b/tests/specs/workspaces/nested_deno_pkg_npm_conflict/member/main.js @@ -0,0 +1,9 @@ +import { add } from "@denotest/add"; + +console.log(add(1, 2)); + +console.log( + JSON.parse(Deno.readTextFileSync( + new URL("node_modules/@denotest/add/package.json", import.meta.url), + )).version, +); diff --git a/tests/testdata/bench/explicit_start_and_end.out b/tests/testdata/bench/explicit_start_and_end.out index 7248464e92..6759d39cad 100644 --- a/tests/testdata/bench/explicit_start_and_end.out +++ b/tests/testdata/bench/explicit_start_and_end.out @@ -8,17 +8,17 @@ benchmark time/iter (avg) iter/s (min … max) p75 start and end [WILDCARD] [WILDCARD] [WILDCARD] ([WILDCARD] … [WILDCARD]) [WILDCARD] start only [WILDCARD] [WILDCARD] [WILDCARD] ([WILDCARD] … [WILDCARD]) [WILDCARD] end only [WILDCARD] [WILDCARD] [WILDCARD] ([WILDCARD] … [WILDCARD]) [WILDCARD] -double start error: Type error: BenchContext::start() has already been invoked. +double start error: Type error: BenchContext::start() has already been invoked t.start(); ^ at BenchContext.start ([WILDCARD]) at [WILDCARD]/explicit_start_and_end.ts:[WILDCARD] -double end error: Type error: BenchContext::end() has already been invoked. +double end error: Type error: BenchContext::end() has already been invoked t.end(); ^ at BenchContext.end ([WILDCARD]) at [WILDCARD]/explicit_start_and_end.ts:[WILDCARD] -captured error: Type error: The benchmark which this context belongs to is not being executed. +captured error: Type error: The benchmark which this context belongs to is not being executed captured!.start(); ^ at BenchContext.start ([WILDCARD]) diff --git a/tests/testdata/coverage/complex_test.ts b/tests/testdata/coverage/complex_test.ts index d6e9c26910..6a711a91a0 100644 --- a/tests/testdata/coverage/complex_test.ts +++ b/tests/testdata/coverage/complex_test.ts @@ -7,32 +7,29 @@ Deno.test("complex", function () { Deno.test("sub process with stdin", async () => { // ensure launching deno run with stdin doesn't affect coverage const code = "console.log('5')"; - // deno-lint-ignore no-deprecated-deno-api - const p = await Deno.run({ - cmd: [Deno.execPath(), "run", "-"], + const command = new Deno.Command(Deno.execPath(), { + args: ["run", "-"], stdin: "piped", stdout: "piped", }); - const encoder = new TextEncoder(); - await p.stdin.write(encoder.encode(code)); - await p.stdin.close(); - const output = new TextDecoder().decode(await p.output()); - p.close(); + await using child = command.spawn(); + await ReadableStream.from([code]) + .pipeThrough(new TextEncoderStream()) + .pipeTo(child.stdin); + const { stdout } = await child.output(); + const output = new TextDecoder().decode(stdout); if (output.trim() !== "5") { throw new Error("Failed"); } }); -Deno.test("sub process with deno eval", async () => { +Deno.test("sub process with deno eval", () => { // ensure launching deno eval doesn't affect coverage const code = "console.log('5')"; - // deno-lint-ignore no-deprecated-deno-api - const p = await Deno.run({ - cmd: [Deno.execPath(), "eval", code], - stdout: "piped", - }); - const output = new TextDecoder().decode(await p.output()); - p.close(); + const { stdout } = new Deno.Command(Deno.execPath(), { + args: ["eval", code], + }).outputSync(); + const output = new TextDecoder().decode(stdout); if (output.trim() !== "5") { throw new Error("Failed"); } diff --git a/tests/testdata/info/with_import_map/deno.lock b/tests/testdata/info/with_import_map/deno.lock index 540a44063a..cb5c6ca45d 100644 --- a/tests/testdata/info/with_import_map/deno.lock +++ b/tests/testdata/info/with_import_map/deno.lock @@ -1,10 +1,10 @@ { "version": "3", "remote": { - "https://esm.sh/preact@10.15.1": "2b79349676a4942fbcf835c4efa909791c2f0aeca195225bf22bac9866e94b4e", - "https://esm.sh/preact@10.15.1/debug": "eb12af10d41f793ab3a8cf90bff89a9cd8efab57b541d43dada6efc5e3fa8e3c", + "https://esm.sh/preact@10.15.1": "4bfd0b2c5a2d432e0c8cda295d6b7304152ae08c85f7d0a22f91289c97085b89", + "https://esm.sh/preact@10.15.1/debug": "4bfd0b2c5a2d432e0c8cda295d6b7304152ae08c85f7d0a22f91289c97085b89", "https://esm.sh/stable/preact@10.15.1/denonext/debug.js": "e8e5e198bd48c93d484c91c4c78af1900bd81d9bfcfd543e8ac75216f5404c10", - "https://esm.sh/stable/preact@10.15.1/denonext/devtools.js": "7e3009ee2208a6cc8bbf747b61e9468d177ef55d94cf9b774ad2a6c926ae51cb", + "https://esm.sh/stable/preact@10.15.1/denonext/devtools.js": "f61430e179a84483f8ea8dc098d7d0d46b2f0546de4027518bfcef197cd665c9", "https://esm.sh/stable/preact@10.15.1/denonext/preact.mjs": "30710ac1d5ff3711ae0c04eddbeb706f34f82d97489f61aaf09897bc75d2a628" } } diff --git a/tests/testdata/npm/compare_globals/main.out b/tests/testdata/npm/compare_globals/main.out index 5b1d264646..f6f90d533f 100644 --- a/tests/testdata/npm/compare_globals/main.out +++ b/tests/testdata/npm/compare_globals/main.out @@ -15,10 +15,6 @@ setTimeout 2 function setTimeout 3 function setTimeout 4 function setTimeout 5 undefined -process 1 false -process 2 false -true -true window 1 false window 2 false false diff --git a/tests/testdata/npm/compare_globals/main.ts b/tests/testdata/npm/compare_globals/main.ts index 5019a5fd5c..9482798d8c 100644 --- a/tests/testdata/npm/compare_globals/main.ts +++ b/tests/testdata/npm/compare_globals/main.ts @@ -30,14 +30,6 @@ globals.deleteSetTimeout(); console.log("setTimeout 4", typeof globalThis.setTimeout); console.log("setTimeout 5", typeof globals.getSetTimeout()); -// In Deno, the process global is not defined, but in Node it is. -console.log("process 1", "process" in globalThis); -console.log( - "process 2", - Object.getOwnPropertyDescriptor(globalThis, "process") !== undefined, -); -globals.checkProcessGlobal(); - // In Deno 2 and Node.js, the window global is not defined. console.log("window 1", "window" in globalThis); console.log( diff --git a/tests/testdata/run/checkjs.tsconfig.json b/tests/testdata/run/checkjs.tsconfig.json index 46d96db9ed..08ac60b6cd 100644 --- a/tests/testdata/run/checkjs.tsconfig.json +++ b/tests/testdata/run/checkjs.tsconfig.json @@ -1,6 +1,5 @@ { "compilerOptions": { - "allowJs": true, "checkJs": true } } diff --git a/tests/testdata/run/decorators/experimental/ts/main.out b/tests/testdata/run/decorators/experimental/ts/main.out index ee77417cf2..ea64fbaa63 100644 --- a/tests/testdata/run/decorators/experimental/ts/main.out +++ b/tests/testdata/run/decorators/experimental/ts/main.out @@ -1,2 +1,3 @@ +Warning experimentalDecorators compiler option is deprecated and may be removed at any time Check [WILDCARD] SomeClass { someField: "asdf" } diff --git a/tests/testdata/run/error_type_definitions.ts.out b/tests/testdata/run/error_type_definitions.ts.out index d60d4d483c..7a71b4ebe8 100644 --- a/tests/testdata/run/error_type_definitions.ts.out +++ b/tests/testdata/run/error_type_definitions.ts.out @@ -1,2 +1,3 @@ [WILDCARD]error: Failed resolving types. Relative import path "baz" not prefixed with / or ./ or ../ + hint: If you want to use a JSR or npm package, try running `deno add baz` at [WILDCARD]/type_definitions/bar.d.ts:[WILDCARD] diff --git a/tests/testdata/run/no_check_imports_not_used_as_values/hello.ts b/tests/testdata/run/no_check_imports_not_used_as_values/hello.ts deleted file mode 100644 index 1a9d8f114f..0000000000 --- a/tests/testdata/run/no_check_imports_not_used_as_values/hello.ts +++ /dev/null @@ -1,2 +0,0 @@ -export type SomeType = unknown; -console.log("Hello, world!"); diff --git a/tests/testdata/run/no_check_imports_not_used_as_values/main.out b/tests/testdata/run/no_check_imports_not_used_as_values/main.out deleted file mode 100644 index f744c41839..0000000000 --- a/tests/testdata/run/no_check_imports_not_used_as_values/main.out +++ /dev/null @@ -1,2 +0,0 @@ -[WILDCARD]Hello, world! -Hi! diff --git a/tests/testdata/run/no_check_imports_not_used_as_values/main.ts b/tests/testdata/run/no_check_imports_not_used_as_values/main.ts deleted file mode 100644 index 80e17aa35d..0000000000 --- a/tests/testdata/run/no_check_imports_not_used_as_values/main.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { SomeType } from "./hello.ts"; - -const string: SomeType = "Hi!"; -console.log(string); diff --git a/tests/testdata/run/no_check_imports_not_used_as_values/preserve_imports.tsconfig.json b/tests/testdata/run/no_check_imports_not_used_as_values/preserve_imports.tsconfig.json deleted file mode 100644 index 9b19291aa0..0000000000 --- a/tests/testdata/run/no_check_imports_not_used_as_values/preserve_imports.tsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "compilerOptions": { - "importsNotUsedAsValues": "preserve" - } -} diff --git a/tests/testdata/run/node_prefix_missing/main.ts.out b/tests/testdata/run/node_prefix_missing/main.ts.out index fd19ed55f7..48b4e37e27 100644 --- a/tests/testdata/run/node_prefix_missing/main.ts.out +++ b/tests/testdata/run/node_prefix_missing/main.ts.out @@ -1,3 +1,3 @@ error: Relative import path "fs" not prefixed with / or ./ or ../ -If you want to use a built-in Node module, add a "node:" prefix (ex. "node:fs"). + hint: If you want to use a built-in Node module, add a "node:" prefix (ex. "node:fs"). at file:///[WILDCARD]/main.ts:1:16 diff --git a/tests/testdata/run/warn_on_deprecated_api/main.js b/tests/testdata/run/warn_on_deprecated_api/main.js index a464be60a3..8811df78de 100644 --- a/tests/testdata/run/warn_on_deprecated_api/main.js +++ b/tests/testdata/run/warn_on_deprecated_api/main.js @@ -1,5 +1,6 @@ import { runEcho as runEcho2 } from "http://localhost:4545/run/warn_on_deprecated_api/mod.ts"; +// @ts-ignore `Deno.run()` was soft-removed in Deno 2. const p = Deno.run({ cmd: [ Deno.execPath(), @@ -11,6 +12,7 @@ await p.status(); p.close(); async function runEcho() { + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. const p = Deno.run({ cmd: [ Deno.execPath(), diff --git a/tests/testdata/run/warn_on_deprecated_api/main.out b/tests/testdata/run/warn_on_deprecated_api/main.out index ff44c885f1..ef85a6f99b 100644 --- a/tests/testdata/run/warn_on_deprecated_api/main.out +++ b/tests/testdata/run/warn_on_deprecated_api/main.out @@ -1,5 +1,4 @@ Download http://localhost:4545/run/warn_on_deprecated_api/mod.ts -warning: Use of deprecated "Deno.run()" API. This API will be removed in Deno 2. Run again with DENO_VERBOSE_WARNINGS=1 to get more details. hello world hello world hello world diff --git a/tests/testdata/run/warn_on_deprecated_api/main.verbose.out b/tests/testdata/run/warn_on_deprecated_api/main.verbose.out index 184051de12..e17562eef3 100644 --- a/tests/testdata/run/warn_on_deprecated_api/main.verbose.out +++ b/tests/testdata/run/warn_on_deprecated_api/main.verbose.out @@ -1,5 +1,4 @@ Download http://localhost:4545/run/warn_on_deprecated_api/mod.ts -warning: Use of deprecated "Deno.run()" API. This API will be removed in Deno 2. See the Deno 1 to 2 Migration Guide for more information at https://docs.deno.com/runtime/manual/advanced/migrate_deprecations @@ -9,7 +8,6 @@ Stack trace: hint: Use "Deno.Command()" API instead. hello world -warning: Use of deprecated "Deno.run()" API. This API will be removed in Deno 2. See the Deno 1 to 2 Migration Guide for more information at https://docs.deno.com/runtime/manual/advanced/migrate_deprecations @@ -20,7 +18,6 @@ Stack trace: hint: Use "Deno.Command()" API instead. hello world -warning: Use of deprecated "Deno.run()" API. This API will be removed in Deno 2. See the Deno 1 to 2 Migration Guide for more information at https://docs.deno.com/runtime/manual/advanced/migrate_deprecations @@ -31,7 +28,6 @@ Stack trace: hint: Use "Deno.Command()" API instead. hello world -warning: Use of deprecated "Deno.run()" API. This API will be removed in Deno 2. See the Deno 1 to 2 Migration Guide for more information at https://docs.deno.com/runtime/manual/advanced/migrate_deprecations @@ -51,7 +47,6 @@ hello world hello world hello world hello world -warning: Use of deprecated "Deno.run()" API. This API will be removed in Deno 2. See the Deno 1 to 2 Migration Guide for more information at https://docs.deno.com/runtime/manual/advanced/migrate_deprecations diff --git a/tests/testdata/run/wasm_streaming_panic_test.js.out b/tests/testdata/run/wasm_streaming_panic_test.js.out index 8a3c68e375..4ec523f1d0 100644 --- a/tests/testdata/run/wasm_streaming_panic_test.js.out +++ b/tests/testdata/run/wasm_streaming_panic_test.js.out @@ -1,2 +1,2 @@ -error: Uncaught (in promise) TypeError: Invalid WebAssembly content type. +error: Uncaught (in promise) TypeError: Invalid WebAssembly content type at handleWasmStreaming (ext:deno_fetch/26_fetch.js:[WILDCARD]) diff --git a/tests/testdata/run/with_package_json/with_stop/main.out b/tests/testdata/run/with_package_json/with_stop/main.out index f5eb79ca6d..afab4910c6 100644 --- a/tests/testdata/run/with_package_json/with_stop/main.out +++ b/tests/testdata/run/with_package_json/with_stop/main.out @@ -1,4 +1,5 @@ [WILDCARD]Config file found at '[WILDCARD]with_package_json[WILDCARD]with_stop[WILDCARD]some[WILDCARD]nested[WILDCARD]deno.json' [WILDCARD] error: Relative import path "chalk" not prefixed with / or ./ or ../ + hint: If you want to use a JSR or npm package, try running `deno add chalk` at file:///[WILDCARD]with_package_json/with_stop/some/nested/dir/main.ts:3:19 diff --git a/tests/unit/buffer_test.ts b/tests/unit/buffer_test.ts index 2295aa5ae4..fcbeb4bc9c 100644 --- a/tests/unit/buffer_test.ts +++ b/tests/unit/buffer_test.ts @@ -354,52 +354,6 @@ Deno.test({ ignore: DENO_FUTURE }, async function bufferTestGrow() { } }); -Deno.test({ ignore: DENO_FUTURE }, async function testReadAll() { - init(); - assert(testBytes); - const reader = new Deno.Buffer(testBytes.buffer as ArrayBuffer); - const actualBytes = await Deno.readAll(reader); - assertEquals(testBytes.byteLength, actualBytes.byteLength); - for (let i = 0; i < testBytes.length; ++i) { - assertEquals(testBytes[i], actualBytes[i]); - } -}); - -Deno.test({ ignore: DENO_FUTURE }, function testReadAllSync() { - init(); - assert(testBytes); - const reader = new Deno.Buffer(testBytes.buffer as ArrayBuffer); - const actualBytes = Deno.readAllSync(reader); - assertEquals(testBytes.byteLength, actualBytes.byteLength); - for (let i = 0; i < testBytes.length; ++i) { - assertEquals(testBytes[i], actualBytes[i]); - } -}); - -Deno.test({ ignore: DENO_FUTURE }, async function testWriteAll() { - init(); - assert(testBytes); - const writer = new Deno.Buffer(); - await Deno.writeAll(writer, testBytes); - const actualBytes = writer.bytes(); - assertEquals(testBytes.byteLength, actualBytes.byteLength); - for (let i = 0; i < testBytes.length; ++i) { - assertEquals(testBytes[i], actualBytes[i]); - } -}); - -Deno.test({ ignore: DENO_FUTURE }, function testWriteAllSync() { - init(); - assert(testBytes); - const writer = new Deno.Buffer(); - Deno.writeAllSync(writer, testBytes); - const actualBytes = writer.bytes(); - assertEquals(testBytes.byteLength, actualBytes.byteLength); - for (let i = 0; i < testBytes.length; ++i) { - assertEquals(testBytes[i], actualBytes[i]); - } -}); - Deno.test({ ignore: DENO_FUTURE }, function testBufferBytesArrayBufferLength() { // defaults to copy const args = [{}, { copy: undefined }, undefined, { copy: true }]; diff --git a/tests/unit/cache_api_test.ts b/tests/unit/cache_api_test.ts index 792929870d..08f768e334 100644 --- a/tests/unit/cache_api_test.ts +++ b/tests/unit/cache_api_test.ts @@ -118,7 +118,7 @@ Deno.test(async function cachePutReaderLock() { await response.arrayBuffer(); }, TypeError, - "Body already consumed.", + "Body already consumed", ); await promise; diff --git a/tests/unit/command_test.ts b/tests/unit/command_test.ts index dd83525473..6352e1fc7b 100644 --- a/tests/unit/command_test.ts +++ b/tests/unit/command_test.ts @@ -975,3 +975,35 @@ Deno.test( ); }, ); + +Deno.test( + { permissions: { write: true, run: true, read: true } }, + async function commandWithCwdOrPath() { + const cwd = Deno.makeTempDirSync({ prefix: "deno_command_test" }); + try { + const suffix = Deno.build.os === "windows" ? ".exe" : ""; + Deno.mkdirSync(`${cwd}/subdir`); + Deno.copyFileSync(Deno.execPath(), `${cwd}/subdir/my_binary${suffix}`); + // cwd + { + const output = await new Deno.Command(`./my_binary${suffix}`, { + cwd: `${cwd}/subdir`, + args: ["-v"], + }).output(); + assertEquals(output.success, true); + } + // path + { + const output = await new Deno.Command(`my_binary${suffix}`, { + env: { + PATH: `${cwd}/subdir`, + }, + args: ["-v"], + }).output(); + assertEquals(output.success, true); + } + } finally { + Deno.removeSync(cwd, { recursive: true }); + } + }, +); diff --git a/tests/unit/cron_test.ts b/tests/unit/cron_test.ts index 02573a898d..5f14f6c784 100644 --- a/tests/unit/cron_test.ts +++ b/tests/unit/cron_test.ts @@ -15,7 +15,7 @@ Deno.test(function noNameTest() { // @ts-ignore test () => Deno.cron(), TypeError, - "Deno.cron requires a unique name", + "Cannot create cron job, a unique name is required: received 'undefined'", ); }); @@ -24,7 +24,7 @@ Deno.test(function noSchedule() { // @ts-ignore test () => Deno.cron("foo"), TypeError, - "Deno.cron requires a valid schedule", + "Cannot create cron job, a schedule is required: received 'undefined'", ); }); @@ -33,7 +33,7 @@ Deno.test(function noHandler() { // @ts-ignore test () => Deno.cron("foo", "*/1 * * * *"), TypeError, - "Deno.cron requires a handler", + "Cannot create cron job: a handler is required", ); }); @@ -66,7 +66,7 @@ Deno.test(function invalidNameTest() { () => {}, ), TypeError, - "Cron name is too long", + "Cron name cannot exceed 64 characters: current length 70", ); }); @@ -388,7 +388,7 @@ Deno.test("error on two handlers", () => { Deno.cron("abc", "* * * * *", () => {}, () => {}); }, TypeError, - "Deno.cron requires a single handler", + "Cannot create cron job, a single handler is required: two handlers were specified", ); }); diff --git a/tests/unit/fetch_test.ts b/tests/unit/fetch_test.ts index 721b6912d5..35d5e563f4 100644 --- a/tests/unit/fetch_test.ts +++ b/tests/unit/fetch_test.ts @@ -1131,7 +1131,7 @@ Deno.test(function fetchResponseConstructorInvalidStatus() { assert(e instanceof RangeError); assert( e.message.endsWith( - "is not equal to 101 and outside the range [200, 599].", + "is not equal to 101 and outside the range [200, 599]", ), ); } @@ -1662,7 +1662,7 @@ Deno.test( ); }, TypeError, - "Fetching files only supports the GET method. Received POST.", + "Fetching files only supports the GET method: received POST", ); }, ); diff --git a/tests/unit/files_test.ts b/tests/unit/files_test.ts index c9c3c01100..7b939d1ece 100644 --- a/tests/unit/files_test.ts +++ b/tests/unit/files_test.ts @@ -1,7 +1,5 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -// deno-lint-ignore-file no-deprecated-deno-api - import { assert, assertEquals, @@ -24,7 +22,6 @@ Deno.test( async function filesCopyToStdout() { const filename = "tests/testdata/assets/fixture.json"; using file = await Deno.open(filename); - assert(file instanceof Deno.File); assert(file instanceof Deno.FsFile); assert(file.rid > 2); const bytesWritten = await copy(file, Deno.stdout); diff --git a/tests/unit/headers_test.ts b/tests/unit/headers_test.ts index ad453b67f6..ea72f784b5 100644 --- a/tests/unit/headers_test.ts +++ b/tests/unit/headers_test.ts @@ -406,11 +406,11 @@ Deno.test(function invalidHeadersFlaky() { assertThrows( () => new Headers([["x", "\u0000x"]]), TypeError, - "Header value is not valid.", + 'Invalid header value: "\u0000x"', ); assertThrows( () => new Headers([["x", "\u0000x"]]), TypeError, - "Header value is not valid.", + 'Invalid header value: "\u0000x"', ); }); diff --git a/tests/unit/http_test.ts b/tests/unit/http_test.ts index 6d3543e444..778cc98fde 100644 --- a/tests/unit/http_test.ts +++ b/tests/unit/http_test.ts @@ -2087,7 +2087,6 @@ Deno.test({ async function client() { const url = `http://${hostname}:${port}/`; const cmd = [ - "curl", "-i", "--request", "GET", @@ -2097,16 +2096,17 @@ Deno.test({ "--header", "Accept-Encoding: deflate, gzip", ]; - const proc = Deno.run({ cmd, stdout: "piped", stderr: "null" }); - const status = await proc.status(); - assert(status.success); - const output = decoder.decode(await proc.output()); + const { success, stdout } = await new Deno.Command("curl", { + args: cmd, + stderr: "null", + }).output(); + assert(success); + const output = decoder.decode(stdout); assert(output.includes("vary: Accept-Encoding\r\n")); assert(output.includes("content-encoding: gzip\r\n")); // Ensure the content-length header is updated. assert(!output.includes(`content-length: ${contentLength}\r\n`)); assert(output.includes("content-length: ")); - proc.close(); } await Promise.all([server(), client()]); @@ -2149,7 +2149,6 @@ Deno.test({ async function client() { const url = `http://${hostname}:${port}/`; const cmd = [ - "curl", "-i", "--request", "GET", @@ -2159,13 +2158,15 @@ Deno.test({ "--header", "Accept-Encoding: deflate, gzip", ]; - const proc = Deno.run({ cmd, stdout: "piped", stderr: "null" }); - const status = await proc.status(); - assert(status.success); - const output = decoder.decode(await proc.output()); + const { success, stdout } = await new Deno.Command("curl", { + args: cmd, + stderr: "null", + stdout: "piped", + }).output(); + assert(success); + const output = decoder.decode(stdout); assert(output.includes("vary: Accept-Encoding\r\n")); assert(output.includes("content-encoding: arbitrary\r\n")); - proc.close(); } await Promise.all([server(), client()]); diff --git a/tests/unit/io_test.ts b/tests/unit/io_test.ts deleted file mode 100644 index 44a04698c9..0000000000 --- a/tests/unit/io_test.ts +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import { assertEquals, DENO_FUTURE } from "./test_util.ts"; -import { Buffer } from "@std/io/buffer"; - -const DEFAULT_BUF_SIZE = 32 * 1024; - -type Spy = { calls: number }; - -function repeat(c: string, bytes: number): Uint8Array { - assertEquals(c.length, 1); - const ui8 = new Uint8Array(bytes); - ui8.fill(c.charCodeAt(0)); - return ui8; -} - -function spyRead(obj: Buffer): Spy { - const spy: Spy = { - calls: 0, - }; - - const orig = obj.read.bind(obj); - - obj.read = (p: Uint8Array): Promise => { - spy.calls++; - return orig(p); - }; - - return spy; -} - -Deno.test({ ignore: DENO_FUTURE }, async function copyWithDefaultBufferSize() { - const xBytes = repeat("b", DEFAULT_BUF_SIZE); - const reader = new Buffer(xBytes.buffer as ArrayBuffer); - const write = new Buffer(); - - const readSpy = spyRead(reader); - - // deno-lint-ignore no-deprecated-deno-api - const n = await Deno.copy(reader, write); - - assertEquals(n, xBytes.length); - assertEquals(write.length, xBytes.length); - assertEquals(readSpy.calls, 2); // read with DEFAULT_BUF_SIZE bytes + read with 0 bytes -}); - -Deno.test({ ignore: DENO_FUTURE }, async function copyWithCustomBufferSize() { - const bufSize = 1024; - const xBytes = repeat("b", DEFAULT_BUF_SIZE); - const reader = new Buffer(xBytes.buffer as ArrayBuffer); - const write = new Buffer(); - - const readSpy = spyRead(reader); - - // deno-lint-ignore no-deprecated-deno-api - const n = await Deno.copy(reader, write, { bufSize }); - - assertEquals(n, xBytes.length); - assertEquals(write.length, xBytes.length); - assertEquals(readSpy.calls, DEFAULT_BUF_SIZE / bufSize + 1); -}); - -Deno.test( - { ignore: DENO_FUTURE, permissions: { write: true } }, - async function copyBufferToFile() { - const filePath = "test-file.txt"; - // bigger than max File possible buffer 16kb - const bufSize = 32 * 1024; - const xBytes = repeat("b", bufSize); - const reader = new Buffer(xBytes.buffer as ArrayBuffer); - const write = await Deno.open(filePath, { write: true, create: true }); - - // deno-lint-ignore no-deprecated-deno-api - const n = await Deno.copy(reader, write, { bufSize }); - - assertEquals(n, xBytes.length); - - write.close(); - await Deno.remove(filePath); - }, -); diff --git a/tests/unit/process_test.ts b/tests/unit/process_test.ts index a35362d090..0d14c9ce7c 100644 --- a/tests/unit/process_test.ts +++ b/tests/unit/process_test.ts @@ -1,3 +1,4 @@ +// deno-lint-ignore-file no-deprecated-deno-api // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. import { assert, @@ -12,7 +13,7 @@ Deno.test( { permissions: { read: true, run: false } }, function runPermissions() { assertThrows(() => { - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. Deno.run({ cmd: [Deno.execPath(), "eval", "console.log('hello world')"], }); @@ -23,7 +24,7 @@ Deno.test( Deno.test( { permissions: { run: true, read: true } }, async function runSuccess() { - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. const p = Deno.run({ // freeze the array to ensure it's not modified cmd: Object.freeze([ @@ -46,7 +47,7 @@ Deno.test( Deno.test( { permissions: { run: true, read: true } }, async function runUrl() { - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. const p = Deno.run({ cmd: [ new URL(`file:///${Deno.execPath()}`), @@ -70,7 +71,7 @@ Deno.test( async function runStdinRid0(): Promise< void > { - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. const p = Deno.run({ cmd: [Deno.execPath(), "eval", "console.log('hello world')"], stdin: 0, @@ -90,26 +91,23 @@ Deno.test( { permissions: { run: true, read: true } }, function runInvalidStdio() { assertThrows(() => - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. Deno.run({ cmd: [Deno.execPath(), "eval", "console.log('hello world')"], - // @ts-expect-error because Deno.run should throw on invalid stdin. stdin: "a", }) ); assertThrows(() => - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. Deno.run({ cmd: [Deno.execPath(), "eval", "console.log('hello world')"], - // @ts-expect-error because Deno.run should throw on invalid stdout. stdout: "b", }) ); assertThrows(() => - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. Deno.run({ cmd: [Deno.execPath(), "eval", "console.log('hello world')"], - // @ts-expect-error because Deno.run should throw on invalid stderr. stderr: "c", }) ); @@ -119,7 +117,7 @@ Deno.test( Deno.test( { permissions: { run: true, read: true } }, async function runCommandFailedWithCode() { - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. const p = Deno.run({ cmd: [Deno.execPath(), "eval", "Deno.exit(41 + 1)"], }); @@ -136,7 +134,7 @@ Deno.test( permissions: { run: true, read: true }, }, async function runCommandFailedWithSignal() { - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. const p = Deno.run({ cmd: [ Deno.execPath(), @@ -160,7 +158,7 @@ Deno.test( Deno.test({ permissions: { run: true } }, function runNotFound() { let error; try { - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. Deno.run({ cmd: ["this file hopefully doesn't exist"] }); } catch (e) { error = e; @@ -192,7 +190,7 @@ tryExit(); `; Deno.writeFileSync(`${cwd}/${programFile}`, enc.encode(program)); - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. const p = Deno.run({ cwd, cmd: [Deno.execPath(), "run", "--allow-read", programFile], @@ -216,7 +214,7 @@ Deno.test( async function runStdinPiped(): Promise< void > { - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. const p = Deno.run({ cmd: [ Deno.execPath(), @@ -254,7 +252,7 @@ Deno.test( async function runStdoutPiped(): Promise< void > { - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. const p = Deno.run({ cmd: [ Deno.execPath(), @@ -291,7 +289,7 @@ Deno.test( async function runStderrPiped(): Promise< void > { - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. const p = Deno.run({ cmd: [ Deno.execPath(), @@ -326,7 +324,7 @@ Deno.test( Deno.test( { permissions: { run: true, read: true } }, async function runOutput() { - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. const p = Deno.run({ cmd: [ Deno.execPath(), @@ -347,7 +345,7 @@ Deno.test( async function runStderrOutput(): Promise< void > { - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. const p = Deno.run({ cmd: [ Deno.execPath(), @@ -377,7 +375,7 @@ Deno.test( write: true, }); - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. const p = Deno.run({ cmd: [ Deno.execPath(), @@ -414,7 +412,7 @@ Deno.test( await Deno.writeTextFile(fileName, "hello"); using file = await Deno.open(fileName); - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. const p = Deno.run({ cmd: [ Deno.execPath(), @@ -439,7 +437,7 @@ Deno.test( Deno.test( { permissions: { run: true, read: true } }, async function runEnv() { - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. const p = Deno.run({ cmd: [ Deno.execPath(), @@ -462,7 +460,7 @@ Deno.test( Deno.test( { permissions: { run: true, read: true } }, async function runClose() { - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. const p = Deno.run({ cmd: [ Deno.execPath(), @@ -486,7 +484,7 @@ Deno.test( Deno.test( { permissions: { run: true, read: true } }, async function runKillAfterStatus() { - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. const p = Deno.run({ cmd: [Deno.execPath(), "eval", 'console.log("hello")'], }); @@ -543,7 +541,7 @@ Deno.test( Deno.test( { permissions: { run: true, read: true } }, async function killSuccess() { - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. const p = Deno.run({ cmd: [Deno.execPath(), "eval", "setTimeout(() => {}, 10000)"], }); @@ -567,7 +565,7 @@ Deno.test( ); Deno.test({ permissions: { run: true, read: true } }, function killFailed() { - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. const p = Deno.run({ cmd: [Deno.execPath(), "eval", "setTimeout(() => {}, 10000)"], }); @@ -588,7 +586,7 @@ Deno.test( ignore: Deno.build.os === "windows", }, async function non_existent_cwd(): Promise { - // deno-lint-ignore no-deprecated-deno-api + // @ts-ignore `Deno.run()` was soft-removed in Deno 2. const p = Deno.run({ cmd: [ Deno.execPath(), @@ -611,6 +609,6 @@ Deno.test( p.close(); p.stdout.close(); assertStrictEquals(code, 1); - assertStringIncludes(stderr, "Failed getting cwd."); + assertStringIncludes(stderr, "failed resolving cwd:"); }, ); diff --git a/tests/unit/serve_test.ts b/tests/unit/serve_test.ts index fde6c7bee6..19a8ccad1b 100644 --- a/tests/unit/serve_test.ts +++ b/tests/unit/serve_test.ts @@ -4191,3 +4191,19 @@ Deno.test({ 'Operation `"op_net_listen_unix"` not supported on non-unix platforms.', ); }); + +Deno.test({ + name: "onListen callback gets 0.0.0.0 hostname as is", +}, async () => { + const { promise, resolve } = Promise.withResolvers<{ hostname: string }>(); + + const server = Deno.serve({ + handler: (_) => new Response("ok"), + hostname: "0.0.0.0", + port: 0, + onListen: resolve, + }); + const { hostname } = await promise; + assertEquals(hostname, "0.0.0.0"); + await server.shutdown(); +}); diff --git a/tests/unit/stat_test.ts b/tests/unit/stat_test.ts index f9d7800312..950ffa81bc 100644 --- a/tests/unit/stat_test.ts +++ b/tests/unit/stat_test.ts @@ -1,48 +1,13 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -// deno-lint-ignore-file no-deprecated-deno-api - import { assert, assertEquals, assertRejects, assertThrows, - DENO_FUTURE, pathToAbsoluteFileUrl, } from "./test_util.ts"; -Deno.test( - { ignore: DENO_FUTURE, permissions: { read: true } }, - function fstatSyncSuccess() { - using file = Deno.openSync("README.md"); - const fileInfo = Deno.fstatSync(file.rid); - assert(fileInfo.isFile); - assert(!fileInfo.isSymlink); - assert(!fileInfo.isDirectory); - assert(fileInfo.size); - assert(fileInfo.atime); - assert(fileInfo.mtime); - // The `birthtime` field is not available on Linux before kernel version 4.11. - assert(fileInfo.birthtime || Deno.build.os === "linux"); - }, -); - -Deno.test( - { ignore: DENO_FUTURE, permissions: { read: true } }, - async function fstatSuccess() { - using file = await Deno.open("README.md"); - const fileInfo = await Deno.fstat(file.rid); - assert(fileInfo.isFile); - assert(!fileInfo.isSymlink); - assert(!fileInfo.isDirectory); - assert(fileInfo.size); - assert(fileInfo.atime); - assert(fileInfo.mtime); - // The `birthtime` field is not available on Linux before kernel version 4.11. - assert(fileInfo.birthtime || Deno.build.os === "linux"); - }, -); - Deno.test( { permissions: { read: true, write: true } }, function statSyncSuccess() { diff --git a/tests/unit/testing_test.ts b/tests/unit/testing_test.ts index e04ab921c7..51372c42b0 100644 --- a/tests/unit/testing_test.ts +++ b/tests/unit/testing_test.ts @@ -8,7 +8,7 @@ Deno.test(function testWrongOverloads() { Deno.test("some name", { fn: () => {} }, () => {}); }, TypeError, - "Unexpected 'fn' field in options, test function is already provided as the third argument.", + "Unexpected 'fn' field in options, test function is already provided as the third argument", ); assertThrows( () => { @@ -16,7 +16,7 @@ Deno.test(function testWrongOverloads() { Deno.test("some name", { name: "some name2" }, () => {}); }, TypeError, - "Unexpected 'name' field in options, test name is already provided as the first argument.", + "Unexpected 'name' field in options, test name is already provided as the first argument", ); assertThrows( () => { @@ -40,7 +40,7 @@ Deno.test(function testWrongOverloads() { Deno.test({ fn: () => {} }, function foo() {}); }, TypeError, - "Unexpected 'fn' field in options, test function is already provided as the second argument.", + "Unexpected 'fn' field in options, test function is already provided as the second argument", ); assertThrows( () => { @@ -48,7 +48,7 @@ Deno.test(function testWrongOverloads() { Deno.test({}); }, TypeError, - "Expected 'fn' field in the first argument to be a test function.", + "Expected 'fn' field in the first argument to be a test function", ); assertThrows( () => { @@ -56,7 +56,7 @@ Deno.test(function testWrongOverloads() { Deno.test({ fn: "boo!" }); }, TypeError, - "Expected 'fn' field in the first argument to be a test function.", + "Expected 'fn' field in the first argument to be a test function", ); }); @@ -87,7 +87,7 @@ Deno.test(async function invalidStepArguments(t) { await (t as any).step("test"); }, TypeError, - "Expected function for second argument.", + "Expected function for second argument", ); await assertRejects( @@ -96,7 +96,7 @@ Deno.test(async function invalidStepArguments(t) { await (t as any).step("test", "not a function"); }, TypeError, - "Expected function for second argument.", + "Expected function for second argument", ); await assertRejects( @@ -105,7 +105,7 @@ Deno.test(async function invalidStepArguments(t) { await (t as any).step(); }, TypeError, - "Expected a test definition or name and function.", + "Expected a test definition or name and function", ); await assertRejects( @@ -114,7 +114,7 @@ Deno.test(async function invalidStepArguments(t) { await (t as any).step(() => {}); }, TypeError, - "The step function must have a name.", + "The step function must have a name", ); }); diff --git a/tests/unit/tty_test.ts b/tests/unit/tty_test.ts index 35e7dd7831..4183fe530e 100644 --- a/tests/unit/tty_test.ts +++ b/tests/unit/tty_test.ts @@ -20,6 +20,7 @@ Deno.test( function isatty() { // CI not under TTY, so cannot test stdin/stdout/stderr. const f = Deno.openSync("tests/testdata/assets/hello.txt"); + // @ts-ignore `Deno.isatty()` was soft-removed in Deno 2. assert(!Deno.isatty(f.rid)); f.close(); }, @@ -29,6 +30,7 @@ Deno.test(function isattyError() { let caught = false; try { // Absurdly large rid. + // @ts-ignore `Deno.isatty()` was soft-removed in Deno 2. Deno.isatty(0x7fffffff); } catch (e) { caught = true; diff --git a/tests/unit/wasm_test.ts b/tests/unit/wasm_test.ts index fab9c9308f..e0db41ed0e 100644 --- a/tests/unit/wasm_test.ts +++ b/tests/unit/wasm_test.ts @@ -53,7 +53,7 @@ Deno.test( await assertRejects( () => wasmPromise, TypeError, - "Invalid WebAssembly content type.", + "Invalid WebAssembly content type", ); }, ); diff --git a/tests/unit_node/events_test.ts b/tests/unit_node/events_test.ts index 1fc7ad1e37..82808d5238 100644 --- a/tests/unit_node/events_test.ts +++ b/tests/unit_node/events_test.ts @@ -1,6 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import events, { EventEmitter } from "node:events"; +// @ts-expect-error: @types/node is outdated +import events, { addAbortListener, EventEmitter } from "node:events"; EventEmitter.captureRejections = true; @@ -34,3 +35,13 @@ Deno.test("eventemitter async resource", () => { // @ts-ignore: @types/node is outdated foo.emit("bar"); }); + +Deno.test("addAbortListener", async () => { + const { promise, resolve } = Promise.withResolvers(); + const abortController = new AbortController(); + addAbortListener(abortController.signal, () => { + resolve(); + }); + abortController.abort(); + await promise; +}); diff --git a/tests/unit_node/http_test.ts b/tests/unit_node/http_test.ts index 7f5e74bf5d..f85b1466b5 100644 --- a/tests/unit_node/http_test.ts +++ b/tests/unit_node/http_test.ts @@ -13,6 +13,7 @@ import { text } from "node:stream/consumers"; import { assert, assertEquals, fail } from "@std/assert"; import { assertSpyCalls, spy } from "@std/testing/mock"; import { fromFileUrl, relative } from "@std/path"; +import { retry } from "@std/async/retry"; import { gzip } from "node:zlib"; import { Buffer } from "node:buffer"; @@ -1604,3 +1605,70 @@ Deno.test("[node/http] In ClientRequest, option.hostname has precedence over opt await responseReceived.promise; }); + +Deno.test("[node/http] upgraded socket closes when the server closed without closing handshake", async () => { + const clientSocketClosed = Promise.withResolvers(); + const serverProcessClosed = Promise.withResolvers(); + + // Uses the server in different process to shutdown it without closing handshake + const server = ` + Deno.serve({ port: 1337 }, (req) => { + if (req.headers.get("upgrade") != "websocket") { + return new Response("ok"); + } + console.log("upgrade on server"); + const { socket, response } = Deno.upgradeWebSocket(req); + socket.addEventListener("message", (event) => { + console.log("server received", event.data); + socket.send("pong"); + }); + return response; + }); + `; + + const p = new Deno.Command("deno", { args: ["eval", server] }).spawn(); + + // Wait for the server to respond + await retry(async () => { + const resp = await fetch("http://localhost:1337"); + const _text = await resp.text(); + }); + + const options = { + port: 1337, + host: "127.0.0.1", + headers: { + "Connection": "Upgrade", + "Upgrade": "websocket", + "Sec-WebSocket-Key": "dGhlIHNhbXBsZSBub25jZQ==", + }, + }; + + http.request(options).on("upgrade", (_res, socket) => { + socket.on("close", () => { + console.log("client socket closed"); + clientSocketClosed.resolve(); + }); + socket.on("data", async (data) => { + // receives pong message + assertEquals(data, Buffer.from("8104706f6e67", "hex")); + + p.kill(); + await p.status; + + console.log("process closed"); + serverProcessClosed.resolve(); + + // sending some additional message + socket.write(Buffer.from("81847de88e01", "hex")); + socket.write(Buffer.from("0d81e066", "hex")); + }); + + // sending ping message + socket.write(Buffer.from("81847de88e01", "hex")); + socket.write(Buffer.from("0d81e066", "hex")); + }).end(); + + await clientSocketClosed.promise; + await serverProcessClosed.promise; +}); diff --git a/tests/unit_node/net_test.ts b/tests/unit_node/net_test.ts index f49ff0ef08..708d06386c 100644 --- a/tests/unit_node/net_test.ts +++ b/tests/unit_node/net_test.ts @@ -79,6 +79,7 @@ Deno.test("[node/net] net.connect().unref() works", async () => { port: 0, // any available port will do handler: () => new Response("hello"), onListen: async ({ port, hostname }) => { + hostname = Deno.build.os === "windows" ? "localhost" : hostname; const { stdout, stderr } = await new Deno.Command(Deno.execPath(), { args: [ "eval", diff --git a/tests/unit_node/process_test.ts b/tests/unit_node/process_test.ts index a647b0369e..962877935b 100644 --- a/tests/unit_node/process_test.ts +++ b/tests/unit_node/process_test.ts @@ -7,6 +7,8 @@ import process, { argv, argv0 as importedArgv0, env, + execArgv as importedExecArgv, + execPath as importedExecPath, geteuid, pid as importedPid, platform as importedPlatform, @@ -1121,3 +1123,11 @@ Deno.test("process.listeners - include SIG* events", () => { Deno.test(function processVersionsOwnProperty() { assert(Object.prototype.hasOwnProperty.call(process, "versions")); }); + +Deno.test(function importedExecArgvTest() { + assert(Array.isArray(importedExecArgv)); +}); + +Deno.test(function importedExecPathTest() { + assertEquals(importedExecPath, Deno.execPath()); +}); diff --git a/tests/unit_node/stream_test.ts b/tests/unit_node/stream_test.ts index a54f8b421b..8d49701464 100644 --- a/tests/unit_node/stream_test.ts +++ b/tests/unit_node/stream_test.ts @@ -1,8 +1,10 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import { assert } from "@std/assert"; +import { assert, assertEquals } from "@std/assert"; import { fromFileUrl, relative } from "@std/path"; import { pipeline } from "node:stream/promises"; +// @ts-expect-error: @types/node is outdated +import { getDefaultHighWaterMark } from "node:stream"; import { createReadStream, createWriteStream } from "node:fs"; Deno.test("stream/promises pipeline", async () => { @@ -23,3 +25,8 @@ Deno.test("stream/promises pipeline", async () => { // pass } }); + +Deno.test("stream getDefaultHighWaterMark", () => { + assertEquals(getDefaultHighWaterMark(false), 16 * 1024); + assertEquals(getDefaultHighWaterMark(true), 16); +}); diff --git a/tests/unit_node/util_test.ts b/tests/unit_node/util_test.ts index 2b639538cb..edd5002623 100644 --- a/tests/unit_node/util_test.ts +++ b/tests/unit_node/util_test.ts @@ -330,3 +330,21 @@ Deno.test("[util] debuglog() and debug()", () => { assertEquals(util.debuglog, util.debug); assertEquals(utilDefault.debuglog, utilDefault.debug); }); + +Deno.test("[util] aborted()", async () => { + const abortController = new AbortController(); + let done = false; + const promise = util.aborted( + // deno-lint-ignore no-explicit-any + abortController.signal as any, + abortController.signal, + ); + promise.then(() => { + done = true; + }); + await new Promise((r) => setTimeout(r, 100)); + assertEquals(done, false); + abortController.abort(); + await promise; + assertEquals(done, true); +}); diff --git a/tests/wpt/runner/expectation.json b/tests/wpt/runner/expectation.json index 6dfcccf164..ef22d1dd79 100644 --- a/tests/wpt/runner/expectation.json +++ b/tests/wpt/runner/expectation.json @@ -2554,9 +2554,9 @@ "Document interface: attribute firstElementChild", "Document interface: attribute lastElementChild", "Document interface: attribute childElementCount", - "Document interface: operation prepend((Node or TrustedScript or DOMString)...)", - "Document interface: operation append((Node or TrustedScript or DOMString)...)", - "Document interface: operation replaceChildren((Node or TrustedScript or DOMString)...)", + "Document interface: operation prepend((Node or DOMString)...)", + "Document interface: operation append((Node or DOMString)...)", + "Document interface: operation replaceChildren((Node or DOMString)...)", "Document interface: operation querySelector(DOMString)", "Document interface: operation querySelectorAll(DOMString)", "Document interface: operation createExpression(DOMString, optional XPathNSResolver?)", @@ -2587,9 +2587,9 @@ "DocumentType interface: attribute name", "DocumentType interface: attribute publicId", "DocumentType interface: attribute systemId", - "DocumentType interface: operation before((Node or TrustedScript or DOMString)...)", - "DocumentType interface: operation after((Node or TrustedScript or DOMString)...)", - "DocumentType interface: operation replaceWith((Node or TrustedScript or DOMString)...)", + "DocumentType interface: operation before((Node or DOMString)...)", + "DocumentType interface: operation after((Node or DOMString)...)", + "DocumentType interface: operation replaceWith((Node or DOMString)...)", "DocumentType interface: operation remove()", "DocumentFragment interface: existence and properties of interface object", "DocumentFragment interface object length", @@ -2602,9 +2602,9 @@ "DocumentFragment interface: attribute firstElementChild", "DocumentFragment interface: attribute lastElementChild", "DocumentFragment interface: attribute childElementCount", - "DocumentFragment interface: operation prepend((Node or TrustedScript or DOMString)...)", - "DocumentFragment interface: operation append((Node or TrustedScript or DOMString)...)", - "DocumentFragment interface: operation replaceChildren((Node or TrustedScript or DOMString)...)", + "DocumentFragment interface: operation prepend((Node or DOMString)...)", + "DocumentFragment interface: operation append((Node or DOMString)...)", + "DocumentFragment interface: operation replaceChildren((Node or DOMString)...)", "DocumentFragment interface: operation querySelector(DOMString)", "DocumentFragment interface: operation querySelectorAll(DOMString)", "ShadowRoot interface: existence and properties of interface object", @@ -2669,16 +2669,16 @@ "Element interface: attribute firstElementChild", "Element interface: attribute lastElementChild", "Element interface: attribute childElementCount", - "Element interface: operation prepend((Node or TrustedScript or DOMString)...)", - "Element interface: operation append((Node or TrustedScript or DOMString)...)", - "Element interface: operation replaceChildren((Node or TrustedScript or DOMString)...)", + "Element interface: operation prepend((Node or DOMString)...)", + "Element interface: operation append((Node or DOMString)...)", + "Element interface: operation replaceChildren((Node or DOMString)...)", "Element interface: operation querySelector(DOMString)", "Element interface: operation querySelectorAll(DOMString)", "Element interface: attribute previousElementSibling", "Element interface: attribute nextElementSibling", - "Element interface: operation before((Node or TrustedScript or DOMString)...)", - "Element interface: operation after((Node or TrustedScript or DOMString)...)", - "Element interface: operation replaceWith((Node or TrustedScript or DOMString)...)", + "Element interface: operation before((Node or DOMString)...)", + "Element interface: operation after((Node or DOMString)...)", + "Element interface: operation replaceWith((Node or DOMString)...)", "Element interface: operation remove()", "Element interface: attribute assignedSlot", "NamedNodeMap interface: existence and properties of interface object", @@ -2723,9 +2723,9 @@ "CharacterData interface: operation replaceData(unsigned long, unsigned long, DOMString)", "CharacterData interface: attribute previousElementSibling", "CharacterData interface: attribute nextElementSibling", - "CharacterData interface: operation before((Node or TrustedScript or DOMString)...)", - "CharacterData interface: operation after((Node or TrustedScript or DOMString)...)", - "CharacterData interface: operation replaceWith((Node or TrustedScript or DOMString)...)", + "CharacterData interface: operation before((Node or DOMString)...)", + "CharacterData interface: operation after((Node or DOMString)...)", + "CharacterData interface: operation replaceWith((Node or DOMString)...)", "CharacterData interface: operation remove()", "Text interface: existence and properties of interface object", "Text interface object length", @@ -3089,7 +3089,16 @@ "Node member must be removed: getFeature", "Node member must be removed: getUserData", "Node member must be removed: setUserData", - "Node member must be removed: rootNode" + "Node member must be removed: rootNode", + "The DOMSubtreeModified mutation event must not be fired.", + "The DOMNodeInserted mutation event must not be fired.", + "The DOMNodeRemoved mutation event must not be fired.", + "The DOMNodeRemovedFromDocument mutation event must not be fired.", + "The DOMNodeInsertedIntoDocument mutation event must not be fired.", + "The DOMCharacterDataModified mutation event must not be fired.", + "The DOMAttrModified mutation event must not be fired.", + "The DOMAttributeNameChanged mutation event must not be fired.", + "The DOMElementNameChanged mutation event must not be fired." ], "idlharness.any.serviceworker.html": false, "idlharness.any.sharedworker.html": false, @@ -4577,7 +4586,31 @@ "≯ (using .host)", "≯ (using .hostname)", "≯ (using .host)", - "≯ (using .hostname)" + "≯ (using .hostname)", + "≠ (using .host)", + "≠ (using .hostname)", + "≠ (using .host)", + "≠ (using .hostname)", + "≮ (using .host)", + "≮ (using .hostname)", + "≮ (using .host)", + "≮ (using .hostname)", + "≯ (using .host)", + "≯ (using .hostname)", + "≯ (using .host)", + "≯ (using .hostname)", + "=­̸ (using .host)", + "=­̸ (using .hostname)", + "=­̸ (using .host)", + "=­̸ (using .hostname)", + "<­̸ (using .host)", + "<­̸ (using .hostname)", + "<­̸ (using .host)", + "<­̸ (using .hostname)", + ">­̸ (using .host)", + ">­̸ (using .hostname)", + ">­̸ (using .host)", + ">­̸ (using .hostname)" ], "url-origin.any.html": [ "Origin parsing: without base", @@ -4850,6 +4883,7 @@ "Parsing: against " ], "url-constructor.any.html?include=file": [ + "Parsing: without base", "Parsing: against ", "Parsing: without base", "Parsing: without base", @@ -4912,6 +4946,7 @@ "Parsing: against " ], "url-constructor.any.worker.html?include=file": [ + "Parsing: without base", "Parsing: against ", "Parsing: without base", "Parsing: without base", @@ -5790,7 +5825,6 @@ "Parsing origin: against ", "Parsing origin: against ", "Parsing origin: against ", - "Parsing origin: against ", "Parsing origin: against ", "Parsing origin: against ", "Parsing origin: against ", @@ -5891,7 +5925,21 @@ "Parsing origin: against ", "Parsing origin: against ", "Parsing origin: against ", - "Parsing origin: against " + "Parsing origin: against ", + "Parsing origin: against ", + "Parsing origin: against ", + "Parsing origin: against ", + "Parsing origin: against ", + "Parsing origin: against ", + "Parsing origin: against ", + "Parsing origin: against ", + "Parsing origin: against ", + "Parsing origin: against ", + "Parsing origin: against ", + "Parsing origin: against ", + "Parsing origin: against ", + "Parsing origin: against ", + "Parsing origin: against " ], "a-element.html?exclude=(file|javascript|mailto)": [ "Test that embedded 0x0A is stripped", @@ -6222,7 +6270,6 @@ "Parsing: against ", "Parsing: against ", "Parsing: against ", - "Parsing: against ", "Parsing: against ", "Parsing: against ", "Parsing: against ", @@ -6568,6 +6615,19 @@ "Parsing: against ", "Parsing: against ", "Parsing: against ", + "Parsing: against ", + "Parsing: against ", + "Parsing: against ", + "Parsing: against ", + "Parsing: against ", + "Parsing: against ", + "Parsing: against ", + "Parsing: against ", + "Parsing: against ", + "Parsing: against ", + "Parsing: against ", + "Parsing: against ", + "Parsing: against ", "Parsing: against ", "Parsing: against ", "Parsing: against ", @@ -6575,7 +6635,8 @@ "Parsing: against ", "Parsing: against ", "Parsing: against ", - "Parsing: against " + "Parsing: against ", + "Parsing: against " ], "a-element.html?include=file": [ "Test that embedded 0x0A is stripped", @@ -6603,6 +6664,11 @@ "Parsing: against ", "Parsing: against ", "Parsing: against ", + "Parsing: against ", + "Parsing: against ", + "Parsing: against ", + "Parsing: against ", + "Parsing: against ", "Parsing: against ", "Parsing: against ", "Parsing: against ", @@ -10323,9 +10389,9 @@ "import() should not drain the microtask queue if it fails during specifier resolution", "import() should not drain the microtask queue when loading an already loaded module" ], - "css-import-in-worker.any.worker.html": false, - "with-import-assertions.any.html": false, - "with-import-assertions.any.worker.html": false + "css-import-in-worker.any.worker.html": true, + "with-import-assertions.any.html": true, + "with-import-assertions.any.worker.html": true } }, "import-meta": { diff --git a/tests/wpt/suite b/tests/wpt/suite index a7b5eac8f2..e78446e34a 160000 --- a/tests/wpt/suite +++ b/tests/wpt/suite @@ -1 +1 @@ -Subproject commit a7b5eac8f2cfac28bb12beeea15a9e2b126a568e +Subproject commit e78446e34a1921371658a5df08c71d83f50a2a2f diff --git a/tools/lint.js b/tools/lint.js index 6784ec6300..4bffead0cc 100755 --- a/tools/lint.js +++ b/tools/lint.js @@ -202,7 +202,7 @@ async function ensureNoNewITests() { "compile_tests.rs": 0, "coverage_tests.rs": 0, "doc_tests.rs": 15, - "eval_tests.rs": 9, + "eval_tests.rs": 0, "flags_tests.rs": 0, "fmt_tests.rs": 17, "info_tests.rs": 18, @@ -221,7 +221,7 @@ async function ensureNoNewITests() { "pm_tests.rs": 0, "publish_tests.rs": 0, "repl_tests.rs": 0, - "run_tests.rs": 351, + "run_tests.rs": 349, "shared_library_tests.rs": 0, "task_tests.rs": 30, "test_tests.rs": 75,