1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-02 20:38:47 -05:00

fix: support workspace:^ and workspace:~ version constraints (#27096)

This commit adds support for understanding "workpace:^"
and "workspace:~" version constraints in npm/pnpm workspaces.

This is done by upgrading various crates to their latest versions.

Closes https://github.com/denoland/deno/issues/26726

---------

Co-authored-by: David Sherret <dsherret@gmail.com>
This commit is contained in:
Bartek Iwańczuk 2024-11-29 23:54:26 +00:00 committed by GitHub
parent f6248601f4
commit 1d49b3cb0f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 766 additions and 342 deletions

229
Cargo.lock generated
View file

@ -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,14 +1425,14 @@ dependencies = [
"deno_webgpu",
"image",
"serde",
"thiserror",
"thiserror 1.0.64",
]
[[package]]
name = "deno_config"
version = "0.39.2"
version = "0.39.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38fb809500238be2b10eee42944a47b3ac38974e1edbb47f73afcfca7df143bf"
checksum = "ce717af3fe6788dae63965d58d5637fd62be8fe4f345f189137ffc06c51837d2"
dependencies = [
"anyhow",
"deno_package_json",
@ -1447,7 +1448,7 @@ dependencies = [
"phf",
"serde",
"serde_json",
"thiserror",
"thiserror 1.0.64",
"url",
]
@ -1508,7 +1509,7 @@ dependencies = [
"chrono",
"deno_core",
"saffron",
"thiserror",
"thiserror 1.0.64",
"tokio",
]
@ -1543,7 +1544,7 @@ dependencies = [
"sha2",
"signature",
"spki",
"thiserror",
"thiserror 1.0.64",
"tokio",
"uuid",
"x25519-dalek",
@ -1551,9 +1552,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",
@ -1578,6 +1579,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"
@ -1602,7 +1626,7 @@ dependencies = [
"rustls-webpki",
"serde",
"serde_json",
"thiserror",
"thiserror 1.0.64",
"tokio",
"tokio-rustls",
"tokio-socks",
@ -1627,7 +1651,7 @@ dependencies = [
"serde",
"serde-value",
"serde_json",
"thiserror",
"thiserror 1.0.64",
"tokio",
"winapi",
]
@ -1650,16 +1674,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",
@ -1679,7 +1703,7 @@ dependencies = [
"serde",
"serde_json",
"sha2",
"thiserror",
"thiserror 2.0.3",
"twox-hash",
"url",
"wasm_dep_analyzer",
@ -1719,7 +1743,7 @@ dependencies = [
"scopeguard",
"serde",
"smallvec",
"thiserror",
"thiserror 1.0.64",
"tokio",
"tokio-util",
]
@ -1773,15 +1797,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",
@ -1797,14 +1821,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]]
@ -1829,7 +1853,7 @@ dependencies = [
"libuv-sys-lite",
"log",
"napi_sym",
"thiserror",
"thiserror 1.0.64",
"windows-sys 0.52.0",
]
@ -1859,7 +1883,7 @@ dependencies = [
"rustls-tokio-stream",
"serde",
"socket2",
"thiserror",
"thiserror 1.0.64",
"tokio",
]
@ -1943,7 +1967,7 @@ dependencies = [
"sm3",
"spki",
"stable_deref_trait",
"thiserror",
"thiserror 1.0.64",
"tokio",
"tokio-eld",
"url",
@ -1957,9 +1981,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",
@ -1970,7 +1994,7 @@ dependencies = [
"monch",
"serde",
"serde_json",
"thiserror",
"thiserror 2.0.3",
"url",
]
@ -1987,20 +2011,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",
]
@ -2011,7 +2037,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff25f6e08e7a0214bbacdd6f7195c7f1ebcd850c87a624e4ff06326b68b42d99"
dependencies = [
"percent-encoding",
"thiserror",
"thiserror 1.0.64",
"url",
]
@ -2028,7 +2054,7 @@ dependencies = [
"once_cell",
"percent-encoding",
"serde",
"thiserror",
"thiserror 1.0.64",
"which 4.4.2",
"winapi",
]
@ -2048,7 +2074,7 @@ dependencies = [
"deno_semver",
"node_resolver",
"test_server",
"thiserror",
"thiserror 1.0.64",
"url",
]
@ -2111,7 +2137,7 @@ dependencies = [
"signal-hook-registry",
"tempfile",
"test_server",
"thiserror",
"thiserror 1.0.64",
"tokio",
"tokio-metrics",
"twox-hash",
@ -2123,14 +2149,15 @@ 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",
]
@ -2147,7 +2174,7 @@ dependencies = [
"nix",
"os_pipe",
"path-dedot",
"thiserror",
"thiserror 1.0.64",
"tokio",
]
@ -2203,7 +2230,7 @@ dependencies = [
"rustls-tokio-stream",
"rustls-webpki",
"serde",
"thiserror",
"thiserror 1.0.64",
"tokio",
"webpki-roots",
]
@ -2249,7 +2276,7 @@ dependencies = [
"deno_console",
"deno_core",
"deno_webidl",
"thiserror",
"thiserror 1.0.64",
"urlpattern",
]
@ -2270,7 +2297,7 @@ dependencies = [
"flate2",
"futures",
"serde",
"thiserror",
"thiserror 1.0.64",
"tokio",
"uuid",
]
@ -2282,7 +2309,7 @@ dependencies = [
"deno_core",
"raw-window-handle",
"serde",
"thiserror",
"thiserror 1.0.64",
"tokio",
"wgpu-core",
"wgpu-types",
@ -2314,7 +2341,7 @@ dependencies = [
"once_cell",
"rustls-tokio-stream",
"serde",
"thiserror",
"thiserror 1.0.64",
"tokio",
]
@ -2325,7 +2352,7 @@ dependencies = [
"deno_core",
"deno_web",
"rusqlite",
"thiserror",
"thiserror 1.0.64",
]
[[package]]
@ -2397,7 +2424,7 @@ dependencies = [
"rand",
"rusqlite",
"serde_json",
"thiserror",
"thiserror 1.0.64",
"tokio",
"tokio-stream",
"uuid",
@ -2690,9 +2717,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",
@ -2838,7 +2865,7 @@ dependencies = [
"debug-ignore",
"indexmap 2.3.0",
"log",
"thiserror",
"thiserror 1.0.64",
"zerocopy",
]
@ -2998,7 +3025,7 @@ dependencies = [
"anyhow",
"async-trait",
"log",
"thiserror",
"thiserror 1.0.64",
"tokio",
"tokio-stream",
]
@ -3033,7 +3060,7 @@ dependencies = [
"rand",
"sha1",
"simdutf8",
"thiserror",
"thiserror 1.0.64",
"tokio",
"utf-8",
]
@ -3091,7 +3118,7 @@ dependencies = [
"deno_terminal 0.1.1",
"parking_lot",
"regex",
"thiserror",
"thiserror 1.0.64",
]
[[package]]
@ -3565,7 +3592,7 @@ dependencies = [
"pest_derive",
"serde",
"serde_json",
"thiserror",
"thiserror 1.0.64",
]
[[package]]
@ -3651,7 +3678,7 @@ dependencies = [
"once_cell",
"radix_trie",
"rand",
"thiserror",
"thiserror 1.0.64",
"tokio",
"tracing",
]
@ -3674,7 +3701,7 @@ dependencies = [
"once_cell",
"rand",
"serde",
"thiserror",
"thiserror 1.0.64",
"tinyvec",
"tokio",
"tracing",
@ -3698,7 +3725,7 @@ dependencies = [
"resolv-conf",
"serde",
"smallvec",
"thiserror",
"thiserror 1.0.64",
"tokio",
"tracing",
]
@ -3716,7 +3743,7 @@ dependencies = [
"futures-util",
"hickory-proto",
"serde",
"thiserror",
"thiserror 1.0.64",
"time",
"tokio",
"tokio-util",
@ -4156,7 +4183,7 @@ dependencies = [
"percent-encoding",
"serde",
"serde_json",
"thiserror",
"thiserror 1.0.64",
"url",
]
@ -4362,7 +4389,7 @@ dependencies = [
"anyhow",
"serde",
"serde_json",
"thiserror",
"thiserror 1.0.64",
"uuid",
]
@ -4812,7 +4839,7 @@ dependencies = [
"serde",
"spirv",
"termcolor",
"thiserror",
"thiserror 1.0.64",
"unicode-xid",
]
@ -4902,7 +4929,7 @@ dependencies = [
"path-clean",
"regex",
"serde_json",
"thiserror",
"thiserror 1.0.64",
"tokio",
"url",
]
@ -5099,7 +5126,7 @@ dependencies = [
"js-sys",
"once_cell",
"pin-project-lite",
"thiserror",
"thiserror 1.0.64",
]
[[package]]
@ -5129,7 +5156,7 @@ dependencies = [
"opentelemetry_sdk",
"prost",
"serde_json",
"thiserror",
"thiserror 1.0.64",
"tokio",
"tonic",
"tracing",
@ -5171,7 +5198,7 @@ dependencies = [
"percent-encoding",
"rand",
"serde_json",
"thiserror",
"thiserror 1.0.64",
"tracing",
]
@ -5355,7 +5382,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "311fb059dee1a7b802f036316d790138c613a4e8b180c822e3925a662e9f0c95"
dependencies = [
"memchr",
"thiserror",
"thiserror 1.0.64",
"ucd-trie",
]
@ -5769,7 +5796,7 @@ dependencies = [
"indexmap 2.3.0",
"quick-xml",
"strip-ansi-escapes",
"thiserror",
"thiserror 1.0.64",
"uuid",
]
@ -5794,7 +5821,7 @@ dependencies = [
"quinn-udp",
"rustc-hash 1.1.0",
"rustls",
"thiserror",
"thiserror 1.0.64",
"tokio",
"tracing",
]
@ -5811,7 +5838,7 @@ dependencies = [
"rustc-hash 2.0.0",
"rustls",
"slab",
"thiserror",
"thiserror 1.0.64",
"tinyvec",
"tracing",
]
@ -5960,7 +5987,7 @@ checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891"
dependencies = [
"getrandom",
"libredox",
"thiserror",
"thiserror 1.0.64",
]
[[package]]
@ -6584,7 +6611,7 @@ dependencies = [
"num-bigint",
"serde",
"smallvec",
"thiserror",
"thiserror 1.0.64",
"v8",
]
@ -7587,7 +7614,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]]
@ -7601,6 +7637,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"
@ -7753,7 +7800,7 @@ checksum = "51165dfa029d2a65969413a6cc96f354b86b464498702f174a4efa13608fd8c0"
dependencies = [
"either",
"futures-util",
"thiserror",
"thiserror 1.0.64",
"tokio",
]
@ -8170,7 +8217,7 @@ dependencies = [
"indexmap 2.3.0",
"num-bigint",
"serde",
"thiserror",
"thiserror 1.0.64",
"wtf8",
]
@ -8342,7 +8389,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f270206a91783fd90625c8bb0d8fbd459d0b1d1bf209b656f713f01ae7c04b8"
dependencies = [
"thiserror",
"thiserror 1.0.64",
]
[[package]]
@ -8396,7 +8443,7 @@ dependencies = [
"rustc-hash 1.1.0",
"serde",
"smallvec",
"thiserror",
"thiserror 1.0.64",
"web-sys",
"wgpu-hal",
"wgpu-types",
@ -8437,7 +8484,7 @@ dependencies = [
"raw-window-handle",
"rustc-hash 1.1.0",
"smallvec",
"thiserror",
"thiserror 1.0.64",
"wasm-bindgen",
"web-sys",
"wgpu-types",
@ -8503,7 +8550,7 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b2b1bf557d947847a30eb73f79aa6cdb3eaf3ce02f5e9599438f77896a62b3c"
dependencies = [
"thiserror",
"thiserror 1.0.64",
"windows",
]
@ -8785,7 +8832,7 @@ dependencies = [
"nom 7.1.3",
"oid-registry",
"rusticata-macros",
"thiserror",
"thiserror 1.0.64",
"time",
]
@ -8929,7 +8976,7 @@ dependencies = [
"parking_lot",
"rand",
"regex",
"thiserror",
"thiserror 1.0.64",
"tokio",
"tokio-util",
"uuid",
@ -8970,7 +9017,7 @@ dependencies = [
"flate2",
"indexmap 2.3.0",
"memchr",
"thiserror",
"thiserror 1.0.64",
]
[[package]]

View file

@ -46,18 +46,18 @@ 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" }
deno_config = { version = "=0.39.2", features = ["workspace", "sync"] }
deno_lockfile = "=0.23.1"
deno_config = { version = "=0.39.3", 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" }
@ -115,8 +115,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"] }

View file

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

View file

@ -18,12 +18,10 @@ impl<'a> deno_config::fs::DenoConfigFs for DenoConfigFsAdapter<'a> {
fn read_to_string_lossy(
&self,
path: &std::path::Path,
) -> Result<String, std::io::Error> {
) -> Result<std::borrow::Cow<'static, str>, 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())
}

View file

@ -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) => {

View file

@ -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)
}) {

15
cli/cache/mod.rs vendored
View file

@ -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<Vec<u8>> {
std::fs::read(path)
fn read_file_bytes(
&self,
path: &Path,
) -> std::io::Result<Cow<'static, [u8]>> {
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<Vec<u8>> {
fn read_file_bytes(
&self,
path: &Path,
) -> std::io::Result<Cow<'static, [u8]>> {
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())
}

View file

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

View file

@ -1540,7 +1540,7 @@ mod tests {
.unwrap()
.unwrap()
.content;
String::from_utf8(bytes).unwrap()
String::from_utf8(bytes.into_owned()).unwrap()
}
#[track_caller]

View file

@ -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;
@ -2092,7 +2093,7 @@ impl<T: Clone> CachedFsItems<T> {
#[derive(Default)]
struct InnerData {
stat_calls: CachedFsItems<deno_config::fs::FsMetadata>,
read_to_string_calls: CachedFsItems<String>,
read_to_string_calls: CachedFsItems<Cow<'static, str>>,
}
#[derive(Default)]
@ -2113,7 +2114,7 @@ impl DenoConfigFs for CachedDenoConfigFs {
fn read_to_string_lossy(
&self,
path: &Path,
) -> Result<String, std::io::Error> {
) -> Result<Cow<'static, str>, std::io::Error> {
self
.0
.lock()

View file

@ -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()?;

View file

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

View file

@ -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<Cow<'_, str>> {
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"))
}

View file

@ -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(),
));

View file

@ -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<PackageJsonDepValue, PackageJsonDepValueParseError> {
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<String, String>>,
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<ConfigFile>,
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<Dep>,
) {
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<Dep>,
) {
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(

View file

@ -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<deno_ast::diagnostics::DiagnosticSnippet<'_>> {
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<Cow<'_, str>> {
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<deno_ast::diagnostics::DiagnosticSnippet<'_>> {
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<Cow<'_, str>> {
None
}
}
enum UnfurlSpecifierError {
Workspace {
package_name: String,
reason: String,
},
}
pub struct SpecifierUnfurler {
sloppy_imports_resolver: Option<CliSloppyImportsResolver>,
workspace_resolver: WorkspaceResolver,
sloppy_imports_resolver: Option<Arc<CliSloppyImportsResolver>>,
workspace_resolver: Arc<WorkspaceResolver>,
bare_node_builtins: bool,
}
impl SpecifierUnfurler {
pub fn new(
sloppy_imports_resolver: Option<CliSloppyImportsResolver>,
workspace_resolver: WorkspaceResolver,
sloppy_imports_resolver: Option<Arc<CliSloppyImportsResolver>>,
workspace_resolver: Arc<WorkspaceResolver>,
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<String> {
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<String> {
) -> Result<Option<String>, 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<Version, anyhow::Error> {
// 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<deno_ast::TextChange>,
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<deno_ast::TextChange>| {
if let Some(unfurled) = self.unfurl_specifier(url, specifier) {
text_changes: &mut Vec<deno_ast::TextChange>,
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);
}
}
}

View file

@ -872,12 +872,10 @@ impl deno_package_json::fs::DenoPkgJsonFs for DenoFsNodeResolverEnv {
fn read_to_string_lossy(
&self,
path: &std::path::Path,
) -> Result<String, std::io::Error> {
) -> Result<Cow<'static, str>, 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<String, std::io::Error> {
) -> Result<Cow<'static, str>, 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())
}
}

View file

@ -179,7 +179,11 @@ impl<Fs: DenoResolverFs, TEnv: NodeResolverEnv> ByonmNpmResolver<Fs, TEnv> {
pkg_json: &PackageJson,
) -> Option<String> {
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) => {

View file

@ -0,0 +1,10 @@
{
"tempDir": true,
"steps": [{
"args": "install",
"output": "[WILDCARD]"
}, {
"args": "run e/main.ts",
"output": "main.out"
}]
}

View file

@ -0,0 +1,3 @@
export function sayHello() {
console.log("Hello from a!");
}

View file

@ -0,0 +1,7 @@
{
"name": "@denotest/a",
"version": "1.0.0",
"exports": {
".": "./mod.ts"
}
}

View file

@ -0,0 +1,3 @@
export function sayHello() {
console.log("Hello from b!");
}

View file

@ -0,0 +1,7 @@
{
"name": "@denotest/b",
"version": "1.0.0",
"exports": {
".": "./mod.ts"
}
}

View file

@ -0,0 +1,3 @@
export function sayHello() {
console.log("Hello from c!");
}

View file

@ -0,0 +1,7 @@
{
"name": "@denotest/c",
"version": "1.0.0",
"exports": {
".": "./mod.ts"
}
}

View file

@ -0,0 +1,3 @@
export function sayHello() {
console.log("Hello from d!");
}

View file

@ -0,0 +1,7 @@
{
"name": "@denotest/d",
"version": "1.2.3",
"exports": {
".": "./mod.ts"
}
}

View file

@ -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();

View file

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

View file

@ -0,0 +1,4 @@
Hello from a!
Hello from b!
Hello from c!
Hello from d!

View file

@ -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();

View file

@ -0,0 +1,9 @@
{
"workspaces": [
"./a",
"./b",
"./c",
"./d",
"./e"
]
}