diff --git a/Cargo.lock b/Cargo.lock
index 2829a11b71..9f7febad24 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -62,17 +62,6 @@ dependencies = [
  "aes",
 ]
 
-[[package]]
-name = "ahash"
-version = "0.7.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
-dependencies = [
- "getrandom 0.2.10",
- "once_cell",
- "version_check",
-]
-
 [[package]]
 name = "ahash"
 version = "0.8.3"
@@ -225,15 +214,15 @@ dependencies = [
 
 [[package]]
 name = "ast_node"
-version = "0.9.4"
+version = "0.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c704e2f6ee1a98223f5a7629a6ef0f3decb3b552ed282889dc957edff98ce1e6"
+checksum = "c09c69dffe06d222d072c878c3afe86eee2179806f20503faec97250268b4c24"
 dependencies = [
- "pmutil 0.5.3",
+ "pmutil",
  "proc-macro2 1.0.66",
  "quote 1.0.32",
  "swc_macros_common",
- "syn 1.0.109",
+ "syn 2.0.28",
 ]
 
 [[package]]
@@ -306,6 +295,18 @@ dependencies = [
  "syn 1.0.109",
 ]
 
+[[package]]
+name = "auto_impl"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89"
+dependencies = [
+ "proc-macro-error",
+ "proc-macro2 1.0.66",
+ "quote 1.0.32",
+ "syn 1.0.109",
+]
+
 [[package]]
 name = "autocfg"
 version = "1.1.0"
@@ -366,9 +367,9 @@ checksum = "7dfdb4953a096c551ce9ace855a604d702e6e62d77fac690575ae347571717f5"
 
 [[package]]
 name = "better_scoped_tls"
-version = "0.1.0"
+version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b73e8ecdec39e98aa3b19e8cd0b8ed8f77ccb86a6b0b2dc7cd86d105438a2123"
+checksum = "794edcc9b3fb07bb4aecaa11f093fd45663b4feadb782d68303a2268bc2701de"
 dependencies = [
  "scoped-tls",
 ]
@@ -405,9 +406,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bitflags"
-version = "2.1.0"
+version = "2.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c70beb79cbb5ce9c4f8e20849978f34225931f665bb49efa6982875a4d5facb3"
+checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
 
 [[package]]
 name = "block-buffer"
@@ -836,7 +837,7 @@ dependencies = [
  "http",
  "hyper 0.14.26",
  "import_map",
- "indexmap 1.9.2",
+ "indexmap 1.9.3",
  "jsonc-parser",
  "junction",
  "lazy-regex",
@@ -907,9 +908,9 @@ dependencies = [
 
 [[package]]
 name = "deno_ast"
-version = "0.27.0"
+version = "0.28.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db178e9f423fe41ff3580e32c43bc13726a5730360ef04e50b84de683a24f7d9"
+checksum = "00c93119b1c487a85603406a988a0ca9a1d0e5315404cccc5c158fb484b1f5a2"
 dependencies = [
  "anyhow",
  "base64 0.13.1",
@@ -919,6 +920,8 @@ dependencies = [
  "swc_atoms",
  "swc_bundler",
  "swc_common",
+ "swc_config",
+ "swc_config_macro",
  "swc_ecma_ast",
  "swc_ecma_codegen",
  "swc_ecma_codegen_macros",
@@ -928,11 +931,17 @@ dependencies = [
  "swc_ecma_transforms_base",
  "swc_ecma_transforms_classes",
  "swc_ecma_transforms_macros",
+ "swc_ecma_transforms_optimization",
  "swc_ecma_transforms_proposal",
  "swc_ecma_transforms_react",
  "swc_ecma_transforms_typescript",
  "swc_ecma_utils",
  "swc_ecma_visit",
+ "swc_eq_ignore_macros",
+ "swc_graph_analyzer",
+ "swc_macros_common",
+ "swc_visit",
+ "swc_visit_macros",
  "text_lines",
  "url",
 ]
@@ -1005,7 +1014,7 @@ dependencies = [
  "bytes",
  "deno_ops",
  "futures",
- "indexmap 1.9.2",
+ "indexmap 1.9.3",
  "libc",
  "log",
  "once_cell",
@@ -1057,9 +1066,9 @@ dependencies = [
 
 [[package]]
 name = "deno_doc"
-version = "0.64.0"
+version = "0.65.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c25d38dc94e4c2190bc7a1851790dd142fd0068888b3a26a1acb958db5113829"
+checksum = "10bb7c24a702ae82d8eaee95a325a9853b951dd0e01bb4950dd427e61e4fd0fe"
 dependencies = [
  "cfg-if",
  "deno_ast",
@@ -1075,9 +1084,9 @@ dependencies = [
 
 [[package]]
 name = "deno_emit"
-version = "0.25.0"
+version = "0.26.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ef00ad78bc75e7f35a01bd4b5c32a97018eebc55c311e4b287e158a29021348"
+checksum = "10663feb7be359aa447e7be4bc76a25a2d470fc9dfa8cd1b09a0a3916e0586e0"
 dependencies = [
  "anyhow",
  "base64 0.13.1",
@@ -1142,16 +1151,16 @@ dependencies = [
 
 [[package]]
 name = "deno_graph"
-version = "0.50.0"
+version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73502c4d93a17f259b6edee6d5a5ba063e2fcdcdaeb6ca1c6953129cc14be6a7"
+checksum = "6acc743895f5e83c985d632998e58af1395c862b28acabd3d290540ef4d57354"
 dependencies = [
  "anyhow",
  "data-url",
  "deno_ast",
  "deno_semver",
  "futures",
- "indexmap 1.9.2",
+ "indexmap 1.9.3",
  "monch",
  "once_cell",
  "parking_lot 0.12.1",
@@ -1232,9 +1241,9 @@ dependencies = [
 
 [[package]]
 name = "deno_lint"
-version = "0.49.0"
+version = "0.50.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5900d62a2115735b3c59a3a6e201d62d8678c03a0a04b9fee2e69a3247afa90"
+checksum = "790851a7216be0460da0ca5b4faeef568b031a4e856a3bd86a8e27cdc3333a9d"
 dependencies = [
  "anyhow",
  "deno_ast",
@@ -1316,7 +1325,7 @@ dependencies = [
  "hex",
  "hkdf",
  "idna 0.3.0",
- "indexmap 1.9.2",
+ "indexmap 1.9.3",
  "lazy-regex",
  "libc",
  "libz-sys",
@@ -1354,9 +1363,9 @@ dependencies = [
 
 [[package]]
 name = "deno_npm"
-version = "0.11.0"
+version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "341f2c3935bee51c15203c587213c42d120f0dc56f0aca912a4bebbf038d1030"
+checksum = "c90198ae433bf22ac9b39fe5e18748d9d5b36db042ef1c24637f43d3b5e101e0"
 dependencies = [
  "anyhow",
  "async-trait",
@@ -1378,7 +1387,7 @@ dependencies = [
  "deno-proc-macro-rules",
  "lazy-regex",
  "once_cell",
- "pmutil 0.6.1",
+ "pmutil",
  "proc-macro-crate",
  "proc-macro2 1.0.66",
  "quote 1.0.32",
@@ -1447,9 +1456,9 @@ dependencies = [
 
 [[package]]
 name = "deno_semver"
-version = "0.3.0"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96f99990457915af1f444900003ffd5a9d3ab2e5337b06d681e56ca371b3e11f"
+checksum = "6f739a9d90c47e2af7e2fcbae0976360f3fb5292f7288a084d035ed44d12a288"
 dependencies = [
  "monch",
  "once_cell",
@@ -1460,9 +1469,9 @@ dependencies = [
 
 [[package]]
 name = "deno_task_shell"
-version = "0.13.1"
+version = "0.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba1dc995d5731f4431520037b53ce6a8bb88ec5e7baaf0627eb273335769cbbf"
+checksum = "4dbbad0a7ba06a961df3cd638ab117f5d67787607f627defa65629a4ef29d576"
 dependencies = [
  "anyhow",
  "futures",
@@ -1688,7 +1697,7 @@ checksum = "e6563addfa2b6c6fa96acdda0341090beba2c5c4ff6ef91f3a232a6d4dd34156"
 dependencies = [
  "anyhow",
  "bumpalo",
- "indexmap 1.9.2",
+ "indexmap 1.9.3",
  "rustc-hash",
  "serde",
  "unicode-width",
@@ -1723,9 +1732,9 @@ dependencies = [
 
 [[package]]
 name = "dprint-plugin-typescript"
-version = "0.86.1"
+version = "0.86.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ef1276e8b038bd3db5a3d8fd9be92941223b308b5edf26db927682f4612506b"
+checksum = "384b423bfa289e57a0fab8eadc5ced6a0890ccc3570258daf4a12b1d0412cfb9"
 dependencies = [
  "anyhow",
  "deno_ast",
@@ -1736,9 +1745,9 @@ dependencies = [
 
 [[package]]
 name = "dprint-swc-ext"
-version = "0.10.0"
+version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd4dda8a1b920e8be367aeaad035753d21bb69b3c50515afb41ab1eefbb886b5"
+checksum = "3f115ea5b6f5d0d02a25a9364f41b8c4f857452c299309dcfd29a694724d0566"
 dependencies = [
  "bumpalo",
  "num-bigint",
@@ -1969,9 +1978,9 @@ dependencies = [
 
 [[package]]
 name = "eszip"
-version = "0.49.0"
+version = "0.50.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b32387a359104b88abe2583679e6dcb817aff5534204ade9e4c4528db8079f3"
+checksum = "e254fcba0a6481f44fa41f41cb9027d811072e7e7fa94780ade4a7fa43b34c4b"
 dependencies = [
  "anyhow",
  "base64 0.21.0",
@@ -2126,23 +2135,23 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 
 [[package]]
 name = "form_urlencoded"
-version = "1.1.0"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
+checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
 dependencies = [
  "percent-encoding",
 ]
 
 [[package]]
 name = "from_variant"
-version = "0.1.5"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d449976075322384507443937df2f1d5577afbf4282f12a5a66ef29fa3e6307"
+checksum = "03ec5dc38ee19078d84a692b1c41181ff9f94331c76cee66ff0208c770b5e54f"
 dependencies = [
- "pmutil 0.5.3",
+ "pmutil",
  "proc-macro2 1.0.66",
  "swc_macros_common",
- "syn 1.0.109",
+ "syn 2.0.28",
 ]
 
 [[package]]
@@ -2375,7 +2384,7 @@ dependencies = [
  "futures-sink",
  "futures-util",
  "http",
- "indexmap 1.9.2",
+ "indexmap 1.9.3",
  "slab",
  "tokio",
  "tokio-util",
@@ -2394,7 +2403,7 @@ version = "0.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
 dependencies = [
- "ahash 0.8.3",
+ "ahash",
 ]
 
 [[package]]
@@ -2629,6 +2638,16 @@ dependencies = [
  "unicode-normalization",
 ]
 
+[[package]]
+name = "idna"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
+dependencies = [
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
 [[package]]
 name = "if_chain"
 version = "1.0.2"
@@ -2642,7 +2661,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "632089ec08bd62e807311104122fb26d5c911ab172e2b9864be154a575979e29"
 dependencies = [
  "cfg-if",
- "indexmap 1.9.2",
+ "indexmap 1.9.3",
  "log",
  "serde",
  "serde_json",
@@ -2651,9 +2670,9 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "1.9.2"
+version = "1.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
 dependencies = [
  "autocfg",
  "hashbrown 0.12.3",
@@ -2741,15 +2760,15 @@ checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146"
 
 [[package]]
 name = "is-macro"
-version = "0.2.2"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a7d079e129b77477a49c5c4f1cfe9ce6c2c909ef52520693e8e811a714c7b20"
+checksum = "f4467ed1321b310c2625c5aa6c1b1ffc5de4d9e42668cf697a08fb033ee8265e"
 dependencies = [
  "Inflector",
- "pmutil 0.5.3",
+ "pmutil",
  "proc-macro2 1.0.66",
  "quote 1.0.32",
- "syn 1.0.109",
+ "syn 2.0.28",
 ]
 
 [[package]]
@@ -2868,79 +2887,6 @@ dependencies = [
  "spin",
 ]
 
-[[package]]
-name = "lexical"
-version = "6.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7aefb36fd43fef7003334742cbf77b243fcd36418a1d1bdd480d613a67968f6"
-dependencies = [
- "lexical-core",
-]
-
-[[package]]
-name = "lexical-core"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2cde5de06e8d4c2faabc400238f9ae1c74d5412d03a7bd067645ccbc47070e46"
-dependencies = [
- "lexical-parse-float",
- "lexical-parse-integer",
- "lexical-util",
- "lexical-write-float",
- "lexical-write-integer",
-]
-
-[[package]]
-name = "lexical-parse-float"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "683b3a5ebd0130b8fb52ba0bdc718cc56815b6a097e28ae5a6997d0ad17dc05f"
-dependencies = [
- "lexical-parse-integer",
- "lexical-util",
- "static_assertions",
-]
-
-[[package]]
-name = "lexical-parse-integer"
-version = "0.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d0994485ed0c312f6d965766754ea177d07f9c00c9b82a5ee62ed5b47945ee9"
-dependencies = [
- "lexical-util",
- "static_assertions",
-]
-
-[[package]]
-name = "lexical-util"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5255b9ff16ff898710eb9eb63cb39248ea8a5bb036bea8085b1a767ff6c4e3fc"
-dependencies = [
- "static_assertions",
-]
-
-[[package]]
-name = "lexical-write-float"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "accabaa1c4581f05a3923d1b4cfd124c329352288b7b9da09e766b0668116862"
-dependencies = [
- "lexical-util",
- "lexical-write-integer",
- "static_assertions",
-]
-
-[[package]]
-name = "lexical-write-integer"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1b6f3d1f4422866b68192d62f77bc5c700bee84f3069f2469d7bc8c77852446"
-dependencies = [
- "lexical-util",
- "static_assertions",
-]
-
 [[package]]
 name = "libc"
 version = "0.2.147"
@@ -3163,9 +3109,9 @@ dependencies = [
 
 [[package]]
 name = "monch"
-version = "0.4.2"
+version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb73e1dc7d232e1ab47ef27f45fa1d173a0979b370e763a9d0584556011150e0"
+checksum = "4519a88847ba2d5ead3dc53f1060ec6a571de93f325d9c5c4968147382b1cbc3"
 
 [[package]]
 name = "napi-build"
@@ -3585,7 +3531,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4"
 dependencies = [
  "fixedbitset",
- "indexmap 1.9.2",
+ "indexmap 1.9.3",
 ]
 
 [[package]]
@@ -3702,17 +3648,6 @@ version = "0.3.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
 
-[[package]]
-name = "pmutil"
-version = "0.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3894e5d549cccbe44afecf72922f277f603cd4bb0219c8342631ef18fffbe004"
-dependencies = [
- "proc-macro2 1.0.66",
- "quote 1.0.32",
- "syn 1.0.109",
-]
-
 [[package]]
 name = "pmutil"
 version = "0.6.1"
@@ -4106,7 +4041,7 @@ version = "0.29.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2"
 dependencies = [
- "bitflags 2.1.0",
+ "bitflags 2.4.0",
  "fallible-iterator",
  "fallible-streaming-iterator",
  "hashlink",
@@ -4707,15 +4642,15 @@ dependencies = [
 
 [[package]]
 name = "string_enum"
-version = "0.4.0"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0090512bdfee4b56d82480d66c0fd8a6f53f0fe0f97e075e949b252acdd482e0"
+checksum = "8fa4d4f81d7c05b9161f8de839975d3326328b8ba2831164b465524cc2f55252"
 dependencies = [
- "pmutil 0.5.3",
+ "pmutil",
  "proc-macro2 1.0.66",
  "quote 1.0.32",
  "swc_macros_common",
- "syn 1.0.109",
+ "syn 2.0.28",
 ]
 
 [[package]]
@@ -4754,9 +4689,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
 
 [[package]]
 name = "swc_atoms"
-version = "0.5.6"
+version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93d0307dc4bfd107d49c7528350c372758cfca94fb503629b9a056e6a1572860"
+checksum = "b8066e17abb484602da673e2d35138ab32ce53f26368d9c92113510e1659220b"
 dependencies = [
  "once_cell",
  "rustc-hash",
@@ -4768,14 +4703,13 @@ dependencies = [
 
 [[package]]
 name = "swc_bundler"
-version = "0.214.25"
+version = "0.217.49"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "503d03f4eb44ae6a57154e4459d9a7050c56e0aa9ec798a93d21ca07a8dd0409"
+checksum = "ce78d316b33559330cb4348144bbd03181369aa62049f540d792c220ed389570"
 dependencies = [
- "ahash 0.7.6",
  "anyhow",
  "crc",
- "indexmap 1.9.2",
+ "indexmap 1.9.3",
  "is-macro",
  "once_cell",
  "parking_lot 0.12.1",
@@ -4799,11 +4733,10 @@ dependencies = [
 
 [[package]]
 name = "swc_common"
-version = "0.31.12"
+version = "0.31.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19c774005489d2907fb67909cf42af926e72edee1366512777c605ba2ef19c94"
+checksum = "de5823ef063f116ad281cde9700f5be6dfb182e543ce3f62c42cee1c03ffbc6b"
 dependencies = [
- "ahash 0.7.6",
  "ast_node",
  "better_scoped_tls",
  "cfg-if",
@@ -4827,11 +4760,11 @@ dependencies = [
 
 [[package]]
 name = "swc_config"
-version = "0.1.5"
+version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89c8fc2c12bb1634c7c32fc3c9b6b963ad8f034cc62c4ecddcf215dc4f6f959d"
+checksum = "9ba1c7a40d38f9dd4e9a046975d3faf95af42937b34b2b963be4d8f01239584b"
 dependencies = [
- "indexmap 1.9.2",
+ "indexmap 1.9.3",
  "serde",
  "serde_json",
  "swc_config_macro",
@@ -4839,24 +4772,24 @@ dependencies = [
 
 [[package]]
 name = "swc_config_macro"
-version = "0.1.1"
+version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7dadb9998d4f5fc36ef558ed5a092579441579ee8c6fcce84a5228cca9df4004"
+checksum = "e5b5aaca9a0082be4515f0fbbecc191bf5829cd25b5b9c0a2810f6a2bb0d6829"
 dependencies = [
- "pmutil 0.5.3",
+ "pmutil",
  "proc-macro2 1.0.66",
  "quote 1.0.32",
  "swc_macros_common",
- "syn 1.0.109",
+ "syn 2.0.28",
 ]
 
 [[package]]
 name = "swc_ecma_ast"
-version = "0.104.5"
+version = "0.107.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5cf9dd351d0c285dcd36535267953a18995d4dda0cbe34ac9d1df61aa415b26"
+checksum = "b7191c8c57af059b75a2aadc927a2608c3962d19e4d09ce8f9c3f03739ddf833"
 dependencies = [
- "bitflags 2.1.0",
+ "bitflags 2.4.0",
  "is-macro",
  "num-bigint",
  "scoped-tls",
@@ -4869,9 +4802,9 @@ dependencies = [
 
 [[package]]
 name = "swc_ecma_codegen"
-version = "0.139.15"
+version = "0.142.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11c6af8e6d6714ecd7ef5cfba322aa1b436f78d9a82b0c3ff16aeaf97b65cd6d"
+checksum = "1e4e3ee8a1f0bfaf630febbe0f6a03f2c28d66d373a9bbdb3f500f6bfb536b43"
 dependencies = [
  "memchr",
  "num-bigint",
@@ -4888,22 +4821,22 @@ dependencies = [
 
 [[package]]
 name = "swc_ecma_codegen_macros"
-version = "0.7.2"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf4ee0caee1018808d94ecd09490cb7affd3d504b19aa11c49238f5fc4b54901"
+checksum = "dcdff076dccca6cc6a0e0b2a2c8acfb066014382bc6df98ec99e755484814384"
 dependencies = [
- "pmutil 0.5.3",
+ "pmutil",
  "proc-macro2 1.0.66",
  "quote 1.0.32",
  "swc_macros_common",
- "syn 1.0.109",
+ "syn 2.0.28",
 ]
 
 [[package]]
 name = "swc_ecma_dep_graph"
-version = "0.106.12"
+version = "0.109.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3130754aba396ad8d849f3fd1a9949d71a33c0943dfd86b23ac595e81fabd0c"
+checksum = "1295557b5960eb97ec63fc2008be0a101d1ff7d2163a1031b3d31d3c898d5bb3"
 dependencies = [
  "swc_atoms",
  "swc_common",
@@ -4913,11 +4846,10 @@ dependencies = [
 
 [[package]]
 name = "swc_ecma_loader"
-version = "0.43.14"
+version = "0.43.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe45f1e5dcc1b005544ff78253b787dea5dfd5e2f712b133964cdc3545c954a4"
+checksum = "82f47bb1ab686f603da93a8b6e559d69b42369ab47d5dee6bdda38ae5902dc2a"
 dependencies = [
- "ahash 0.7.6",
  "anyhow",
  "pathdiff",
  "serde",
@@ -4927,13 +4859,13 @@ dependencies = [
 
 [[package]]
 name = "swc_ecma_parser"
-version = "0.134.12"
+version = "0.137.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0a3fcfe3d83dd445cbd9321882e47b467594433d9a21c4d6c37a27f534bb89e"
+checksum = "29c0d554865a63bfa58cf1c433fa91d7d4adf40030fa8e4530e8065d0578166a"
 dependencies = [
  "either",
- "lexical",
  "num-bigint",
+ "num-traits",
  "serde",
  "smallvec",
  "smartstring",
@@ -4947,13 +4879,13 @@ dependencies = [
 
 [[package]]
 name = "swc_ecma_transforms_base"
-version = "0.127.16"
+version = "0.130.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6232e641bef05c462bc7da34a3771f9b3f1f3352349ae0cd72b8eee8b0f5d5e0"
+checksum = "d8d8ca5dd849cea79e6a9792d725f4082ad3ade7a9541fba960c42d55ae778f2"
 dependencies = [
  "better_scoped_tls",
- "bitflags 2.1.0",
- "indexmap 1.9.2",
+ "bitflags 2.4.0",
+ "indexmap 1.9.3",
  "once_cell",
  "phf",
  "rustc-hash",
@@ -4970,9 +4902,9 @@ dependencies = [
 
 [[package]]
 name = "swc_ecma_transforms_classes"
-version = "0.116.16"
+version = "0.119.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f086829a3e645382f5609c9c6dce1d29e5204b3c81f82fe8d65d3bf17bcca68b"
+checksum = "a09d0e350963d4fb14bf9dc31c85eb28e58a88614e779c75f49296710f9cb381"
 dependencies = [
  "swc_atoms",
  "swc_common",
@@ -4984,26 +4916,25 @@ dependencies = [
 
 [[package]]
 name = "swc_ecma_transforms_macros"
-version = "0.5.1"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "984d5ac69b681fc5438f9abf82b0fda34fe04e119bc75f8213b7e01128c7c9a2"
+checksum = "f59c4b6ed5d78d3ad9fc7c6f8ab4f85bba99573d31d9a2c0a712077a6b45efd2"
 dependencies = [
- "pmutil 0.5.3",
+ "pmutil",
  "proc-macro2 1.0.66",
  "quote 1.0.32",
  "swc_macros_common",
- "syn 1.0.109",
+ "syn 2.0.28",
 ]
 
 [[package]]
 name = "swc_ecma_transforms_optimization"
-version = "0.187.21"
+version = "0.190.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d27c12926427f235d149e60f9a9e67a2181fe1eb418c12b53b8e0778c5052a2"
+checksum = "93c2801884a19a5d35dd6ac6f7e7a3147502325337f3f7fd11cda7c7b4202007"
 dependencies = [
- "ahash 0.7.6",
  "dashmap",
- "indexmap 1.9.2",
+ "indexmap 1.9.3",
  "once_cell",
  "petgraph",
  "rustc-hash",
@@ -5022,9 +4953,9 @@ dependencies = [
 
 [[package]]
 name = "swc_ecma_transforms_proposal"
-version = "0.161.20"
+version = "0.164.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "416fbb84f84644ef0e81df80bf44fd575bbb297a78887e359e16a61f6dc5af86"
+checksum = "62d3a04de35f6c79d8f343822138e7313934d3530cc4e4f891a079f7e2415c1a"
 dependencies = [
  "either",
  "rustc-hash",
@@ -5042,14 +4973,13 @@ dependencies = [
 
 [[package]]
 name = "swc_ecma_transforms_react"
-version = "0.173.18"
+version = "0.176.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d39a0de45fa34ee797a1c80497c8b9dcb6cf6e56b455c163453399894c58a812"
+checksum = "607017e6fbfe3229b69ffce7b47383eb9b62025ea93a50cd1cc1788d2a29a4ca"
 dependencies = [
- "ahash 0.7.6",
  "base64 0.13.1",
  "dashmap",
- "indexmap 1.9.2",
+ "indexmap 1.9.3",
  "once_cell",
  "serde",
  "sha-1",
@@ -5067,9 +4997,9 @@ dependencies = [
 
 [[package]]
 name = "swc_ecma_transforms_typescript"
-version = "0.177.20"
+version = "0.180.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "340cc027a6e87966715005b94e3a7ac95baf76c80b8aedad8afdd1c134740c80"
+checksum = "ea349e787a62af0dcf1b8b52d507045345871571c18cb78a2f892912f7d6b753"
 dependencies = [
  "serde",
  "swc_atoms",
@@ -5083,11 +5013,11 @@ dependencies = [
 
 [[package]]
 name = "swc_ecma_utils"
-version = "0.117.13"
+version = "0.120.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad791bbfdafcebd878584021e050964c8ab68aba7eeac9d0ee4afba4c284a629"
+checksum = "2cb60e20e1eb9e9f7c88d99ac8659fd0561d70abd27853f550fbd907a448c878"
 dependencies = [
- "indexmap 1.9.2",
+ "indexmap 1.9.3",
  "num_cpus",
  "once_cell",
  "rustc-hash",
@@ -5101,9 +5031,9 @@ dependencies = [
 
 [[package]]
 name = "swc_ecma_visit"
-version = "0.90.5"
+version = "0.93.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ce3ac941ae1d6c7e683aa375fc71fbf58df58b441f614d757fbb10554936ca2"
+checksum = "bb23a48abd9f5731b6275dbf4ea89f6e03dc60b7c8e3e1e383bb4a6c39fd7e25"
 dependencies = [
  "num-bigint",
  "swc_atoms",
@@ -5115,23 +5045,23 @@ dependencies = [
 
 [[package]]
 name = "swc_eq_ignore_macros"
-version = "0.1.1"
+version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c20468634668c2bbab581947bb8c75c97158d5a6959f4ba33df20983b20b4f6"
+checksum = "05a95d367e228d52484c53336991fdcf47b6b553ef835d9159db4ba40efb0ee8"
 dependencies = [
- "pmutil 0.5.3",
+ "pmutil",
  "proc-macro2 1.0.66",
  "quote 1.0.32",
- "syn 1.0.109",
+ "syn 2.0.28",
 ]
 
 [[package]]
 name = "swc_fast_graph"
-version = "0.19.12"
+version = "0.19.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6291149aec4ba55076fd54a12ceb84cac1f703b2f571c3b2f19aa66ab9ec3009"
+checksum = "b07b6c9a4d1659b7e6826fb384b3994b47c5ac35cb76a98a15ca483dd0a5d7b7"
 dependencies = [
- "indexmap 1.9.2",
+ "indexmap 1.9.3",
  "petgraph",
  "rustc-hash",
  "swc_common",
@@ -5139,34 +5069,34 @@ dependencies = [
 
 [[package]]
 name = "swc_graph_analyzer"
-version = "0.20.13"
+version = "0.20.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6575adec8b200801d429ffa79166224a6e298292a1b307750f4763aec5aa16c3"
+checksum = "2126bce41c5c755f649bc5fc74fbd5e1ea01306acbf26b49f8aab2bd53f8025f"
 dependencies = [
- "ahash 0.7.6",
- "auto_impl",
+ "auto_impl 1.1.0",
  "petgraph",
+ "swc_common",
  "swc_fast_graph",
  "tracing",
 ]
 
 [[package]]
 name = "swc_macros_common"
-version = "0.3.7"
+version = "0.3.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e582c3e3c2269238524923781df5be49e011dbe29cf7683a2215d600a562ea6"
+checksum = "7a273205ccb09b51fabe88c49f3b34c5a4631c4c00a16ae20e03111d6a42e832"
 dependencies = [
- "pmutil 0.5.3",
+ "pmutil",
  "proc-macro2 1.0.66",
  "quote 1.0.32",
- "syn 1.0.109",
+ "syn 2.0.28",
 ]
 
 [[package]]
 name = "swc_visit"
-version = "0.5.6"
+version = "0.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f412dd4fbc58f509a04e64f5c8038333142fc139e8232f01b883db0094b3b51"
+checksum = "e87c337fbb2d191bf371173dea6a957f01899adb8f189c6c31b122a6cfc98fc3"
 dependencies = [
  "either",
  "swc_visit_macros",
@@ -5174,16 +5104,16 @@ dependencies = [
 
 [[package]]
 name = "swc_visit_macros"
-version = "0.5.7"
+version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cfc226380ba54a5feed2c12f3ccd33f1ae8e959160290e5d2d9b4e918b6472a"
+checksum = "0f322730fb82f3930a450ac24de8c98523af7d34ab8cb2f46bcb405839891a99"
 dependencies = [
  "Inflector",
- "pmutil 0.5.3",
+ "pmutil",
  "proc-macro2 1.0.66",
  "quote 1.0.32",
  "swc_macros_common",
- "syn 1.0.109",
+ "syn 2.0.28",
 ]
 
 [[package]]
@@ -5515,7 +5445,7 @@ version = "0.19.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dc18466501acd8ac6a3f615dd29a3438f8ca6bb3b19537138b3106e575621274"
 dependencies = [
- "indexmap 1.9.2",
+ "indexmap 1.9.3",
  "toml_datetime",
  "winnow",
 ]
@@ -5547,7 +5477,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "43e094780b4447366c59f79acfd65b1375ecaa84e61dddbde1421aa506334024"
 dependencies = [
  "async-trait",
- "auto_impl",
+ "auto_impl 0.5.0",
  "bytes",
  "dashmap",
  "futures",
@@ -5859,12 +5789,12 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
 
 [[package]]
 name = "url"
-version = "2.3.1"
+version = "2.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
+checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb"
 dependencies = [
  "form_urlencoded",
- "idna 0.3.0",
+ "idna 0.4.0",
  "percent-encoding",
  "serde",
 ]
diff --git a/Cargo.toml b/Cargo.toml
index 5c4ea6a77c..3e19274662 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -38,7 +38,7 @@ license = "MIT"
 repository = "https://github.com/denoland/deno"
 
 [workspace.dependencies]
-deno_ast = { version = "0.27.0", features = ["transpiling"] }
+deno_ast = { version = "0.28.0", features = ["transpiling"] }
 
 deno_core = "0.202.0"
 
@@ -48,8 +48,8 @@ deno_bench_util = { version = "0.109.0", path = "./bench_util" }
 test_util = { path = "./test_util" }
 deno_lockfile = "0.15.0"
 deno_media_type = { version = "0.1.1", features = ["module_specifier"] }
-deno_npm = "0.11.0"
-deno_semver = "0.3.0"
+deno_npm = "0.12.0"
+deno_semver = "0.4.0"
 
 # exts
 deno_broadcast_channel = { version = "0.109.0", path = "./ext/broadcast_channel" }
diff --git a/cli/Cargo.toml b/cli/Cargo.toml
index c2c4b3ede0..dec23e6a5a 100644
--- a/cli/Cargo.toml
+++ b/cli/Cargo.toml
@@ -48,16 +48,16 @@ winres.workspace = true
 deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "dep_graph", "module_specifier", "proposal", "react", "sourcemap", "transforms", "typescript", "view", "visit"] }
 deno_cache_dir = "=0.5.2"
 deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] }
-deno_doc = "=0.64.0"
-deno_emit = "=0.25.0"
-deno_graph = "=0.50.0"
-deno_lint = { version = "=0.49.0", features = ["docs"] }
+deno_doc = "=0.65.0"
+deno_emit = "=0.26.0"
+deno_graph = "=0.52.0"
+deno_lint = { version = "=0.50.1", features = ["docs"] }
 deno_lockfile.workspace = true
 deno_npm.workspace = true
 deno_runtime = { workspace = true, features = ["dont_create_runtime_snapshot", "include_js_files_for_snapshotting"] }
 deno_semver.workspace = true
-deno_task_shell = "=0.13.1"
-eszip = "=0.49.0"
+deno_task_shell = "=0.13.2"
+eszip = "=0.50.0"
 napi_sym.workspace = true
 
 async-trait.workspace = true
@@ -75,7 +75,7 @@ data-url.workspace = true
 dissimilar = "=1.0.4"
 dprint-plugin-json = "=0.17.4"
 dprint-plugin-markdown = "=0.15.3"
-dprint-plugin-typescript = "=0.86.1"
+dprint-plugin-typescript = "=0.86.2"
 encoding_rs.workspace = true
 env_logger = "=0.9.0"
 fancy-regex = "=0.10.0"
@@ -92,7 +92,7 @@ lazy-regex.workspace = true
 libc.workspace = true
 log = { workspace = true, features = ["serde"] }
 lsp-types.workspace = true
-monch = "=0.4.2"
+monch = "=0.4.3"
 notify.workspace = true
 once_cell.workspace = true
 os_pipe.workspace = true
diff --git a/cli/args/mod.rs b/cli/args/mod.rs
index f7f73fd4ae..65c6e73084 100644
--- a/cli/args/mod.rs
+++ b/cli/args/mod.rs
@@ -1383,10 +1383,7 @@ pub fn has_flag_env_var(name: &str) -> bool {
 pub fn npm_pkg_req_ref_to_binary_command(
   req_ref: &NpmPackageReqReference,
 ) -> String {
-  let binary_name = req_ref
-    .sub_path
-    .as_deref()
-    .unwrap_or(req_ref.req.name.as_str());
+  let binary_name = req_ref.sub_path().unwrap_or(req_ref.req().name.as_str());
   binary_name.to_string()
 }
 
diff --git a/cli/args/package_json.rs b/cli/args/package_json.rs
index 76a09eadd6..8ee30214e0 100644
--- a/cli/args/package_json.rs
+++ b/cli/args/package_json.rs
@@ -10,9 +10,9 @@ use deno_core::error::AnyError;
 use deno_npm::registry::parse_dep_entry_name_and_raw_version;
 use deno_npm::registry::PackageDepNpmSchemeValueParseError;
 use deno_runtime::deno_node::PackageJson;
-use deno_semver::npm::NpmPackageReq;
-use deno_semver::npm::NpmVersionReqSpecifierParseError;
+use deno_semver::package::PackageReq;
 use deno_semver::VersionReq;
+use deno_semver::VersionReqSpecifierParseError;
 use thiserror::Error;
 
 #[derive(Debug, Error, Clone)]
@@ -20,13 +20,13 @@ pub enum PackageJsonDepValueParseError {
   #[error(transparent)]
   SchemeValue(#[from] PackageDepNpmSchemeValueParseError),
   #[error(transparent)]
-  Specifier(#[from] NpmVersionReqSpecifierParseError),
+  Specifier(#[from] VersionReqSpecifierParseError),
   #[error("Not implemented scheme '{scheme}'")]
   Unsupported { scheme: String },
 }
 
 pub type PackageJsonDeps =
-  BTreeMap<String, Result<NpmPackageReq, PackageJsonDepValueParseError>>;
+  BTreeMap<String, Result<PackageReq, PackageJsonDepValueParseError>>;
 
 #[derive(Debug, Default)]
 pub struct PackageJsonDepsProvider(Option<PackageJsonDeps>);
@@ -40,7 +40,7 @@ impl PackageJsonDepsProvider {
     self.0.as_ref()
   }
 
-  pub fn reqs(&self) -> Vec<&NpmPackageReq> {
+  pub fn reqs(&self) -> Vec<&PackageReq> {
     match &self.0 {
       Some(deps) => {
         let mut package_reqs = deps
@@ -67,7 +67,7 @@ pub fn get_local_package_json_version_reqs(
   fn parse_entry(
     key: &str,
     value: &str,
-  ) -> Result<NpmPackageReq, PackageJsonDepValueParseError> {
+  ) -> Result<PackageReq, PackageJsonDepValueParseError> {
     if value.starts_with("workspace:")
       || value.starts_with("file:")
       || value.starts_with("git:")
@@ -83,7 +83,7 @@ pub fn get_local_package_json_version_reqs(
 
     let result = VersionReq::parse_from_specifier(version_req);
     match result {
-      Ok(version_req) => Ok(NpmPackageReq {
+      Ok(version_req) => Ok(PackageReq {
         name: name.to_string(),
         version_req,
       }),
@@ -182,7 +182,7 @@ mod test {
 
   fn get_local_package_json_version_reqs_for_tests(
     package_json: &PackageJson,
-  ) -> BTreeMap<String, Result<NpmPackageReq, String>> {
+  ) -> BTreeMap<String, Result<PackageReq, String>> {
     get_local_package_json_version_reqs(package_json)
       .into_iter()
       .map(|(k, v)| {
@@ -215,15 +215,15 @@ mod test {
       BTreeMap::from([
         (
           "test".to_string(),
-          Ok(NpmPackageReq::from_str("test@^1.2").unwrap())
+          Ok(PackageReq::from_str("test@^1.2").unwrap())
         ),
         (
           "other".to_string(),
-          Ok(NpmPackageReq::from_str("package@~1.3").unwrap())
+          Ok(PackageReq::from_str("package@~1.3").unwrap())
         ),
         (
           "package_b".to_string(),
-          Ok(NpmPackageReq::from_str("package_b@~2.2").unwrap())
+          Ok(PackageReq::from_str("package_b@~2.2").unwrap())
         )
       ])
     );
@@ -243,7 +243,7 @@ mod test {
         "test".to_string(),
         Err(
           concat!(
-            "Invalid npm specifier version requirement. Unexpected character.\n",
+            "Invalid specifier version requirement. Unexpected character.\n",
             "   - 1.3\n",
             "  ~"
           )
@@ -286,7 +286,7 @@ mod test {
         ),
         (
           "test".to_string(),
-          Ok(NpmPackageReq::from_str("test@1").unwrap())
+          Ok(PackageReq::from_str("test@1").unwrap())
         ),
         (
           "work-test".to_string(),
diff --git a/cli/lsp/analysis.rs b/cli/lsp/analysis.rs
index 63e0549fd1..ec279022d1 100644
--- a/cli/lsp/analysis.rs
+++ b/cli/lsp/analysis.rs
@@ -23,7 +23,7 @@ use deno_core::ModuleSpecifier;
 use deno_lint::rules::LintRule;
 use deno_runtime::deno_node::PackageJson;
 use deno_runtime::deno_node::PathClean;
-use deno_semver::npm::NpmPackageReq;
+use deno_semver::package::PackageReq;
 use import_map::ImportMap;
 use once_cell::sync::Lazy;
 use regex::Regex;
@@ -187,7 +187,7 @@ impl<'a> TsResponseImportMapper<'a> {
   ) -> Option<String> {
     fn concat_npm_specifier(
       prefix: &str,
-      pkg_req: &NpmPackageReq,
+      pkg_req: &PackageReq,
       sub_path: Option<&str>,
     ) -> String {
       let result = format!("{}{}", prefix, pkg_req);
diff --git a/cli/lsp/diagnostics.rs b/cli/lsp/diagnostics.rs
index 4e24673f3b..817d2fbc49 100644
--- a/cli/lsp/diagnostics.rs
+++ b/cli/lsp/diagnostics.rs
@@ -39,6 +39,7 @@ use deno_lint::rules::LintRule;
 use deno_runtime::deno_node;
 use deno_runtime::tokio_util::create_basic_runtime;
 use deno_semver::npm::NpmPackageReqReference;
+use deno_semver::package::PackageReq;
 use log::error;
 use std::collections::HashMap;
 use std::collections::HashSet;
@@ -876,7 +877,7 @@ pub enum DenoDiagnostic {
   /// A remote module was not found in the cache.
   NoCache(ModuleSpecifier),
   /// A remote npm package reference was not found in the cache.
-  NoCacheNpm(NpmPackageReqReference, ModuleSpecifier),
+  NoCacheNpm(PackageReq, ModuleSpecifier),
   /// A local module was not found on the local file system.
   NoLocal(ModuleSpecifier),
   /// The specifier resolved to a remote specifier that was redirected to
@@ -1086,7 +1087,7 @@ impl DenoDiagnostic {
       Self::InvalidAssertType(assert_type) => (lsp::DiagnosticSeverity::ERROR, format!("The module is a JSON module and expected an assertion type of \"json\". Instead got \"{assert_type}\"."), None),
       Self::NoAssertType => (lsp::DiagnosticSeverity::ERROR, "The module is a JSON module and not being imported with an import assertion. Consider adding `assert { type: \"json\" }` to the import statement.".to_string(), None),
       Self::NoCache(specifier) => (lsp::DiagnosticSeverity::ERROR, format!("Uncached or missing remote URL: {specifier}"), Some(json!({ "specifier": specifier }))),
-      Self::NoCacheNpm(pkg_ref, specifier) => (lsp::DiagnosticSeverity::ERROR, format!("Uncached or missing npm package: {}", pkg_ref.req), Some(json!({ "specifier": specifier }))),
+      Self::NoCacheNpm(pkg_req, specifier) => (lsp::DiagnosticSeverity::ERROR, format!("Uncached or missing npm package: {}", pkg_req), Some(json!({ "specifier": specifier }))),
       Self::NoLocal(specifier) => (lsp::DiagnosticSeverity::ERROR, format!("Unable to load a local module: {specifier}\n  Please check the file path."), None),
       Self::Redirect { from, to} => (lsp::DiagnosticSeverity::INFORMATION, format!("The import of \"{from}\" was redirected to \"{to}\"."), Some(json!({ "specifier": from, "redirect": to }))),
       Self::ResolutionError(err) => (
@@ -1159,9 +1160,10 @@ fn diagnose_resolution(
       {
         if let Some(npm_resolver) = &snapshot.maybe_npm_resolver {
           // show diagnostics for npm package references that aren't cached
-          if !npm_resolver.is_pkg_req_folder_cached(&pkg_ref.req) {
+          let req = pkg_ref.into_inner().req;
+          if !npm_resolver.is_pkg_req_folder_cached(&req) {
             diagnostics
-              .push(DenoDiagnostic::NoCacheNpm(pkg_ref, specifier.clone()));
+              .push(DenoDiagnostic::NoCacheNpm(req, specifier.clone()));
           }
         }
       } else if let Some(module_name) = specifier.as_str().strip_prefix("node:")
@@ -1171,11 +1173,10 @@ fn diagnose_resolution(
             .push(DenoDiagnostic::InvalidNodeSpecifier(specifier.clone()));
         } else if let Some(npm_resolver) = &snapshot.maybe_npm_resolver {
           // check that a @types/node package exists in the resolver
-          let types_node_ref =
-            NpmPackageReqReference::from_str("npm:@types/node").unwrap();
-          if !npm_resolver.is_pkg_req_folder_cached(&types_node_ref.req) {
+          let types_node_req = PackageReq::from_str("@types/node").unwrap();
+          if !npm_resolver.is_pkg_req_folder_cached(&types_node_req) {
             diagnostics.push(DenoDiagnostic::NoCacheNpm(
-              types_node_ref,
+              types_node_req,
               ModuleSpecifier::parse("npm:@types/node").unwrap(),
             ));
           }
diff --git a/cli/lsp/documents.rs b/cli/lsp/documents.rs
index 8227d2e4c2..11fba693f9 100644
--- a/cli/lsp/documents.rs
+++ b/cli/lsp/documents.rs
@@ -43,8 +43,8 @@ use deno_runtime::deno_node::NodeResolutionMode;
 use deno_runtime::deno_node::NodeResolver;
 use deno_runtime::deno_node::PackageJson;
 use deno_runtime::permissions::PermissionsContainer;
-use deno_semver::npm::NpmPackageReq;
 use deno_semver::npm::NpmPackageReqReference;
+use deno_semver::package::PackageReq;
 use indexmap::IndexMap;
 use lsp::Url;
 use once_cell::sync::Lazy;
@@ -846,7 +846,7 @@ pub struct Documents {
   /// settings.
   resolver: Arc<CliGraphResolver>,
   /// The npm package requirements found in npm specifiers.
-  npm_specifier_reqs: Arc<Vec<NpmPackageReq>>,
+  npm_specifier_reqs: Arc<Vec<PackageReq>>,
   /// Gets if any document had a node: specifier such that a @types/node package
   /// should be injected.
   has_injected_types_node_package: bool,
@@ -1017,7 +1017,7 @@ impl Documents {
   }
 
   /// Returns a collection of npm package requirements.
-  pub fn npm_package_reqs(&mut self) -> Arc<Vec<NpmPackageReq>> {
+  pub fn npm_package_reqs(&mut self) -> Arc<Vec<PackageReq>> {
     self.calculate_dependents_if_dirty();
     self.npm_specifier_reqs.clone()
   }
@@ -1398,7 +1398,7 @@ impl Documents {
       dependents_map: HashMap<ModuleSpecifier, HashSet<ModuleSpecifier>>,
       analyzed_specifiers: HashSet<ModuleSpecifier>,
       pending_specifiers: VecDeque<ModuleSpecifier>,
-      npm_reqs: HashSet<NpmPackageReq>,
+      npm_reqs: HashSet<PackageReq>,
       has_node_builtin_specifier: bool,
     }
 
@@ -1410,7 +1410,7 @@ impl Documents {
           // been analyzed in order to not cause an extra file system lookup
           self.pending_specifiers.push_back(dep.clone());
           if let Ok(reference) = NpmPackageReqReference::from_specifier(dep) {
-            self.npm_reqs.insert(reference.req);
+            self.npm_reqs.insert(reference.into_inner().req);
           }
         }
 
@@ -1468,7 +1468,7 @@ impl Documents {
       .has_node_builtin_specifier
       && !npm_reqs.iter().any(|r| r.name == "@types/node");
     if self.has_injected_types_node_package {
-      npm_reqs.insert(NpmPackageReq::from_str("@types/node").unwrap());
+      npm_reqs.insert(PackageReq::from_str("@types/node").unwrap());
     }
 
     self.dependents_map = Arc::new(doc_analyzer.dependents_map);
diff --git a/cli/npm/cache.rs b/cli/npm/cache.rs
index c657beef35..587ce6fd0b 100644
--- a/cli/npm/cache.rs
+++ b/cli/npm/cache.rs
@@ -16,7 +16,7 @@ use deno_core::url::Url;
 use deno_npm::registry::NpmPackageVersionDistInfo;
 use deno_npm::NpmPackageCacheFolderId;
 use deno_runtime::deno_fs;
-use deno_semver::npm::NpmPackageNv;
+use deno_semver::package::PackageNv;
 use deno_semver::Version;
 use once_cell::sync::Lazy;
 
@@ -43,7 +43,7 @@ pub fn should_sync_download() -> bool {
 const NPM_PACKAGE_SYNC_LOCK_FILENAME: &str = ".deno_sync_lock";
 
 pub fn with_folder_sync_lock(
-  package: &NpmPackageNv,
+  package: &PackageNv,
   output_folder: &Path,
   action: impl FnOnce() -> Result<(), AnyError>,
 ) -> Result<(), AnyError> {
@@ -162,7 +162,7 @@ impl NpmCacheDir {
 
   pub fn package_folder_for_name_and_version(
     &self,
-    package: &NpmPackageNv,
+    package: &PackageNv,
     registry_url: &Url,
   ) -> PathBuf {
     self
@@ -251,7 +251,7 @@ impl NpmCacheDir {
         (version_part, 0)
       };
     Some(NpmPackageCacheFolderId {
-      nv: NpmPackageNv {
+      nv: PackageNv {
         name,
         version: Version::parse_from_npm(version).ok()?,
       },
@@ -273,7 +273,7 @@ pub struct NpmCache {
   http_client: Arc<HttpClient>,
   progress_bar: ProgressBar,
   /// ensures a package is only downloaded once per run
-  previously_reloaded_packages: Mutex<HashSet<NpmPackageNv>>,
+  previously_reloaded_packages: Mutex<HashSet<PackageNv>>,
 }
 
 impl NpmCache {
@@ -311,10 +311,7 @@ impl NpmCache {
   /// to ensure a package is only downloaded once per run of the CLI. This
   /// prevents downloads from re-occurring when someone has `--reload` and
   /// and imports a dynamic import that imports the same package again for example.
-  fn should_use_global_cache_for_package(
-    &self,
-    package: &NpmPackageNv,
-  ) -> bool {
+  fn should_use_global_cache_for_package(&self, package: &PackageNv) -> bool {
     self.cache_setting.should_use_for_npm_package(&package.name)
       || !self
         .previously_reloaded_packages
@@ -324,7 +321,7 @@ impl NpmCache {
 
   pub async fn ensure_package(
     &self,
-    package: &NpmPackageNv,
+    package: &PackageNv,
     dist: &NpmPackageVersionDistInfo,
     registry_url: &Url,
   ) -> Result<(), AnyError> {
@@ -336,7 +333,7 @@ impl NpmCache {
 
   async fn ensure_package_inner(
     &self,
-    package: &NpmPackageNv,
+    package: &PackageNv,
     dist: &NpmPackageVersionDistInfo,
     registry_url: &Url,
   ) -> Result<(), AnyError> {
@@ -422,7 +419,7 @@ impl NpmCache {
 
   pub fn package_folder_for_name_and_version(
     &self,
-    package: &NpmPackageNv,
+    package: &PackageNv,
     registry_url: &Url,
   ) -> PathBuf {
     self
@@ -467,7 +464,7 @@ pub fn mixed_case_package_name_decode(name: &str) -> Option<String> {
 #[cfg(test)]
 mod test {
   use deno_core::url::Url;
-  use deno_semver::npm::NpmPackageNv;
+  use deno_semver::package::PackageNv;
   use deno_semver::Version;
 
   use super::NpmCacheDir;
@@ -483,7 +480,7 @@ mod test {
     assert_eq!(
       cache.package_folder_for_id(
         &NpmPackageCacheFolderId {
-          nv: NpmPackageNv {
+          nv: PackageNv {
             name: "json".to_string(),
             version: Version::parse_from_npm("1.2.5").unwrap(),
           },
@@ -500,7 +497,7 @@ mod test {
     assert_eq!(
       cache.package_folder_for_id(
         &NpmPackageCacheFolderId {
-          nv: NpmPackageNv {
+          nv: PackageNv {
             name: "json".to_string(),
             version: Version::parse_from_npm("1.2.5").unwrap(),
           },
@@ -517,7 +514,7 @@ mod test {
     assert_eq!(
       cache.package_folder_for_id(
         &NpmPackageCacheFolderId {
-          nv: NpmPackageNv {
+          nv: PackageNv {
             name: "JSON".to_string(),
             version: Version::parse_from_npm("2.1.5").unwrap(),
           },
@@ -534,7 +531,7 @@ mod test {
     assert_eq!(
       cache.package_folder_for_id(
         &NpmPackageCacheFolderId {
-          nv: NpmPackageNv {
+          nv: PackageNv {
             name: "@types/JSON".to_string(),
             version: Version::parse_from_npm("2.1.5").unwrap(),
           },
diff --git a/cli/npm/installer.rs b/cli/npm/installer.rs
index adb4344ee4..9e7b413b41 100644
--- a/cli/npm/installer.rs
+++ b/cli/npm/installer.rs
@@ -8,7 +8,7 @@ use deno_core::futures::stream::FuturesOrdered;
 use deno_core::futures::StreamExt;
 use deno_npm::registry::NpmRegistryApi;
 use deno_npm::registry::NpmRegistryPackageInfoLoadError;
-use deno_semver::npm::NpmPackageReq;
+use deno_semver::package::PackageReq;
 
 use crate::args::PackageJsonDepsProvider;
 use crate::util::sync::AtomicFlag;
@@ -27,11 +27,11 @@ struct PackageJsonDepsInstallerInner {
 impl PackageJsonDepsInstallerInner {
   pub fn reqs_with_info_futures<'a>(
     &self,
-    reqs: &'a [&'a NpmPackageReq],
+    reqs: &'a [&'a PackageReq],
   ) -> FuturesOrdered<
     impl Future<
       Output = Result<
-        (&'a NpmPackageReq, Arc<deno_npm::registry::NpmPackageInfo>),
+        (&'a PackageReq, Arc<deno_npm::registry::NpmPackageInfo>),
         NpmRegistryPackageInfoLoadError,
       >,
     >,
diff --git a/cli/npm/resolution.rs b/cli/npm/resolution.rs
index 6beb520900..d097f8cd43 100644
--- a/cli/npm/resolution.rs
+++ b/cli/npm/resolution.rs
@@ -27,8 +27,8 @@ use deno_npm::NpmPackageCacheFolderId;
 use deno_npm::NpmPackageId;
 use deno_npm::NpmResolutionPackage;
 use deno_npm::NpmSystemInfo;
-use deno_semver::npm::NpmPackageNv;
-use deno_semver::npm::NpmPackageReq;
+use deno_semver::package::PackageNv;
+use deno_semver::package::PackageReq;
 use deno_semver::VersionReq;
 
 use crate::args::Lockfile;
@@ -82,7 +82,7 @@ impl NpmResolution {
 
   pub async fn add_package_reqs(
     &self,
-    package_reqs: &[NpmPackageReq],
+    package_reqs: &[PackageReq],
   ) -> Result<(), AnyError> {
     // only allow one thread in here at a time
     let _permit = self.update_queue.acquire().await;
@@ -100,7 +100,7 @@ impl NpmResolution {
 
   pub async fn set_package_reqs(
     &self,
-    package_reqs: &[NpmPackageReq],
+    package_reqs: &[PackageReq],
   ) -> Result<(), AnyError> {
     // only allow one thread in here at a time
     let _permit = self.update_queue.acquire().await;
@@ -185,7 +185,7 @@ impl NpmResolution {
   /// Resolve a node package from a deno module.
   pub fn resolve_pkg_id_from_pkg_req(
     &self,
-    req: &NpmPackageReq,
+    req: &PackageReq,
   ) -> Result<NpmPackageId, PackageReqNotFoundError> {
     self
       .snapshot
@@ -197,7 +197,7 @@ impl NpmResolution {
   pub fn resolve_pkg_reqs_from_pkg_id(
     &self,
     id: &NpmPackageId,
-  ) -> Vec<NpmPackageReq> {
+  ) -> Vec<PackageReq> {
     let snapshot = self.snapshot.read();
     let mut pkg_reqs = snapshot
       .package_reqs()
@@ -211,7 +211,7 @@ impl NpmResolution {
 
   pub fn resolve_pkg_id_from_deno_module(
     &self,
-    id: &NpmPackageNv,
+    id: &PackageNv,
   ) -> Result<NpmPackageId, PackageNvNotFoundError> {
     self
       .snapshot
@@ -225,8 +225,8 @@ impl NpmResolution {
   /// a package.json
   pub fn resolve_package_req_as_pending(
     &self,
-    pkg_req: &NpmPackageReq,
-  ) -> Result<NpmPackageNv, NpmPackageVersionResolutionError> {
+    pkg_req: &PackageReq,
+  ) -> Result<PackageNv, NpmPackageVersionResolutionError> {
     // we should always have this because it should have been cached before here
     let package_info = self.api.get_cached_package_info(&pkg_req.name).unwrap();
     self.resolve_package_req_as_pending_with_info(pkg_req, &package_info)
@@ -237,9 +237,9 @@ impl NpmResolution {
   /// a package.json
   pub fn resolve_package_req_as_pending_with_info(
     &self,
-    pkg_req: &NpmPackageReq,
+    pkg_req: &PackageReq,
     package_info: &NpmPackageInfo,
-  ) -> Result<NpmPackageNv, NpmPackageVersionResolutionError> {
+  ) -> Result<PackageNv, NpmPackageVersionResolutionError> {
     debug_assert_eq!(pkg_req.name, package_info.name);
     let mut snapshot = self.snapshot.write();
     let pending_resolver = get_npm_pending_resolver(&self.api);
@@ -251,7 +251,7 @@ impl NpmResolution {
     Ok(nv)
   }
 
-  pub fn package_reqs(&self) -> HashMap<NpmPackageReq, NpmPackageNv> {
+  pub fn package_reqs(&self) -> HashMap<PackageReq, PackageNv> {
     self.snapshot.read().package_reqs().clone()
   }
 
@@ -304,7 +304,7 @@ impl NpmResolution {
 
 async fn add_package_reqs_to_snapshot(
   api: &CliNpmRegistryApi,
-  package_reqs: &[NpmPackageReq],
+  package_reqs: &[PackageReq],
   maybe_lockfile: Option<Arc<Mutex<Lockfile>>>,
   get_new_snapshot: impl Fn() -> NpmResolutionSnapshot,
 ) -> Result<NpmResolutionSnapshot, AnyError> {
diff --git a/cli/npm/resolvers/local.rs b/cli/npm/resolvers/local.rs
index 6a0065ba8d..71b91c4526 100644
--- a/cli/npm/resolvers/local.rs
+++ b/cli/npm/resolvers/local.rs
@@ -37,7 +37,7 @@ use deno_runtime::deno_fs;
 use deno_runtime::deno_node::NodePermissions;
 use deno_runtime::deno_node::NodeResolutionMode;
 use deno_runtime::deno_node::PackageJson;
-use deno_semver::npm::NpmPackageNv;
+use deno_semver::package::PackageNv;
 use serde::Deserialize;
 use serde::Serialize;
 
@@ -657,7 +657,7 @@ fn get_package_folder_id_from_folder_name(
   };
   let version = deno_semver::Version::parse_from_npm(raw_version).ok()?;
   Some(NpmPackageCacheFolderId {
-    nv: NpmPackageNv { name, version },
+    nv: PackageNv { name, version },
     copy_index,
   })
 }
@@ -726,7 +726,7 @@ fn join_package_name(path: &Path, package_name: &str) -> PathBuf {
 #[cfg(test)]
 mod test {
   use deno_npm::NpmPackageCacheFolderId;
-  use deno_semver::npm::NpmPackageNv;
+  use deno_semver::package::PackageNv;
   use test_util::TempDir;
 
   use super::*;
@@ -736,20 +736,14 @@ mod test {
     let cases = vec![
       (
         NpmPackageCacheFolderId {
-          nv: NpmPackageNv {
-            name: "@types/foo".to_string(),
-            version: deno_semver::Version::parse_standard("1.2.3").unwrap(),
-          },
+          nv: PackageNv::from_str("@types/foo@1.2.3").unwrap(),
           copy_index: 1,
         },
         "@types+foo@1.2.3_1".to_string(),
       ),
       (
         NpmPackageCacheFolderId {
-          nv: NpmPackageNv {
-            name: "JSON".to_string(),
-            version: deno_semver::Version::parse_standard("3.2.1").unwrap(),
-          },
+          nv: PackageNv::from_str("JSON@3.2.1").unwrap(),
           copy_index: 0,
         },
         "_jjju6tq@3.2.1".to_string(),
diff --git a/cli/npm/resolvers/mod.rs b/cli/npm/resolvers/mod.rs
index 1b3f57c9a3..58a70dff07 100644
--- a/cli/npm/resolvers/mod.rs
+++ b/cli/npm/resolvers/mod.rs
@@ -25,8 +25,8 @@ use deno_runtime::deno_node::NodePermissions;
 use deno_runtime::deno_node::NodeResolutionMode;
 use deno_runtime::deno_node::NpmResolver;
 use deno_runtime::deno_node::PathClean;
-use deno_semver::npm::NpmPackageNv;
-use deno_semver::npm::NpmPackageReq;
+use deno_semver::package::PackageNv;
+use deno_semver::package::PackageReq;
 use global::GlobalNpmPackageResolver;
 use serde::Deserialize;
 use serde::Serialize;
@@ -91,7 +91,7 @@ impl CliNpmResolver {
   }
 
   /// Checks if the provided package req's folder is cached.
-  pub fn is_pkg_req_folder_cached(&self, req: &NpmPackageReq) -> bool {
+  pub fn is_pkg_req_folder_cached(&self, req: &PackageReq) -> bool {
     self
       .resolve_pkg_id_from_pkg_req(req)
       .ok()
@@ -102,7 +102,7 @@ impl CliNpmResolver {
 
   pub fn resolve_pkg_id_from_pkg_req(
     &self,
-    req: &NpmPackageReq,
+    req: &PackageReq,
   ) -> Result<NpmPackageId, PackageReqNotFoundError> {
     self.resolution.resolve_pkg_id_from_pkg_req(req)
   }
@@ -182,7 +182,7 @@ impl CliNpmResolver {
   /// Adds package requirements to the resolver and ensures everything is setup.
   pub async fn add_package_reqs(
     &self,
-    packages: &[NpmPackageReq],
+    packages: &[PackageReq],
   ) -> Result<(), AnyError> {
     if packages.is_empty() {
       return Ok(());
@@ -205,7 +205,7 @@ impl CliNpmResolver {
   /// This will retrieve and resolve package information, but not cache any package files.
   pub async fn set_package_reqs(
     &self,
-    packages: &[NpmPackageReq],
+    packages: &[PackageReq],
   ) -> Result<(), AnyError> {
     self.resolution.set_package_reqs(packages).await
   }
@@ -225,7 +225,7 @@ impl CliNpmResolver {
     .unwrap()
   }
 
-  pub fn package_reqs(&self) -> HashMap<NpmPackageReq, NpmPackageNv> {
+  pub fn package_reqs(&self) -> HashMap<PackageReq, PackageNv> {
     self.resolution.package_reqs()
   }
 
@@ -241,7 +241,7 @@ impl CliNpmResolver {
     &self,
   ) -> Result<(), AnyError> {
     // add and ensure this isn't added to the lockfile
-    let package_reqs = vec![NpmPackageReq::from_str("@types/node").unwrap()];
+    let package_reqs = vec![PackageReq::from_str("@types/node").unwrap()];
     self.resolution.add_package_reqs(&package_reqs).await?;
     self.fs_resolver.cache_packages().await?;
 
@@ -279,7 +279,7 @@ impl NpmResolver for CliNpmResolver {
 
   fn resolve_package_folder_from_deno_module(
     &self,
-    pkg_nv: &NpmPackageNv,
+    pkg_nv: &PackageNv,
   ) -> Result<PathBuf, AnyError> {
     let pkg_id = self.resolution.resolve_pkg_id_from_deno_module(pkg_nv)?;
     self.resolve_pkg_folder_from_pkg_id(&pkg_id)
@@ -287,7 +287,7 @@ impl NpmResolver for CliNpmResolver {
 
   fn resolve_pkg_id_from_pkg_req(
     &self,
-    req: &NpmPackageReq,
+    req: &PackageReq,
   ) -> Result<NpmPackageId, PackageReqNotFoundError> {
     self.resolution.resolve_pkg_id_from_pkg_req(req)
   }
diff --git a/cli/npm/tarball.rs b/cli/npm/tarball.rs
index 18a5556716..f2f8d1ba4b 100644
--- a/cli/npm/tarball.rs
+++ b/cli/npm/tarball.rs
@@ -8,7 +8,7 @@ use std::path::PathBuf;
 use deno_core::anyhow::bail;
 use deno_core::error::AnyError;
 use deno_npm::registry::NpmPackageVersionDistInfo;
-use deno_semver::npm::NpmPackageNv;
+use deno_semver::package::PackageNv;
 use flate2::read::GzDecoder;
 use tar::Archive;
 use tar::EntryType;
@@ -16,7 +16,7 @@ use tar::EntryType;
 use super::cache::with_folder_sync_lock;
 
 pub fn verify_and_extract_tarball(
-  package: &NpmPackageNv,
+  package: &PackageNv,
   data: &[u8],
   dist_info: &NpmPackageVersionDistInfo,
   output_folder: &Path,
@@ -29,7 +29,7 @@ pub fn verify_and_extract_tarball(
 }
 
 fn verify_tarball_integrity(
-  package: &NpmPackageNv,
+  package: &PackageNv,
   data: &[u8],
   npm_integrity: &str,
 ) -> Result<(), AnyError> {
@@ -140,7 +140,7 @@ mod test {
 
   #[test]
   pub fn test_verify_tarball() {
-    let package = NpmPackageNv {
+    let package = PackageNv {
       name: "package".to_string(),
       version: Version::parse_from_npm("1.0.0").unwrap(),
     };
diff --git a/cli/resolver.rs b/cli/resolver.rs
index f78f31e8dd..dfa709bcb8 100644
--- a/cli/resolver.rs
+++ b/cli/resolver.rs
@@ -8,14 +8,14 @@ use deno_core::futures::future::LocalBoxFuture;
 use deno_core::futures::FutureExt;
 use deno_core::ModuleSpecifier;
 use deno_core::TaskQueue;
-use deno_graph::source::NpmPackageReqResolution;
 use deno_graph::source::NpmResolver;
+use deno_graph::source::PackageReqResolution;
 use deno_graph::source::Resolver;
 use deno_graph::source::UnknownBuiltInNodeModuleError;
 use deno_graph::source::DEFAULT_JSX_IMPORT_SOURCE_MODULE;
 use deno_npm::registry::NpmRegistryApi;
 use deno_runtime::deno_node::is_builtin_node_module;
-use deno_semver::npm::NpmPackageReq;
+use deno_semver::package::PackageReq;
 use import_map::ImportMap;
 use std::path::PathBuf;
 use std::sync::Arc;
@@ -333,12 +333,9 @@ impl NpmResolver for CliGraphResolver {
     .boxed()
   }
 
-  fn resolve_npm(
-    &self,
-    package_req: &NpmPackageReq,
-  ) -> NpmPackageReqResolution {
+  fn resolve_npm(&self, package_req: &PackageReq) -> PackageReqResolution {
     if self.no_npm {
-      return NpmPackageReqResolution::Err(anyhow!(
+      return PackageReqResolution::Err(anyhow!(
         "npm specifiers were requested; but --no-npm is specified"
       ));
     }
@@ -347,13 +344,13 @@ impl NpmResolver for CliGraphResolver {
       .npm_resolution
       .resolve_package_req_as_pending(package_req);
     match result {
-      Ok(nv) => NpmPackageReqResolution::Ok(nv),
+      Ok(nv) => PackageReqResolution::Ok(nv),
       Err(err) => {
         if self.npm_registry_api.mark_force_reload() {
           log::debug!("Restarting npm specifier resolution to check for new registry information. Error: {:#}", err);
-          NpmPackageReqResolution::ReloadRegistryInfo(err.into())
+          PackageReqResolution::ReloadRegistryInfo(err.into())
         } else {
-          NpmPackageReqResolution::Err(err.into())
+          PackageReqResolution::Err(err.into())
         }
       }
     }
@@ -370,7 +367,7 @@ mod test {
   fn test_resolve_package_json_dep() {
     fn resolve(
       specifier: &str,
-      deps: &BTreeMap<String, NpmPackageReq>,
+      deps: &BTreeMap<String, PackageReq>,
     ) -> Result<Option<String>, String> {
       let deps = deps
         .iter()
@@ -384,15 +381,15 @@ mod test {
     let deps = BTreeMap::from([
       (
         "package".to_string(),
-        NpmPackageReq::from_str("package@1.0").unwrap(),
+        PackageReq::from_str("package@1.0").unwrap(),
       ),
       (
         "package-alias".to_string(),
-        NpmPackageReq::from_str("package@^1.2").unwrap(),
+        PackageReq::from_str("package@^1.2").unwrap(),
       ),
       (
         "@deno/test".to_string(),
-        NpmPackageReq::from_str("@deno/test@~0.2").unwrap(),
+        PackageReq::from_str("@deno/test@~0.2").unwrap(),
       ),
     ]);
 
diff --git a/cli/standalone/binary.rs b/cli/standalone/binary.rs
index bfafcdb6be..48ef043da5 100644
--- a/cli/standalone/binary.rs
+++ b/cli/standalone/binary.rs
@@ -21,8 +21,8 @@ use deno_core::url::Url;
 use deno_npm::registry::PackageDepNpmSchemeValueParseError;
 use deno_npm::NpmSystemInfo;
 use deno_runtime::permissions::PermissionsOptions;
-use deno_semver::npm::NpmPackageReq;
-use deno_semver::npm::NpmVersionReqSpecifierParseError;
+use deno_semver::package::PackageReq;
+use deno_semver::VersionReqSpecifierParseError;
 use log::Level;
 use serde::Deserialize;
 use serde::Serialize;
@@ -81,7 +81,7 @@ impl SerializablePackageJsonDepValueParseError {
       }
       SerializablePackageJsonDepValueParseError::Specifier(source) => {
         PackageJsonDepValueParseError::Specifier(
-          NpmVersionReqSpecifierParseError {
+          VersionReqSpecifierParseError {
             source: monch::ParseErrorFailureError::new(source),
           },
         )
@@ -97,7 +97,7 @@ impl SerializablePackageJsonDepValueParseError {
 pub struct SerializablePackageJsonDeps(
   BTreeMap<
     String,
-    Result<NpmPackageReq, SerializablePackageJsonDepValueParseError>,
+    Result<PackageReq, SerializablePackageJsonDepValueParseError>,
   >,
 );
 
diff --git a/cli/tests/integration/compile_tests.rs b/cli/tests/integration/compile_tests.rs
index 022148ce4e..f43b1cff98 100644
--- a/cli/tests/integration/compile_tests.rs
+++ b/cli/tests/integration/compile_tests.rs
@@ -120,9 +120,9 @@ fn standalone_error() {
   assert_contains!(stderr, "error: Uncaught Error: boom!");
   assert_contains!(stderr, "throw new Error(\"boom!\");");
   assert_contains!(stderr, "\n    at boom (file://");
-  assert_contains!(stderr, "standalone_error.ts:2:11");
+  assert_contains!(stderr, "standalone_error.ts:2:9");
   assert_contains!(stderr, "at foo (file://");
-  assert_contains!(stderr, "standalone_error.ts:5:5");
+  assert_contains!(stderr, "standalone_error.ts:5:3");
   assert_contains!(stderr, "standalone_error.ts:7:1");
 }
 
diff --git a/cli/tests/integration/inspector_tests.rs b/cli/tests/integration/inspector_tests.rs
index 79422ee5a8..c507204e47 100644
--- a/cli/tests/integration/inspector_tests.rs
+++ b/cli/tests/integration/inspector_tests.rs
@@ -75,6 +75,12 @@ struct InspectorTester {
   stdout_lines: Box<dyn Iterator<Item = String>>,
 }
 
+impl Drop for InspectorTester {
+  fn drop(&mut self) {
+    _ = self.child.kill();
+  }
+}
+
 fn ignore_script_parsed(msg: &str) -> bool {
   !msg.starts_with(r#"{"method":"Debugger.scriptParsed","#)
 }
@@ -953,7 +959,7 @@ async fn inspector_with_ts_files() {
   tester.assert_received_messages(
       &[
         r#"{"id":4,"result":{"scriptSource":"import { foo } from \"./foo.ts\";\nimport { bar } from \"./bar.js\";\nconsole.log(foo());\nconsole.log(bar());\n//# sourceMappingURL=data:application/json;base64,"#,
-        r#"{"id":5,"result":{"scriptSource":"class Foo {\n    hello() {\n        return \"hello\";\n    }\n}\nexport function foo() {\n    const f = new Foo();\n    return f.hello();\n}\n//# sourceMappingURL=data:application/json;base64,"#,
+        r#"{"id":5,"result":{"scriptSource":"class Foo {\n  hello() {\n    return \"hello\";\n  }\n}\nexport function foo() {\n  const f = new Foo();\n  return f.hello();\n}\n//# sourceMappingURL=data:application/json;base64,"#,
         r#"{"id":6,"result":{"scriptSource":"export function bar() {\n  return \"world\";\n}\n"#,
       ],
       &[],
diff --git a/cli/tests/integration/npm_tests.rs b/cli/tests/integration/npm_tests.rs
index f27befe547..1352777d25 100644
--- a/cli/tests/integration/npm_tests.rs
+++ b/cli/tests/integration/npm_tests.rs
@@ -988,12 +988,12 @@ fn ensure_registry_files_local() {
 }
 
 itest!(bundle_errors {
-    args: "bundle --quiet npm/esm/main.js",
-    output_str: Some("error: npm specifiers have not yet been implemented for this subcommand (https://github.com/denoland/deno/issues/15960). Found: npm:chalk@5.0.1\n"),
-    exit_code: 1,
-    envs: env_vars_for_npm_tests(),
-    http_server: true,
-  });
+  args: "bundle --quiet npm/esm/main.js",
+  output_str: Some("error: npm specifiers have not yet been implemented for this subcommand (https://github.com/denoland/deno/issues/15960). Found: npm:/chalk@5.0.1\n"),
+  exit_code: 1,
+  envs: env_vars_for_npm_tests(),
+  http_server: true,
+});
 
 itest!(info_chalk_display {
   args: "info --quiet npm/cjs_with_deps/main.js",
diff --git a/cli/tests/testdata/npm/cjs_with_deps/main_info.out b/cli/tests/testdata/npm/cjs_with_deps/main_info.out
index cf84197e16..bcaaf1eecf 100644
--- a/cli/tests/testdata/npm/cjs_with_deps/main_info.out
+++ b/cli/tests/testdata/npm/cjs_with_deps/main_info.out
@@ -4,19 +4,19 @@ dependencies: 14 unique
 size: [WILDCARD]
 
 file:///[WILDCARD]/npm/cjs_with_deps/main.js ([WILDCARD])
-├─┬ npm:chalk@4.1.2 ([WILDCARD])
-│ ├─┬ npm:ansi-styles@4.3.0 ([WILDCARD])
-│ │ └─┬ npm:color-convert@2.0.1 ([WILDCARD])
-│ │   └── npm:color-name@1.1.4 ([WILDCARD])
-│ └─┬ npm:supports-color@7.2.0 ([WILDCARD])
-│   └── npm:has-flag@4.0.0 ([WILDCARD])
-└─┬ npm:chai@4.3.6 ([WILDCARD])
-  ├── npm:assertion-error@1.1.0 ([WILDCARD])
-  ├── npm:check-error@1.0.2 ([WILDCARD])
-  ├─┬ npm:deep-eql@3.0.1 ([WILDCARD])
-  │ └── npm:type-detect@4.0.8 ([WILDCARD])
-  ├── npm:get-func-name@2.0.0 ([WILDCARD])
-  ├─┬ npm:loupe@2.3.4 ([WILDCARD])
-  │ └── npm:get-func-name@2.0.0 ([WILDCARD])
-  ├── npm:pathval@1.1.1 ([WILDCARD])
-  └── npm:type-detect@4.0.8 ([WILDCARD])
+├─┬ npm:/chalk@4.1.2 ([WILDCARD])
+│ ├─┬ npm:/ansi-styles@4.3.0 ([WILDCARD])
+│ │ └─┬ npm:/color-convert@2.0.1 ([WILDCARD])
+│ │   └── npm:/color-name@1.1.4 ([WILDCARD])
+│ └─┬ npm:/supports-color@7.2.0 ([WILDCARD])
+│   └── npm:/has-flag@4.0.0 ([WILDCARD])
+└─┬ npm:/chai@4.3.6 ([WILDCARD])
+  ├── npm:/assertion-error@1.1.0 ([WILDCARD])
+  ├── npm:/check-error@1.0.2 ([WILDCARD])
+  ├─┬ npm:/deep-eql@3.0.1 ([WILDCARD])
+  │ └── npm:/type-detect@4.0.8 ([WILDCARD])
+  ├── npm:/get-func-name@2.0.0 ([WILDCARD])
+  ├─┬ npm:/loupe@2.3.4 ([WILDCARD])
+  │ └── npm:/get-func-name@2.0.0 ([WILDCARD])
+  ├── npm:/pathval@1.1.1 ([WILDCARD])
+  └── npm:/type-detect@4.0.8 ([WILDCARD])
diff --git a/cli/tests/testdata/npm/cjs_with_deps/main_info_json.out b/cli/tests/testdata/npm/cjs_with_deps/main_info_json.out
index e2a659a42d..fd850b8a1c 100644
--- a/cli/tests/testdata/npm/cjs_with_deps/main_info_json.out
+++ b/cli/tests/testdata/npm/cjs_with_deps/main_info_json.out
@@ -50,8 +50,8 @@
     }
   ],
   "redirects": {
-    "npm:chai@4.3": "npm:chai@4.3.6",
-    "npm:chalk@4": "npm:chalk@4.1.2"
+    "npm:chai@4.3": "npm:/chai@4.3.6",
+    "npm:chalk@4": "npm:/chalk@4.1.2"
   },
   "npmPackages": {
     "ansi-styles@4.3.0": {
diff --git a/cli/tests/testdata/npm/info/chalk.out b/cli/tests/testdata/npm/info/chalk.out
index d7ac95120e..63fa20da54 100644
--- a/cli/tests/testdata/npm/info/chalk.out
+++ b/cli/tests/testdata/npm/info/chalk.out
@@ -1,9 +1,9 @@
 dependencies: 5 unique
 size: [WILDCARD]
 
-npm:chalk@4.1.2 ([WILDCARD])
-├─┬ npm:ansi-styles@4.3.0 ([WILDCARD])
-│ └─┬ npm:color-convert@2.0.1 ([WILDCARD])
-│   └── npm:color-name@1.1.4 ([WILDCARD])
-└─┬ npm:supports-color@7.2.0 ([WILDCARD])
-  └── npm:has-flag@4.0.0 ([WILDCARD])
+npm:/chalk@4.1.2 ([WILDCARD])
+├─┬ npm:/ansi-styles@4.3.0 ([WILDCARD])
+│ └─┬ npm:/color-convert@2.0.1 ([WILDCARD])
+│   └── npm:/color-name@1.1.4 ([WILDCARD])
+└─┬ npm:/supports-color@7.2.0 ([WILDCARD])
+  └── npm:/has-flag@4.0.0 ([WILDCARD])
diff --git a/cli/tests/testdata/npm/info/chalk_json.out b/cli/tests/testdata/npm/info/chalk_json.out
index 0f86bc9941..bffed4ad44 100644
--- a/cli/tests/testdata/npm/info/chalk_json.out
+++ b/cli/tests/testdata/npm/info/chalk_json.out
@@ -5,12 +5,12 @@
   "modules": [
     {
       "kind": "npm",
-      "specifier": "npm:chalk@4.1.2",
+      "specifier": "npm:/chalk@4.1.2",
       "npmPackage": "chalk@4.1.2"
     }
   ],
   "redirects": {
-    "npm:chalk@4": "npm:chalk@4.1.2"
+    "npm:chalk@4": "npm:/chalk@4.1.2"
   },
   "npmPackages": {
     "ansi-styles@4.3.0": {
diff --git a/cli/tests/testdata/npm/invalid_package_name/main.out b/cli/tests/testdata/npm/invalid_package_name/main.out
index 7d2b3754df..b4a421bd7f 100644
--- a/cli/tests/testdata/npm/invalid_package_name/main.out
+++ b/cli/tests/testdata/npm/invalid_package_name/main.out
@@ -1,2 +1,2 @@
-error: Not a valid package: @foo
+error: Invalid package specifier 'npm:@foo'. Did not contain a valid package name.
     at [WILDCARD]/invalid_package_name/main.js:1:22
diff --git a/cli/tests/testdata/npm/peer_deps_with_copied_folders/main_info.out b/cli/tests/testdata/npm/peer_deps_with_copied_folders/main_info.out
index d85b00094c..638f9328d0 100644
--- a/cli/tests/testdata/npm/peer_deps_with_copied_folders/main_info.out
+++ b/cli/tests/testdata/npm/peer_deps_with_copied_folders/main_info.out
@@ -4,11 +4,11 @@ dependencies: 6 unique
 size: [WILDCARD]
 
 file:///[WILDCARD]/testdata/npm/peer_deps_with_copied_folders/main.ts (171B)
-├─┬ npm:@denotest/peer-dep-test-child@1.0.0 ([WILDCARD])
-│ ├─┬ npm:@denotest/peer-dep-test-grandchild@1.0.0_@denotest+peer-dep-test-peer@1.0.0 ([WILDCARD])
-│ │ └── npm:@denotest/peer-dep-test-peer@1.0.0 ([WILDCARD])
-│ └── npm:@denotest/peer-dep-test-peer@1.0.0 ([WILDCARD])
-└─┬ npm:@denotest/peer-dep-test-child@2.0.0 ([WILDCARD])
-  ├─┬ npm:@denotest/peer-dep-test-grandchild@1.0.0_@denotest+peer-dep-test-peer@2.0.0 ([WILDCARD])
-  │ └── npm:@denotest/peer-dep-test-peer@2.0.0 ([WILDCARD])
-  └── npm:@denotest/peer-dep-test-peer@2.0.0 ([WILDCARD])
+├─┬ npm:/@denotest/peer-dep-test-child@1.0.0 ([WILDCARD])
+│ ├─┬ npm:/@denotest/peer-dep-test-grandchild@1.0.0_@denotest+peer-dep-test-peer@1.0.0 ([WILDCARD])
+│ │ └── npm:/@denotest/peer-dep-test-peer@1.0.0 ([WILDCARD])
+│ └── npm:/@denotest/peer-dep-test-peer@1.0.0 ([WILDCARD])
+└─┬ npm:/@denotest/peer-dep-test-child@2.0.0 ([WILDCARD])
+  ├─┬ npm:/@denotest/peer-dep-test-grandchild@1.0.0_@denotest+peer-dep-test-peer@2.0.0 ([WILDCARD])
+  │ └── npm:/@denotest/peer-dep-test-peer@2.0.0 ([WILDCARD])
+  └── npm:/@denotest/peer-dep-test-peer@2.0.0 ([WILDCARD])
diff --git a/cli/tests/testdata/npm/peer_deps_with_copied_folders/main_info_json.out b/cli/tests/testdata/npm/peer_deps_with_copied_folders/main_info_json.out
index 6a455b0017..a4306a6d5f 100644
--- a/cli/tests/testdata/npm/peer_deps_with_copied_folders/main_info_json.out
+++ b/cli/tests/testdata/npm/peer_deps_with_copied_folders/main_info_json.out
@@ -50,8 +50,8 @@
     }
   ],
   "redirects": {
-    "npm:@denotest/peer-dep-test-child@1": "npm:@denotest/peer-dep-test-child@1.0.0",
-    "npm:@denotest/peer-dep-test-child@2": "npm:@denotest/peer-dep-test-child@2.0.0"
+    "npm:@denotest/peer-dep-test-child@1": "npm:/@denotest/peer-dep-test-child@1.0.0",
+    "npm:@denotest/peer-dep-test-child@2": "npm:/@denotest/peer-dep-test-child@2.0.0"
   },
   "npmPackages": {
     "@denotest/peer-dep-test-child@1.0.0_@denotest+peer-dep-test-peer@1.0.0": {
diff --git a/cli/tests/testdata/package_json/basic/main.info.out b/cli/tests/testdata/package_json/basic/main.info.out
index 3572c75e11..b283a0ee0a 100644
--- a/cli/tests/testdata/package_json/basic/main.info.out
+++ b/cli/tests/testdata/package_json/basic/main.info.out
@@ -5,4 +5,4 @@ size: [WILDCARD]
 
 file:///[WILDCARD]/main.ts (63B)
 └─┬ file:///[WILDCARD]/lib.ts (166B)
-  └── npm:@denotest/esm-basic@1.0.0 (416B)
+  └── npm:/@denotest/esm-basic@1.0.0 (416B)
diff --git a/cli/tests/testdata/package_json/invalid_value/error.ts.out b/cli/tests/testdata/package_json/invalid_value/error.ts.out
index 866388e60f..faa811a306 100644
--- a/cli/tests/testdata/package_json/invalid_value/error.ts.out
+++ b/cli/tests/testdata/package_json/invalid_value/error.ts.out
@@ -1,6 +1,6 @@
 error: Parsing version constraints in the application-level package.json is more strict at the moment.
 
-Invalid npm specifier version requirement. Unexpected character.
+Invalid specifier version requirement. Unexpected character.
   invalid stuff that won't parse
   ~
     at file:///[WILDCARD]/error.ts:2:23
diff --git a/cli/tests/testdata/package_json/invalid_value/task.out b/cli/tests/testdata/package_json/invalid_value/task.out
index 823c50612f..c78a327393 100644
--- a/cli/tests/testdata/package_json/invalid_value/task.out
+++ b/cli/tests/testdata/package_json/invalid_value/task.out
@@ -1,4 +1,4 @@
-Warning Ignoring dependency '@denotest/cjs-default-export' in package.json because its version requirement failed to parse: Invalid npm specifier version requirement. Unexpected character.
+Warning Ignoring dependency '@denotest/cjs-default-export' in package.json because its version requirement failed to parse: Invalid specifier version requirement. Unexpected character.
   invalid stuff that won't parse
   ~
 Warning Currently only basic package.json `scripts` are supported. Programs like `rimraf` or `cross-env` will not work correctly. This will be fixed in an upcoming release.
diff --git a/cli/tools/check.rs b/cli/tools/check.rs
index f2e31b153c..85ce44b955 100644
--- a/cli/tools/check.rs
+++ b/cli/tools/check.rs
@@ -11,8 +11,8 @@ use deno_graph::Module;
 use deno_graph::ModuleGraph;
 use deno_runtime::colors;
 use deno_runtime::deno_node::NodeResolver;
-use deno_semver::npm::NpmPackageNv;
-use deno_semver::npm::NpmPackageReq;
+use deno_semver::package::PackageNv;
+use deno_semver::package::PackageReq;
 use once_cell::sync::Lazy;
 use regex::Regex;
 
@@ -194,7 +194,7 @@ enum CheckHashResult {
 /// be used to tell
 fn get_check_hash(
   graph: &ModuleGraph,
-  package_reqs: HashMap<NpmPackageReq, NpmPackageNv>,
+  package_reqs: HashMap<PackageReq, PackageNv>,
   type_check_mode: TypeCheckMode,
   ts_config: &TsConfig,
 ) -> CheckHashResult {
diff --git a/cli/tools/info.rs b/cli/tools/info.rs
index 08345887b1..c0dd686f8f 100644
--- a/cli/tools/info.rs
+++ b/cli/tools/info.rs
@@ -21,9 +21,9 @@ use deno_npm::resolution::NpmResolutionSnapshot;
 use deno_npm::NpmPackageId;
 use deno_npm::NpmResolutionPackage;
 use deno_runtime::colors;
-use deno_semver::npm::NpmPackageNv;
 use deno_semver::npm::NpmPackageNvReference;
 use deno_semver::npm::NpmPackageReqReference;
+use deno_semver::package::PackageNv;
 
 use crate::args::Flags;
 use crate::args::InfoFlags;
@@ -185,7 +185,7 @@ fn add_npm_packages_to_json(
         .and_then(|specifier| NpmPackageNvReference::from_str(specifier).ok())
         .and_then(|package_ref| {
           snapshot
-            .resolve_package_from_deno_module(&package_ref.nv)
+            .resolve_package_from_deno_module(package_ref.nv())
             .ok()
         });
       if let Some(pkg) = maybe_package {
@@ -220,7 +220,8 @@ fn add_npm_packages_to_json(
             let specifier = dep.get("specifier").and_then(|s| s.as_str());
             if let Some(specifier) = specifier {
               if let Ok(npm_ref) = NpmPackageReqReference::from_str(specifier) {
-                if let Ok(pkg) = snapshot.resolve_pkg_from_pkg_req(&npm_ref.req)
+                if let Ok(pkg) =
+                  snapshot.resolve_pkg_from_pkg_req(npm_ref.req())
                 {
                   dep.insert(
                     "npmPackage".to_string(),
@@ -331,7 +332,7 @@ fn print_tree_node<TWrite: Write>(
 #[derive(Default)]
 struct NpmInfo {
   package_sizes: HashMap<NpmPackageId, u64>,
-  resolved_ids: HashMap<NpmPackageNv, NpmPackageId>,
+  resolved_ids: HashMap<PackageNv, NpmPackageId>,
   packages: HashMap<NpmPackageId, NpmResolutionPackage>,
 }
 
@@ -348,7 +349,7 @@ impl NpmInfo {
 
     for module in graph.modules() {
       if let Module::Npm(module) = module {
-        let nv = &module.nv_reference.nv;
+        let nv = module.nv_reference.nv();
         if let Ok(package) = npm_snapshot.resolve_package_from_deno_module(nv) {
           info.resolved_ids.insert(nv.clone(), package.id.clone());
           if !info.packages.contains_key(&package.id) {
@@ -382,7 +383,7 @@ impl NpmInfo {
 
   pub fn resolve_package(
     &self,
-    nv: &NpmPackageNv,
+    nv: &PackageNv,
   ) -> Option<&NpmResolutionPackage> {
     let id = self.resolved_ids.get(nv)?;
     self.packages.get(id)
@@ -542,7 +543,7 @@ impl<'a> GraphDisplayContext<'a> {
     use PackageOrSpecifier::*;
 
     let package_or_specifier = match module.npm() {
-      Some(npm) => match self.npm_info.resolve_package(&npm.nv_reference.nv) {
+      Some(npm) => match self.npm_info.resolve_package(npm.nv_reference.nv()) {
         Some(package) => Package(package.clone()),
         None => Specifier(module.specifier().clone()), // should never happen
       },
@@ -615,7 +616,7 @@ impl<'a> GraphDisplayContext<'a> {
       let maybe_size = self.npm_info.package_sizes.get(dep_id).cloned();
       let size_str = maybe_size_to_text(maybe_size);
       let mut child = TreeNode::from_text(format!(
-        "npm:{} {}",
+        "npm:/{} {}",
         dep_id.as_serialized(),
         size_str
       ));
diff --git a/cli/tools/installer.rs b/cli/tools/installer.rs
index 03c2ffdcfc..cabae9e28b 100644
--- a/cli/tools/installer.rs
+++ b/cli/tools/installer.rs
@@ -140,6 +140,7 @@ pub async fn infer_name_from_url(url: &Url) -> Option<String> {
   }
 
   if let Ok(npm_ref) = NpmPackageReqReference::from_specifier(&url) {
+    let npm_ref = npm_ref.into_inner();
     if let Some(sub_path) = npm_ref.sub_path {
       if !sub_path.contains('/') {
         return Some(sub_path);
diff --git a/cli/tools/repl/session.rs b/cli/tools/repl/session.rs
index 9261299dfa..d89cc95c3b 100644
--- a/cli/tools/repl/session.rs
+++ b/cli/tools/repl/session.rs
@@ -505,7 +505,7 @@ impl ReplSession {
     let npm_imports = resolved_imports
       .iter()
       .flat_map(|url| NpmPackageReqReference::from_specifier(url).ok())
-      .map(|r| r.req)
+      .map(|r| r.into_inner().req)
       .collect::<Vec<_>>();
     let has_node_specifier =
       resolved_imports.iter().any(|url| url.scheme() == "node");
diff --git a/cli/tools/task.rs b/cli/tools/task.rs
index f99e7431cd..dcb53e4ecd 100644
--- a/cli/tools/task.rs
+++ b/cli/tools/task.rs
@@ -13,7 +13,7 @@ use deno_core::error::AnyError;
 use deno_core::futures;
 use deno_core::futures::future::LocalBoxFuture;
 use deno_runtime::deno_node::NodeResolver;
-use deno_semver::npm::NpmPackageNv;
+use deno_semver::package::PackageNv;
 use deno_task_shell::ExecuteResult;
 use deno_task_shell::ShellCommand;
 use deno_task_shell::ShellCommandContext;
@@ -237,7 +237,7 @@ impl ShellCommand for NpxCommand {
 #[derive(Clone)]
 struct NpmPackageBinCommand {
   name: String,
-  npm_package: NpmPackageNv,
+  npm_package: PackageNv,
 }
 
 impl ShellCommand for NpmPackageBinCommand {
diff --git a/cli/worker.rs b/cli/worker.rs
index b451cdbed5..1d9252e65c 100644
--- a/cli/worker.rs
+++ b/cli/worker.rs
@@ -346,7 +346,7 @@ impl CliMainWorkerFactory {
     {
       shared
         .npm_resolver
-        .add_package_reqs(&[package_ref.req.clone()])
+        .add_package_reqs(&[package_ref.req().clone()])
         .await?;
       let node_resolution =
         self.resolve_binary_entrypoint(&package_ref, &permissions)?;
@@ -500,7 +500,7 @@ impl CliMainWorkerFactory {
     permissions: &PermissionsContainer,
   ) -> Result<Option<NodeResolution>, AnyError> {
     // only fallback if the user specified a sub path
-    if package_ref.sub_path.is_none() {
+    if package_ref.sub_path().is_none() {
       // it's confusing to users if the package doesn't have any binary
       // entrypoint and we just execute the main script which will likely
       // have blank output, so do not resolve the entrypoint in this case
diff --git a/ext/node/lib.rs b/ext/node/lib.rs
index c7d617666f..fa7213c266 100644
--- a/ext/node/lib.rs
+++ b/ext/node/lib.rs
@@ -19,8 +19,8 @@ use deno_fs::sync::MaybeSend;
 use deno_fs::sync::MaybeSync;
 use deno_npm::resolution::PackageReqNotFoundError;
 use deno_npm::NpmPackageId;
-use deno_semver::npm::NpmPackageNv;
-use deno_semver::npm::NpmPackageReq;
+use deno_semver::package::PackageNv;
+use deno_semver::package::PackageReq;
 use once_cell::sync::Lazy;
 
 pub mod analyze;
@@ -94,12 +94,12 @@ pub trait NpmResolver: std::fmt::Debug + MaybeSend + MaybeSync {
   /// Resolves an npm package folder path from a Deno module.
   fn resolve_package_folder_from_deno_module(
     &self,
-    pkg_nv: &NpmPackageNv,
+    pkg_nv: &PackageNv,
   ) -> Result<PathBuf, AnyError>;
 
   fn resolve_pkg_id_from_pkg_req(
     &self,
-    req: &NpmPackageReq,
+    req: &PackageReq,
   ) -> Result<NpmPackageId, PackageReqNotFoundError>;
 
   fn in_npm_package(&self, specifier: &ModuleSpecifier) -> bool;
diff --git a/ext/node/resolution.rs b/ext/node/resolution.rs
index 20501b0f1c..4272b8c866 100644
--- a/ext/node/resolution.rs
+++ b/ext/node/resolution.rs
@@ -15,9 +15,10 @@ use deno_core::url::Url;
 use deno_core::ModuleSpecifier;
 use deno_fs::FileSystemRc;
 use deno_media_type::MediaType;
-use deno_semver::npm::NpmPackageNv;
 use deno_semver::npm::NpmPackageNvReference;
 use deno_semver::npm::NpmPackageReqReference;
+use deno_semver::package::PackageNv;
+use deno_semver::package::PackageNvReference;
 
 use crate::errors;
 use crate::AllowAllNodePermissions;
@@ -336,11 +337,11 @@ impl NodeResolver {
   ) -> Result<Option<NodeResolution>, AnyError> {
     let pkg_id = self
       .npm_resolver
-      .resolve_pkg_id_from_pkg_req(&reference.req)?;
-    let reference = NpmPackageNvReference {
+      .resolve_pkg_id_from_pkg_req(reference.req())?;
+    let reference = NpmPackageNvReference::new(PackageNvReference {
       nv: pkg_id.nv,
-      sub_path: reference.sub_path.clone(),
-    };
+      sub_path: reference.sub_path().map(ToOwned::to_owned),
+    });
     self.resolve_npm_reference(&reference, mode, permissions)
   }
 
@@ -352,13 +353,12 @@ impl NodeResolver {
   ) -> Result<Option<NodeResolution>, AnyError> {
     let package_folder = self
       .npm_resolver
-      .resolve_package_folder_from_deno_module(&reference.nv)?;
+      .resolve_package_folder_from_deno_module(reference.nv())?;
     let node_module_kind = NodeModuleKind::Esm;
     let maybe_resolved_path = self
       .package_config_resolve(
         &reference
-          .sub_path
-          .as_ref()
+          .sub_path()
           .map(|s| format!("./{s}"))
           .unwrap_or_else(|| ".".to_string()),
         &package_folder,
@@ -392,7 +392,7 @@ impl NodeResolver {
 
   pub fn resolve_binary_commands(
     &self,
-    pkg_nv: &NpmPackageNv,
+    pkg_nv: &PackageNv,
   ) -> Result<Vec<String>, AnyError> {
     let package_folder = self
       .npm_resolver
@@ -416,9 +416,9 @@ impl NodeResolver {
   ) -> Result<NodeResolution, AnyError> {
     let pkg_nv = self
       .npm_resolver
-      .resolve_pkg_id_from_pkg_req(&pkg_ref.req)?
+      .resolve_pkg_id_from_pkg_req(pkg_ref.req())?
       .nv;
-    let bin_name = pkg_ref.sub_path.as_deref();
+    let bin_name = pkg_ref.sub_path();
     let package_folder = self
       .npm_resolver
       .resolve_package_folder_from_deno_module(&pkg_nv)?;
@@ -1288,7 +1288,7 @@ impl NodeResolver {
 }
 
 fn resolve_bin_entry_value<'a>(
-  pkg_nv: &NpmPackageNv,
+  pkg_nv: &PackageNv,
   bin_name: Option<&str>,
   bin: &'a Value,
 ) -> Result<&'a str, AnyError> {
@@ -1600,7 +1600,7 @@ mod tests {
     });
     assert_eq!(
       resolve_bin_entry_value(
-        &NpmPackageNv::from_str("test@1.1.1").unwrap(),
+        &PackageNv::from_str("test@1.1.1").unwrap(),
         Some("bin1"),
         &value
       )
@@ -1611,7 +1611,7 @@ mod tests {
     // should resolve the value with the same name when not specified
     assert_eq!(
       resolve_bin_entry_value(
-        &NpmPackageNv::from_str("test@1.1.1").unwrap(),
+        &PackageNv::from_str("test@1.1.1").unwrap(),
         None,
         &value
       )
@@ -1622,7 +1622,7 @@ mod tests {
     // should not resolve when specified value does not exist
     assert_eq!(
       resolve_bin_entry_value(
-        &NpmPackageNv::from_str("test@1.1.1").unwrap(),
+        &PackageNv::from_str("test@1.1.1").unwrap(),
         Some("other"),
         &value
       )
@@ -1642,7 +1642,7 @@ mod tests {
     // should not resolve when default value can't be determined
     assert_eq!(
       resolve_bin_entry_value(
-        &NpmPackageNv::from_str("asdf@1.2.3").unwrap(),
+        &PackageNv::from_str("asdf@1.2.3").unwrap(),
         None,
         &value
       )
@@ -1666,7 +1666,7 @@ mod tests {
     });
     assert_eq!(
       resolve_bin_entry_value(
-        &NpmPackageNv::from_str("test@1.2.3").unwrap(),
+        &PackageNv::from_str("test@1.2.3").unwrap(),
         None,
         &value
       )
@@ -1678,7 +1678,7 @@ mod tests {
     let value = json!("./value");
     assert_eq!(
       resolve_bin_entry_value(
-        &NpmPackageNv::from_str("test@1.2.3").unwrap(),
+        &PackageNv::from_str("test@1.2.3").unwrap(),
         Some("path"),
         &value
       )
diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json
index c3deef9bd1..865a2d5f4d 100644
--- a/tools/wpt/expectation.json
+++ b/tools/wpt/expectation.json
@@ -3211,10 +3211,10 @@
     "urlsearchparams-constructor.any.html": true,
     "urlsearchparams-constructor.any.worker.html": true,
     "urlsearchparams-delete.any.html": [
-      "Changing the query of a URL with an opaque path can impact the path"
+      "Changing the query of a URL with an opaque path can impact the path if the URL has no fragment"
     ],
     "urlsearchparams-delete.any.worker.html": [
-      "Changing the query of a URL with an opaque path can impact the path"
+      "Changing the query of a URL with an opaque path can impact the path if the URL has no fragment"
     ],
     "urlsearchparams-foreach.any.html": true,
     "urlsearchparams-foreach.any.worker.html": true,
@@ -3276,9 +3276,7 @@
       "Input  with encoding utf-8",
       "Input − with encoding shift_jis",
       "Input − with encoding utf-8",
-      "Input á| with encoding utf-8",
-      "Input \ud800 with encoding utf-8",
-      "Input \ud800 with encoding windows-1252"
+      "Input á| with encoding utf-8"
     ],
     "url-setters-a-area.window.html": {
       "ignore": true
@@ -3568,18 +3566,510 @@
     ],
     "url-constructor.any.worker.html?include=javascript": true,
     "url-constructor.any.worker.html?include=mailto": true,
-    "url-setters-a-area.window.html?exclude=(file|javascript|mailto)": {
-      "ignore": true
-    },
-    "url-setters-a-area.window.html?include=file": {
-      "ignore": true
-    },
-    "url-setters-a-area.window.html?include=javascript": {
-      "ignore": true
-    },
-    "url-setters-a-area.window.html?include=mailto": {
-      "ignore": true
-    },
+    "url-setters-a-area.window.html?exclude=(file|javascript|mailto)": [
+      "<a>: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged.",
+      "<area>: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged.",
+      "<a>: Setting <a://example.net>.protocol = 'b'",
+      "<area>: Setting <a://example.net>.protocol = 'b'",
+      "<a>: Setting <a://example.net>.protocol = 'B' Upper-case ASCII is lower-cased",
+      "<area>: Setting <a://example.net>.protocol = 'B' Upper-case ASCII is lower-cased",
+      "<a>: Setting <a://example.net>.protocol = 'é' Non-ASCII is rejected",
+      "<area>: Setting <a://example.net>.protocol = 'é' Non-ASCII is rejected",
+      "<a>: Setting <a://example.net>.protocol = '0b' No leading digit",
+      "<area>: Setting <a://example.net>.protocol = '0b' No leading digit",
+      "<a>: Setting <a://example.net>.protocol = '+b' No leading punctuation",
+      "<area>: Setting <a://example.net>.protocol = '+b' No leading punctuation",
+      "<a>: Setting <a://example.net>.protocol = 'bC0+-.'",
+      "<area>: Setting <a://example.net>.protocol = 'bC0+-.'",
+      "<a>: Setting <a://example.net>.protocol = 'b,c' Only some punctuation is acceptable",
+      "<area>: Setting <a://example.net>.protocol = 'b,c' Only some punctuation is acceptable",
+      "<a>: Setting <a://example.net>.protocol = 'bé' Non-ASCII is rejected",
+      "<area>: Setting <a://example.net>.protocol = 'bé' Non-ASCII is rejected",
+      "<a>: Setting <http://test@example.net>.protocol = 'file' Can’t switch from URL containing username/password/port to file",
+      "<area>: Setting <http://test@example.net>.protocol = 'file' Can’t switch from URL containing username/password/port to file",
+      "<a>: Setting <https://example.net:1234>.protocol = 'file'",
+      "<area>: Setting <https://example.net:1234>.protocol = 'file'",
+      "<a>: Setting <wss://x:x@example.net:1234>.protocol = 'file'",
+      "<area>: Setting <wss://x:x@example.net:1234>.protocol = 'file'",
+      "<a>: Setting <http://example.net>.protocol = 'b' Can’t switch from special scheme to non-special",
+      "<area>: Setting <http://example.net>.protocol = 'b' Can’t switch from special scheme to non-special",
+      "<a>: Setting <https://example.net>.protocol = 's'",
+      "<area>: Setting <https://example.net>.protocol = 's'",
+      "<a>: Setting <ftp://example.net>.protocol = 'test'",
+      "<area>: Setting <ftp://example.net>.protocol = 'test'",
+      "<a>: Setting <ssh://me@example.net>.protocol = 'http' Can’t switch from non-special scheme to special",
+      "<area>: Setting <ssh://me@example.net>.protocol = 'http' Can’t switch from non-special scheme to special",
+      "<a>: Setting <ssh://me@example.net>.protocol = 'https'",
+      "<area>: Setting <ssh://me@example.net>.protocol = 'https'",
+      "<a>: Setting <ssh://me@example.net>.protocol = 'file'",
+      "<area>: Setting <ssh://me@example.net>.protocol = 'file'",
+      "<a>: Setting <ssh://example.net>.protocol = 'file'",
+      "<area>: Setting <ssh://example.net>.protocol = 'file'",
+      "<a>: Setting <nonsense:///test>.protocol = 'https'",
+      "<area>: Setting <nonsense:///test>.protocol = 'https'",
+      "<a>: Setting <http://example.net>.protocol = 'https:foo : bar' Stuff after the first ':' is ignored",
+      "<area>: Setting <http://example.net>.protocol = 'https:foo : bar' Stuff after the first ':' is ignored",
+      "<a>: Setting <data:text/html,<p>Test>.protocol = 'view-source+data:foo : bar' Stuff after the first ':' is ignored",
+      "<area>: Setting <data:text/html,<p>Test>.protocol = 'view-source+data:foo : bar' Stuff after the first ':' is ignored",
+      "<a>: Setting <http://foo.com:443/>.protocol = 'https' Port is set to null if it is the default for new scheme.",
+      "<area>: Setting <http://foo.com:443/>.protocol = 'https' Port is set to null if it is the default for new scheme.",
+      "<a>: Setting <http://test/>.protocol = 'h\r\ntt\tps' Tab and newline are stripped",
+      "<area>: Setting <http://test/>.protocol = 'h\r\ntt\tps' Tab and newline are stripped",
+      "<a>: Setting <http://test/>.protocol = 'https\r'",
+      "<area>: Setting <http://test/>.protocol = 'https\r'",
+      "<a>: Setting <http://test/>.protocol = 'https\u0000' Non-tab/newline C0 controls result in no-op",
+      "<area>: Setting <http://test/>.protocol = 'https\u0000' Non-tab/newline C0 controls result in no-op",
+      "<a>: Setting <http://test/>.protocol = 'https\f'",
+      "<area>: Setting <http://test/>.protocol = 'https\f'",
+      "<a>: Setting <http://test/>.protocol = 'https\u000e'",
+      "<area>: Setting <http://test/>.protocol = 'https\u000e'",
+      "<a>: Setting <http://test/>.protocol = 'https '",
+      "<area>: Setting <http://test/>.protocol = 'https '",
+      "<a>: Setting <unix:/run/foo.socket>.username = 'me' No host means no username",
+      "<area>: Setting <unix:/run/foo.socket>.username = 'me' No host means no username",
+      "<a>: Setting <http://example.net>.username = 'me'",
+      "<area>: Setting <http://example.net>.username = 'me'",
+      "<a>: Setting <http://:secret@example.net>.username = 'me'",
+      "<area>: Setting <http://:secret@example.net>.username = 'me'",
+      "<a>: Setting <http://me@example.net>.username = ''",
+      "<area>: Setting <http://me@example.net>.username = ''",
+      "<a>: Setting <http://me:secret@example.net>.username = ''",
+      "<area>: Setting <http://me:secret@example.net>.username = ''",
+      "<a>: Setting <http://example.net>.username = '\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~€Éé' UTF-8 percent encoding with the userinfo encode set.",
+      "<area>: Setting <http://example.net>.username = '\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~€Éé' UTF-8 percent encoding with the userinfo encode set.",
+      "<a>: Setting <http://example.net>.username = '%c3%89té' Bytes already percent-encoded are left as-is.",
+      "<area>: Setting <http://example.net>.username = '%c3%89té' Bytes already percent-encoded are left as-is.",
+      "<a>: Setting <sc:///>.username = 'x'",
+      "<area>: Setting <sc:///>.username = 'x'",
+      "<a>: Setting <unix:/run/foo.socket>.password = 'secret' No host means no password",
+      "<area>: Setting <unix:/run/foo.socket>.password = 'secret' No host means no password",
+      "<a>: Setting <http://example.net>.password = 'secret'",
+      "<area>: Setting <http://example.net>.password = 'secret'",
+      "<a>: Setting <http://me@example.net>.password = 'secret'",
+      "<area>: Setting <http://me@example.net>.password = 'secret'",
+      "<a>: Setting <http://:secret@example.net>.password = ''",
+      "<area>: Setting <http://:secret@example.net>.password = ''",
+      "<a>: Setting <http://me:secret@example.net>.password = ''",
+      "<area>: Setting <http://me:secret@example.net>.password = ''",
+      "<a>: Setting <http://example.net>.password = '\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~€Éé' UTF-8 percent encoding with the userinfo encode set.",
+      "<area>: Setting <http://example.net>.password = '\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~€Éé' UTF-8 percent encoding with the userinfo encode set.",
+      "<a>: Setting <http://example.net>.password = '%c3%89té' Bytes already percent-encoded are left as-is.",
+      "<area>: Setting <http://example.net>.password = '%c3%89té' Bytes already percent-encoded are left as-is.",
+      "<a>: Setting <sc:///>.password = 'x'",
+      "<area>: Setting <sc:///>.password = 'x'",
+      "<a>: Setting <sc://x/>.host = '\u0000' Non-special scheme",
+      "<area>: Setting <sc://x/>.host = '\u0000' Non-special scheme",
+      "<a>: Setting <sc://x/>.host = '\t'",
+      "<area>: Setting <sc://x/>.host = '\t'",
+      "<a>: Setting <sc://x/>.host = '\n'",
+      "<area>: Setting <sc://x/>.host = '\n'",
+      "<a>: Setting <sc://x/>.host = '\r'",
+      "<area>: Setting <sc://x/>.host = '\r'",
+      "<a>: Setting <sc://x/>.host = ' '",
+      "<area>: Setting <sc://x/>.host = ' '",
+      "<a>: Setting <sc://x/>.host = '#'",
+      "<area>: Setting <sc://x/>.host = '#'",
+      "<a>: Setting <sc://x/>.host = '/'",
+      "<area>: Setting <sc://x/>.host = '/'",
+      "<a>: Setting <sc://x/>.host = '?'",
+      "<area>: Setting <sc://x/>.host = '?'",
+      "<a>: Setting <sc://x/>.host = '@'",
+      "<area>: Setting <sc://x/>.host = '@'",
+      "<a>: Setting <sc://x/>.host = 'ß'",
+      "<area>: Setting <sc://x/>.host = 'ß'",
+      "<a>: Setting <https://x/>.host = 'ß' IDNA Nontransitional_Processing",
+      "<area>: Setting <https://x/>.host = 'ß' IDNA Nontransitional_Processing",
+      "<a>: Setting <data:text/plain,Stuff>.host = 'example.net' Cannot-be-a-base means no host",
+      "<area>: Setting <data:text/plain,Stuff>.host = 'example.net' Cannot-be-a-base means no host",
+      "<a>: Setting <http://example.net>.host = 'example.com:8080'",
+      "<area>: Setting <http://example.net>.host = 'example.com:8080'",
+      "<a>: Setting <http://example.net:8080>.host = 'example.com' Port number is unchanged if not specified in the new value",
+      "<area>: Setting <http://example.net:8080>.host = 'example.com' Port number is unchanged if not specified in the new value",
+      "<a>: Setting <http://example.net:8080>.host = 'example.com:' Port number is unchanged if not specified",
+      "<area>: Setting <http://example.net:8080>.host = 'example.com:' Port number is unchanged if not specified",
+      "<a>: Setting <http://example.net>.host = '' The empty host is not valid for special schemes",
+      "<area>: Setting <http://example.net>.host = '' The empty host is not valid for special schemes",
+      "<a>: Setting <view-source+http://example.net/foo>.host = '' The empty host is OK for non-special schemes",
+      "<area>: Setting <view-source+http://example.net/foo>.host = '' The empty host is OK for non-special schemes",
+      "<a>: Setting <a:/foo>.host = 'example.net' Path-only URLs can gain a host",
+      "<area>: Setting <a:/foo>.host = 'example.net' Path-only URLs can gain a host",
+      "<a>: Setting <http://example.net>.host = '0x7F000001:8080' IPv4 address syntax is normalized",
+      "<area>: Setting <http://example.net>.host = '0x7F000001:8080' IPv4 address syntax is normalized",
+      "<a>: Setting <http://example.net>.host = '[::0:01]:2' IPv6 address syntax is normalized",
+      "<area>: Setting <http://example.net>.host = '[::0:01]:2' IPv6 address syntax is normalized",
+      "<a>: Setting <http://example.net>.host = '[2001:db8::2]:4002' IPv6 literal address with port, crbug.com/1012416",
+      "<area>: Setting <http://example.net>.host = '[2001:db8::2]:4002' IPv6 literal address with port, crbug.com/1012416",
+      "<a>: Setting <http://example.net>.host = 'example.com:80' Default port number is removed",
+      "<area>: Setting <http://example.net>.host = 'example.com:80' Default port number is removed",
+      "<a>: Setting <https://example.net>.host = 'example.com:443' Default port number is removed",
+      "<area>: Setting <https://example.net>.host = 'example.com:443' Default port number is removed",
+      "<a>: Setting <https://example.net>.host = 'example.com:80' Default port number is only removed for the relevant scheme",
+      "<area>: Setting <https://example.net>.host = 'example.com:80' Default port number is only removed for the relevant scheme",
+      "<a>: Setting <http://example.net:8080>.host = 'example.com:80' Port number is removed if new port is scheme default and existing URL has a non-default port",
+      "<area>: Setting <http://example.net:8080>.host = 'example.com:80' Port number is removed if new port is scheme default and existing URL has a non-default port",
+      "<a>: Setting <http://example.net/path>.host = 'example.com/stuff' Stuff after a / delimiter is ignored",
+      "<area>: Setting <http://example.net/path>.host = 'example.com/stuff' Stuff after a / delimiter is ignored",
+      "<a>: Setting <http://example.net/path>.host = 'example.com:8080/stuff' Stuff after a / delimiter is ignored",
+      "<area>: Setting <http://example.net/path>.host = 'example.com:8080/stuff' Stuff after a / delimiter is ignored",
+      "<a>: Setting <http://example.net/path>.host = 'example.com?stuff' Stuff after a ? delimiter is ignored",
+      "<area>: Setting <http://example.net/path>.host = 'example.com?stuff' Stuff after a ? delimiter is ignored",
+      "<a>: Setting <http://example.net/path>.host = 'example.com:8080?stuff' Stuff after a ? delimiter is ignored",
+      "<area>: Setting <http://example.net/path>.host = 'example.com:8080?stuff' Stuff after a ? delimiter is ignored",
+      "<a>: Setting <http://example.net/path>.host = 'example.com#stuff' Stuff after a # delimiter is ignored",
+      "<area>: Setting <http://example.net/path>.host = 'example.com#stuff' Stuff after a # delimiter is ignored",
+      "<a>: Setting <http://example.net/path>.host = 'example.com:8080#stuff' Stuff after a # delimiter is ignored",
+      "<area>: Setting <http://example.net/path>.host = 'example.com:8080#stuff' Stuff after a # delimiter is ignored",
+      "<a>: Setting <http://example.net/path>.host = 'example.com\\stuff' Stuff after a \\ delimiter is ignored for special schemes",
+      "<area>: Setting <http://example.net/path>.host = 'example.com\\stuff' Stuff after a \\ delimiter is ignored for special schemes",
+      "<a>: Setting <http://example.net/path>.host = 'example.com:8080\\stuff' Stuff after a \\ delimiter is ignored for special schemes",
+      "<area>: Setting <http://example.net/path>.host = 'example.com:8080\\stuff' Stuff after a \\ delimiter is ignored for special schemes",
+      "<a>: Setting <view-source+http://example.net/path>.host = 'example.com\\stuff' \\ is not a delimiter for non-special schemes, but still forbidden in hosts",
+      "<area>: Setting <view-source+http://example.net/path>.host = 'example.com\\stuff' \\ is not a delimiter for non-special schemes, but still forbidden in hosts",
+      "<a>: Setting <view-source+http://example.net/path>.host = 'example.com:8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error",
+      "<area>: Setting <view-source+http://example.net/path>.host = 'example.com:8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error",
+      "<a>: Setting <http://example.net/path>.host = 'example.com:8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error",
+      "<area>: Setting <http://example.net/path>.host = 'example.com:8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error",
+      "<a>: Setting <http://example.net/path>.host = 'example.com:8080+2' Anything other than ASCII digit stops the port parser in a setter but is not an error",
+      "<area>: Setting <http://example.net/path>.host = 'example.com:8080+2' Anything other than ASCII digit stops the port parser in a setter but is not an error",
+      "<a>: Setting <http://example.net/path>.host = 'example.com:65535' Port numbers are 16 bit integers",
+      "<area>: Setting <http://example.net/path>.host = 'example.com:65535' Port numbers are 16 bit integers",
+      "<a>: Setting <http://example.net/path>.host = 'example.com:65536' Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though.",
+      "<area>: Setting <http://example.net/path>.host = 'example.com:65536' Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though.",
+      "<a>: Setting <http://example.net/>.host = '[google.com]' Broken IPv6",
+      "<area>: Setting <http://example.net/>.host = '[google.com]' Broken IPv6",
+      "<a>: Setting <http://example.net/>.host = '[::1.2.3.4x]'",
+      "<area>: Setting <http://example.net/>.host = '[::1.2.3.4x]'",
+      "<a>: Setting <http://example.net/>.host = '[::1.2.3.]'",
+      "<area>: Setting <http://example.net/>.host = '[::1.2.3.]'",
+      "<a>: Setting <http://example.net/>.host = '[::1.2.]'",
+      "<area>: Setting <http://example.net/>.host = '[::1.2.]'",
+      "<a>: Setting <http://example.net/>.host = '[::1.]'",
+      "<area>: Setting <http://example.net/>.host = '[::1.]'",
+      "<a>: Setting <sc://test@test/>.host = ''",
+      "<area>: Setting <sc://test@test/>.host = ''",
+      "<a>: Setting <sc://test:12/>.host = ''",
+      "<area>: Setting <sc://test:12/>.host = ''",
+      "<a>: Setting <http://example.com/>.host = '///bad.com' Leading / is not stripped",
+      "<area>: Setting <http://example.com/>.host = '///bad.com' Leading / is not stripped",
+      "<a>: Setting <sc://example.com/>.host = '///bad.com' Leading / is not stripped",
+      "<area>: Setting <sc://example.com/>.host = '///bad.com' Leading / is not stripped",
+      "<a>: Setting <https://example.com/>.host = 'a%C2%ADb'",
+      "<area>: Setting <https://example.com/>.host = 'a%C2%ADb'",
+      "<a>: Setting <https://example.com/>.host = '­'",
+      "<area>: Setting <https://example.com/>.host = '­'",
+      "<a>: Setting <https://example.com/>.host = '%C2%AD'",
+      "<area>: Setting <https://example.com/>.host = '%C2%AD'",
+      "<a>: Setting <https://example.com/>.host = 'xn--'",
+      "<area>: Setting <https://example.com/>.host = 'xn--'",
+      "<a>: Setting <sc://x/>.hostname = '\u0000' Non-special scheme",
+      "<area>: Setting <sc://x/>.hostname = '\u0000' Non-special scheme",
+      "<a>: Setting <sc://x/>.hostname = '\t'",
+      "<area>: Setting <sc://x/>.hostname = '\t'",
+      "<a>: Setting <sc://x/>.hostname = '\n'",
+      "<area>: Setting <sc://x/>.hostname = '\n'",
+      "<a>: Setting <sc://x/>.hostname = '\r'",
+      "<area>: Setting <sc://x/>.hostname = '\r'",
+      "<a>: Setting <sc://x/>.hostname = ' '",
+      "<area>: Setting <sc://x/>.hostname = ' '",
+      "<a>: Setting <sc://x/>.hostname = '#'",
+      "<area>: Setting <sc://x/>.hostname = '#'",
+      "<a>: Setting <sc://x/>.hostname = '/'",
+      "<area>: Setting <sc://x/>.hostname = '/'",
+      "<a>: Setting <sc://x/>.hostname = '?'",
+      "<area>: Setting <sc://x/>.hostname = '?'",
+      "<a>: Setting <sc://x/>.hostname = '@'",
+      "<area>: Setting <sc://x/>.hostname = '@'",
+      "<a>: Setting <data:text/plain,Stuff>.hostname = 'example.net' Cannot-be-a-base means no host",
+      "<area>: Setting <data:text/plain,Stuff>.hostname = 'example.net' Cannot-be-a-base means no host",
+      "<a>: Setting <http://example.net:8080>.hostname = 'example.com'",
+      "<area>: Setting <http://example.net:8080>.hostname = 'example.com'",
+      "<a>: Setting <http://example.net>.hostname = '' The empty host is not valid for special schemes",
+      "<area>: Setting <http://example.net>.hostname = '' The empty host is not valid for special schemes",
+      "<a>: Setting <view-source+http://example.net/foo>.hostname = '' The empty host is OK for non-special schemes",
+      "<area>: Setting <view-source+http://example.net/foo>.hostname = '' The empty host is OK for non-special schemes",
+      "<a>: Setting <a:/foo>.hostname = 'example.net' Path-only URLs can gain a host",
+      "<area>: Setting <a:/foo>.hostname = 'example.net' Path-only URLs can gain a host",
+      "<a>: Setting <http://example.net:8080>.hostname = '0x7F000001' IPv4 address syntax is normalized",
+      "<area>: Setting <http://example.net:8080>.hostname = '0x7F000001' IPv4 address syntax is normalized",
+      "<a>: Setting <http://example.net>.hostname = '[::0:01]' IPv6 address syntax is normalized",
+      "<area>: Setting <http://example.net>.hostname = '[::0:01]' IPv6 address syntax is normalized",
+      "<a>: Setting <http://example.net/path>.hostname = 'example.com:8080' : delimiter invalidates entire value",
+      "<area>: Setting <http://example.net/path>.hostname = 'example.com:8080' : delimiter invalidates entire value",
+      "<a>: Setting <http://example.net:8080/path>.hostname = 'example.com:' : delimiter invalidates entire value",
+      "<area>: Setting <http://example.net:8080/path>.hostname = 'example.com:' : delimiter invalidates entire value",
+      "<a>: Setting <http://example.net/path>.hostname = 'example.com/stuff' Stuff after a / delimiter is ignored",
+      "<area>: Setting <http://example.net/path>.hostname = 'example.com/stuff' Stuff after a / delimiter is ignored",
+      "<a>: Setting <http://example.net/path>.hostname = 'example.com?stuff' Stuff after a ? delimiter is ignored",
+      "<area>: Setting <http://example.net/path>.hostname = 'example.com?stuff' Stuff after a ? delimiter is ignored",
+      "<a>: Setting <http://example.net/path>.hostname = 'example.com#stuff' Stuff after a # delimiter is ignored",
+      "<area>: Setting <http://example.net/path>.hostname = 'example.com#stuff' Stuff after a # delimiter is ignored",
+      "<a>: Setting <http://example.net/path>.hostname = 'example.com\\stuff' Stuff after a \\ delimiter is ignored for special schemes",
+      "<area>: Setting <http://example.net/path>.hostname = 'example.com\\stuff' Stuff after a \\ delimiter is ignored for special schemes",
+      "<a>: Setting <view-source+http://example.net/path>.hostname = 'example.com\\stuff' \\ is not a delimiter for non-special schemes, but still forbidden in hosts",
+      "<area>: Setting <view-source+http://example.net/path>.hostname = 'example.com\\stuff' \\ is not a delimiter for non-special schemes, but still forbidden in hosts",
+      "<a>: Setting <http://example.net/>.hostname = '[google.com]' Broken IPv6",
+      "<area>: Setting <http://example.net/>.hostname = '[google.com]' Broken IPv6",
+      "<a>: Setting <http://example.net/>.hostname = '[::1.2.3.4x]'",
+      "<area>: Setting <http://example.net/>.hostname = '[::1.2.3.4x]'",
+      "<a>: Setting <http://example.net/>.hostname = '[::1.2.3.]'",
+      "<area>: Setting <http://example.net/>.hostname = '[::1.2.3.]'",
+      "<a>: Setting <http://example.net/>.hostname = '[::1.2.]'",
+      "<area>: Setting <http://example.net/>.hostname = '[::1.2.]'",
+      "<a>: Setting <http://example.net/>.hostname = '[::1.]'",
+      "<area>: Setting <http://example.net/>.hostname = '[::1.]'",
+      "<a>: Setting <sc://test@test/>.hostname = ''",
+      "<area>: Setting <sc://test@test/>.hostname = ''",
+      "<a>: Setting <sc://test:12/>.hostname = ''",
+      "<area>: Setting <sc://test:12/>.hostname = ''",
+      "<a>: Setting <non-spec:/.//p>.hostname = 'h' Drop /. from path",
+      "<area>: Setting <non-spec:/.//p>.hostname = 'h' Drop /. from path",
+      "<a>: Setting <non-spec:/.//p>.hostname = ''",
+      "<area>: Setting <non-spec:/.//p>.hostname = ''",
+      "<a>: Setting <http://example.com/>.hostname = '///bad.com' Leading / is not stripped",
+      "<area>: Setting <http://example.com/>.hostname = '///bad.com' Leading / is not stripped",
+      "<a>: Setting <sc://example.com/>.hostname = '///bad.com' Leading / is not stripped",
+      "<area>: Setting <sc://example.com/>.hostname = '///bad.com' Leading / is not stripped",
+      "<a>: Setting <https://example.com/>.hostname = 'a%C2%ADb'",
+      "<area>: Setting <https://example.com/>.hostname = 'a%C2%ADb'",
+      "<a>: Setting <https://example.com/>.hostname = '­'",
+      "<area>: Setting <https://example.com/>.hostname = '­'",
+      "<a>: Setting <https://example.com/>.hostname = '%C2%AD'",
+      "<area>: Setting <https://example.com/>.hostname = '%C2%AD'",
+      "<a>: Setting <https://example.com/>.hostname = 'xn--'",
+      "<area>: Setting <https://example.com/>.hostname = 'xn--'",
+      "<a>: Setting <http://example.net>.port = '8080'",
+      "<area>: Setting <http://example.net>.port = '8080'",
+      "<a>: Setting <http://example.net:8080>.port = '' Port number is removed if empty is the new value",
+      "<area>: Setting <http://example.net:8080>.port = '' Port number is removed if empty is the new value",
+      "<a>: Setting <http://example.net:8080>.port = '80' Default port number is removed",
+      "<area>: Setting <http://example.net:8080>.port = '80' Default port number is removed",
+      "<a>: Setting <https://example.net:4433>.port = '443' Default port number is removed",
+      "<area>: Setting <https://example.net:4433>.port = '443' Default port number is removed",
+      "<a>: Setting <https://example.net>.port = '80' Default port number is only removed for the relevant scheme",
+      "<area>: Setting <https://example.net>.port = '80' Default port number is only removed for the relevant scheme",
+      "<a>: Setting <http://example.net/path>.port = '8080/stuff' Stuff after a / delimiter is ignored",
+      "<area>: Setting <http://example.net/path>.port = '8080/stuff' Stuff after a / delimiter is ignored",
+      "<a>: Setting <http://example.net/path>.port = '8080?stuff' Stuff after a ? delimiter is ignored",
+      "<area>: Setting <http://example.net/path>.port = '8080?stuff' Stuff after a ? delimiter is ignored",
+      "<a>: Setting <http://example.net/path>.port = '8080#stuff' Stuff after a # delimiter is ignored",
+      "<area>: Setting <http://example.net/path>.port = '8080#stuff' Stuff after a # delimiter is ignored",
+      "<a>: Setting <http://example.net/path>.port = '8080\\stuff' Stuff after a \\ delimiter is ignored for special schemes",
+      "<area>: Setting <http://example.net/path>.port = '8080\\stuff' Stuff after a \\ delimiter is ignored for special schemes",
+      "<a>: Setting <view-source+http://example.net/path>.port = '8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error",
+      "<area>: Setting <view-source+http://example.net/path>.port = '8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error",
+      "<a>: Setting <http://example.net/path>.port = '8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error",
+      "<area>: Setting <http://example.net/path>.port = '8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error",
+      "<a>: Setting <http://example.net/path>.port = '8080+2' Anything other than ASCII digit stops the port parser in a setter but is not an error",
+      "<area>: Setting <http://example.net/path>.port = '8080+2' Anything other than ASCII digit stops the port parser in a setter but is not an error",
+      "<a>: Setting <http://example.net/path>.port = '65535' Port numbers are 16 bit integers",
+      "<area>: Setting <http://example.net/path>.port = '65535' Port numbers are 16 bit integers",
+      "<a>: Setting <http://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error",
+      "<area>: Setting <http://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error",
+      "<a>: Setting <http://example.net:8080/path>.port = 'randomstring' Setting port to a string that doesn't parse as a number",
+      "<area>: Setting <http://example.net:8080/path>.port = 'randomstring' Setting port to a string that doesn't parse as a number",
+      "<a>: Setting <non-special://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error",
+      "<area>: Setting <non-special://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error",
+      "<a>: Setting <non-base:value>.port = '12'",
+      "<area>: Setting <non-base:value>.port = '12'",
+      "<a>: Setting <sc:///>.port = '12'",
+      "<area>: Setting <sc:///>.port = '12'",
+      "<a>: Setting <sc://x/>.port = '12'",
+      "<area>: Setting <sc://x/>.port = '12'",
+      "<a>: Setting <https://domain.com:443>.port = '\t8080' Leading u0009 on special scheme",
+      "<area>: Setting <https://domain.com:443>.port = '\t8080' Leading u0009 on special scheme",
+      "<a>: Setting <wpt++://domain.com:443>.port = '\t8080' Leading u0009 on non-special scheme",
+      "<area>: Setting <wpt++://domain.com:443>.port = '\t8080' Leading u0009 on non-special scheme",
+      "<a>: Setting <https://www.google.com:4343>.port = '4wpt' Should use all ascii prefixed characters as port",
+      "<area>: Setting <https://www.google.com:4343>.port = '4wpt' Should use all ascii prefixed characters as port",
+      "<a>: Setting <data:original>.pathname = 'new value'",
+      "<area>: Setting <data:original>.pathname = 'new value'",
+      "<a>: Setting <sc:original>.pathname = 'new value'",
+      "<area>: Setting <sc:original>.pathname = 'new value'",
+      "<a>: Setting <foo://somehost/some/path>.pathname = '' Non-special URLs can have their paths erased",
+      "<area>: Setting <foo://somehost/some/path>.pathname = '' Non-special URLs can have their paths erased",
+      "<a>: Setting <foo:///some/path>.pathname = '' Non-special URLs with an empty host can have their paths erased",
+      "<area>: Setting <foo:///some/path>.pathname = '' Non-special URLs with an empty host can have their paths erased",
+      "<a>: Setting <foo:/some/path>.pathname = '' Path-only URLs cannot have their paths erased",
+      "<area>: Setting <foo:/some/path>.pathname = '' Path-only URLs cannot have their paths erased",
+      "<a>: Setting <foo:/some/path>.pathname = 'test' Path-only URLs always have an initial slash",
+      "<area>: Setting <foo:/some/path>.pathname = 'test' Path-only URLs always have an initial slash",
+      "<a>: Setting <unix:/run/foo.socket?timeout=10>.pathname = '/var/log/../run/bar.socket'",
+      "<area>: Setting <unix:/run/foo.socket?timeout=10>.pathname = '/var/log/../run/bar.socket'",
+      "<a>: Setting <https://example.net#nav>.pathname = 'home'",
+      "<area>: Setting <https://example.net#nav>.pathname = 'home'",
+      "<a>: Setting <https://example.net#nav>.pathname = '../home'",
+      "<area>: Setting <https://example.net#nav>.pathname = '../home'",
+      "<a>: Setting <http://example.net/home?lang=fr#nav>.pathname = '\\a\\%2E\\b\\%2e.\\c' \\ is a segment delimiter for 'special' URLs",
+      "<area>: Setting <http://example.net/home?lang=fr#nav>.pathname = '\\a\\%2E\\b\\%2e.\\c' \\ is a segment delimiter for 'special' URLs",
+      "<a>: Setting <view-source+http://example.net/home?lang=fr#nav>.pathname = '\\a\\%2E\\b\\%2e.\\c' \\ is *not* a segment delimiter for non-'special' URLs",
+      "<area>: Setting <view-source+http://example.net/home?lang=fr#nav>.pathname = '\\a\\%2E\\b\\%2e.\\c' \\ is *not* a segment delimiter for non-'special' URLs",
+      "<a>: Setting <a:/>.pathname = '\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~€Éé' UTF-8 percent encoding with the default encode set. Tabs and newlines are removed.",
+      "<area>: Setting <a:/>.pathname = '\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~€Éé' UTF-8 percent encoding with the default encode set. Tabs and newlines are removed.",
+      "<a>: Setting <http://example.net>.pathname = '%2e%2E%c3%89té' Bytes already percent-encoded are left as-is, including %2E outside dotted segments.",
+      "<area>: Setting <http://example.net>.pathname = '%2e%2E%c3%89té' Bytes already percent-encoded are left as-is, including %2E outside dotted segments.",
+      "<a>: Setting <http://example.net>.pathname = '?' ? needs to be encoded",
+      "<area>: Setting <http://example.net>.pathname = '?' ? needs to be encoded",
+      "<a>: Setting <http://example.net>.pathname = '#' # needs to be encoded",
+      "<area>: Setting <http://example.net>.pathname = '#' # needs to be encoded",
+      "<a>: Setting <sc://example.net>.pathname = '?' ? needs to be encoded, non-special scheme",
+      "<area>: Setting <sc://example.net>.pathname = '?' ? needs to be encoded, non-special scheme",
+      "<a>: Setting <sc://example.net>.pathname = '#' # needs to be encoded, non-special scheme",
+      "<area>: Setting <sc://example.net>.pathname = '#' # needs to be encoded, non-special scheme",
+      "<a>: Setting <http://example.net>.pathname = '/?é' ? doesn't mess up encoding",
+      "<area>: Setting <http://example.net>.pathname = '/?é' ? doesn't mess up encoding",
+      "<a>: Setting <http://example.net>.pathname = '/#é' # doesn't mess up encoding",
+      "<area>: Setting <http://example.net>.pathname = '/#é' # doesn't mess up encoding",
+      "<a>: Setting <non-spec:/>.pathname = '/.//p' Serialize /. in path",
+      "<area>: Setting <non-spec:/>.pathname = '/.//p' Serialize /. in path",
+      "<a>: Setting <non-spec:/>.pathname = '/..//p'",
+      "<area>: Setting <non-spec:/>.pathname = '/..//p'",
+      "<a>: Setting <non-spec:/>.pathname = '//p'",
+      "<area>: Setting <non-spec:/>.pathname = '//p'",
+      "<a>: Setting <non-spec:/.//>.pathname = 'p' Drop /. from path",
+      "<area>: Setting <non-spec:/.//>.pathname = 'p' Drop /. from path",
+      "<a>: Setting <data:/nospace>.pathname = 'space ' Non-special URLs with non-opaque paths percent-encode U+0020",
+      "<area>: Setting <data:/nospace>.pathname = 'space ' Non-special URLs with non-opaque paths percent-encode U+0020",
+      "<a>: Setting <sc:/nospace>.pathname = 'space '",
+      "<area>: Setting <sc:/nospace>.pathname = 'space '",
+      "<a>: Setting <https://example.net#nav>.search = 'lang=fr'",
+      "<area>: Setting <https://example.net#nav>.search = 'lang=fr'",
+      "<a>: Setting <https://example.net?lang=en-US#nav>.search = 'lang=fr'",
+      "<area>: Setting <https://example.net?lang=en-US#nav>.search = 'lang=fr'",
+      "<a>: Setting <https://example.net?lang=en-US#nav>.search = '?lang=fr'",
+      "<area>: Setting <https://example.net?lang=en-US#nav>.search = '?lang=fr'",
+      "<a>: Setting <https://example.net?lang=en-US#nav>.search = '??lang=fr'",
+      "<area>: Setting <https://example.net?lang=en-US#nav>.search = '??lang=fr'",
+      "<a>: Setting <https://example.net?lang=en-US#nav>.search = '?'",
+      "<area>: Setting <https://example.net?lang=en-US#nav>.search = '?'",
+      "<a>: Setting <https://example.net?lang=en-US#nav>.search = ''",
+      "<area>: Setting <https://example.net?lang=en-US#nav>.search = ''",
+      "<a>: Setting <https://example.net?lang=en-US>.search = ''",
+      "<area>: Setting <https://example.net?lang=en-US>.search = ''",
+      "<a>: Setting <https://example.net>.search = ''",
+      "<area>: Setting <https://example.net>.search = ''",
+      "<a>: Setting <a:/>.search = '\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~€Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed.",
+      "<area>: Setting <a:/>.search = '\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~€Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed.",
+      "<a>: Setting <http://example.net>.search = '%c3%89té' Bytes already percent-encoded are left as-is",
+      "<area>: Setting <http://example.net>.search = '%c3%89té' Bytes already percent-encoded are left as-is",
+      "<a>: Setting <data:space ?query>.search = '' Drop trailing spaces from trailing opaque paths",
+      "<area>: Setting <data:space ?query>.search = '' Drop trailing spaces from trailing opaque paths",
+      "<a>: Setting <sc:space ?query>.search = ''",
+      "<area>: Setting <sc:space ?query>.search = ''",
+      "<a>: Setting <data:space  ?query#fragment>.search = '' Do not drop trailing spaces from non-trailing opaque paths",
+      "<area>: Setting <data:space  ?query#fragment>.search = '' Do not drop trailing spaces from non-trailing opaque paths",
+      "<a>: Setting <sc:space  ?query#fragment>.search = ''",
+      "<area>: Setting <sc:space  ?query#fragment>.search = ''",
+      "<a>: Setting <https://example.net>.hash = 'main'",
+      "<area>: Setting <https://example.net>.hash = 'main'",
+      "<a>: Setting <https://example.net#nav>.hash = 'main'",
+      "<area>: Setting <https://example.net#nav>.hash = 'main'",
+      "<a>: Setting <https://example.net?lang=en-US>.hash = '##nav'",
+      "<area>: Setting <https://example.net?lang=en-US>.hash = '##nav'",
+      "<a>: Setting <https://example.net?lang=en-US#nav>.hash = '#main'",
+      "<area>: Setting <https://example.net?lang=en-US#nav>.hash = '#main'",
+      "<a>: Setting <https://example.net?lang=en-US#nav>.hash = '#'",
+      "<area>: Setting <https://example.net?lang=en-US#nav>.hash = '#'",
+      "<a>: Setting <https://example.net?lang=en-US#nav>.hash = ''",
+      "<area>: Setting <https://example.net?lang=en-US#nav>.hash = ''",
+      "<a>: Setting <http://example.net>.hash = '#foo bar'",
+      "<area>: Setting <http://example.net>.hash = '#foo bar'",
+      "<a>: Setting <http://example.net>.hash = '#foo\"bar'",
+      "<area>: Setting <http://example.net>.hash = '#foo\"bar'",
+      "<a>: Setting <http://example.net>.hash = '#foo<bar'",
+      "<area>: Setting <http://example.net>.hash = '#foo<bar'",
+      "<a>: Setting <http://example.net>.hash = '#foo>bar'",
+      "<area>: Setting <http://example.net>.hash = '#foo>bar'",
+      "<a>: Setting <http://example.net>.hash = '#foo`bar'",
+      "<area>: Setting <http://example.net>.hash = '#foo`bar'",
+      "<a>: Setting <a:/>.hash = '\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~€Éé' Simple percent-encoding; tabs and newlines are removed",
+      "<area>: Setting <a:/>.hash = '\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~€Éé' Simple percent-encoding; tabs and newlines are removed",
+      "<a>: Setting <http://example.net>.hash = 'a\u0000b' Percent-encode NULLs in fragment",
+      "<area>: Setting <http://example.net>.hash = 'a\u0000b' Percent-encode NULLs in fragment",
+      "<a>: Setting <non-spec:/>.hash = 'a\u0000b' Percent-encode NULLs in fragment",
+      "<area>: Setting <non-spec:/>.hash = 'a\u0000b' Percent-encode NULLs in fragment",
+      "<a>: Setting <http://example.net>.hash = '%c3%89té' Bytes already percent-encoded are left as-is",
+      "<area>: Setting <http://example.net>.hash = '%c3%89té' Bytes already percent-encoded are left as-is",
+      "<a>: Setting <data:space                                                                                                                                  #fragment>.hash = '' Drop trailing spaces from trailing opaque paths",
+      "<area>: Setting <data:space                                                                                                                                  #fragment>.hash = '' Drop trailing spaces from trailing opaque paths",
+      "<a>: Setting <sc:space    #fragment>.hash = ''",
+      "<area>: Setting <sc:space    #fragment>.hash = ''",
+      "<a>: Setting <data:space  ?query#fragment>.hash = '' Do not drop trailing spaces from non-trailing opaque paths",
+      "<area>: Setting <data:space  ?query#fragment>.hash = '' Do not drop trailing spaces from non-trailing opaque paths",
+      "<a>: Setting <sc:space  ?query#fragment>.hash = ''",
+      "<area>: Setting <sc:space  ?query#fragment>.hash = ''"
+    ],
+    "url-setters-a-area.window.html?include=file": [
+      "<a>: Setting <file://localhost/>.protocol = 'http' Can’t switch from file URL with no host",
+      "<area>: Setting <file://localhost/>.protocol = 'http' Can’t switch from file URL with no host",
+      "<a>: Setting <file:///test>.protocol = 'https'",
+      "<area>: Setting <file:///test>.protocol = 'https'",
+      "<a>: Setting <file:>.protocol = 'wss'",
+      "<area>: Setting <file:>.protocol = 'wss'",
+      "<a>: Setting <file://hi/path>.protocol = 's'",
+      "<area>: Setting <file://hi/path>.protocol = 's'",
+      "<a>: Setting <file:///home/you/index.html>.username = 'me' No host means no username",
+      "<area>: Setting <file:///home/you/index.html>.username = 'me' No host means no username",
+      "<a>: Setting <file://test/>.username = 'test'",
+      "<area>: Setting <file://test/>.username = 'test'",
+      "<a>: Setting <file:///home/me/index.html>.password = 'secret' No host means no password",
+      "<area>: Setting <file:///home/me/index.html>.password = 'secret' No host means no password",
+      "<a>: Setting <file://test/>.password = 'test'",
+      "<area>: Setting <file://test/>.password = 'test'",
+      "<a>: Setting <file://y/>.host = 'x:123'",
+      "<area>: Setting <file://y/>.host = 'x:123'",
+      "<a>: Setting <file://y/>.host = 'loc%41lhost'",
+      "<area>: Setting <file://y/>.host = 'loc%41lhost'",
+      "<a>: Setting <file://hi/x>.host = ''",
+      "<area>: Setting <file://hi/x>.host = ''",
+      "<a>: Setting <file://y/>.hostname = 'x:123'",
+      "<area>: Setting <file://y/>.hostname = 'x:123'",
+      "<a>: Setting <file://y/>.hostname = 'loc%41lhost'",
+      "<area>: Setting <file://y/>.hostname = 'loc%41lhost'",
+      "<a>: Setting <file://hi/x>.hostname = ''",
+      "<area>: Setting <file://hi/x>.hostname = ''",
+      "<a>: Setting <file://test/>.port = '12'",
+      "<area>: Setting <file://test/>.port = '12'",
+      "<a>: Setting <file://localhost/>.port = '12'",
+      "<area>: Setting <file://localhost/>.port = '12'",
+      "<a>: Setting <file:///some/path>.pathname = '' Special URLs cannot have their paths erased",
+      "<area>: Setting <file:///some/path>.pathname = '' Special URLs cannot have their paths erased",
+      "<a>: Setting <file://monkey/>.pathname = '\\\\' File URLs and (back)slashes",
+      "<area>: Setting <file://monkey/>.pathname = '\\\\' File URLs and (back)slashes",
+      "<a>: Setting <file:///unicorn>.pathname = '//\\/' File URLs and (back)slashes",
+      "<area>: Setting <file:///unicorn>.pathname = '//\\/' File URLs and (back)slashes",
+      "<a>: Setting <file:///unicorn>.pathname = '//monkey/..//' File URLs and (back)slashes",
+      "<area>: Setting <file:///unicorn>.pathname = '//monkey/..//' File URLs and (back)slashes",
+      "<a>: Setting <file:///var/log/system.log>.href = 'http://0300.168.0xF0'",
+      "<area>: Setting <file:///var/log/system.log>.href = 'http://0300.168.0xF0'"
+    ],
+    "url-setters-a-area.window.html?include=javascript": [
+      "<a>: Setting <javascript:alert(1)>.protocol = 'defuse'",
+      "<area>: Setting <javascript:alert(1)>.protocol = 'defuse'",
+      "<a>: Setting <javascript:alert(1)>.username = 'wario'",
+      "<area>: Setting <javascript:alert(1)>.username = 'wario'",
+      "<a>: Setting <javascript://x/>.username = 'wario'",
+      "<area>: Setting <javascript://x/>.username = 'wario'",
+      "<a>: Setting <javascript://x/>.password = 'bowser'",
+      "<area>: Setting <javascript://x/>.password = 'bowser'",
+      "<a>: Setting <javascript://x/>.port = '12'",
+      "<area>: Setting <javascript://x/>.port = '12'",
+      "<a>: Setting <javascript:alert(1)>.hash = 'castle'",
+      "<area>: Setting <javascript:alert(1)>.hash = 'castle'"
+    ],
+    "url-setters-a-area.window.html?include=mailto": [
+      "<a>: Setting <mailto:me@example.net>.protocol = 'http' Cannot-be-a-base URL doesn’t have a host, but URL in a special scheme must.",
+      "<area>: Setting <mailto:me@example.net>.protocol = 'http' Cannot-be-a-base URL doesn’t have a host, but URL in a special scheme must.",
+      "<a>: Setting <mailto:you@example.net>.username = 'me' Cannot-be-a-base means no username",
+      "<area>: Setting <mailto:you@example.net>.username = 'me' Cannot-be-a-base means no username",
+      "<a>: Setting <mailto:me@example.net>.password = 'secret' Cannot-be-a-base means no password",
+      "<area>: Setting <mailto:me@example.net>.password = 'secret' Cannot-be-a-base means no password",
+      "<a>: Setting <mailto:me@example.net>.host = 'example.com' Cannot-be-a-base means no host",
+      "<area>: Setting <mailto:me@example.net>.host = 'example.com' Cannot-be-a-base means no host",
+      "<a>: Setting <mailto:me@example.net>.hostname = 'example.com' Cannot-be-a-base means no host",
+      "<area>: Setting <mailto:me@example.net>.hostname = 'example.com' Cannot-be-a-base means no host",
+      "<a>: Setting <mailto:me@example.net>.pathname = '/foo' Opaque paths cannot be set",
+      "<area>: Setting <mailto:me@example.net>.pathname = '/foo' Opaque paths cannot be set"
+    ],
     "url-setters.any.html?exclude=(file|javascript|mailto)": [
       "URL: Setting <http://test/>.protocol = 'https\u0000' Non-tab/newline C0 controls result in no-op",
       "URL: Setting <http://test/>.protocol = 'https\f'",
@@ -3598,10 +4088,8 @@
       "URL: Setting <non-spec:/.//>.pathname = 'p' Drop /. from path",
       "URL: Setting <data:/nospace>.pathname = 'space ' Non-special URLs with non-opaque paths percent-encode U+0020",
       "URL: Setting <sc:/nospace>.pathname = 'space '",
-      "URL: Setting <data:space ?query>.search = '' Drop trailing spaces from trailing opaque paths",
-      "URL: Setting <sc:space ?query>.search = ''",
-      "URL: Setting <data:space                                                                                                                                  #fragment>.hash = '' Drop trailing spaces from trailing opaque paths",
-      "URL: Setting <sc:space    #fragment>.hash = ''"
+      "URL: Setting <data:space  ?query#fragment>.search = '' Do not drop trailing spaces from non-trailing opaque paths",
+      "URL: Setting <sc:space  ?query#fragment>.search = ''"
     ],
     "url-setters.any.html?include=file": [
       "URL: Setting <file://monkey/>.pathname = '\\\\' File URLs and (back)slashes",
@@ -3628,10 +4116,8 @@
       "URL: Setting <non-spec:/.//>.pathname = 'p' Drop /. from path",
       "URL: Setting <data:/nospace>.pathname = 'space ' Non-special URLs with non-opaque paths percent-encode U+0020",
       "URL: Setting <sc:/nospace>.pathname = 'space '",
-      "URL: Setting <data:space ?query>.search = '' Drop trailing spaces from trailing opaque paths",
-      "URL: Setting <sc:space ?query>.search = ''",
-      "URL: Setting <data:space                                                                                                                                  #fragment>.hash = '' Drop trailing spaces from trailing opaque paths",
-      "URL: Setting <sc:space    #fragment>.hash = ''"
+      "URL: Setting <data:space  ?query#fragment>.search = '' Do not drop trailing spaces from non-trailing opaque paths",
+      "URL: Setting <sc:space  ?query#fragment>.search = ''"
     ],
     "url-setters.any.worker.html?include=file": [
       "URL: Setting <file://monkey/>.pathname = '\\\\' File URLs and (back)slashes",
@@ -9679,4 +10165,4 @@
       "media-sniff.window.html": false
     }
   }
-}
+}
\ No newline at end of file