diff --git a/Cargo.lock b/Cargo.lock index 1809c4f968..085687b779 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -231,7 +231,7 @@ dependencies = [ "nom 7.1.3", "num-traits", "rusticata-macros", - "thiserror", + "thiserror 1.0.64", "time", ] @@ -1292,7 +1292,7 @@ dependencies = [ "test_server", "text-size", "text_lines", - "thiserror", + "thiserror 1.0.64", "tokio", "tokio-util", "tracing", @@ -1321,13 +1321,14 @@ dependencies = [ [[package]] name = "deno_ast" -version = "0.43.3" +version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d00b724e06d2081a141ec1155756a0b465d413d8e2a7515221f61d482eb2ee" +checksum = "eebc7aaabfdb3ddcad32aee1b62d250149dc8b35dfbdccbb125df2bdc62da952" dependencies = [ "base64 0.21.7", + "deno_error", "deno_media_type", - "deno_terminal 0.1.1", + "deno_terminal 0.2.0", "dprint-swc-ext", "once_cell", "percent-encoding", @@ -1358,7 +1359,7 @@ dependencies = [ "swc_visit", "swc_visit_macros", "text_lines", - "thiserror", + "thiserror 2.0.3", "unicode-width", "url", ] @@ -1378,7 +1379,7 @@ version = "0.174.0" dependencies = [ "async-trait", "deno_core", - "thiserror", + "thiserror 1.0.64", "tokio", "uuid", ] @@ -1392,15 +1393,15 @@ dependencies = [ "rusqlite", "serde", "sha2", - "thiserror", + "thiserror 1.0.64", "tokio", ] [[package]] name = "deno_cache_dir" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c1f52170cd7715f8006da54cde1444863a0d6fbd9c11d037a737db2dec8e22" +checksum = "cca43605c8cbce6c6787e0daf227864487c07c2b31d438c0bf43d1b38da94b7f" dependencies = [ "base32", "deno_media_type", @@ -1412,7 +1413,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "thiserror", + "thiserror 1.0.64", "url", ] @@ -1424,13 +1425,13 @@ dependencies = [ "deno_webgpu", "image", "serde", - "thiserror", + "thiserror 1.0.64", ] [[package]] name = "deno_config" -version = "0.39.2" -source = "git+https://github.com/denoland/deno_config.git?rev=485e7a71f1057437d2a2c4adddbfbe348a812667#485e7a71f1057437d2a2c4adddbfbe348a812667" +version = "0.39.3" +source = "git+https://github.com/denoland/deno_config.git?branch=compiler-options-from-workspace-member#81d8e844624a8f6b3961213d1480dcc923d08b11" dependencies = [ "anyhow", "deno_package_json", @@ -1446,7 +1447,7 @@ dependencies = [ "phf", "serde", "serde_json", - "thiserror", + "thiserror 1.0.64", "url", ] @@ -1507,7 +1508,7 @@ dependencies = [ "chrono", "deno_core", "saffron", - "thiserror", + "thiserror 1.0.64", "tokio", ] @@ -1542,7 +1543,7 @@ dependencies = [ "sha2", "signature", "spki", - "thiserror", + "thiserror 1.0.64", "tokio", "uuid", "x25519-dalek", @@ -1550,9 +1551,9 @@ dependencies = [ [[package]] name = "deno_doc" -version = "0.161.1" +version = "0.161.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d994915f85e873865fc341e592080a487b0a987d06177016b2d93fd62162f8" +checksum = "3af787319136f3e7f73ef551c618aeec70794522e36cd75ae35132a3bad983ef" dependencies = [ "anyhow", "cfg-if", @@ -1577,6 +1578,29 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "deno_error" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "199c66ffd17ee1a948904d33f3d3f364573951c1f9fb3f859bfe7770bf33862a" +dependencies = [ + "deno_error_macro", + "libc", + "serde", + "serde_json", +] + +[[package]] +name = "deno_error_macro" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cd99df6ae75443907e1f959fc42ec6dcea67a7bd083e76cf23a117102c9a2ce" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "deno_fetch" version = "0.204.0" @@ -1601,7 +1625,7 @@ dependencies = [ "rustls-webpki", "serde", "serde_json", - "thiserror", + "thiserror 1.0.64", "tokio", "tokio-rustls", "tokio-socks", @@ -1626,7 +1650,7 @@ dependencies = [ "serde", "serde-value", "serde_json", - "thiserror", + "thiserror 1.0.64", "tokio", "winapi", ] @@ -1649,16 +1673,16 @@ dependencies = [ "rand", "rayon", "serde", - "thiserror", + "thiserror 1.0.64", "winapi", "windows-sys 0.52.0", ] [[package]] name = "deno_graph" -version = "0.86.2" +version = "0.86.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c3f4be49dad28e794ff4eeb2daaf7956c97f8557097ef6f9c3ff1292e0a5c28" +checksum = "fc78ed0b4bbcb4197300f0d6e7d1edc2d2c5019cdb9dedba7ff229158441885b" dependencies = [ "anyhow", "async-trait", @@ -1678,7 +1702,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "thiserror", + "thiserror 2.0.3", "twox-hash", "url", "wasm_dep_analyzer", @@ -1718,7 +1742,7 @@ dependencies = [ "scopeguard", "serde", "smallvec", - "thiserror", + "thiserror 1.0.64", "tokio", "tokio-util", ] @@ -1772,15 +1796,15 @@ dependencies = [ "rand", "rusqlite", "serde", - "thiserror", + "thiserror 1.0.64", "url", ] [[package]] name = "deno_lint" -version = "0.68.0" +version = "0.68.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb994e6d1b18223df0a756c7948143b35682941d615edffef60d5b38822f38ac" +checksum = "ce2a040657166e39c7d59ad34230f0cc829f8ea8b7b2377038cc012ec1a1ef16" dependencies = [ "anyhow", "deno_ast", @@ -1796,14 +1820,14 @@ dependencies = [ [[package]] name = "deno_lockfile" -version = "0.23.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579117d5815aa9bae0212637d6f4d5f45f9649bb2c8988dca434077545535039" +checksum = "559c19feb00af0c34f0bd4a20e56e12463fafd5c5069d6005f3ce33008027eea" dependencies = [ "deno_semver", "serde", "serde_json", - "thiserror", + "thiserror 2.0.3", ] [[package]] @@ -1828,7 +1852,7 @@ dependencies = [ "libuv-sys-lite", "log", "napi_sym", - "thiserror", + "thiserror 1.0.64", "windows-sys 0.52.0", ] @@ -1858,7 +1882,7 @@ dependencies = [ "rustls-tokio-stream", "serde", "socket2", - "thiserror", + "thiserror 1.0.64", "tokio", ] @@ -1942,7 +1966,7 @@ dependencies = [ "sm3", "spki", "stable_deref_trait", - "thiserror", + "thiserror 1.0.64", "tokio", "tokio-eld", "url", @@ -1956,9 +1980,9 @@ dependencies = [ [[package]] name = "deno_npm" -version = "0.25.4" +version = "0.25.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b4dc4a9f1cff63d5638e7d93042f24f46300d1cc77b86f3caaa699a7ddccf7" +checksum = "89ded7af9db5d9f2986a739d1b5fbe1c57f498e4f996ae4114728e7c6dad213f" dependencies = [ "anyhow", "async-trait", @@ -1969,7 +1993,7 @@ dependencies = [ "monch", "serde", "serde_json", - "thiserror", + "thiserror 2.0.3", "url", ] @@ -1986,20 +2010,22 @@ dependencies = [ "strum", "strum_macros", "syn 2.0.87", - "thiserror", + "thiserror 1.0.64", ] [[package]] name = "deno_package_json" -version = "0.1.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cbc4c4d3eb0960b58e8f43f9fc2d3f620fcac9a03cd85203e08db5b04e83c1f" +checksum = "80b0a3d81c592624a1ae15332a04b4dc2b7c163ef1dfc7c60171f736d1babdf5" dependencies = [ + "deno_error", + "deno_path_util", "deno_semver", "indexmap 2.3.0", "serde", "serde_json", - "thiserror", + "thiserror 2.0.3", "url", ] @@ -2010,7 +2036,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff25f6e08e7a0214bbacdd6f7195c7f1ebcd850c87a624e4ff06326b68b42d99" dependencies = [ "percent-encoding", - "thiserror", + "thiserror 1.0.64", "url", ] @@ -2027,7 +2053,7 @@ dependencies = [ "once_cell", "percent-encoding", "serde", - "thiserror", + "thiserror 1.0.64", "which 4.4.2", "winapi", ] @@ -2047,7 +2073,7 @@ dependencies = [ "deno_semver", "node_resolver", "test_server", - "thiserror", + "thiserror 1.0.64", "url", ] @@ -2110,7 +2136,7 @@ dependencies = [ "signal-hook-registry", "tempfile", "test_server", - "thiserror", + "thiserror 1.0.64", "tokio", "tokio-metrics", "twox-hash", @@ -2122,32 +2148,33 @@ dependencies = [ [[package]] name = "deno_semver" -version = "0.5.16" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c957c6a57c38b7dde2315df0da0ec228911e56a74f185b108a488d0401841a67" +checksum = "4756be7351289726087408984db18b9eb5e0186907673f39f858d119d0162071" dependencies = [ + "deno_error", "monch", "once_cell", "serde", - "thiserror", + "thiserror 2.0.3", "url", ] [[package]] name = "deno_task_shell" -version = "0.18.1" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f444918f7102c1a5a143e9d57809e499fb4d365070519bf2e8bdb16d586af2a" +checksum = "01e09966ce29f8d26b652a43355397e1df43b85759e7824196bf0ceaeaa9a2f4" dependencies = [ "anyhow", "futures", "glob", "monch", + "nix", "os_pipe", "path-dedot", - "thiserror", + "thiserror 1.0.64", "tokio", - "tokio-util", ] [[package]] @@ -2202,7 +2229,7 @@ dependencies = [ "rustls-tokio-stream", "rustls-webpki", "serde", - "thiserror", + "thiserror 1.0.64", "tokio", "webpki-roots", ] @@ -2248,7 +2275,7 @@ dependencies = [ "deno_console", "deno_core", "deno_webidl", - "thiserror", + "thiserror 1.0.64", "urlpattern", ] @@ -2269,7 +2296,7 @@ dependencies = [ "flate2", "futures", "serde", - "thiserror", + "thiserror 1.0.64", "tokio", "uuid", ] @@ -2281,7 +2308,7 @@ dependencies = [ "deno_core", "raw-window-handle", "serde", - "thiserror", + "thiserror 1.0.64", "tokio", "wgpu-core", "wgpu-types", @@ -2313,7 +2340,7 @@ dependencies = [ "once_cell", "rustls-tokio-stream", "serde", - "thiserror", + "thiserror 1.0.64", "tokio", ] @@ -2324,7 +2351,7 @@ dependencies = [ "deno_core", "deno_web", "rusqlite", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -2396,7 +2423,7 @@ dependencies = [ "rand", "rusqlite", "serde_json", - "thiserror", + "thiserror 1.0.64", "tokio", "tokio-stream", "uuid", @@ -2689,9 +2716,9 @@ dependencies = [ [[package]] name = "dprint-plugin-typescript" -version = "0.93.2" +version = "0.93.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff29fd136541e59d51946f0d2d353fefc886776f61a799ebfb5838b06cef13b" +checksum = "5804d1809f6191a9261f423c41cd51a50e49567d61caa5a8f6224eea94ae0d12" dependencies = [ "anyhow", "deno_ast", @@ -2837,7 +2864,7 @@ dependencies = [ "debug-ignore", "indexmap 2.3.0", "log", - "thiserror", + "thiserror 1.0.64", "zerocopy", ] @@ -2997,7 +3024,7 @@ dependencies = [ "anyhow", "async-trait", "log", - "thiserror", + "thiserror 1.0.64", "tokio", "tokio-stream", ] @@ -3032,7 +3059,7 @@ dependencies = [ "rand", "sha1", "simdutf8", - "thiserror", + "thiserror 1.0.64", "tokio", "utf-8", ] @@ -3090,7 +3117,7 @@ dependencies = [ "deno_terminal 0.1.1", "parking_lot", "regex", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -3564,7 +3591,7 @@ dependencies = [ "pest_derive", "serde", "serde_json", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -3650,7 +3677,7 @@ dependencies = [ "once_cell", "radix_trie", "rand", - "thiserror", + "thiserror 1.0.64", "tokio", "tracing", ] @@ -3673,7 +3700,7 @@ dependencies = [ "once_cell", "rand", "serde", - "thiserror", + "thiserror 1.0.64", "tinyvec", "tokio", "tracing", @@ -3697,7 +3724,7 @@ dependencies = [ "resolv-conf", "serde", "smallvec", - "thiserror", + "thiserror 1.0.64", "tokio", "tracing", ] @@ -3715,7 +3742,7 @@ dependencies = [ "futures-util", "hickory-proto", "serde", - "thiserror", + "thiserror 1.0.64", "time", "tokio", "tokio-util", @@ -4155,7 +4182,7 @@ dependencies = [ "percent-encoding", "serde", "serde_json", - "thiserror", + "thiserror 1.0.64", "url", ] @@ -4361,7 +4388,7 @@ dependencies = [ "anyhow", "serde", "serde_json", - "thiserror", + "thiserror 1.0.64", "uuid", ] @@ -4811,7 +4838,7 @@ dependencies = [ "serde", "spirv", "termcolor", - "thiserror", + "thiserror 1.0.64", "unicode-xid", ] @@ -4901,7 +4928,7 @@ dependencies = [ "path-clean", "regex", "serde_json", - "thiserror", + "thiserror 1.0.64", "tokio", "url", ] @@ -5098,7 +5125,7 @@ dependencies = [ "js-sys", "once_cell", "pin-project-lite", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -5128,7 +5155,7 @@ dependencies = [ "opentelemetry_sdk", "prost", "serde_json", - "thiserror", + "thiserror 1.0.64", "tokio", "tonic", "tracing", @@ -5170,7 +5197,7 @@ dependencies = [ "percent-encoding", "rand", "serde_json", - "thiserror", + "thiserror 1.0.64", "tracing", ] @@ -5354,7 +5381,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "311fb059dee1a7b802f036316d790138c613a4e8b180c822e3925a662e9f0c95" dependencies = [ "memchr", - "thiserror", + "thiserror 1.0.64", "ucd-trie", ] @@ -5768,7 +5795,7 @@ dependencies = [ "indexmap 2.3.0", "quick-xml", "strip-ansi-escapes", - "thiserror", + "thiserror 1.0.64", "uuid", ] @@ -5793,7 +5820,7 @@ dependencies = [ "quinn-udp", "rustc-hash 1.1.0", "rustls", - "thiserror", + "thiserror 1.0.64", "tokio", "tracing", ] @@ -5810,7 +5837,7 @@ dependencies = [ "rustc-hash 2.0.0", "rustls", "slab", - "thiserror", + "thiserror 1.0.64", "tinyvec", "tracing", ] @@ -5959,7 +5986,7 @@ checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ "getrandom", "libredox", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -6583,7 +6610,7 @@ dependencies = [ "num-bigint", "serde", "smallvec", - "thiserror", + "thiserror 1.0.64", "v8", ] @@ -7586,7 +7613,16 @@ version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.64", +] + +[[package]] +name = "thiserror" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" +dependencies = [ + "thiserror-impl 2.0.3", ] [[package]] @@ -7600,6 +7636,17 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "thiserror-impl" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "thousands" version = "0.2.0" @@ -7752,7 +7799,7 @@ checksum = "51165dfa029d2a65969413a6cc96f354b86b464498702f174a4efa13608fd8c0" dependencies = [ "either", "futures-util", - "thiserror", + "thiserror 1.0.64", "tokio", ] @@ -8169,7 +8216,7 @@ dependencies = [ "indexmap 2.3.0", "num-bigint", "serde", - "thiserror", + "thiserror 1.0.64", "wtf8", ] @@ -8341,7 +8388,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f270206a91783fd90625c8bb0d8fbd459d0b1d1bf209b656f713f01ae7c04b8" dependencies = [ - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -8395,7 +8442,7 @@ dependencies = [ "rustc-hash 1.1.0", "serde", "smallvec", - "thiserror", + "thiserror 1.0.64", "web-sys", "wgpu-hal", "wgpu-types", @@ -8436,7 +8483,7 @@ dependencies = [ "raw-window-handle", "rustc-hash 1.1.0", "smallvec", - "thiserror", + "thiserror 1.0.64", "wasm-bindgen", "web-sys", "wgpu-types", @@ -8502,7 +8549,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b2b1bf557d947847a30eb73f79aa6cdb3eaf3ce02f5e9599438f77896a62b3c" dependencies = [ - "thiserror", + "thiserror 1.0.64", "windows", ] @@ -8784,7 +8831,7 @@ dependencies = [ "nom 7.1.3", "oid-registry", "rusticata-macros", - "thiserror", + "thiserror 1.0.64", "time", ] @@ -8928,7 +8975,7 @@ dependencies = [ "parking_lot", "rand", "regex", - "thiserror", + "thiserror 1.0.64", "tokio", "tokio-util", "uuid", @@ -8969,7 +9016,7 @@ dependencies = [ "flate2", "indexmap 2.3.0", "memchr", - "thiserror", + "thiserror 1.0.64", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 4420a6928f..68979c8fe0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,19 +46,19 @@ license = "MIT" repository = "https://github.com/denoland/deno" [workspace.dependencies] -deno_ast = { version = "=0.43.3", features = ["transpiling"] } +deno_ast = { version = "=0.44.0", features = ["transpiling"] } deno_core = { version = "0.323.0" } deno_bench_util = { version = "0.174.0", path = "./bench_util" } # TODO(nayeemrmn): Use proper version when https://github.com/denoland/deno_config/pull/143 lands! -deno_config = { git = "https://github.com/denoland/deno_config.git", rev = "485e7a71f1057437d2a2c4adddbfbe348a812667", features = ["workspace", "sync"] } -deno_lockfile = "=0.23.1" +deno_config = { git = "https://github.com/denoland/deno_config.git", branch = "compiler-options-from-workspace-member", features = ["workspace", "sync"] } +deno_lockfile = "=0.23.2" deno_media_type = { version = "0.2.0", features = ["module_specifier"] } -deno_npm = "=0.25.4" +deno_npm = "=0.25.5" deno_path_util = "=0.2.1" deno_permissions = { version = "0.40.0", path = "./runtime/permissions" } deno_runtime = { version = "0.189.0", path = "./runtime" } -deno_semver = "=0.5.16" +deno_semver = "=0.6.0" deno_terminal = "0.2.0" napi_sym = { version = "0.110.0", path = "./ext/napi/sym" } test_util = { package = "test_server", path = "./tests/util/server" } @@ -116,8 +116,8 @@ console_static_text = "=0.8.1" dashmap = "5.5.3" data-encoding = "2.3.3" data-url = "=0.3.0" -deno_cache_dir = "=0.13.2" -deno_package_json = { version = "0.1.2", default-features = false } +deno_cache_dir = "=0.14.0" +deno_package_json = { version = "0.2.1", default-features = false } dlopen2 = "0.6.1" ecb = "=0.1.2" elliptic-curve = { version = "0.13.4", features = ["alloc", "arithmetic", "ecdh", "std", "pem", "jwk"] } diff --git a/cli/Cargo.toml b/cli/Cargo.toml index dd75f903e4..ac093a7238 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -72,9 +72,9 @@ deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "proposa deno_cache_dir.workspace = true deno_config.workspace = true deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] } -deno_doc = { version = "=0.161.1", features = ["rust", "comrak"] } -deno_graph = { version = "=0.86.2" } -deno_lint = { version = "=0.68.0", features = ["docs"] } +deno_doc = { version = "=0.161.2", features = ["rust", "comrak"] } +deno_graph = { version = "=0.86.3" } +deno_lint = { version = "=0.68.1", features = ["docs"] } deno_lockfile.workspace = true deno_npm.workspace = true deno_package_json.workspace = true @@ -82,7 +82,7 @@ deno_path_util.workspace = true deno_resolver.workspace = true deno_runtime = { workspace = true, features = ["include_js_files_for_snapshotting"] } deno_semver.workspace = true -deno_task_shell = "=0.18.1" +deno_task_shell = "=0.20.1" deno_telemetry.workspace = true deno_terminal.workspace = true libsui = "0.5.0" @@ -108,7 +108,7 @@ dotenvy = "0.15.7" dprint-plugin-json = "=0.19.4" dprint-plugin-jupyter = "=0.1.5" dprint-plugin-markdown = "=0.17.8" -dprint-plugin-typescript = "=0.93.2" +dprint-plugin-typescript = "=0.93.3" env_logger = "=0.10.0" fancy-regex = "=0.10.0" faster-hex.workspace = true diff --git a/cli/args/deno_json.rs b/cli/args/deno_json.rs index 3e6eb617a6..c2ba31fd36 100644 --- a/cli/args/deno_json.rs +++ b/cli/args/deno_json.rs @@ -18,12 +18,10 @@ impl<'a> deno_config::fs::DenoConfigFs for DenoConfigFsAdapter<'a> { fn read_to_string_lossy( &self, path: &std::path::Path, - ) -> Result { + ) -> Result, std::io::Error> { self .0 .read_text_file_lossy_sync(path, None) - // todo(https://github.com/denoland/deno_config/pull/140): avoid clone - .map(|s| s.into_owned()) .map_err(|err| err.into_io_error()) } diff --git a/cli/args/lockfile.rs b/cli/args/lockfile.rs index a9eb8a0d7c..6c1a2ca0ef 100644 --- a/cli/args/lockfile.rs +++ b/cli/args/lockfile.rs @@ -109,9 +109,12 @@ impl CliLockfile { let Some(pkg_json) = maybe_pkg_json else { return Default::default(); }; - pkg_json - .resolve_local_package_json_deps() + let deps = pkg_json.resolve_local_package_json_deps(); + + deps + .dependencies .values() + .chain(deps.dev_dependencies.values()) .filter_map(|dep| dep.as_ref().ok()) .filter_map(|dep| match dep { PackageJsonDepValue::Req(req) => { diff --git a/cli/args/package_json.rs b/cli/args/package_json.rs index 7dc75550c3..b0f0a2f9ba 100644 --- a/cli/args/package_json.rs +++ b/cli/args/package_json.rs @@ -8,8 +8,10 @@ use deno_core::serde_json; use deno_core::url::Url; use deno_package_json::PackageJsonDepValue; use deno_package_json::PackageJsonDepValueParseError; +use deno_package_json::PackageJsonDepWorkspaceReq; use deno_semver::npm::NpmPackageReqReference; use deno_semver::package::PackageReq; +use deno_semver::VersionReq; use thiserror::Error; #[derive(Debug)] @@ -95,8 +97,14 @@ impl NpmInstallDepsProvider { 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 mut pkg_pkgs = Vec::with_capacity( + deps.dependencies.len() + deps.dev_dependencies.len(), + ); + for (alias, dep) in deps + .dependencies + .into_iter() + .chain(deps.dev_dependencies.into_iter()) + { let dep = match dep { Ok(dep) => dep, Err(err) => { @@ -131,7 +139,16 @@ impl NpmInstallDepsProvider { }); } } - PackageJsonDepValue::Workspace(version_req) => { + PackageJsonDepValue::Workspace(workspace_version_req) => { + let version_req = match workspace_version_req { + PackageJsonDepWorkspaceReq::VersionReq(version_req) => { + version_req + } + PackageJsonDepWorkspaceReq::Tilde + | PackageJsonDepWorkspaceReq::Caret => { + VersionReq::parse_from_npm("*").unwrap() + } + }; if let Some(pkg) = workspace_npm_pkgs.iter().find(|pkg| { pkg.matches_name_and_version_req(&alias, &version_req) }) { diff --git a/cli/cache/mod.rs b/cli/cache/mod.rs index 73a3895a10..e3e242e975 100644 --- a/cli/cache/mod.rs +++ b/cli/cache/mod.rs @@ -23,6 +23,7 @@ use deno_graph::source::Loader; use deno_runtime::deno_fs; use deno_runtime::deno_permissions::PermissionsContainer; use node_resolver::InNpmPackageChecker; +use std::borrow::Cow; use std::collections::HashMap; use std::path::Path; use std::path::PathBuf; @@ -67,8 +68,11 @@ pub const CACHE_PERM: u32 = 0o644; pub struct RealDenoCacheEnv; impl deno_cache_dir::DenoCacheEnv for RealDenoCacheEnv { - fn read_file_bytes(&self, path: &Path) -> std::io::Result> { - std::fs::read(path) + fn read_file_bytes( + &self, + path: &Path, + ) -> std::io::Result> { + std::fs::read(path).map(Cow::Owned) } fn atomic_write_file( @@ -112,12 +116,13 @@ pub struct DenoCacheEnvFsAdapter<'a>( ); impl<'a> deno_cache_dir::DenoCacheEnv for DenoCacheEnvFsAdapter<'a> { - fn read_file_bytes(&self, path: &Path) -> std::io::Result> { + fn read_file_bytes( + &self, + path: &Path, + ) -> std::io::Result> { self .0 .read_file_sync(path, None) - // todo(https://github.com/denoland/deno_cache_dir/pull/66): avoid clone - .map(|bytes| bytes.into_owned()) .map_err(|err| err.into_io_error()) } diff --git a/cli/factory.rs b/cli/factory.rs index 5d9a2c0824..6937b750f9 100644 --- a/cli/factory.rs +++ b/cli/factory.rs @@ -504,7 +504,12 @@ impl CliFactory { let resolver = cli_options .create_workspace_resolver( self.file_fetcher()?, - if cli_options.use_byonm() { + if cli_options.use_byonm() + && !matches!( + cli_options.sub_command(), + DenoSubcommand::Publish(_) + ) + { PackageJsonDepResolution::Disabled } else { // todo(dsherret): this should be false for nodeModulesDir: true diff --git a/cli/file_fetcher.rs b/cli/file_fetcher.rs index 640f83c35c..f0adc60e3b 100644 --- a/cli/file_fetcher.rs +++ b/cli/file_fetcher.rs @@ -1540,7 +1540,7 @@ mod tests { .unwrap() .unwrap() .content; - String::from_utf8(bytes).unwrap() + String::from_utf8(bytes.into_owned()).unwrap() } #[track_caller] diff --git a/cli/lsp/config.rs b/cli/lsp/config.rs index 0bda1f80ae..ef28f00886 100644 --- a/cli/lsp/config.rs +++ b/cli/lsp/config.rs @@ -41,6 +41,7 @@ use deno_path_util::url_to_file_path; use deno_runtime::deno_node::PackageJson; use indexmap::IndexSet; use lsp_types::ClientCapabilities; +use std::borrow::Cow; use std::collections::BTreeMap; use std::collections::BTreeSet; use std::collections::HashMap; @@ -2093,7 +2094,7 @@ impl CachedFsItems { #[derive(Default)] struct InnerData { stat_calls: CachedFsItems, - read_to_string_calls: CachedFsItems, + read_to_string_calls: CachedFsItems>, } #[derive(Default)] @@ -2114,7 +2115,7 @@ impl DenoConfigFs for CachedDenoConfigFs { fn read_to_string_lossy( &self, path: &Path, - ) -> Result { + ) -> Result, std::io::Error> { self .0 .lock() diff --git a/cli/lsp/documents.rs b/cli/lsp/documents.rs index df51c07a39..b9ec8ffc46 100644 --- a/cli/lsp/documents.rs +++ b/cli/lsp/documents.rs @@ -925,7 +925,7 @@ impl FileSystemDocuments { let content = bytes_to_content( specifier, media_type, - cached_file.content, + cached_file.content.into_owned(), maybe_charset, ) .ok()?; diff --git a/cli/lsp/jsr.rs b/cli/lsp/jsr.rs index 9a738ec287..ab570f6348 100644 --- a/cli/lsp/jsr.rs +++ b/cli/lsp/jsr.rs @@ -262,7 +262,7 @@ fn read_cached_url( cache .get(&cache.cache_item_key(url).ok()?, None) .ok()? - .map(|f| f.content) + .map(|f| f.content.into_owned()) } #[derive(Debug)] diff --git a/cli/lsp/tsc.rs b/cli/lsp/tsc.rs index a8e2b91e77..d3d821ebb3 100644 --- a/cli/lsp/tsc.rs +++ b/cli/lsp/tsc.rs @@ -1297,16 +1297,10 @@ impl TsServer { { // When an LSP request is cancelled by the client, the future this is being // executed under and any local variables here will be dropped at the next - // await point. To pass on that cancellation to the TS thread, we make this - // wrapper which cancels the request's token on drop. - struct DroppableToken(CancellationToken); - impl Drop for DroppableToken { - fn drop(&mut self) { - self.0.cancel(); - } - } + // await point. To pass on that cancellation to the TS thread, we use drop_guard + // which cancels the request's token on drop. let token = token.child_token(); - let droppable_token = DroppableToken(token.clone()); + let droppable_token = token.clone().drop_guard(); let (tx, mut rx) = oneshot::channel::>(); let change = self.pending_change.lock().take(); @@ -1320,7 +1314,7 @@ impl TsServer { tokio::select! { value = &mut rx => { let value = value??; - drop(droppable_token); + droppable_token.disarm(); Ok(serde_json::from_str(&value)?) } _ = token.cancelled() => { diff --git a/cli/npm/managed/resolvers/common/lifecycle_scripts.rs b/cli/npm/managed/resolvers/common/lifecycle_scripts.rs index f8b9e8a7e8..958c4bcd19 100644 --- a/cli/npm/managed/resolvers/common/lifecycle_scripts.rs +++ b/cli/npm/managed/resolvers/common/lifecycle_scripts.rs @@ -9,6 +9,7 @@ use deno_npm::resolution::NpmResolutionSnapshot; use deno_runtime::deno_io::FromRawIoHandle; use deno_semver::package::PackageNv; use deno_semver::Version; +use deno_task_shell::KillSignal; use std::borrow::Cow; use std::collections::HashSet; use std::rc::Rc; @@ -155,6 +156,29 @@ impl<'a> LifecycleScripts<'a> { packages: &[NpmResolutionPackage], root_node_modules_dir_path: &Path, progress_bar: &ProgressBar, + ) -> Result<(), AnyError> { + let kill_signal = KillSignal::default(); + let _drop_signal = kill_signal.clone().drop_guard(); + // we don't run with signals forwarded because once signals + // are setup then they're process wide. + self + .finish_with_cancellation( + snapshot, + packages, + root_node_modules_dir_path, + progress_bar, + kill_signal, + ) + .await + } + + async fn finish_with_cancellation( + self, + snapshot: &NpmResolutionSnapshot, + packages: &[NpmResolutionPackage], + root_node_modules_dir_path: &Path, + progress_bar: &ProgressBar, + kill_signal: KillSignal, ) -> Result<(), AnyError> { self.warn_not_run_scripts()?; let get_package_path = @@ -246,6 +270,7 @@ impl<'a> LifecycleScripts<'a> { stderr: TaskStdio::piped(), stdout: TaskStdio::piped(), }), + kill_signal: kill_signal.clone(), }, ) .await?; diff --git a/cli/task_runner.rs b/cli/task_runner.rs index ec043f280e..aabdaf5777 100644 --- a/cli/task_runner.rs +++ b/cli/task_runner.rs @@ -14,6 +14,7 @@ use deno_runtime::deno_node::NodeResolver; use deno_semver::package::PackageNv; use deno_task_shell::ExecutableCommand; use deno_task_shell::ExecuteResult; +use deno_task_shell::KillSignal; use deno_task_shell::ShellCommand; use deno_task_shell::ShellCommandContext; use deno_task_shell::ShellPipeReader; @@ -22,6 +23,7 @@ use lazy_regex::Lazy; use regex::Regex; use tokio::task::JoinHandle; use tokio::task::LocalSet; +use tokio_util::sync::CancellationToken; use crate::npm::CliNpmResolver; use crate::npm::InnerCliNpmResolverRef; @@ -45,9 +47,11 @@ impl TaskStdio { pub fn stdout() -> Self { Self(None, ShellPipeWriter::stdout()) } + pub fn stderr() -> Self { Self(None, ShellPipeWriter::stderr()) } + pub fn piped() -> Self { let (r, w) = deno_task_shell::pipe(); Self(Some(r), w) @@ -62,8 +66,8 @@ pub struct TaskIo { impl Default for TaskIo { fn default() -> Self { Self { - stderr: TaskStdio::stderr(), stdout: TaskStdio::stdout(), + stderr: TaskStdio::stderr(), } } } @@ -78,6 +82,7 @@ pub struct RunTaskOptions<'a> { pub custom_commands: HashMap>, pub root_node_modules_dir: Option<&'a Path>, pub stdio: Option, + pub kill_signal: KillSignal, } pub type TaskCustomCommands = HashMap>; @@ -96,8 +101,12 @@ pub async fn run_task( .with_context(|| format!("Error parsing script '{}'.", opts.task_name))?; let env_vars = prepare_env_vars(opts.env_vars, opts.init_cwd, opts.root_node_modules_dir); - let state = - deno_task_shell::ShellState::new(env_vars, opts.cwd, opts.custom_commands); + let state = deno_task_shell::ShellState::new( + env_vars, + opts.cwd, + opts.custom_commands, + opts.kill_signal, + ); let stdio = opts.stdio.unwrap_or_default(); let ( TaskStdio(stdout_read, stdout_write), @@ -537,6 +546,80 @@ fn resolve_managed_npm_commands( Ok(result) } +/// Runs a deno task future forwarding any signals received +/// to the process. +/// +/// Signal listeners and ctrl+c listening will be setup. +pub async fn run_future_forwarding_signals( + kill_signal: KillSignal, + future: impl std::future::Future, +) -> TOutput { + fn spawn_future_with_cancellation( + future: impl std::future::Future + 'static, + token: CancellationToken, + ) { + deno_core::unsync::spawn(async move { + tokio::select! { + _ = future => {} + _ = token.cancelled() => {} + } + }); + } + + let token = CancellationToken::new(); + let _token_drop_guard = token.clone().drop_guard(); + let _drop_guard = kill_signal.clone().drop_guard(); + + spawn_future_with_cancellation( + listen_ctrl_c(kill_signal.clone()), + token.clone(), + ); + #[cfg(unix)] + spawn_future_with_cancellation( + listen_and_forward_all_signals(kill_signal), + token, + ); + + future.await +} + +async fn listen_ctrl_c(kill_signal: KillSignal) { + while let Ok(()) = tokio::signal::ctrl_c().await { + kill_signal.send(deno_task_shell::SignalKind::SIGINT) + } +} + +#[cfg(unix)] +async fn listen_and_forward_all_signals(kill_signal: KillSignal) { + use deno_core::futures::FutureExt; + use deno_runtime::signal::SIGNAL_NUMS; + + // listen and forward every signal we support + let mut futures = Vec::with_capacity(SIGNAL_NUMS.len()); + for signo in SIGNAL_NUMS.iter().copied() { + if signo == libc::SIGKILL || signo == libc::SIGSTOP { + continue; // skip, can't listen to these + } + + let kill_signal = kill_signal.clone(); + futures.push( + async move { + let Ok(mut stream) = tokio::signal::unix::signal( + tokio::signal::unix::SignalKind::from_raw(signo), + ) else { + return; + }; + let signal_kind: deno_task_shell::SignalKind = signo.into(); + while let Some(()) = stream.recv().await { + kill_signal.send(signal_kind); + } + } + .boxed_local(), + ) + } + futures::future::join_all(futures).await; +} + #[cfg(test)] mod test { diff --git a/cli/tools/registry/diagnostics.rs b/cli/tools/registry/diagnostics.rs index ef38affc30..9c32b8e36d 100644 --- a/cli/tools/registry/diagnostics.rs +++ b/cli/tools/registry/diagnostics.rs @@ -169,7 +169,7 @@ impl Diagnostic for PublishDiagnostic { .. }) => DiagnosticLevel::Warning, FastCheck(_) => DiagnosticLevel::Error, - SpecifierUnfurl(_) => DiagnosticLevel::Warning, + SpecifierUnfurl(d) => d.level(), InvalidPath { .. } => DiagnosticLevel::Error, DuplicatePath { .. } => DiagnosticLevel::Error, UnsupportedFileType { .. } => DiagnosticLevel::Warning, @@ -187,7 +187,7 @@ impl Diagnostic for PublishDiagnostic { use PublishDiagnostic::*; match &self { FastCheck(diagnostic) => diagnostic.code(), - SpecifierUnfurl(diagnostic) => Cow::Borrowed(diagnostic.code()), + SpecifierUnfurl(diagnostic) => diagnostic.code(), InvalidPath { .. } => Cow::Borrowed("invalid-path"), DuplicatePath { .. } => Cow::Borrowed("case-insensitive-duplicate-path"), UnsupportedFileType { .. } => Cow::Borrowed("unsupported-file-type"), @@ -207,7 +207,7 @@ impl Diagnostic for PublishDiagnostic { use PublishDiagnostic::*; match &self { FastCheck(diagnostic) => diagnostic.message(), - SpecifierUnfurl(diagnostic) => Cow::Borrowed(diagnostic.message()), + SpecifierUnfurl(diagnostic) => diagnostic.message(), InvalidPath { message, .. } => Cow::Borrowed(message.as_str()), DuplicatePath { .. } => { Cow::Borrowed("package path is a case insensitive duplicate of another path in the package") @@ -243,17 +243,7 @@ impl Diagnostic for PublishDiagnostic { use PublishDiagnostic::*; match &self { FastCheck(diagnostic) => diagnostic.location(), - SpecifierUnfurl(diagnostic) => match diagnostic { - SpecifierUnfurlerDiagnostic::UnanalyzableDynamicImport { - specifier, - text_info, - range, - } => DiagnosticLocation::ModulePosition { - specifier: Cow::Borrowed(specifier), - text_info: Cow::Borrowed(text_info), - source_pos: DiagnosticSourcePos::SourcePos(range.start), - }, - }, + SpecifierUnfurl(diagnostic) => diagnostic.location(), InvalidPath { path, .. } => { DiagnosticLocation::Path { path: path.clone() } } @@ -325,24 +315,8 @@ impl Diagnostic for PublishDiagnostic { use PublishDiagnostic::*; match &self { - FastCheck(diagnostic) => diagnostic.snippet(), - SpecifierUnfurl(diagnostic) => match diagnostic { - SpecifierUnfurlerDiagnostic::UnanalyzableDynamicImport { - text_info, - range, - .. - } => Some(DiagnosticSnippet { - source: Cow::Borrowed(text_info), - highlights: vec![DiagnosticSnippetHighlight { - style: DiagnosticSnippetHighlightStyle::Warning, - range: DiagnosticSourceRange { - start: DiagnosticSourcePos::SourcePos(range.start), - end: DiagnosticSourcePos::SourcePos(range.end), - }, - description: Some("the unanalyzable dynamic import".into()), - }], - }), - }, + FastCheck(d) => d.snippet(), + SpecifierUnfurl(d) => d.snippet(), InvalidPath { .. } => None, DuplicatePath { .. } => None, UnsupportedFileType { .. } => None, @@ -380,7 +354,7 @@ impl Diagnostic for PublishDiagnostic { use PublishDiagnostic::*; match &self { FastCheck(diagnostic) => diagnostic.hint(), - SpecifierUnfurl(_) => None, + SpecifierUnfurl(d) => d.hint(), InvalidPath { .. } => Some( Cow::Borrowed("rename or remove the file, or add it to 'publish.exclude' in the config file"), ), @@ -436,9 +410,9 @@ impl Diagnostic for PublishDiagnostic { None => None, } } - SyntaxError(diagnostic) => diagnostic.snippet_fixed(), + SyntaxError(d) => d.snippet_fixed(), + SpecifierUnfurl(d) => d.snippet_fixed(), FastCheck(_) - | SpecifierUnfurl(_) | InvalidPath { .. } | DuplicatePath { .. } | UnsupportedFileType { .. } @@ -453,16 +427,8 @@ impl Diagnostic for PublishDiagnostic { fn info(&self) -> Cow<'_, [Cow<'_, str>]> { use PublishDiagnostic::*; match &self { - FastCheck(diagnostic) => { - diagnostic.info() - } - SpecifierUnfurl(diagnostic) => match diagnostic { - SpecifierUnfurlerDiagnostic::UnanalyzableDynamicImport { .. } => Cow::Borrowed(&[ - Cow::Borrowed("after publishing this package, imports from the local import map / package.json do not work"), - Cow::Borrowed("dynamic imports that can not be analyzed at publish time will not be rewritten automatically"), - Cow::Borrowed("make sure the dynamic import is resolvable at runtime without an import map / package.json") - ]), - }, + FastCheck(d) => d.info(), + SpecifierUnfurl(d) => d.info(), InvalidPath { .. } => Cow::Borrowed(&[ Cow::Borrowed("to portably support all platforms, including windows, the allowed characters in package paths are limited"), ]), @@ -503,10 +469,8 @@ impl Diagnostic for PublishDiagnostic { fn docs_url(&self) -> Option> { use PublishDiagnostic::*; match &self { - FastCheck(diagnostic) => diagnostic.docs_url(), - SpecifierUnfurl(diagnostic) => match diagnostic { - SpecifierUnfurlerDiagnostic::UnanalyzableDynamicImport { .. } => None, - }, + FastCheck(d) => d.docs_url(), + SpecifierUnfurl(d) => d.docs_url(), InvalidPath { .. } => { Some(Cow::Borrowed("https://jsr.io/go/invalid-path")) } diff --git a/cli/tools/registry/mod.rs b/cli/tools/registry/mod.rs index a866660f36..001e401459 100644 --- a/cli/tools/registry/mod.rs +++ b/cli/tools/registry/mod.rs @@ -14,7 +14,6 @@ use base64::Engine; use deno_ast::ModuleSpecifier; use deno_config::deno_json::ConfigFile; use deno_config::workspace::JsrPackageConfig; -use deno_config::workspace::PackageJsonDepResolution; use deno_config::workspace::Workspace; use deno_core::anyhow::bail; use deno_core::anyhow::Context; @@ -44,8 +43,6 @@ use crate::cache::ParsedSourceCache; use crate::factory::CliFactory; use crate::graph_util::ModuleGraphCreator; use crate::http_util::HttpClient; -use crate::resolver::CliSloppyImportsResolver; -use crate::resolver::SloppyImportsCachedFs; use crate::tools::check::CheckOptions; use crate::tools::lint::collect_no_slow_type_diagnostics; use crate::tools::registry::diagnostics::PublishDiagnostic; @@ -123,19 +120,8 @@ pub async fn publish( } let specifier_unfurler = Arc::new(SpecifierUnfurler::new( - if cli_options.unstable_sloppy_imports() { - Some(CliSloppyImportsResolver::new(SloppyImportsCachedFs::new( - cli_factory.fs().clone(), - ))) - } else { - None - }, - cli_options - .create_workspace_resolver( - cli_factory.file_fetcher()?, - PackageJsonDepResolution::Enabled, - ) - .await?, + cli_factory.sloppy_imports_resolver()?.cloned(), + cli_factory.workspace_resolver().await?.clone(), cli_options.unstable_bare_node_builtins(), )); diff --git a/cli/tools/registry/pm/deps.rs b/cli/tools/registry/pm/deps.rs index 4778d6f327..b7e1c0f0d4 100644 --- a/cli/tools/registry/pm/deps.rs +++ b/cli/tools/registry/pm/deps.rs @@ -19,8 +19,7 @@ use deno_core::futures::FutureExt; use deno_core::futures::StreamExt; use deno_core::serde_json; use deno_graph::FillFromLockfileOptions; -use deno_package_json::PackageJsonDepValue; -use deno_package_json::PackageJsonDepValueParseError; +use deno_package_json::PackageJsonDepsMap; use deno_package_json::PackageJsonRc; use deno_runtime::deno_permissions::PermissionsContainer; use deno_semver::jsr::JsrPackageReqReference; @@ -32,7 +31,6 @@ use deno_semver::VersionReq; use import_map::ImportMap; use import_map::ImportMapWithDiagnostics; use import_map::SpecifierMapEntry; -use indexmap::IndexMap; use tokio::sync::Semaphore; use crate::args::CliLockfile; @@ -269,94 +267,6 @@ enum PackageJsonDepKind { Dev, } -type PackageJsonDeps = IndexMap< - String, - Result< - (PackageJsonDepKind, PackageJsonDepValue), - PackageJsonDepValueParseError, - >, ->; - -/// Resolve the package.json's dependencies. -// TODO(nathanwhit): Remove once we update deno_package_json with dev deps split out -fn resolve_local_package_json_deps( - package_json: &PackageJsonRc, -) -> PackageJsonDeps { - /// Gets the name and raw version constraint for a registry info or - /// package.json dependency entry taking into account npm package aliases. - fn parse_dep_entry_name_and_raw_version<'a>( - key: &'a str, - value: &'a str, - ) -> (&'a str, &'a str) { - if let Some(package_and_version) = value.strip_prefix("npm:") { - if let Some((name, version)) = package_and_version.rsplit_once('@') { - // if empty, then the name was scoped and there's no version - if name.is_empty() { - (package_and_version, "*") - } else { - (name, version) - } - } else { - (package_and_version, "*") - } - } else { - (key, value) - } - } - - fn parse_entry( - key: &str, - value: &str, - ) -> Result { - if let Some(workspace_key) = value.strip_prefix("workspace:") { - let version_req = VersionReq::parse_from_npm(workspace_key)?; - return Ok(PackageJsonDepValue::Workspace(version_req)); - } - if value.starts_with("file:") - || value.starts_with("git:") - || value.starts_with("http:") - || value.starts_with("https:") - { - return Err(PackageJsonDepValueParseError::Unsupported { - scheme: value.split(':').next().unwrap().to_string(), - }); - } - let (name, version_req) = parse_dep_entry_name_and_raw_version(key, value); - let result = VersionReq::parse_from_npm(version_req); - match result { - Ok(version_req) => Ok(PackageJsonDepValue::Req(PackageReq { - name: name.to_string(), - version_req, - })), - Err(err) => Err(PackageJsonDepValueParseError::VersionReq(err)), - } - } - - fn insert_deps( - deps: Option<&IndexMap>, - result: &mut PackageJsonDeps, - kind: PackageJsonDepKind, - ) { - if let Some(deps) = deps { - for (key, value) in deps { - result.entry(key.to_string()).or_insert_with(|| { - parse_entry(key, value).map(|entry| (kind, entry)) - }); - } - } - } - - let deps = package_json.dependencies.as_ref(); - let dev_deps = package_json.dev_dependencies.as_ref(); - let mut result = IndexMap::new(); - - // favors the deps over dev_deps - insert_deps(deps, &mut result, PackageJsonDepKind::Normal); - insert_deps(dev_deps, &mut result, PackageJsonDepKind::Dev); - - result -} - fn add_deps_from_deno_json( deno_json: &Arc, mut filter: impl DepFilter, @@ -406,40 +316,64 @@ fn add_deps_from_deno_json( fn add_deps_from_package_json( package_json: &PackageJsonRc, - mut filter: impl DepFilter, + filter: impl DepFilter, deps: &mut Vec, ) { - let package_json_deps = resolve_local_package_json_deps(package_json); - for (k, v) in package_json_deps { - let (package_dep_kind, v) = match v { - Ok((k, v)) => (k, v), - Err(e) => { - log::warn!("bad package json dep value: {e}"); - continue; - } - }; - match v { - deno_package_json::PackageJsonDepValue::Req(req) => { - let alias = k.as_str(); - let alias = (alias != req.name).then(|| alias.to_string()); - if !filter.should_include(alias.as_deref(), &req, DepKind::Npm) { + let package_json_deps = package_json.resolve_local_package_json_deps(); + + fn iterate( + package_json: &PackageJsonRc, + mut filter: impl DepFilter, + package_dep_kind: PackageJsonDepKind, + package_json_deps: PackageJsonDepsMap, + deps: &mut Vec, + ) { + for (k, v) in package_json_deps { + let v = match v { + Ok(v) => v, + Err(e) => { + log::warn!("bad package json dep value: {e}"); continue; } - let id = DepId(deps.len()); - deps.push(Dep { - id, - kind: DepKind::Npm, - location: DepLocation::PackageJson( - package_json.clone(), - KeyPath::from_parts([package_dep_kind.into(), k.into()]), - ), - req, - alias, - }) + }; + match v { + deno_package_json::PackageJsonDepValue::Req(req) => { + let alias = k.as_str(); + let alias = (alias != req.name).then(|| alias.to_string()); + if !filter.should_include(alias.as_deref(), &req, DepKind::Npm) { + continue; + } + let id = DepId(deps.len()); + deps.push(Dep { + id, + kind: DepKind::Npm, + location: DepLocation::PackageJson( + package_json.clone(), + KeyPath::from_parts([package_dep_kind.into(), k.into()]), + ), + req, + alias, + }) + } + deno_package_json::PackageJsonDepValue::Workspace(_) => continue, } - deno_package_json::PackageJsonDepValue::Workspace(_) => continue, } } + + iterate( + package_json, + filter, + PackageJsonDepKind::Normal, + package_json_deps.dependencies, + deps, + ); + iterate( + package_json, + filter, + PackageJsonDepKind::Dev, + package_json_deps.dev_dependencies, + deps, + ); } fn deps_from_workspace( diff --git a/cli/tools/registry/unfurl.rs b/cli/tools/registry/unfurl.rs index 90343ac656..bf6aaaf50d 100644 --- a/cli/tools/registry/unfurl.rs +++ b/cli/tools/registry/unfurl.rs @@ -1,19 +1,35 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use std::borrow::Cow; +use std::sync::Arc; + +use deno_ast::diagnostics::Diagnostic; +use deno_ast::diagnostics::DiagnosticLevel; +use deno_ast::diagnostics::DiagnosticLocation; +use deno_ast::diagnostics::DiagnosticSnippet; +use deno_ast::diagnostics::DiagnosticSnippetHighlight; +use deno_ast::diagnostics::DiagnosticSnippetHighlightStyle; +use deno_ast::diagnostics::DiagnosticSourcePos; +use deno_ast::diagnostics::DiagnosticSourceRange; use deno_ast::ParsedSource; use deno_ast::SourceRange; use deno_ast::SourceTextInfo; +use deno_ast::SourceTextProvider; use deno_config::workspace::MappedResolution; use deno_config::workspace::PackageJsonDepResolution; use deno_config::workspace::WorkspaceResolver; +use deno_core::anyhow; use deno_core::ModuleSpecifier; use deno_graph::DependencyDescriptor; use deno_graph::DynamicTemplatePart; use deno_graph::ParserModuleAnalyzer; use deno_graph::TypeScriptReference; use deno_package_json::PackageJsonDepValue; +use deno_package_json::PackageJsonDepWorkspaceReq; use deno_resolver::sloppy_imports::SloppyImportsResolutionKind; use deno_runtime::deno_node::is_builtin_node_module; +use deno_semver::Version; +use deno_semver::VersionReq; use crate::resolver::CliSloppyImportsResolver; @@ -24,34 +40,163 @@ pub enum SpecifierUnfurlerDiagnostic { text_info: SourceTextInfo, range: SourceRange, }, + ResolvingNpmWorkspacePackage { + specifier: ModuleSpecifier, + package_name: String, + text_info: SourceTextInfo, + range: SourceRange, + reason: String, + }, } -impl SpecifierUnfurlerDiagnostic { - pub fn code(&self) -> &'static str { +impl Diagnostic for SpecifierUnfurlerDiagnostic { + fn level(&self) -> DiagnosticLevel { match self { - Self::UnanalyzableDynamicImport { .. } => "unanalyzable-dynamic-import", - } - } - - pub fn message(&self) -> &'static str { - match self { - Self::UnanalyzableDynamicImport { .. } => { - "unable to analyze dynamic import" + SpecifierUnfurlerDiagnostic::UnanalyzableDynamicImport { .. } => { + DiagnosticLevel::Warning + } + SpecifierUnfurlerDiagnostic::ResolvingNpmWorkspacePackage { .. } => { + DiagnosticLevel::Error } } } + + fn code(&self) -> Cow<'_, str> { + match self { + Self::UnanalyzableDynamicImport { .. } => "unanalyzable-dynamic-import", + Self::ResolvingNpmWorkspacePackage { .. } => "npm-workspace-package", + } + .into() + } + + fn message(&self) -> Cow<'_, str> { + match self { + Self::UnanalyzableDynamicImport { .. } => { + "unable to analyze dynamic import".into() + } + Self::ResolvingNpmWorkspacePackage { + package_name, + reason, + .. + } => format!( + "failed resolving npm workspace package '{}': {}", + package_name, reason + ) + .into(), + } + } + + fn location(&self) -> deno_ast::diagnostics::DiagnosticLocation { + match self { + SpecifierUnfurlerDiagnostic::UnanalyzableDynamicImport { + specifier, + text_info, + range, + } => DiagnosticLocation::ModulePosition { + specifier: Cow::Borrowed(specifier), + text_info: Cow::Borrowed(text_info), + source_pos: DiagnosticSourcePos::SourcePos(range.start), + }, + SpecifierUnfurlerDiagnostic::ResolvingNpmWorkspacePackage { + specifier, + text_info, + range, + .. + } => DiagnosticLocation::ModulePosition { + specifier: Cow::Borrowed(specifier), + text_info: Cow::Borrowed(text_info), + source_pos: DiagnosticSourcePos::SourcePos(range.start), + }, + } + } + + fn snippet(&self) -> Option> { + match self { + SpecifierUnfurlerDiagnostic::UnanalyzableDynamicImport { + text_info, + range, + .. + } => Some(DiagnosticSnippet { + source: Cow::Borrowed(text_info), + highlights: vec![DiagnosticSnippetHighlight { + style: DiagnosticSnippetHighlightStyle::Warning, + range: DiagnosticSourceRange { + start: DiagnosticSourcePos::SourcePos(range.start), + end: DiagnosticSourcePos::SourcePos(range.end), + }, + description: Some("the unanalyzable dynamic import".into()), + }], + }), + SpecifierUnfurlerDiagnostic::ResolvingNpmWorkspacePackage { + text_info, + range, + .. + } => Some(DiagnosticSnippet { + source: Cow::Borrowed(text_info), + highlights: vec![DiagnosticSnippetHighlight { + style: DiagnosticSnippetHighlightStyle::Warning, + range: DiagnosticSourceRange { + start: DiagnosticSourcePos::SourcePos(range.start), + end: DiagnosticSourcePos::SourcePos(range.end), + }, + description: Some("the unresolved import".into()), + }], + }), + } + } + + fn hint(&self) -> Option> { + match self { + SpecifierUnfurlerDiagnostic::UnanalyzableDynamicImport { .. } => { + None + } + SpecifierUnfurlerDiagnostic::ResolvingNpmWorkspacePackage { .. } => Some( + "make sure the npm workspace package is resolvable and has a version field in its package.json".into() + ), + } + } + + fn snippet_fixed( + &self, + ) -> Option> { + None + } + + fn info(&self) -> Cow<'_, [Cow<'_, str>]> { + match self { + SpecifierUnfurlerDiagnostic::UnanalyzableDynamicImport { .. } => Cow::Borrowed(&[ + Cow::Borrowed("after publishing this package, imports from the local import map / package.json do not work"), + Cow::Borrowed("dynamic imports that can not be analyzed at publish time will not be rewritten automatically"), + Cow::Borrowed("make sure the dynamic import is resolvable at runtime without an import map / package.json") + ]), + SpecifierUnfurlerDiagnostic::ResolvingNpmWorkspacePackage { .. } => { + Cow::Borrowed(&[]) + }, + } + } + + fn docs_url(&self) -> Option> { + None + } +} + +enum UnfurlSpecifierError { + Workspace { + package_name: String, + reason: String, + }, } pub struct SpecifierUnfurler { - sloppy_imports_resolver: Option, - workspace_resolver: WorkspaceResolver, + sloppy_imports_resolver: Option>, + workspace_resolver: Arc, bare_node_builtins: bool, } impl SpecifierUnfurler { pub fn new( - sloppy_imports_resolver: Option, - workspace_resolver: WorkspaceResolver, + sloppy_imports_resolver: Option>, + workspace_resolver: Arc, bare_node_builtins: bool, ) -> Self { debug_assert_eq!( @@ -65,11 +210,45 @@ impl SpecifierUnfurler { } } + fn unfurl_specifier_reporting_diagnostic( + &self, + referrer: &ModuleSpecifier, + specifier: &str, + text_info: &SourceTextInfo, + range: &deno_graph::PositionRange, + diagnostic_reporter: &mut dyn FnMut(SpecifierUnfurlerDiagnostic), + ) -> Option { + match self.unfurl_specifier(referrer, specifier) { + Ok(maybe_unfurled) => maybe_unfurled, + Err(diagnostic) => match diagnostic { + UnfurlSpecifierError::Workspace { + package_name, + reason, + } => { + let range = to_range(text_info, range); + diagnostic_reporter( + SpecifierUnfurlerDiagnostic::ResolvingNpmWorkspacePackage { + specifier: referrer.clone(), + package_name, + text_info: text_info.clone(), + range: SourceRange::new( + text_info.start_pos() + range.start, + text_info.start_pos() + range.end, + ), + reason, + }, + ); + None + } + }, + } + } + fn unfurl_specifier( &self, referrer: &ModuleSpecifier, specifier: &str, - ) -> Option { + ) -> Result, UnfurlSpecifierError> { let resolved = if let Ok(resolved) = self.workspace_resolver.resolve(specifier, referrer) { @@ -120,8 +299,40 @@ impl SpecifierUnfurler { )) .ok() } - PackageJsonDepValue::Workspace(version_req) => { - // todo(#24612): consider warning or error when this is also a jsr package? + PackageJsonDepValue::Workspace(workspace_version_req) => { + let version_req = match workspace_version_req { + PackageJsonDepWorkspaceReq::VersionReq(version_req) => { + Cow::Borrowed(version_req) + } + PackageJsonDepWorkspaceReq::Caret => { + let version = self + .find_workspace_npm_dep_version(alias) + .map_err(|err| UnfurlSpecifierError::Workspace { + package_name: alias.to_string(), + reason: err.to_string(), + })?; + // version was validated, so ok to unwrap + Cow::Owned( + VersionReq::parse_from_npm(&format!("^{}", version)) + .unwrap(), + ) + } + PackageJsonDepWorkspaceReq::Tilde => { + let version = self + .find_workspace_npm_dep_version(alias) + .map_err(|err| UnfurlSpecifierError::Workspace { + package_name: alias.to_string(), + reason: err.to_string(), + })?; + // version was validated, so ok to unwrap + Cow::Owned( + VersionReq::parse_from_npm(&format!("~{}", version)) + .unwrap(), + ) + } + }; + // todo(#24612): warn when this is also a jsr package telling + // people to map the specifiers in the import map ModuleSpecifier::parse(&format!( "npm:{}@{}{}", alias, @@ -151,10 +362,14 @@ impl SpecifierUnfurler { None if self.bare_node_builtins && is_builtin_node_module(specifier) => { format!("node:{specifier}").parse().unwrap() } - None => ModuleSpecifier::options() + None => match ModuleSpecifier::options() .base_url(Some(referrer)) .parse(specifier) - .ok()?, + .ok() + { + Some(value) => value, + None => return Ok(None), + }, }; // TODO(lucacasonato): this requires integration in deno_graph first // let resolved = if let Ok(specifier) = @@ -188,7 +403,7 @@ impl SpecifierUnfurler { }; let relative_resolved = relative_url(&resolved, referrer); if relative_resolved == specifier { - None // nothing to unfurl + Ok(None) // nothing to unfurl } else { log::debug!( "Unfurled specifier: {} from {} -> {}", @@ -196,7 +411,29 @@ impl SpecifierUnfurler { referrer, relative_resolved ); - Some(relative_resolved) + Ok(Some(relative_resolved)) + } + } + + fn find_workspace_npm_dep_version( + &self, + pkg_name: &str, + ) -> Result { + // todo(#24612): warn when this is also a jsr package telling + // people to map the specifiers in the import map + let pkg_json = self + .workspace_resolver + .package_jsons() + .find(|pkg| pkg.name.as_deref() == Some(pkg_name)) + .ok_or_else(|| { + anyhow::anyhow!("unable to find npm package in workspace") + })?; + if let Some(version) = &pkg_json.version { + Ok(Version::parse_from_npm(version)?) + } else { + Err(anyhow::anyhow!( + "missing version in package.json of npm package", + )) } } @@ -208,6 +445,7 @@ impl SpecifierUnfurler { text_info: &SourceTextInfo, dep: &deno_graph::DynamicDependencyDescriptor, text_changes: &mut Vec, + diagnostic_reporter: &mut dyn FnMut(SpecifierUnfurlerDiagnostic), ) -> bool { match &dep.argument { deno_graph::DynamicArgument::String(specifier) => { @@ -217,8 +455,14 @@ impl SpecifierUnfurler { let Some(relative_index) = maybe_relative_index else { return true; // always say it's analyzable for a string }; - let unfurled = self.unfurl_specifier(module_url, specifier); - if let Some(unfurled) = unfurled { + let maybe_unfurled = self.unfurl_specifier_reporting_diagnostic( + module_url, + specifier, + text_info, + &dep.argument_range, + diagnostic_reporter, + ); + if let Some(unfurled) = maybe_unfurled { let start = range.start + relative_index; text_changes.push(deno_ast::TextChange { range: start..start + specifier.len(), @@ -238,7 +482,13 @@ impl SpecifierUnfurler { if !specifier.ends_with('/') { return false; } - let unfurled = self.unfurl_specifier(module_url, specifier); + let unfurled = self.unfurl_specifier_reporting_diagnostic( + module_url, + specifier, + text_info, + &dep.argument_range, + diagnostic_reporter, + ); let Some(unfurled) = unfurled else { return true; // nothing to unfurl }; @@ -280,8 +530,15 @@ impl SpecifierUnfurler { let analyze_specifier = |specifier: &str, range: &deno_graph::PositionRange, - text_changes: &mut Vec| { - if let Some(unfurled) = self.unfurl_specifier(url, specifier) { + text_changes: &mut Vec, + diagnostic_reporter: &mut dyn FnMut(SpecifierUnfurlerDiagnostic)| { + if let Some(unfurled) = self.unfurl_specifier_reporting_diagnostic( + url, + specifier, + text_info, + range, + diagnostic_reporter, + ) { text_changes.push(deno_ast::TextChange { range: to_range(text_info, range), new_text: unfurled, @@ -295,11 +552,17 @@ impl SpecifierUnfurler { &dep.specifier, &dep.specifier_range, &mut text_changes, + diagnostic_reporter, ); } DependencyDescriptor::Dynamic(dep) => { - let success = - self.try_unfurl_dynamic_dep(url, text_info, dep, &mut text_changes); + let success = self.try_unfurl_dynamic_dep( + url, + text_info, + dep, + &mut text_changes, + diagnostic_reporter, + ); if !success { let start_pos = text_info.line_start(dep.argument_range.start.line) @@ -326,6 +589,7 @@ impl SpecifierUnfurler { &specifier_with_range.text, &specifier_with_range.range, &mut text_changes, + diagnostic_reporter, ); } for jsdoc in &module_info.jsdoc_imports { @@ -333,6 +597,7 @@ impl SpecifierUnfurler { &jsdoc.specifier.text, &jsdoc.specifier.range, &mut text_changes, + diagnostic_reporter, ); } if let Some(specifier_with_range) = &module_info.jsx_import_source { @@ -340,6 +605,7 @@ impl SpecifierUnfurler { &specifier_with_range.text, &specifier_with_range.range, &mut text_changes, + diagnostic_reporter, ); } @@ -458,10 +724,10 @@ mod tests { ); let fs = Arc::new(RealFs); let unfurler = SpecifierUnfurler::new( - Some(CliSloppyImportsResolver::new(SloppyImportsCachedFs::new( - fs, + Some(Arc::new(CliSloppyImportsResolver::new( + SloppyImportsCachedFs::new(fs), ))), - workspace_resolver, + Arc::new(workspace_resolver), true, ); @@ -547,4 +813,114 @@ const warn2 = await import(`${expr}`); assert_eq!(unfurled_source, expected_source); } } + + #[test] + fn test_unfurling_npm_dep_workspace_specifier() { + let cwd = testdata_path().join("unfurl").to_path_buf(); + + let pkg_json_add = PackageJson::load_from_value( + cwd.join("add/package.json"), + json!({ "name": "add", "version": "0.1.0", }), + ); + let pkg_json_subtract = PackageJson::load_from_value( + cwd.join("subtract/package.json"), + json!({ "name": "subtract", "version": "0.2.0", }), + ); + let pkg_json_publishing = PackageJson::load_from_value( + cwd.join("publish/package.json"), + json!({ + "name": "@denotest/main", + "version": "1.0.0", + "dependencies": { + "add": "workspace:~", + "subtract": "workspace:^", + "non-existent": "workspace:~", + } + }), + ); + let root_pkg_json = PackageJson::load_from_value( + cwd.join("package.json"), + json!({ "workspaces": ["./publish", "./subtract", "./add"] }), + ); + let workspace_resolver = WorkspaceResolver::new_raw( + Arc::new(ModuleSpecifier::from_directory_path(&cwd).unwrap()), + None, + vec![ResolverWorkspaceJsrPackage { + is_patch: false, + base: ModuleSpecifier::from_directory_path( + cwd.join("publish/jsr.json"), + ) + .unwrap(), + name: "@denotest/main".to_string(), + version: Some(Version::parse_standard("1.0.0").unwrap()), + exports: IndexMap::from([(".".to_string(), "mod.ts".to_string())]), + }], + vec![ + Arc::new(root_pkg_json), + Arc::new(pkg_json_add), + Arc::new(pkg_json_subtract), + Arc::new(pkg_json_publishing), + ], + deno_config::workspace::PackageJsonDepResolution::Enabled, + ); + let fs = Arc::new(RealFs); + let unfurler = SpecifierUnfurler::new( + Some(Arc::new(CliSloppyImportsResolver::new( + SloppyImportsCachedFs::new(fs), + ))), + Arc::new(workspace_resolver), + true, + ); + + { + let source_code = r#"import add from "add"; +import subtract from "subtract"; + +console.log(add, subtract); +"#; + let specifier = + ModuleSpecifier::from_file_path(cwd.join("publish").join("mod.ts")) + .unwrap(); + let source = parse_ast(&specifier, source_code); + let mut d = Vec::new(); + let mut reporter = |diagnostic| d.push(diagnostic); + let unfurled_source = unfurler.unfurl(&specifier, &source, &mut reporter); + assert_eq!(d.len(), 0); + // it will inline the version + let expected_source = r#"import add from "npm:add@~0.1.0"; +import subtract from "npm:subtract@^0.2.0"; + +console.log(add, subtract); +"#; + assert_eq!(unfurled_source, expected_source); + } + + { + let source_code = r#"import nonExistent from "non-existent"; +console.log(nonExistent); +"#; + let specifier = + ModuleSpecifier::from_file_path(cwd.join("publish").join("other.ts")) + .unwrap(); + let source = parse_ast(&specifier, source_code); + let mut d = Vec::new(); + let mut reporter = |diagnostic| d.push(diagnostic); + let unfurled_source = unfurler.unfurl(&specifier, &source, &mut reporter); + assert_eq!(d.len(), 1); + match &d[0] { + SpecifierUnfurlerDiagnostic::ResolvingNpmWorkspacePackage { + package_name, + reason, + .. + } => { + assert_eq!(package_name, "non-existent"); + assert_eq!(reason, "unable to find npm package in workspace"); + } + _ => unreachable!(), + } + // won't make any changes, but the above will be a fatal error + assert!(matches!(d[0].level(), DiagnosticLevel::Error)); + assert_eq!(unfurled_source, source_code); + } + } } diff --git a/cli/tools/task.rs b/cli/tools/task.rs index 4752738c52..a2f76aaf1f 100644 --- a/cli/tools/task.rs +++ b/cli/tools/task.rs @@ -26,6 +26,7 @@ use deno_core::futures::StreamExt; use deno_core::url::Url; use deno_path_util::normalize_path; use deno_runtime::deno_node::NodeResolver; +use deno_task_shell::KillSignal; use deno_task_shell::ShellCommand; use indexmap::IndexMap; use regex::Regex; @@ -37,6 +38,7 @@ use crate::colors; use crate::factory::CliFactory; use crate::npm::CliNpmResolver; use crate::task_runner; +use crate::task_runner::run_future_forwarding_signals; use crate::util::fs::canonicalize_path; #[derive(Debug)] @@ -226,28 +228,33 @@ pub async fn execute_script( concurrency: no_of_concurrent_tasks.into(), }; - if task_flags.eval { - return task_runner - .run_deno_task( - &Url::from_directory_path(cli_options.initial_cwd()).unwrap(), - "", - &TaskDefinition { - command: task_flags.task.as_ref().unwrap().to_string(), - dependencies: vec![], - description: None, - }, - ) - .await; - } - - for task_config in &packages_task_configs { - let exit_code = task_runner.run_tasks(task_config).await?; - if exit_code > 0 { - return Ok(exit_code); + let kill_signal = KillSignal::default(); + run_future_forwarding_signals(kill_signal.clone(), async { + if task_flags.eval { + return task_runner + .run_deno_task( + &Url::from_directory_path(cli_options.initial_cwd()).unwrap(), + "", + &TaskDefinition { + command: task_flags.task.as_ref().unwrap().to_string(), + dependencies: vec![], + description: None, + }, + kill_signal, + ) + .await; } - } - Ok(0) + for task_config in &packages_task_configs { + let exit_code = task_runner.run_tasks(task_config, &kill_signal).await?; + if exit_code > 0 { + return Ok(exit_code); + } + } + + Ok(0) + }) + .await } struct RunSingleOptions<'a> { @@ -255,6 +262,7 @@ struct RunSingleOptions<'a> { script: &'a str, cwd: &'a Path, custom_commands: HashMap>, + kill_signal: KillSignal, } struct TaskRunner<'a> { @@ -270,9 +278,10 @@ impl<'a> TaskRunner<'a> { pub async fn run_tasks( &self, pkg_tasks_config: &PackageTaskInfo, + kill_signal: &KillSignal, ) -> Result { match sort_tasks_topo(pkg_tasks_config) { - Ok(sorted) => self.run_tasks_in_parallel(sorted).await, + Ok(sorted) => self.run_tasks_in_parallel(sorted, kill_signal).await, Err(err) => match err { TaskError::NotFound(name) => { if self.task_flags.is_run { @@ -307,6 +316,7 @@ impl<'a> TaskRunner<'a> { async fn run_tasks_in_parallel( &self, tasks: Vec>, + kill_signal: &KillSignal, ) -> Result { struct PendingTasksContext<'a> { completed: HashSet, @@ -327,6 +337,7 @@ impl<'a> TaskRunner<'a> { fn get_next_task<'b>( &mut self, runner: &'b TaskRunner<'b>, + kill_signal: &KillSignal, ) -> Option< LocalBoxFuture<'b, Result<(i32, &'a ResolvedTask<'a>), AnyError>>, > @@ -349,15 +360,23 @@ impl<'a> TaskRunner<'a> { } self.running.insert(task.id); + let kill_signal = kill_signal.clone(); return Some( async move { match task.task_or_script { TaskOrScript::Task(_, def) => { - runner.run_deno_task(task.folder_url, task.name, def).await + runner + .run_deno_task(task.folder_url, task.name, def, kill_signal) + .await } TaskOrScript::Script(scripts, _) => { runner - .run_npm_script(task.folder_url, task.name, scripts) + .run_npm_script( + task.folder_url, + task.name, + scripts, + kill_signal, + ) .await } } @@ -380,7 +399,7 @@ impl<'a> TaskRunner<'a> { while context.has_remaining_tasks() { while queue.len() < self.concurrency { - if let Some(task) = context.get_next_task(self) { + if let Some(task) = context.get_next_task(self, kill_signal) { queue.push(task); } else { break; @@ -409,6 +428,7 @@ impl<'a> TaskRunner<'a> { dir_url: &Url, task_name: &str, definition: &TaskDefinition, + kill_signal: KillSignal, ) -> Result { let cwd = match &self.task_flags.cwd { Some(path) => canonicalize_path(&PathBuf::from(path)) @@ -426,6 +446,7 @@ impl<'a> TaskRunner<'a> { script: &definition.command, cwd: &cwd, custom_commands, + kill_signal, }) .await } @@ -435,6 +456,7 @@ impl<'a> TaskRunner<'a> { dir_url: &Url, task_name: &str, scripts: &IndexMap, + kill_signal: KillSignal, ) -> Result { // ensure the npm packages are installed if using a managed resolver if let Some(npm_resolver) = self.npm_resolver.as_managed() { @@ -466,6 +488,7 @@ impl<'a> TaskRunner<'a> { script, cwd: &cwd, custom_commands: custom_commands.clone(), + kill_signal: kill_signal.clone(), }) .await?; if exit_code > 0 { @@ -486,6 +509,7 @@ impl<'a> TaskRunner<'a> { script, cwd, custom_commands, + kill_signal, } = opts; output_task( @@ -504,6 +528,7 @@ impl<'a> TaskRunner<'a> { argv: self.cli_options.argv(), root_node_modules_dir: self.npm_resolver.root_node_modules_path(), stdio: None, + kill_signal, }) .await? .exit_code, diff --git a/ext/node/lib.rs b/ext/node/lib.rs index 9986b0f607..bf593ad432 100644 --- a/ext/node/lib.rs +++ b/ext/node/lib.rs @@ -872,12 +872,10 @@ impl deno_package_json::fs::DenoPkgJsonFs for DenoFsNodeResolverEnv { fn read_to_string_lossy( &self, path: &std::path::Path, - ) -> Result { + ) -> Result, std::io::Error> { self .fs .read_text_file_lossy_sync(path, None) - // todo(https://github.com/denoland/deno_package_json/pull/9): don't clone - .map(|text| text.into_owned()) .map_err(|err| err.into_io_error()) } } @@ -888,12 +886,10 @@ impl<'a> deno_package_json::fs::DenoPkgJsonFs for DenoPkgJsonFsAdapter<'a> { fn read_to_string_lossy( &self, path: &Path, - ) -> Result { + ) -> Result, std::io::Error> { self .0 .read_text_file_lossy_sync(path, None) - // todo(https://github.com/denoland/deno_package_json/pull/9): don't clone - .map(|text| text.into_owned()) .map_err(|err| err.into_io_error()) } } diff --git a/resolvers/deno/npm/byonm.rs b/resolvers/deno/npm/byonm.rs index e9182d47a1..771f23ce23 100644 --- a/resolvers/deno/npm/byonm.rs +++ b/resolvers/deno/npm/byonm.rs @@ -179,7 +179,11 @@ impl ByonmNpmResolver { pkg_json: &PackageJson, ) -> Option { let deps = pkg_json.resolve_local_package_json_deps(); - for (key, value) in deps { + for (key, value) in deps + .dependencies + .into_iter() + .chain(deps.dev_dependencies.into_iter()) + { if let Ok(value) = value { match value { PackageJsonDepValue::Req(dep_req) => { diff --git a/runtime/lib.rs b/runtime/lib.rs index 53d4f265e0..1ce325964f 100644 --- a/runtime/lib.rs +++ b/runtime/lib.rs @@ -34,6 +34,7 @@ pub mod inspector_server; pub mod js; pub mod ops; pub mod permissions; +pub mod signal; pub mod snapshot; pub mod sys_info; pub mod tokio_util; diff --git a/runtime/ops/process.rs b/runtime/ops/process.rs index 83d9317d32..422f229632 100644 --- a/runtime/ops/process.rs +++ b/runtime/ops/process.rs @@ -256,9 +256,7 @@ impl TryFrom for ChildStatus { success: false, code: 128 + signal, #[cfg(unix)] - signal: Some( - crate::ops::signal::signal_int_to_str(signal)?.to_string(), - ), + signal: Some(crate::signal::signal_int_to_str(signal)?.to_string()), #[cfg(not(unix))] signal: None, } @@ -1076,7 +1074,8 @@ mod deprecated { #[cfg(unix)] pub fn kill(pid: i32, signal: &str) -> Result<(), ProcessError> { - let signo = super::super::signal::signal_str_to_int(signal)?; + let signo = crate::signal::signal_str_to_int(signal) + .map_err(SignalError::InvalidSignalStr)?; use nix::sys::signal::kill as unix_kill; use nix::sys::signal::Signal; use nix::unistd::Pid; @@ -1099,7 +1098,12 @@ mod deprecated { use winapi::um::winnt::PROCESS_TERMINATE; if !matches!(signal, "SIGKILL" | "SIGTERM") { - Err(SignalError::InvalidSignalStr(signal.to_string()).into()) + Err( + SignalError::InvalidSignalStr(crate::signal::InvalidSignalStrError( + signal.to_string(), + )) + .into(), + ) } else if pid <= 0 { Err(ProcessError::InvalidPid) } else { diff --git a/runtime/ops/signal.rs b/runtime/ops/signal.rs index e1e4ab68bc..ef87c37297 100644 --- a/runtime/ops/signal.rs +++ b/runtime/ops/signal.rs @@ -46,34 +46,10 @@ deno_core::extension!( #[derive(Debug, thiserror::Error)] pub enum SignalError { - #[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "openbsd", - target_os = "openbsd", - target_os = "macos", - target_os = "solaris", - target_os = "illumos" - ))] - #[error("Invalid signal: {0}")] - InvalidSignalStr(String), - #[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "openbsd", - target_os = "openbsd", - target_os = "macos", - target_os = "solaris", - target_os = "illumos" - ))] - #[error("Invalid signal: {0}")] - InvalidSignalInt(libc::c_int), - #[cfg(target_os = "windows")] - #[error("Windows only supports ctrl-c (SIGINT) and ctrl-break (SIGBREAK), but got {0}")] - InvalidSignalStr(String), - #[cfg(target_os = "windows")] - #[error("Windows only supports ctrl-c (SIGINT) and ctrl-break (SIGBREAK), but got {0}")] - InvalidSignalInt(libc::c_int), + #[error(transparent)] + InvalidSignalStr(#[from] crate::signal::InvalidSignalStrError), + #[error(transparent)] + InvalidSignalInt(#[from] crate::signal::InvalidSignalIntError), #[error("Binding to signal '{0}' is not allowed")] SignalNotAllowed(String), #[error("{0}")] @@ -181,218 +157,6 @@ impl Resource for SignalStreamResource { } } -macro_rules! first_literal { - ($head:literal $(, $tail:literal)*) => { - $head - }; -} -macro_rules! signal_dict { - ($(($number:literal, $($name:literal)|+)),*) => { - pub fn signal_str_to_int(s: &str) -> Result { - match s { - $($($name)|* => Ok($number),)* - _ => Err(SignalError::InvalidSignalStr(s.to_string())), - } - } - - pub fn signal_int_to_str(s: libc::c_int) -> Result<&'static str, SignalError> { - match s { - $($number => Ok(first_literal!($($name),+)),)* - _ => Err(SignalError::InvalidSignalInt(s)), - } - } - } -} - -#[cfg(target_os = "freebsd")] -signal_dict!( - (1, "SIGHUP"), - (2, "SIGINT"), - (3, "SIGQUIT"), - (4, "SIGILL"), - (5, "SIGTRAP"), - (6, "SIGABRT" | "SIGIOT"), - (7, "SIGEMT"), - (8, "SIGFPE"), - (9, "SIGKILL"), - (10, "SIGBUS"), - (11, "SIGSEGV"), - (12, "SIGSYS"), - (13, "SIGPIPE"), - (14, "SIGALRM"), - (15, "SIGTERM"), - (16, "SIGURG"), - (17, "SIGSTOP"), - (18, "SIGTSTP"), - (19, "SIGCONT"), - (20, "SIGCHLD"), - (21, "SIGTTIN"), - (22, "SIGTTOU"), - (23, "SIGIO"), - (24, "SIGXCPU"), - (25, "SIGXFSZ"), - (26, "SIGVTALRM"), - (27, "SIGPROF"), - (28, "SIGWINCH"), - (29, "SIGINFO"), - (30, "SIGUSR1"), - (31, "SIGUSR2"), - (32, "SIGTHR"), - (33, "SIGLIBRT") -); - -#[cfg(target_os = "openbsd")] -signal_dict!( - (1, "SIGHUP"), - (2, "SIGINT"), - (3, "SIGQUIT"), - (4, "SIGILL"), - (5, "SIGTRAP"), - (6, "SIGABRT" | "SIGIOT"), - (7, "SIGEMT"), - (8, "SIGKILL"), - (10, "SIGBUS"), - (11, "SIGSEGV"), - (12, "SIGSYS"), - (13, "SIGPIPE"), - (14, "SIGALRM"), - (15, "SIGTERM"), - (16, "SIGURG"), - (17, "SIGSTOP"), - (18, "SIGTSTP"), - (19, "SIGCONT"), - (20, "SIGCHLD"), - (21, "SIGTTIN"), - (22, "SIGTTOU"), - (23, "SIGIO"), - (24, "SIGXCPU"), - (25, "SIGXFSZ"), - (26, "SIGVTALRM"), - (27, "SIGPROF"), - (28, "SIGWINCH"), - (29, "SIGINFO"), - (30, "SIGUSR1"), - (31, "SIGUSR2"), - (32, "SIGTHR") -); - -#[cfg(any(target_os = "android", target_os = "linux"))] -signal_dict!( - (1, "SIGHUP"), - (2, "SIGINT"), - (3, "SIGQUIT"), - (4, "SIGILL"), - (5, "SIGTRAP"), - (6, "SIGABRT" | "SIGIOT"), - (7, "SIGBUS"), - (8, "SIGFPE"), - (9, "SIGKILL"), - (10, "SIGUSR1"), - (11, "SIGSEGV"), - (12, "SIGUSR2"), - (13, "SIGPIPE"), - (14, "SIGALRM"), - (15, "SIGTERM"), - (16, "SIGSTKFLT"), - (17, "SIGCHLD"), - (18, "SIGCONT"), - (19, "SIGSTOP"), - (20, "SIGTSTP"), - (21, "SIGTTIN"), - (22, "SIGTTOU"), - (23, "SIGURG"), - (24, "SIGXCPU"), - (25, "SIGXFSZ"), - (26, "SIGVTALRM"), - (27, "SIGPROF"), - (28, "SIGWINCH"), - (29, "SIGIO" | "SIGPOLL"), - (30, "SIGPWR"), - (31, "SIGSYS" | "SIGUNUSED") -); - -#[cfg(target_os = "macos")] -signal_dict!( - (1, "SIGHUP"), - (2, "SIGINT"), - (3, "SIGQUIT"), - (4, "SIGILL"), - (5, "SIGTRAP"), - (6, "SIGABRT" | "SIGIOT"), - (7, "SIGEMT"), - (8, "SIGFPE"), - (9, "SIGKILL"), - (10, "SIGBUS"), - (11, "SIGSEGV"), - (12, "SIGSYS"), - (13, "SIGPIPE"), - (14, "SIGALRM"), - (15, "SIGTERM"), - (16, "SIGURG"), - (17, "SIGSTOP"), - (18, "SIGTSTP"), - (19, "SIGCONT"), - (20, "SIGCHLD"), - (21, "SIGTTIN"), - (22, "SIGTTOU"), - (23, "SIGIO"), - (24, "SIGXCPU"), - (25, "SIGXFSZ"), - (26, "SIGVTALRM"), - (27, "SIGPROF"), - (28, "SIGWINCH"), - (29, "SIGINFO"), - (30, "SIGUSR1"), - (31, "SIGUSR2") -); - -#[cfg(any(target_os = "solaris", target_os = "illumos"))] -signal_dict!( - (1, "SIGHUP"), - (2, "SIGINT"), - (3, "SIGQUIT"), - (4, "SIGILL"), - (5, "SIGTRAP"), - (6, "SIGABRT" | "SIGIOT"), - (7, "SIGEMT"), - (8, "SIGFPE"), - (9, "SIGKILL"), - (10, "SIGBUS"), - (11, "SIGSEGV"), - (12, "SIGSYS"), - (13, "SIGPIPE"), - (14, "SIGALRM"), - (15, "SIGTERM"), - (16, "SIGUSR1"), - (17, "SIGUSR2"), - (18, "SIGCHLD"), - (19, "SIGPWR"), - (20, "SIGWINCH"), - (21, "SIGURG"), - (22, "SIGPOLL"), - (23, "SIGSTOP"), - (24, "SIGTSTP"), - (25, "SIGCONT"), - (26, "SIGTTIN"), - (27, "SIGTTOU"), - (28, "SIGVTALRM"), - (29, "SIGPROF"), - (30, "SIGXCPU"), - (31, "SIGXFSZ"), - (32, "SIGWAITING"), - (33, "SIGLWP"), - (34, "SIGFREEZE"), - (35, "SIGTHAW"), - (36, "SIGCANCEL"), - (37, "SIGLOST"), - (38, "SIGXRES"), - (39, "SIGJVM1"), - (40, "SIGJVM2") -); - -#[cfg(target_os = "windows")] -signal_dict!((2, "SIGINT"), (21, "SIGBREAK")); - #[cfg(unix)] #[op2(fast)] #[smi] @@ -400,7 +164,7 @@ fn op_signal_bind( state: &mut OpState, #[string] sig: &str, ) -> Result { - let signo = signal_str_to_int(sig)?; + let signo = crate::signal::signal_str_to_int(sig)?; if signal_hook_registry::FORBIDDEN.contains(&signo) { return Err(SignalError::SignalNotAllowed(sig.to_string())); } @@ -437,7 +201,7 @@ fn op_signal_bind( state: &mut OpState, #[string] sig: &str, ) -> Result { - let signo = signal_str_to_int(sig)?; + let signo = crate::signal::signal_str_to_int(sig)?; let resource = SignalStreamResource { signal: AsyncRefCell::new(match signo { // SIGINT diff --git a/runtime/signal.rs b/runtime/signal.rs new file mode 100644 index 0000000000..0ef83d7de8 --- /dev/null +++ b/runtime/signal.rs @@ -0,0 +1,257 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +#[cfg(target_os = "windows")] +#[derive(Debug, thiserror::Error)] +#[error("Windows only supports ctrl-c (SIGINT) and ctrl-break (SIGBREAK), but got {0}")] +pub struct InvalidSignalStrError(pub String); + +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "openbsd", + target_os = "openbsd", + target_os = "macos", + target_os = "solaris", + target_os = "illumos" +))] +#[derive(Debug, thiserror::Error)] +#[error("Invalid signal: {0}")] +pub struct InvalidSignalStrError(pub String); + +#[cfg(target_os = "windows")] +#[derive(Debug, thiserror::Error)] +#[error("Windows only supports ctrl-c (SIGINT) and ctrl-break (SIGBREAK), but got {0}")] +pub struct InvalidSignalIntError(pub libc::c_int); + +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "openbsd", + target_os = "openbsd", + target_os = "macos", + target_os = "solaris", + target_os = "illumos" +))] +#[derive(Debug, thiserror::Error)] +#[error("Invalid signal: {0}")] +pub struct InvalidSignalIntError(pub libc::c_int); + +macro_rules! first_literal { + ($head:literal $(, $tail:literal)*) => { + $head + }; +} + +macro_rules! signal_dict { + ($(($number:literal, $($name:literal)|+)),*) => { + + pub const SIGNAL_NUMS: &'static [libc::c_int] = &[ + $( + $number + ),* + ]; + + pub fn signal_str_to_int(s: &str) -> Result { + match s { + $($($name)|* => Ok($number),)* + _ => Err(InvalidSignalStrError(s.to_string())), + } + } + + pub fn signal_int_to_str(s: libc::c_int) -> Result<&'static str, InvalidSignalIntError> { + match s { + $($number => Ok(first_literal!($($name),+)),)* + _ => Err(InvalidSignalIntError(s)), + } + } + } +} + +#[cfg(target_os = "freebsd")] +signal_dict!( + (1, "SIGHUP"), + (2, "SIGINT"), + (3, "SIGQUIT"), + (4, "SIGILL"), + (5, "SIGTRAP"), + (6, "SIGABRT" | "SIGIOT"), + (7, "SIGEMT"), + (8, "SIGFPE"), + (9, "SIGKILL"), + (10, "SIGBUS"), + (11, "SIGSEGV"), + (12, "SIGSYS"), + (13, "SIGPIPE"), + (14, "SIGALRM"), + (15, "SIGTERM"), + (16, "SIGURG"), + (17, "SIGSTOP"), + (18, "SIGTSTP"), + (19, "SIGCONT"), + (20, "SIGCHLD"), + (21, "SIGTTIN"), + (22, "SIGTTOU"), + (23, "SIGIO"), + (24, "SIGXCPU"), + (25, "SIGXFSZ"), + (26, "SIGVTALRM"), + (27, "SIGPROF"), + (28, "SIGWINCH"), + (29, "SIGINFO"), + (30, "SIGUSR1"), + (31, "SIGUSR2"), + (32, "SIGTHR"), + (33, "SIGLIBRT") +); + +#[cfg(target_os = "openbsd")] +signal_dict!( + (1, "SIGHUP"), + (2, "SIGINT"), + (3, "SIGQUIT"), + (4, "SIGILL"), + (5, "SIGTRAP"), + (6, "SIGABRT" | "SIGIOT"), + (7, "SIGEMT"), + (8, "SIGKILL"), + (10, "SIGBUS"), + (11, "SIGSEGV"), + (12, "SIGSYS"), + (13, "SIGPIPE"), + (14, "SIGALRM"), + (15, "SIGTERM"), + (16, "SIGURG"), + (17, "SIGSTOP"), + (18, "SIGTSTP"), + (19, "SIGCONT"), + (20, "SIGCHLD"), + (21, "SIGTTIN"), + (22, "SIGTTOU"), + (23, "SIGIO"), + (24, "SIGXCPU"), + (25, "SIGXFSZ"), + (26, "SIGVTALRM"), + (27, "SIGPROF"), + (28, "SIGWINCH"), + (29, "SIGINFO"), + (30, "SIGUSR1"), + (31, "SIGUSR2"), + (32, "SIGTHR") +); + +#[cfg(any(target_os = "android", target_os = "linux"))] +signal_dict!( + (1, "SIGHUP"), + (2, "SIGINT"), + (3, "SIGQUIT"), + (4, "SIGILL"), + (5, "SIGTRAP"), + (6, "SIGABRT" | "SIGIOT"), + (7, "SIGBUS"), + (8, "SIGFPE"), + (9, "SIGKILL"), + (10, "SIGUSR1"), + (11, "SIGSEGV"), + (12, "SIGUSR2"), + (13, "SIGPIPE"), + (14, "SIGALRM"), + (15, "SIGTERM"), + (16, "SIGSTKFLT"), + (17, "SIGCHLD"), + (18, "SIGCONT"), + (19, "SIGSTOP"), + (20, "SIGTSTP"), + (21, "SIGTTIN"), + (22, "SIGTTOU"), + (23, "SIGURG"), + (24, "SIGXCPU"), + (25, "SIGXFSZ"), + (26, "SIGVTALRM"), + (27, "SIGPROF"), + (28, "SIGWINCH"), + (29, "SIGIO" | "SIGPOLL"), + (30, "SIGPWR"), + (31, "SIGSYS" | "SIGUNUSED") +); + +#[cfg(target_os = "macos")] +signal_dict!( + (1, "SIGHUP"), + (2, "SIGINT"), + (3, "SIGQUIT"), + (4, "SIGILL"), + (5, "SIGTRAP"), + (6, "SIGABRT" | "SIGIOT"), + (7, "SIGEMT"), + (8, "SIGFPE"), + (9, "SIGKILL"), + (10, "SIGBUS"), + (11, "SIGSEGV"), + (12, "SIGSYS"), + (13, "SIGPIPE"), + (14, "SIGALRM"), + (15, "SIGTERM"), + (16, "SIGURG"), + (17, "SIGSTOP"), + (18, "SIGTSTP"), + (19, "SIGCONT"), + (20, "SIGCHLD"), + (21, "SIGTTIN"), + (22, "SIGTTOU"), + (23, "SIGIO"), + (24, "SIGXCPU"), + (25, "SIGXFSZ"), + (26, "SIGVTALRM"), + (27, "SIGPROF"), + (28, "SIGWINCH"), + (29, "SIGINFO"), + (30, "SIGUSR1"), + (31, "SIGUSR2") +); + +#[cfg(any(target_os = "solaris", target_os = "illumos"))] +signal_dict!( + (1, "SIGHUP"), + (2, "SIGINT"), + (3, "SIGQUIT"), + (4, "SIGILL"), + (5, "SIGTRAP"), + (6, "SIGABRT" | "SIGIOT"), + (7, "SIGEMT"), + (8, "SIGFPE"), + (9, "SIGKILL"), + (10, "SIGBUS"), + (11, "SIGSEGV"), + (12, "SIGSYS"), + (13, "SIGPIPE"), + (14, "SIGALRM"), + (15, "SIGTERM"), + (16, "SIGUSR1"), + (17, "SIGUSR2"), + (18, "SIGCHLD"), + (19, "SIGPWR"), + (20, "SIGWINCH"), + (21, "SIGURG"), + (22, "SIGPOLL"), + (23, "SIGSTOP"), + (24, "SIGTSTP"), + (25, "SIGCONT"), + (26, "SIGTTIN"), + (27, "SIGTTOU"), + (28, "SIGVTALRM"), + (29, "SIGPROF"), + (30, "SIGXCPU"), + (31, "SIGXFSZ"), + (32, "SIGWAITING"), + (33, "SIGLWP"), + (34, "SIGFREEZE"), + (35, "SIGTHAW"), + (36, "SIGCANCEL"), + (37, "SIGLOST"), + (38, "SIGXRES"), + (39, "SIGJVM1"), + (40, "SIGJVM2") +); + +#[cfg(target_os = "windows")] +signal_dict!((2, "SIGINT"), (21, "SIGBREAK")); diff --git a/tests/specs/npm/workspace_version_wildcards/__test__.jsonc b/tests/specs/npm/workspace_version_wildcards/__test__.jsonc new file mode 100644 index 0000000000..1dfb3dc6a5 --- /dev/null +++ b/tests/specs/npm/workspace_version_wildcards/__test__.jsonc @@ -0,0 +1,10 @@ +{ + "tempDir": true, + "steps": [{ + "args": "install", + "output": "[WILDCARD]" + }, { + "args": "run e/main.ts", + "output": "main.out" + }] +} diff --git a/tests/specs/npm/workspace_version_wildcards/a/mod.ts b/tests/specs/npm/workspace_version_wildcards/a/mod.ts new file mode 100644 index 0000000000..784e2aed80 --- /dev/null +++ b/tests/specs/npm/workspace_version_wildcards/a/mod.ts @@ -0,0 +1,3 @@ +export function sayHello() { + console.log("Hello from a!"); +} diff --git a/tests/specs/npm/workspace_version_wildcards/a/package.json b/tests/specs/npm/workspace_version_wildcards/a/package.json new file mode 100644 index 0000000000..0b4b7cedc6 --- /dev/null +++ b/tests/specs/npm/workspace_version_wildcards/a/package.json @@ -0,0 +1,7 @@ +{ + "name": "@denotest/a", + "version": "1.0.0", + "exports": { + ".": "./mod.ts" + } +} diff --git a/tests/specs/npm/workspace_version_wildcards/b/mod.ts b/tests/specs/npm/workspace_version_wildcards/b/mod.ts new file mode 100644 index 0000000000..74b0441515 --- /dev/null +++ b/tests/specs/npm/workspace_version_wildcards/b/mod.ts @@ -0,0 +1,3 @@ +export function sayHello() { + console.log("Hello from b!"); +} diff --git a/tests/specs/npm/workspace_version_wildcards/b/package.json b/tests/specs/npm/workspace_version_wildcards/b/package.json new file mode 100644 index 0000000000..d01d890f72 --- /dev/null +++ b/tests/specs/npm/workspace_version_wildcards/b/package.json @@ -0,0 +1,7 @@ +{ + "name": "@denotest/b", + "version": "1.0.0", + "exports": { + ".": "./mod.ts" + } +} diff --git a/tests/specs/npm/workspace_version_wildcards/c/mod.ts b/tests/specs/npm/workspace_version_wildcards/c/mod.ts new file mode 100644 index 0000000000..462fbd398c --- /dev/null +++ b/tests/specs/npm/workspace_version_wildcards/c/mod.ts @@ -0,0 +1,3 @@ +export function sayHello() { + console.log("Hello from c!"); +} diff --git a/tests/specs/npm/workspace_version_wildcards/c/package.json b/tests/specs/npm/workspace_version_wildcards/c/package.json new file mode 100644 index 0000000000..caf23c77cd --- /dev/null +++ b/tests/specs/npm/workspace_version_wildcards/c/package.json @@ -0,0 +1,7 @@ +{ + "name": "@denotest/c", + "version": "1.0.0", + "exports": { + ".": "./mod.ts" + } +} diff --git a/tests/specs/npm/workspace_version_wildcards/d/mod.ts b/tests/specs/npm/workspace_version_wildcards/d/mod.ts new file mode 100644 index 0000000000..a21866ee89 --- /dev/null +++ b/tests/specs/npm/workspace_version_wildcards/d/mod.ts @@ -0,0 +1,3 @@ +export function sayHello() { + console.log("Hello from d!"); +} diff --git a/tests/specs/npm/workspace_version_wildcards/d/package.json b/tests/specs/npm/workspace_version_wildcards/d/package.json new file mode 100644 index 0000000000..b908366c25 --- /dev/null +++ b/tests/specs/npm/workspace_version_wildcards/d/package.json @@ -0,0 +1,7 @@ +{ + "name": "@denotest/d", + "version": "1.2.3", + "exports": { + ".": "./mod.ts" + } +} diff --git a/tests/specs/npm/workspace_version_wildcards/e/main.ts b/tests/specs/npm/workspace_version_wildcards/e/main.ts new file mode 100644 index 0000000000..c626db09e8 --- /dev/null +++ b/tests/specs/npm/workspace_version_wildcards/e/main.ts @@ -0,0 +1,9 @@ +import * as a from "@denotest/a"; +import * as b from "@denotest/b"; +import * as c from "@denotest/c"; +import * as d from "@denotest/d"; + +a.sayHello(); +b.sayHello(); +c.sayHello(); +d.sayHello(); diff --git a/tests/specs/npm/workspace_version_wildcards/e/package.json b/tests/specs/npm/workspace_version_wildcards/e/package.json new file mode 100644 index 0000000000..9dca2bb729 --- /dev/null +++ b/tests/specs/npm/workspace_version_wildcards/e/package.json @@ -0,0 +1,10 @@ +{ + "name": "@denotest/e", + "version": "1.0.0", + "dependencies": { + "@denotest/a": "workspace:*", + "@denotest/b": "workspace:~", + "@denotest/c": "workspace:^", + "@denotest/d": "workspace:1.2.3" + } +} diff --git a/tests/specs/npm/workspace_version_wildcards/main.out b/tests/specs/npm/workspace_version_wildcards/main.out new file mode 100644 index 0000000000..ac501447e5 --- /dev/null +++ b/tests/specs/npm/workspace_version_wildcards/main.out @@ -0,0 +1,4 @@ +Hello from a! +Hello from b! +Hello from c! +Hello from d! diff --git a/tests/specs/npm/workspace_version_wildcards/main.ts b/tests/specs/npm/workspace_version_wildcards/main.ts new file mode 100644 index 0000000000..316503b9ca --- /dev/null +++ b/tests/specs/npm/workspace_version_wildcards/main.ts @@ -0,0 +1,6 @@ +// should resolve these as bare specifiers within the workspace +import * as a from "@denotest/a"; +import * as c from "@denotest/c"; + +a.sayHello(); +c.sayHello(); diff --git a/tests/specs/npm/workspace_version_wildcards/package.json b/tests/specs/npm/workspace_version_wildcards/package.json new file mode 100644 index 0000000000..0516fa6921 --- /dev/null +++ b/tests/specs/npm/workspace_version_wildcards/package.json @@ -0,0 +1,9 @@ +{ + "workspaces": [ + "./a", + "./b", + "./c", + "./d", + "./e" + ] +} diff --git a/tests/specs/task/signals/__test__.jsonc b/tests/specs/task/signals/__test__.jsonc new file mode 100644 index 0000000000..69801c46bf --- /dev/null +++ b/tests/specs/task/signals/__test__.jsonc @@ -0,0 +1,8 @@ +{ + // signals don't really exist on windows + "if": "unix", + // this runs a deno task + "args": "run -A --check sender.ts", + // just ensure this doesn't hang and completes successfully + "output": "[WILDCARD]" +} diff --git a/tests/specs/task/signals/deno.jsonc b/tests/specs/task/signals/deno.jsonc new file mode 100644 index 0000000000..18057558ee --- /dev/null +++ b/tests/specs/task/signals/deno.jsonc @@ -0,0 +1,5 @@ +{ + "tasks": { + "listener": "deno run listener.ts" + } +} diff --git a/tests/specs/task/signals/listener.ts b/tests/specs/task/signals/listener.ts new file mode 100644 index 0000000000..e4f54c2117 --- /dev/null +++ b/tests/specs/task/signals/listener.ts @@ -0,0 +1,16 @@ +import { signals } from "./signals.ts"; + +for (const signal of signals) { + Deno.addSignalListener(signal, () => { + console.log("Received", signal); + if (signal === "SIGTERM") { + Deno.exit(0); + } + }); +} + +setInterval(() => { + // keep alive +}, 1000); + +console.log("Ready"); diff --git a/tests/specs/task/signals/sender.ts b/tests/specs/task/signals/sender.ts new file mode 100644 index 0000000000..70f4dd788d --- /dev/null +++ b/tests/specs/task/signals/sender.ts @@ -0,0 +1,55 @@ +import { signals } from "./signals.ts"; + +class StdoutReader { + readonly #reader: ReadableStreamDefaultReader; + #text = ""; + + constructor(stream: ReadableStream) { + const textStream = stream.pipeThrough(new TextDecoderStream()); + this.#reader = textStream.getReader(); + } + + [Symbol.dispose]() { + this.#reader.releaseLock(); + } + + async waitForText(waitingText: string) { + if (this.#text.includes(waitingText)) { + return; + } + + while (true) { + const { value, done } = await this.#reader.read(); + if (value) { + this.#text += value; + if (this.#text.includes(waitingText)) { + break; + } + } + if (done) { + throw new Error("Did not find text: " + waitingText); + } + } + } +} + +const command = new Deno.Command(Deno.execPath(), { + args: ["task", "listener"], + stdout: "piped", +}); + +const child = command.spawn(); +const reader = new StdoutReader(child.stdout!); +await reader.waitForText("Ready"); + +for (const signal of signals) { + if (signal === "SIGTERM") { + continue; + } + console.error("Sending", signal); + child.kill(signal); + await reader.waitForText("Received " + signal); +} + +console.error("Sending SIGTERM"); +child.kill("SIGTERM"); diff --git a/tests/specs/task/signals/signals.ts b/tests/specs/task/signals/signals.ts new file mode 100644 index 0000000000..dd05ee1d17 --- /dev/null +++ b/tests/specs/task/signals/signals.ts @@ -0,0 +1,65 @@ +const signals = [ + "SIGABRT", + "SIGALRM", + "SIGBUS", + "SIGCHLD", + "SIGCONT", + "SIGEMT", + "SIGFPE", + "SIGHUP", + "SIGILL", + "SIGINFO", + "SIGINT", + "SIGIO", + "SIGPOLL", + "SIGPIPE", + "SIGPROF", + "SIGPWR", + "SIGQUIT", + "SIGSEGV", + "SIGSTKFLT", + "SIGSYS", + "SIGTERM", + "SIGTRAP", + "SIGTSTP", + "SIGTTIN", + "SIGTTOU", + "SIGURG", + "SIGUSR1", + "SIGUSR2", + "SIGVTALRM", + "SIGWINCH", + "SIGXCPU", + "SIGXFSZ", +] as const; + +// SIGKILL and SIGSTOP are not stoppable, SIGBREAK is for windows, and SIGUNUSED is not defined +type SignalsToTest = Exclude< + Deno.Signal, + "SIGKILL" | "SIGSTOP" | "SIGBREAK" | "SIGUNUSED" +>; +type EnsureAllSignalsIncluded = SignalsToTest extends typeof signals[number] + ? typeof signals[number] extends SignalsToTest ? true + : never + : never; +const _checkSignals: EnsureAllSignalsIncluded = true; + +const osSpecificSignals = signals.filter((s) => { + switch (s) { + case "SIGEMT": + return Deno.build.os === "darwin"; + case "SIGINFO": + case "SIGFPE": + case "SIGILL": + case "SIGSEGV": + return Deno.build.os === "freebsd"; + case "SIGPOLL": + case "SIGPWR": + case "SIGSTKFLT": + return Deno.build.os === "linux"; + default: + return true; + } +}); + +export { osSpecificSignals as signals };