Merge branch 'main' into x/tunnel

# Conflicts:
#	cli/args/flags.rs
#	cli/factory.rs
#	cli/rt/run.rs
#	cli/tools/deploy.rs
#	ext/net/ops.rs
#	ext/telemetry/lib.rs
This commit is contained in:
Leo Kettmeir 2025-07-07 16:43:48 +02:00
commit 4492634bec
No known key found for this signature in database
GPG key ID: A82C9D461FC483E8
2036 changed files with 18954 additions and 112216 deletions

View file

@ -33,6 +33,7 @@
"cli/tsc/dts/typescript.d.ts",
"cli/tools/doc/prism.css",
"cli/tools/doc/prism.js",
"ext/node/polyfills/deps",
"ext/websocket/autobahn/reports",
"gh-pages",
"libs/config/testdata",
@ -43,6 +44,7 @@
"tests/node_compat/test",
"tests/registry/",
"tests/specs/bench/default_ts",
"tests/specs/compile/bytes_and_text_imports",
"tests/specs/fmt",
"tests/specs/lint/bom",
"tests/specs/lint/default_ts",
@ -50,7 +52,6 @@
"tests/specs/publish/no_check_surfaces_syntax_error",
"tests/specs/run/default_ts",
"tests/specs/test/default_ts",
"tests/testdata/byte_order_mark.ts",
"tests/testdata/encoding",
"tests/testdata/file_extensions/ts_with_js_extension.js",
"tests/testdata/fmt/",
@ -61,6 +62,7 @@
"tests/testdata/lint/glob/",
"tests/testdata/malformed_config/",
"tests/testdata/run/byte_order_mark.ts",
"tests/testdata/run/invalid_utf8.ts",
"tests/testdata/run/error_syntax_empty_trailing_line.mjs",
"tests/testdata/run/inline_js_source_map*",
"tests/testdata/test/markdown_windows.md",
@ -69,6 +71,7 @@
"tests/wpt/runner/manifest.json",
"tests/wpt/suite",
"third_party",
"tests/specs/run/bytes_and_text_imports",
"tests/specs/run/shebang_with_json_imports_tsc",
"tests/specs/run/shebang_with_json_imports_swc",
"tests/specs/run/ext_flag_takes_precedence_over_extension",

View file

@ -65,7 +65,7 @@ To use a development version of the LSP in VSCode:
In addition to the above make sure that:
> To use the commands below, you need to first install the necessary tools on
> your system as described [here](building_from_source).
> your system as described [here](#building-from-source).
1. `cargo test` passes - this will run full test suite for `deno` including unit
tests, integration tests and Web Platform Tests

View file

@ -5,7 +5,7 @@ import { stringify } from "jsr:@std/yaml@^0.221/stringify";
// Bump this number when you want to purge the cache.
// Note: the tools/release/01_bump_crate_versions.ts script will update this version
// automatically via regex, so ensure that this line maintains this format.
const cacheVersion = 63;
const cacheVersion = 64;
const ubuntuX86Runner = "ubuntu-24.04";
const ubuntuX86XlRunner = "ubuntu-24.04-xl";
@ -479,7 +479,7 @@ const ci = {
},
{
...submoduleStep("./tests/node_compat/runner/suite"),
if: "matrix.job == 'lint' && matrix.os == 'linux'",
if: "matrix.job == 'test'",
},
{
...submoduleStep("./cli/bench/testdata/lsp_benchdata"),
@ -711,12 +711,6 @@ const ci = {
run:
"deno run --allow-read --allow-env --allow-sys ./tools/jsdoc_checker.js",
},
{
name: "node_compat/setup.ts --check",
if: "matrix.job == 'lint' && matrix.os == 'linux'",
run:
"deno run --allow-write --allow-read --allow-run=git ./tests/node_compat/runner/setup.ts --check",
},
{
name: "Check tracing build",
if:

View file

@ -163,7 +163,7 @@ jobs:
if: '!(matrix.skip) && (matrix.wpt)'
- name: Clone submodule ./tests/node_compat/runner/suite
run: git submodule update --init --recursive --depth=1 -- ./tests/node_compat/runner/suite
if: '!(matrix.skip) && (matrix.job == ''lint'' && matrix.os == ''linux'')'
if: '!(matrix.skip) && (matrix.job == ''test'')'
- name: Clone submodule ./cli/bench/testdata/lsp_benchdata
run: git submodule update --init --recursive --depth=1 -- ./cli/bench/testdata/lsp_benchdata
if: '!(matrix.skip) && (matrix.job == ''bench'')'
@ -188,8 +188,8 @@ jobs:
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
key: '63-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}'
restore-keys: '63-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-'
key: '64-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}'
restore-keys: '64-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-'
if: '!(matrix.skip)'
- uses: dsherret/rust-toolchain-file@v1
if: '!(matrix.skip)'
@ -391,7 +391,7 @@ jobs:
!./target/*/*.zip
!./target/*/*.tar.gz
key: never_saved
restore-keys: '63-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-'
restore-keys: '64-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-'
- name: Apply and update mtime cache
if: '!(matrix.skip) && (!startsWith(github.ref, ''refs/tags/''))'
uses: ./.github/mtime_cache
@ -419,9 +419,6 @@ jobs:
- name: jsdoc_checker.js
if: '!(matrix.skip) && (matrix.job == ''lint'')'
run: deno run --allow-read --allow-env --allow-sys ./tools/jsdoc_checker.js
- name: node_compat/setup.ts --check
if: '!(matrix.skip) && (matrix.job == ''lint'' && matrix.os == ''linux'')'
run: deno run --allow-write --allow-read --allow-run=git ./tests/node_compat/runner/setup.ts --check
- name: Check tracing build
if: '!(matrix.skip) && (matrix.job == ''test'' && matrix.profile == ''debug'' && matrix.os == ''linux'' && matrix.arch == ''x86_64'')'
run: cargo check -p deno --features=lsp-tracing
@ -780,7 +777,7 @@ jobs:
!./target/*/gn_root
!./target/*/*.zip
!./target/*/*.tar.gz
key: '63-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}'
key: '64-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}'
libs:
name: build libs
needs:

1
.gitmodules vendored
View file

@ -10,6 +10,7 @@
path = tests/node_compat/runner/suite
url = https://github.com/denoland/node_test.git
shallow = true
ignore = untracked
[submodule "cli/bench/testdata/lsp_benchdata"]
path = cli/bench/testdata/lsp_benchdata
url = https://github.com/denoland/deno_lsp_benchdata.git

View file

@ -1,3 +1,3 @@
max_width = 80
tab_spaces = 2
edition = "2021"
edition = "2024"

154
Cargo.lock generated
View file

@ -941,7 +941,7 @@ dependencies = [
"chrono",
"deno_bench_util",
"deno_cache_dir",
"deno_lockfile 0.30.1",
"deno_lockfile 0.30.2",
"deno_semver",
"deno_terminal 0.2.2",
"deno_tower_lsp",
@ -1530,7 +1530,7 @@ dependencies = [
[[package]]
name = "deno"
version = "2.3.7"
version = "2.4.0"
dependencies = [
"anstream",
"async-trait",
@ -1558,7 +1558,7 @@ dependencies = [
"deno_graph",
"deno_lib",
"deno_lint",
"deno_lockfile 0.30.1",
"deno_lockfile 0.30.2",
"deno_media_type",
"deno_npm 0.35.0",
"deno_npm_cache",
@ -1676,9 +1676,9 @@ dependencies = [
[[package]]
name = "deno_ast"
version = "0.48.0"
version = "0.48.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f883bd8eae4dfc8019d925ec3dd04b634b6af9346a5168acc259d55f5f5021d"
checksum = "0ced09fdb8884e29716cc0691e8510f9c655762bbb9da3111dacc0a2ef6e8960"
dependencies = [
"base64 0.22.1",
"capacity_builder",
@ -1721,7 +1721,7 @@ dependencies = [
[[package]]
name = "deno_bench_util"
version = "0.202.0"
version = "0.203.0"
dependencies = [
"bencher",
"deno_core",
@ -1730,7 +1730,7 @@ dependencies = [
[[package]]
name = "deno_broadcast_channel"
version = "0.202.0"
version = "0.203.0"
dependencies = [
"async-trait",
"deno_core",
@ -1743,7 +1743,7 @@ dependencies = [
[[package]]
name = "deno_cache"
version = "0.140.0"
version = "0.141.0"
dependencies = [
"async-stream",
"async-trait",
@ -1770,9 +1770,9 @@ dependencies = [
[[package]]
name = "deno_cache_dir"
version = "0.22.2"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa3c29ca22ddd84eea69891b03f24be7fb9200beb4005ed105f0ad3afcdcd4f2"
checksum = "7825da0551e670a270a3a20b92f8a0bffeb7d6120fa86b64e5daa969b8dd1a10"
dependencies = [
"async-trait",
"base32",
@ -1799,7 +1799,7 @@ dependencies = [
[[package]]
name = "deno_canvas"
version = "0.77.0"
version = "0.78.0"
dependencies = [
"bytemuck",
"deno_core",
@ -1812,7 +1812,7 @@ dependencies = [
[[package]]
name = "deno_config"
version = "0.58.0"
version = "0.59.0"
dependencies = [
"boxed_error",
"capacity_builder",
@ -1839,16 +1839,16 @@ dependencies = [
[[package]]
name = "deno_console"
version = "0.208.0"
version = "0.209.0"
dependencies = [
"deno_core",
]
[[package]]
name = "deno_core"
version = "0.351.0"
version = "0.352.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4301eb6d378f3ae81fbac4cde14c3f467379efd7d46043268d76905effe3611d"
checksum = "f79c49675a4356068f4dfae6513f7e0097e1ee8548c098a68f5bbf9a93330c51"
dependencies = [
"anyhow",
"az",
@ -1890,7 +1890,7 @@ checksum = "fe4dccb6147bb3f3ba0c7a48e993bfeb999d2c2e47a81badee80e2b370c8d695"
[[package]]
name = "deno_cron"
version = "0.88.0"
version = "0.89.0"
dependencies = [
"async-trait",
"chrono",
@ -1904,7 +1904,7 @@ dependencies = [
[[package]]
name = "deno_crypto"
version = "0.222.0"
version = "0.223.0"
dependencies = [
"aes",
"aes-gcm",
@ -1942,7 +1942,7 @@ dependencies = [
[[package]]
name = "deno_crypto_provider"
version = "0.2.0"
version = "0.3.0"
dependencies = [
"aws-lc-rs",
"aws-lc-sys",
@ -1950,9 +1950,9 @@ dependencies = [
[[package]]
name = "deno_doc"
version = "0.178.0"
version = "0.179.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52fe9fb2d9e6efed6c19dbceecd14d169023ee61223336e386e0d7aa396249c4"
checksum = "15013f500ab72ef8512a5d86eb62253707daad4206fcb958dfa4e4f952f199e0"
dependencies = [
"anyhow",
"cfg-if",
@ -2005,7 +2005,7 @@ dependencies = [
[[package]]
name = "deno_features"
version = "0.5.0"
version = "0.6.0"
dependencies = [
"deno_core",
"serde",
@ -2014,7 +2014,7 @@ dependencies = [
[[package]]
name = "deno_fetch"
version = "0.232.0"
version = "0.233.0"
dependencies = [
"base64 0.22.1",
"bytes",
@ -2054,7 +2054,7 @@ dependencies = [
[[package]]
name = "deno_ffi"
version = "0.195.0"
version = "0.196.0"
dependencies = [
"cranelift",
"cranelift-native",
@ -2078,7 +2078,7 @@ dependencies = [
[[package]]
name = "deno_fs"
version = "0.118.0"
version = "0.119.0"
dependencies = [
"async-trait",
"base32",
@ -2102,11 +2102,12 @@ dependencies = [
[[package]]
name = "deno_graph"
version = "0.95.1"
version = "0.96.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "365b662cfc14021c2994156d5a58b9c91d655879b817715e2d92d8adce5b3c31"
checksum = "0733ed99295ebeddeb0fb33efa41ccd47ccd9481ab1ebe01f2ea8af80204479e"
dependencies = [
"async-trait",
"boxed_error",
"capacity_builder",
"data-url",
"deno_ast",
@ -2115,7 +2116,6 @@ dependencies = [
"deno_path_util",
"deno_semver",
"deno_unsync",
"encoding_rs",
"futures",
"import_map",
"indexmap 2.9.0",
@ -2136,7 +2136,7 @@ dependencies = [
[[package]]
name = "deno_http"
version = "0.206.0"
version = "0.207.0"
dependencies = [
"async-compression",
"async-trait",
@ -2179,7 +2179,7 @@ dependencies = [
[[package]]
name = "deno_io"
version = "0.118.0"
version = "0.119.0"
dependencies = [
"async-trait",
"deno_core",
@ -2203,7 +2203,7 @@ dependencies = [
[[package]]
name = "deno_kv"
version = "0.116.0"
version = "0.117.0"
dependencies = [
"anyhow",
"async-trait",
@ -2235,7 +2235,7 @@ dependencies = [
[[package]]
name = "deno_lib"
version = "0.26.0"
version = "0.27.0"
dependencies = [
"aws-lc-rs",
"base64 0.22.1",
@ -2299,9 +2299,9 @@ dependencies = [
[[package]]
name = "deno_lockfile"
version = "0.30.1"
version = "0.30.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5a7c1929be2f1558f798c1b75fbc828d8bc62b200435c10601a346f5a8fd67b"
checksum = "0d4346e56cda020df5da35a3ec2624f09bd77c9f5ed18d903915007825fe9d3f"
dependencies = [
"async-trait",
"deno_semver",
@ -2312,9 +2312,9 @@ dependencies = [
[[package]]
name = "deno_media_type"
version = "0.2.8"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d9080fcfcea53bcd6eea1916217bd5611c896f3a0db4c001a859722a1258a47"
checksum = "f0ec0dada9dc5ac4733b4175d36f6a150b7dd68fab46db35cb1ef00dd7366acb"
dependencies = [
"data-url",
"encoding_rs",
@ -2324,7 +2324,7 @@ dependencies = [
[[package]]
name = "deno_napi"
version = "0.139.0"
version = "0.140.0"
dependencies = [
"deno_core",
"deno_error",
@ -2354,7 +2354,7 @@ dependencies = [
[[package]]
name = "deno_net"
version = "0.200.0"
version = "0.201.0"
dependencies = [
"deno_core",
"deno_error",
@ -2379,7 +2379,7 @@ dependencies = [
[[package]]
name = "deno_node"
version = "0.146.0"
version = "0.147.0"
dependencies = [
"aead-gcm-stream",
"aes",
@ -2497,7 +2497,7 @@ dependencies = [
"async-trait",
"capacity_builder",
"deno_error",
"deno_lockfile 0.30.1",
"deno_lockfile 0.30.2",
"deno_semver",
"futures",
"indexmap 2.9.0",
@ -2511,7 +2511,7 @@ dependencies = [
[[package]]
name = "deno_npm_cache"
version = "0.27.0"
version = "0.28.0"
dependencies = [
"async-trait",
"base64 0.22.1",
@ -2541,7 +2541,7 @@ dependencies = [
[[package]]
name = "deno_npm_installer"
version = "0.3.0"
version = "0.4.0"
dependencies = [
"anyhow",
"async-once-cell",
@ -2552,7 +2552,7 @@ dependencies = [
"deno_config",
"deno_error",
"deno_graph",
"deno_lockfile 0.30.1",
"deno_lockfile 0.30.2",
"deno_npm 0.35.0",
"deno_npm_cache",
"deno_package_json",
@ -2580,9 +2580,9 @@ dependencies = [
[[package]]
name = "deno_ops"
version = "0.227.0"
version = "0.228.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bab1eaf578a8cc0ae6fb933e91dc3388b41df22e5974d5891c17ba66b3a0bbb"
checksum = "714adefbea6c347318737207f00eaf42c68c14ef51c040a96a6324b831ca59df"
dependencies = [
"indexmap 2.9.0",
"proc-macro-rules",
@ -2597,7 +2597,7 @@ dependencies = [
[[package]]
name = "deno_os"
version = "0.25.0"
version = "0.26.0"
dependencies = [
"deno_core",
"deno_error",
@ -2618,7 +2618,7 @@ dependencies = [
[[package]]
name = "deno_package_json"
version = "0.10.0"
version = "0.11.0"
dependencies = [
"boxed_error",
"deno_error",
@ -2657,7 +2657,7 @@ dependencies = [
[[package]]
name = "deno_permissions"
version = "0.67.0"
version = "0.68.0"
dependencies = [
"capacity_builder",
"deno_error",
@ -2665,6 +2665,7 @@ dependencies = [
"deno_terminal 0.2.2",
"deno_unsync",
"fqdn",
"ipnetwork",
"libc",
"log",
"nix 0.27.1",
@ -2683,7 +2684,7 @@ dependencies = [
[[package]]
name = "deno_process"
version = "0.23.0"
version = "0.24.0"
dependencies = [
"deno_core",
"deno_error",
@ -2711,7 +2712,7 @@ dependencies = [
[[package]]
name = "deno_resolver"
version = "0.39.0"
version = "0.40.0"
dependencies = [
"anyhow",
"async-once-cell",
@ -2724,7 +2725,7 @@ dependencies = [
"deno_config",
"deno_error",
"deno_graph",
"deno_lockfile 0.30.1",
"deno_lockfile 0.30.2",
"deno_media_type",
"deno_npm 0.35.0",
"deno_package_json",
@ -2738,6 +2739,7 @@ dependencies = [
"http 1.1.0",
"import_map",
"indexmap 2.9.0",
"jsonc-parser",
"log",
"node_resolver",
"once_cell",
@ -2753,7 +2755,7 @@ dependencies = [
[[package]]
name = "deno_runtime"
version = "0.216.0"
version = "0.217.0"
dependencies = [
"color-print",
"deno_ast",
@ -2835,14 +2837,14 @@ dependencies = [
[[package]]
name = "deno_snapshots"
version = "0.23.0"
version = "0.24.0"
dependencies = [
"deno_runtime",
]
[[package]]
name = "deno_subprocess_windows"
version = "0.3.0"
version = "0.4.0"
dependencies = [
"fastrand",
"futures-channel",
@ -2873,7 +2875,7 @@ dependencies = [
[[package]]
name = "deno_telemetry"
version = "0.30.0"
version = "0.31.0"
dependencies = [
"async-trait",
"deno_core",
@ -2895,6 +2897,8 @@ dependencies = [
"serde",
"thiserror 2.0.12",
"tokio",
"tokio-vsock",
"tower-service",
]
[[package]]
@ -2919,7 +2923,7 @@ dependencies = [
[[package]]
name = "deno_tls"
version = "0.195.0"
version = "0.196.0"
dependencies = [
"deno_core",
"deno_error",
@ -2970,7 +2974,7 @@ dependencies = [
[[package]]
name = "deno_url"
version = "0.208.0"
version = "0.209.0"
dependencies = [
"deno_bench_util",
"deno_console",
@ -2982,7 +2986,7 @@ dependencies = [
[[package]]
name = "deno_web"
version = "0.239.0"
version = "0.240.0"
dependencies = [
"async-trait",
"base64-simd",
@ -3005,7 +3009,7 @@ dependencies = [
[[package]]
name = "deno_webgpu"
version = "0.175.0"
version = "0.176.0"
dependencies = [
"deno_core",
"deno_error",
@ -3022,7 +3026,7 @@ dependencies = [
[[package]]
name = "deno_webidl"
version = "0.208.0"
version = "0.209.0"
dependencies = [
"deno_bench_util",
"deno_core",
@ -3030,7 +3034,7 @@ dependencies = [
[[package]]
name = "deno_websocket"
version = "0.213.0"
version = "0.214.0"
dependencies = [
"bytes",
"deno_core",
@ -3053,7 +3057,7 @@ dependencies = [
[[package]]
name = "deno_webstorage"
version = "0.203.0"
version = "0.204.0"
dependencies = [
"deno_core",
"deno_error",
@ -3140,7 +3144,7 @@ dependencies = [
[[package]]
name = "denort"
version = "2.3.7"
version = "2.4.0"
dependencies = [
"async-trait",
"bincode",
@ -3177,7 +3181,7 @@ dependencies = [
[[package]]
name = "denort_helper"
version = "0.6.0"
version = "0.7.0"
dependencies = [
"deno_error",
"deno_path_util",
@ -3473,9 +3477,9 @@ dependencies = [
[[package]]
name = "dprint-plugin-typescript"
version = "0.95.7"
version = "0.95.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6761cbedde994ff3be4a5f7ad4ca822f10edf2c978725177f529789cb249c3c4"
checksum = "a1107e3e0e59a4a5f8a07fef0427822a570295bf1f4971d70a22c23bb16a11f4"
dependencies = [
"anyhow",
"capacity_builder",
@ -3749,9 +3753,9 @@ dependencies = [
[[package]]
name = "eszip"
version = "0.92.0"
version = "0.93.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dccf7977c7fcddecd68242e657b6a7b91047553da6bae3f7d1febb4e92e077b0"
checksum = "404b07854be8333e4827b3cb3055c36ba385c7dafb4e27b8da1a0d078857723b"
dependencies = [
"anyhow",
"async-trait",
@ -5598,9 +5602,9 @@ dependencies = [
[[package]]
name = "malva"
version = "0.11.2"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a952f521471c6c8302a17fc0c64a512221a9d4ff268af4d43a02bc2be48c712"
checksum = "aa8f6005fe3f2348f1fc59d647ee6945d5832fd080178e6d034bab1bf7976348"
dependencies = [
"aho-corasick",
"itertools 0.14.0",
@ -5611,9 +5615,9 @@ dependencies = [
[[package]]
name = "markup_fmt"
version = "0.21.0"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e59dd52b196245d3575b2af66ef15b0e20362de18b453dfbf264c258e8eefbf5"
checksum = "2cc6a5130d40b34be77fbd52645323c199d2db25f90922d5cef1da2a9eca96b0"
dependencies = [
"aho-corasick",
"css_dataset",
@ -5833,7 +5837,7 @@ dependencies = [
[[package]]
name = "napi_sym"
version = "0.138.0"
version = "0.139.0"
dependencies = [
"quote",
"serde",
@ -5901,7 +5905,7 @@ dependencies = [
[[package]]
name = "node_resolver"
version = "0.46.0"
version = "0.47.0"
dependencies = [
"anyhow",
"async-trait",
@ -7749,9 +7753,9 @@ dependencies = [
[[package]]
name = "serde_v8"
version = "0.260.0"
version = "0.261.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4f284b4d521591b17ddee01aff830dd005a04476f7862aca9298c038d00fb7e"
checksum = "5390adb1572a22916f7cff2e89e603053f2f1e1c7644e5c83fdaefb5ea1cb82b"
dependencies = [
"deno_error",
"num-bigint",

View file

@ -53,21 +53,21 @@ exclude = ["tests/util/std/hash/_wasm"]
[workspace.package]
authors = ["the Deno authors"]
edition = "2021"
edition = "2024"
license = "MIT"
repository = "https://github.com/denoland/deno"
[workspace.dependencies]
deno_ast = { version = "=0.48.0", features = ["transpiling"] }
deno_core = { version = "0.351.0" }
deno_ast = { version = "=0.48.1", features = ["transpiling"] }
deno_core = { version = "0.352.0" }
deno_cache_dir = "=0.22.2"
deno_doc = "=0.178.0"
deno_cache_dir = "=0.23.0"
deno_doc = "=0.179.0"
deno_error = "=0.6.1"
deno_graph = { version = "=0.95.1", default-features = false }
deno_graph = { version = "=0.96.2", default-features = false }
deno_lint = "=0.76.0"
deno_lockfile = "=0.30.1"
deno_media_type = { version = "=0.2.8", features = ["module_specifier"] }
deno_lockfile = "=0.30.2"
deno_media_type = { version = "=0.2.9", features = ["module_specifier"] }
deno_native_certs = "0.3.0"
deno_npm = "=0.35.0"
deno_path_util = "=0.4.0"
@ -76,7 +76,7 @@ deno_task_shell = "=0.24.0"
deno_terminal = "=0.2.2"
deno_unsync = { version = "0.4.4", default-features = false }
deno_whoami = "0.1.0"
eszip = "=0.92.0"
eszip = "=0.93.0"
denokv_proto = "0.11.0"
denokv_remote = "0.11.0"
@ -84,49 +84,49 @@ denokv_remote = "0.11.0"
denokv_sqlite = { default-features = false, version = "0.11.0" }
# exts
deno_broadcast_channel = { version = "0.202.0", path = "./ext/broadcast_channel" }
deno_cache = { version = "0.140.0", path = "./ext/cache" }
deno_canvas = { version = "0.77.0", path = "./ext/canvas" }
deno_console = { version = "0.208.0", path = "./ext/console" }
deno_cron = { version = "0.88.0", path = "./ext/cron" }
deno_crypto = { version = "0.222.0", path = "./ext/crypto" }
deno_fetch = { version = "0.232.0", path = "./ext/fetch" }
deno_ffi = { version = "0.195.0", path = "./ext/ffi" }
deno_fs = { version = "0.118.0", path = "./ext/fs" }
deno_http = { version = "0.206.0", path = "./ext/http" }
deno_io = { version = "0.118.0", path = "./ext/io" }
deno_kv = { version = "0.116.0", path = "./ext/kv" }
deno_napi = { version = "0.139.0", path = "./ext/napi" }
deno_net = { version = "0.200.0", path = "./ext/net" }
deno_node = { version = "0.146.0", path = "./ext/node" }
deno_os = { version = "0.25.0", path = "./ext/os" }
deno_process = { version = "0.23.0", path = "./ext/process" }
deno_telemetry = { version = "0.30.0", path = "./ext/telemetry" }
deno_tls = { version = "0.195.0", path = "./ext/tls" }
deno_url = { version = "0.208.0", path = "./ext/url" }
deno_web = { version = "0.239.0", path = "./ext/web" }
deno_webgpu = { version = "0.175.0", path = "./ext/webgpu" }
deno_webidl = { version = "0.208.0", path = "./ext/webidl" }
deno_websocket = { version = "0.213.0", path = "./ext/websocket" }
deno_webstorage = { version = "0.203.0", path = "./ext/webstorage" }
denort_helper = { version = "0.6.0", path = "./ext/rt_helper" }
deno_broadcast_channel = { version = "0.203.0", path = "./ext/broadcast_channel" }
deno_cache = { version = "0.141.0", path = "./ext/cache" }
deno_canvas = { version = "0.78.0", path = "./ext/canvas" }
deno_console = { version = "0.209.0", path = "./ext/console" }
deno_cron = { version = "0.89.0", path = "./ext/cron" }
deno_crypto = { version = "0.223.0", path = "./ext/crypto" }
deno_fetch = { version = "0.233.0", path = "./ext/fetch" }
deno_ffi = { version = "0.196.0", path = "./ext/ffi" }
deno_fs = { version = "0.119.0", path = "./ext/fs" }
deno_http = { version = "0.207.0", path = "./ext/http" }
deno_io = { version = "0.119.0", path = "./ext/io" }
deno_kv = { version = "0.117.0", path = "./ext/kv" }
deno_napi = { version = "0.140.0", path = "./ext/napi" }
deno_net = { version = "0.201.0", path = "./ext/net" }
deno_node = { version = "0.147.0", path = "./ext/node" }
deno_os = { version = "0.26.0", path = "./ext/os" }
deno_process = { version = "0.24.0", path = "./ext/process" }
deno_telemetry = { version = "0.31.0", path = "./ext/telemetry" }
deno_tls = { version = "0.196.0", path = "./ext/tls" }
deno_url = { version = "0.209.0", path = "./ext/url" }
deno_web = { version = "0.240.0", path = "./ext/web" }
deno_webgpu = { version = "0.176.0", path = "./ext/webgpu" }
deno_webidl = { version = "0.209.0", path = "./ext/webidl" }
deno_websocket = { version = "0.214.0", path = "./ext/websocket" }
deno_webstorage = { version = "0.204.0", path = "./ext/webstorage" }
denort_helper = { version = "0.7.0", path = "./ext/rt_helper" }
# workspace libraries
deno_bench_util = { version = "0.202.0", path = "./bench_util" }
deno_config = { version = "0.58.0", features = ["workspace"], path = "./libs/config" }
deno_crypto_provider = { version = "0.2.0", path = "./libs/crypto" }
deno_features = { version = "0.5.0", path = "./runtime/features" }
deno_lib = { version = "0.26.0", path = "./cli/lib" }
deno_npm_cache = { version = "0.27.0", path = "./libs/npm_cache" }
deno_npm_installer = { version = "0.3.0", path = "./libs/npm_installer" }
deno_package_json = { version = "0.10.0", default-features = false, path = "./libs/package_json" }
deno_permissions = { version = "0.67.0", path = "./runtime/permissions" }
deno_resolver = { version = "0.39.0", path = "./libs/resolver" }
deno_runtime = { version = "0.216.0", path = "./runtime" }
deno_snapshots = { version = "0.23.0", path = "./cli/snapshot" }
deno_subprocess_windows = { path = "./runtime/subprocess_windows", version = "0.3.0" }
napi_sym = { version = "0.138.0", path = "./ext/napi/sym" }
node_resolver = { version = "0.46.0", path = "./libs/node_resolver" }
deno_bench_util = { version = "0.203.0", path = "./bench_util" }
deno_config = { version = "0.59.0", features = ["workspace"], path = "./libs/config" }
deno_crypto_provider = { version = "0.3.0", path = "./libs/crypto" }
deno_features = { version = "0.6.0", path = "./runtime/features" }
deno_lib = { version = "0.27.0", path = "./cli/lib" }
deno_npm_cache = { version = "0.28.0", path = "./libs/npm_cache" }
deno_npm_installer = { version = "0.4.0", path = "./libs/npm_installer" }
deno_package_json = { version = "0.11.0", default-features = false, path = "./libs/package_json" }
deno_permissions = { version = "0.68.0", path = "./runtime/permissions" }
deno_resolver = { version = "0.40.0", path = "./libs/resolver" }
deno_runtime = { version = "0.217.0", path = "./runtime" }
deno_snapshots = { version = "0.24.0", path = "./cli/snapshot" }
deno_subprocess_windows = { path = "./runtime/subprocess_windows", version = "0.4.0" }
napi_sym = { version = "0.139.0", path = "./ext/napi/sym" }
node_resolver = { version = "0.47.0", path = "./libs/node_resolver" }
test_util = { package = "test_server", path = "./tests/util/server" }
# widely used libraries
@ -303,12 +303,12 @@ dprint-core = "=0.67.4"
dprint-plugin-json = "=0.20.0"
dprint-plugin-jupyter = "=0.2.0"
dprint-plugin-markdown = "=0.18.0"
dprint-plugin-typescript = "=0.95.7"
dprint-plugin-typescript = "=0.95.8"
env_logger = "=0.11.6"
fancy-regex = "=0.14.0"
libsui = "0.10.0"
malva = "=0.11.2"
markup_fmt = "=0.21.0"
malva = "=0.12.1"
markup_fmt = "=0.22.0"
open = "5.0.1"
pathdiff = "0.2.1"
pretty_yaml = "=0.5.0"

View file

@ -6,6 +6,64 @@ https://github.com/denoland/deno/releases
We also have one-line install commands at:
https://github.com/denoland/deno_install
### 2.4.0 / 2025.07.01
- feat(bundle): support text and bytes imports in bundle (#29908)
- feat(check): tsconfig "references", "extends", "files", "include" and
"exclude" (#29843)
- feat(cli): add `--coverage` flag to `deno run` command (#29329)
- feat(cli): alias --unstable-sloppy-imports to --sloppy-imports (#29780)
- feat(ext/http): support `onListen()` callback in `deno serve` (#29449)
- feat(fmt): add support for .xml, .svg and .mustache files (#29851)
- feat(fmt): remove UTF-8 BOM instead of maintaining it (#29796)
- feat(node API): add `fs.glob`, `fs.globSync`, `fs.promises.glob` (#28972)
- feat(otel): stabilize OpenTelemetry support (#29822)
- feat(process): add detached option to `Deno.Command` (#29933)
- feat(run): resolve main module with workspace resolver (#29928)
- feat(signals): support listening for ctrl+close on Windows (#27880)
- feat(unstable): add DENO_NODE_CONDITIONS env var (#29848)
- feat(unstable): bytes and text imports (#29855)
- feat(unstable): support bytes and text imports in `deno compile` (#29924)
- feat: --allow-net supports CIDR ranges (#29704)
- feat: Add --deny-import flag (#29702)
- feat: Deno.execPath() no longer requires --allow-read permission (#29620)
- feat: add 'deno update' subcommand (#29187)
- feat: add `DENO_AUTO_SERVE` env var (#29852)
- feat: add `DENO_COMPAT` env var (#29889)
- feat: add support for --preload/--import flag (#29626)
- feat: deprecate --unstable-node-globals flag (#29887)
- feat: make 'Buffer' and 'global' available as globals (#29416)
- feat: make `setImmediate` and `clearImmediate` as globals (#29877)
- feat: rename --unstable-node-conditions to --unstable-conditions (#29885)
- feat: stabilize --allow-net subdomain wildcards (#29902)
- feat: stabilize --node-conditions flag (#29628)
- feat: unflag the deploy subcommand (#29863)
- fix(bench): Make output table markdown compatible (#29532)
- fix(bundle): only replace require shim in js files, spruce up output (#29892)
- fix(check): don't detect tsconfigs with no deno.json/package.json or
--no-config (#29925)
- fix(coverage): Make output table markdown compatible (#29533)
- fix(ext/node): add `lchmod`, `lchmod` promise, `lchmodSync` to `node:fs`
(#29833)
- fix(ext/node): add type check to LibuvStreamWrap.writeBuffer (#29879)
- fix(ext/node): don't show deprecation warnings for dependencies (#29909)
- fix(ext/node): export promise based `lchown` and `lutimes` from
`node:fs/promises` (#29870)
- fix(ext/node): fix reference error in node:stream (#29894)
- fix(ext/node): improve assert.fail (#29850)
- fix(ext/node): improve input validations of stream/consumers (#29880)
- fix(ext/node): keep BOM in buffer.toString('utf8') (#29896)
- fix(ext/node): remove duplicated stream classes (#29860)
- fix(fmt/css): prefer collapsing font-family values (#29864)
- fix(install): purge more packages from lockfile on config change (#29953)
- fix(install/global): resolve bin name from npm packument (#29884)
- fix(lsp): don't show no-export diagnostics for type-only npm imports (#29888)
- fix(node): use primordials more consistently in `_events.mjs` (#29930)
- fix(publish): disallow publishing with bytes or text imports (#29954)
- fix: support `Deno.permissions.query({name:"import"})` (#29610)
- perf: skip loading bytes and text imports into memory when already cached and
building module graph (#29931)
### 2.3.7 / 2025.06.23
- feat(unstable): add `--platform` flag to deno bundle (#29697)

View file

@ -2,7 +2,7 @@
[package]
name = "deno_bench_util"
version = "0.202.0"
version = "0.203.0"
authors.workspace = true
edition.workspace = true
license.workspace = true

View file

@ -5,8 +5,8 @@ Example:
```rust
use deno_bench_util::bench_js_sync;
use deno_bench_util::bench_or_profile;
use deno_bench_util::bencher::benchmark_group;
use deno_bench_util::bencher::Bencher;
use deno_bench_util::bencher::benchmark_group;
use deno_core::Extension;
#[op2]

View file

@ -1,10 +1,10 @@
// Copyright 2018-2025 the Deno authors. MIT license.
use deno_bench_util::BenchOptions;
use deno_bench_util::bench_js_sync_with;
use deno_bench_util::bench_or_profile;
use deno_bench_util::bencher::benchmark_group;
use deno_bench_util::bencher::Bencher;
use deno_bench_util::BenchOptions;
use deno_bench_util::bencher::benchmark_group;
use deno_core::Extension;
fn setup() -> Vec<Extension> {

View file

@ -1,10 +1,10 @@
// Copyright 2018-2025 the Deno authors. MIT license.
use bencher::Bencher;
use deno_core::v8;
use deno_core::Extension;
use deno_core::JsRuntime;
use deno_core::PollEventLoopOptions;
use deno_core::RuntimeOptions;
use deno_core::v8;
use crate::profiling::is_profiling;

View file

@ -2,7 +2,7 @@
[package]
name = "deno"
version = "2.3.7"
version = "2.4.0"
authors.workspace = true
default-run = "deno"
edition.workspace = true

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,6 @@ use std::str::FromStr;
use deno_core::url::Url;
use deno_runtime::deno_permissions::NetDescriptor;
use deno_runtime::deno_permissions::UnstableSubdomainWildcards;
#[derive(Debug, PartialEq, Eq)]
pub struct ParsePortError(String);
@ -33,11 +32,7 @@ pub fn validator(host_and_port: &str) -> Result<String, String> {
if Url::parse(&format!("internal://{host_and_port}")).is_ok()
|| host_and_port.parse::<IpAddr>().is_ok()
|| host_and_port.parse::<BarePort>().is_ok()
|| NetDescriptor::parse_for_list(
host_and_port,
UnstableSubdomainWildcards::Enabled,
)
.is_ok()
|| NetDescriptor::parse_for_list(host_and_port).is_ok()
{
Ok(host_and_port.to_string())
} else {
@ -57,11 +52,7 @@ pub fn parse(paths: Vec<String>) -> clap::error::Result<Vec<String>> {
out.push(format!("{}:{}", host, port.0));
}
} else {
NetDescriptor::parse_for_list(
&host_and_port,
UnstableSubdomainWildcards::Enabled,
)
.map_err(|e| {
NetDescriptor::parse_for_list(&host_and_port).map_err(|e| {
clap::Error::raw(clap::error::ErrorKind::InvalidValue, e.to_string())
})?;
out.push(host_and_port)
@ -146,7 +137,10 @@ mod tests {
"localhost:8000",
"0.0.0.0:4545",
"127.0.0.1:4545",
"999.0.88.1:80"
"999.0.88.1:80",
"127.0.0.0/24",
"192.168.1.0/24",
"10.0.0.0/8"
];
let expected = svec![
"deno.land",
@ -168,7 +162,10 @@ mod tests {
"localhost:8000",
"0.0.0.0:4545",
"127.0.0.1:4545",
"999.0.88.1:80"
"999.0.88.1:80",
"127.0.0.0/24",
"192.168.1.0/24",
"10.0.0.0/8"
];
let actual = parse(entries).unwrap();
assert_eq!(actual, expected);

View file

@ -24,8 +24,8 @@ pub use deno_config::deno_json::LintRulesConfig;
use deno_config::deno_json::NodeModulesDirMode;
pub use deno_config::deno_json::ProseWrap;
use deno_config::deno_json::TestConfig;
pub use deno_config::deno_json::TsTypeLib;
pub use deno_config::glob::FilePatterns;
pub use deno_config::workspace::TsTypeLib;
use deno_config::workspace::Workspace;
use deno_config::workspace::WorkspaceDirLintConfig;
use deno_config::workspace::WorkspaceDirectory;
@ -35,20 +35,20 @@ use deno_core::error::AnyError;
use deno_core::resolve_url_or_path;
use deno_core::url::Url;
use deno_graph::GraphKind;
use deno_lib::args::CaData;
use deno_lib::args::has_flag_env_var;
use deno_lib::args::npm_pkg_req_ref_to_binary_command;
use deno_lib::args::npm_process_state;
use deno_lib::args::CaData;
use deno_lib::version::DENO_VERSION_INFO;
use deno_lib::worker::StorageKeyResolver;
use deno_npm::NpmSystemInfo;
use deno_npm_installer::graph::NpmCachingStrategy;
use deno_npm_installer::LifecycleScriptsConfig;
use deno_npm_installer::graph::NpmCachingStrategy;
use deno_resolver::factory::resolve_jsr_url;
use deno_runtime::deno_permissions::PermissionsOptions;
use deno_runtime::inspector_server::InspectorServer;
use deno_semver::npm::NpmPackageReqReference;
use deno_semver::StackString;
use deno_semver::npm::NpmPackageReqReference;
use deno_telemetry::OtelConfig;
use deno_terminal::colors;
use dotenvy::from_filename;
@ -59,8 +59,6 @@ use thiserror::Error;
use crate::sys::CliSys;
pub type CliLockfile = deno_resolver::lockfile::LockfileLock<CliSys>;
pub type CliTsConfigResolver =
deno_resolver::deno_json::TsConfigResolver<CliSys>;
pub fn jsr_url() -> &'static Url {
static JSR_URL: Lazy<Url> = Lazy::new(|| resolve_jsr_url(&CliSys::default()));
@ -355,6 +353,110 @@ fn resolve_lint_rules_options(
}
}
pub struct WorkspaceMainModuleResolver {
workspace_resolver: Arc<deno_resolver::workspace::WorkspaceResolver<CliSys>>,
node_resolver: Arc<crate::node::CliNodeResolver>,
}
impl WorkspaceMainModuleResolver {
pub fn new(
workspace_resolver: Arc<
deno_resolver::workspace::WorkspaceResolver<CliSys>,
>,
node_resolver: Arc<crate::node::CliNodeResolver>,
) -> Self {
Self {
workspace_resolver,
node_resolver,
}
}
}
impl WorkspaceMainModuleResolver {
fn resolve_main_module(
&self,
specifier: &str,
cwd: &Url,
) -> Result<Url, AnyError> {
let resolution = self.workspace_resolver.resolve(
specifier,
cwd,
deno_resolver::workspace::ResolutionKind::Execution,
)?;
let url = match resolution {
deno_resolver::workspace::MappedResolution::Normal {
specifier, ..
} => specifier,
deno_resolver::workspace::MappedResolution::WorkspaceJsrPackage {
specifier,
..
} => specifier,
deno_resolver::workspace::MappedResolution::WorkspaceNpmPackage {
target_pkg_json,
sub_path,
..
} => self
.node_resolver
.resolve_package_subpath_from_deno_module(
target_pkg_json.clone().dir_path(),
sub_path.as_deref(),
Some(cwd),
node_resolver::ResolutionMode::Import,
node_resolver::NodeResolutionKind::Execution,
)?
.into_url()?,
deno_resolver::workspace::MappedResolution::PackageJson {
sub_path,
dep_result,
alias,
..
} => {
let result = dep_result
.as_ref()
.map_err(|e| deno_core::anyhow::anyhow!("{e}"))?;
match result {
deno_package_json::PackageJsonDepValue::File(file) => {
let cwd_path = deno_path_util::url_to_file_path(cwd)?;
deno_path_util::resolve_path(file, &cwd_path)?
}
deno_package_json::PackageJsonDepValue::Req(package_req) => {
ModuleSpecifier::parse(&format!(
"npm:{}{}",
package_req,
sub_path.map(|s| format!("/{}", s)).unwrap_or_default()
))?
}
deno_package_json::PackageJsonDepValue::Workspace(version_req) => {
let pkg_folder = self
.workspace_resolver
.resolve_workspace_pkg_json_folder_for_pkg_json_dep(
alias,
version_req,
)?;
self
.node_resolver
.resolve_package_subpath_from_deno_module(
pkg_folder,
sub_path.as_deref(),
Some(cwd),
node_resolver::ResolutionMode::Import,
node_resolver::NodeResolutionKind::Execution,
)?
.into_url()?
}
deno_package_json::PackageJsonDepValue::JsrReq(_) => {
return Err(
deno_resolver::DenoResolveErrorKind::UnsupportedPackageJsonJsrReq
.into_box()
.into(),
);
}
}
}
};
Ok(url)
}
}
/// Holds the resolved options of many sources used by subcommands
/// and provides some helper function for creating common objects.
#[derive(Debug)]
@ -472,7 +574,11 @@ impl CliOptions {
let maybe_node_channel_fd = std::env::var("NODE_CHANNEL_FD").ok();
if let Some(node_channel_fd) = maybe_node_channel_fd {
// Remove so that child processes don't inherit this environment variable.
std::env::remove_var("NODE_CHANNEL_FD");
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
std::env::remove_var("NODE_CHANNEL_FD")
};
node_channel_fd.parse::<i64>().ok()
} else {
None
@ -515,7 +621,43 @@ impl CliOptions {
self.flags.env_file.as_ref()
}
pub fn resolve_main_module(&self) -> Result<&ModuleSpecifier, AnyError> {
pub fn preload_modules(&self) -> Result<Vec<ModuleSpecifier>, AnyError> {
if self.flags.preload.is_empty() {
return Ok(vec![]);
}
let mut preload = Vec::with_capacity(self.flags.preload.len());
for preload_specifier in self.flags.preload.iter() {
preload.push(resolve_url_or_path(preload_specifier, self.initial_cwd())?);
}
Ok(preload)
}
fn resolve_main_module_with_resolver_if_bare(
&self,
raw_specifier: &str,
resolver: Option<&WorkspaceMainModuleResolver>,
default_resolve: impl Fn() -> Result<ModuleSpecifier, AnyError>,
) -> Result<ModuleSpecifier, AnyError> {
match resolver {
Some(resolver)
if !raw_specifier.starts_with('.')
&& !Path::new(raw_specifier).is_absolute() =>
{
let cwd = deno_path_util::url_from_directory_path(self.initial_cwd())?;
resolver
.resolve_main_module(raw_specifier, &cwd)
.or_else(|_| default_resolve())
}
_ => default_resolve(),
}
}
pub fn resolve_main_module_with_resolver(
&self,
resolver: Option<&WorkspaceMainModuleResolver>,
) -> Result<&ModuleSpecifier, AnyError> {
self
.main_module_cell
.get_or_init(|| {
@ -533,25 +675,40 @@ impl CliOptions {
if run_flags.is_stdin() {
resolve_url_or_path("./$deno$stdin.mts", self.initial_cwd())?
} else {
let url =
resolve_url_or_path(&run_flags.script, self.initial_cwd())?;
if self.is_node_main()
&& url.scheme() == "file"
&& MediaType::from_specifier(&url) == MediaType::Unknown
{
try_resolve_node_binary_main_entrypoint(
&run_flags.script,
self.initial_cwd(),
)?
.unwrap_or(url)
} else {
url
}
let default_resolve = || {
let url =
resolve_url_or_path(&run_flags.script, self.initial_cwd())?;
if self.is_node_main()
&& url.scheme() == "file"
&& MediaType::from_specifier(&url) == MediaType::Unknown
{
Ok::<_, AnyError>(
try_resolve_node_binary_main_entrypoint(
&run_flags.script,
self.initial_cwd(),
)?
.unwrap_or(url),
)
} else {
Ok(url)
}
};
self.resolve_main_module_with_resolver_if_bare(
&run_flags.script,
resolver,
default_resolve,
)?
}
}
DenoSubcommand::Serve(run_flags) => {
resolve_url_or_path(&run_flags.script, self.initial_cwd())?
}
DenoSubcommand::Serve(run_flags) => self
.resolve_main_module_with_resolver_if_bare(
&run_flags.script,
resolver,
|| {
resolve_url_or_path(&run_flags.script, self.initial_cwd())
.map_err(|e| e.into())
},
)?,
_ => {
bail!("No main module.")
}
@ -561,6 +718,10 @@ impl CliOptions {
.map_err(|err| deno_core::anyhow::anyhow!("{}", err))
}
pub fn resolve_main_module(&self) -> Result<&ModuleSpecifier, AnyError> {
self.resolve_main_module_with_resolver(None)
}
pub fn resolve_file_header_overrides(
&self,
) -> HashMap<ModuleSpecifier, HashMap<String, String>> {
@ -762,6 +923,11 @@ impl CliOptions {
.as_ref()
.map(ToOwned::to_owned)
.or_else(|| env::var("DENO_COVERAGE_DIR").ok()),
DenoSubcommand::Run(flags) => flags
.coverage_dir
.as_ref()
.map(ToOwned::to_owned)
.or_else(|| env::var("DENO_COVERAGE_DIR").ok()),
_ => None,
}
}
@ -868,6 +1034,7 @@ impl CliOptions {
allow_write: handle_allow(flags.allow_all, flags.allow_write.clone()),
deny_write: flags.deny_write.clone(),
allow_import: handle_allow(flags.allow_all, flags.allow_import.clone()),
deny_import: flags.deny_import.clone(),
prompt: !resolve_no_prompt(flags),
}
}
@ -882,6 +1049,7 @@ impl CliOptions {
if !options.allow_all && options.allow_import.is_none() {
options.allow_import = Some(self.implicit_allow_import());
}
options.deny_import = options.deny_import.clone();
}
fn implicit_allow_import(&self) -> Vec<String> {
@ -978,7 +1146,11 @@ impl CliOptions {
match std::env::var(NPM_CMD_NAME_ENV_VAR_NAME) {
Ok(var) => {
// remove the env var so that child sub processes won't pick this up
std::env::remove_var(NPM_CMD_NAME_ENV_VAR_NAME);
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
std::env::remove_var(NPM_CMD_NAME_ENV_VAR_NAME)
};
Some(var)
}
Err(_) => NpmPackageReqReference::from_str(&flags.script).ok().map(
@ -998,11 +1170,6 @@ impl CliOptions {
&self.flags.unsafely_ignore_certificate_errors
}
pub fn unstable_subdomain_wildcards(&self) -> bool {
self.flags.unstable_config.subdomain_wildcards
|| self.workspace().has_unstable("subdomain-wildcards")
}
pub fn unstable_bare_node_builtins(&self) -> bool {
self.flags.unstable_config.bare_node_builtins
|| self.workspace().has_unstable("bare-node-builtins")
@ -1020,6 +1187,11 @@ impl CliOptions {
self.workspace().package_jsons().next().is_some() || self.is_node_main()
}
pub fn unstable_raw_imports(&self) -> bool {
self.flags.unstable_config.raw_imports
|| self.workspace().has_unstable("raw-imports")
}
pub fn unstable_lazy_dynamic_imports(&self) -> bool {
self.flags.unstable_config.lazy_dynamic_imports
|| self.workspace().has_unstable("lazy-dynamic-imports")
@ -1252,10 +1424,28 @@ pub fn load_env_variables_from_env_file(
.unwrap_or(true)
{
match error {
dotenvy::Error::LineParse(line, index)=> eprintln!("{} Parsing failed within the specified environment file: {} at index: {} of the value: {}", colors::yellow("Warning"), env_file_name, index, line),
dotenvy::Error::Io(_)=> eprintln!("{} The `--env-file` flag was used, but the environment file specified '{}' was not found.", colors::yellow("Warning"), env_file_name),
dotenvy::Error::EnvVar(_)=> eprintln!("{} One or more of the environment variables isn't present or not unicode within the specified environment file: {}", colors::yellow("Warning"), env_file_name),
_ => eprintln!("{} Unknown failure occurred with the specified environment file: {}", colors::yellow("Warning"), env_file_name),
dotenvy::Error::LineParse(line, index) => eprintln!(
"{} Parsing failed within the specified environment file: {} at index: {} of the value: {}",
colors::yellow("Warning"),
env_file_name,
index,
line
),
dotenvy::Error::Io(_) => eprintln!(
"{} The `--env-file` flag was used, but the environment file specified '{}' was not found.",
colors::yellow("Warning"),
env_file_name
),
dotenvy::Error::EnvVar(_) => eprintln!(
"{} One or more of the environment variables isn't present or not unicode within the specified environment file: {}",
colors::yellow("Warning"),
env_file_name
),
_ => eprintln!(
"{} Unknown failure occurred with the specified environment file: {}",
colors::yellow("Warning"),
env_file_name
),
}
}
}

View file

@ -7,11 +7,11 @@ use std::time::Duration;
use deno_core::serde::Deserialize;
use deno_core::serde_json;
use deno_core::serde_json::json;
use deno_core::serde_json::Value;
use deno_core::serde_json::json;
use lsp_types::Uri;
use test_util::lsp::LspClientBuilder;
use test_util::PathRef;
use test_util::lsp::LspClientBuilder;
use tower_lsp::lsp_types as lsp;
static FIXTURE_CODE_LENS_TS: &str = include_str!("testdata/code_lens.ts");

View file

@ -1,10 +1,10 @@
// Copyright 2018-2025 the Deno authors. MIT license.
use deno_bench_util::bencher::Bencher;
use deno_bench_util::bencher::benchmark_group;
use deno_bench_util::bencher::benchmark_main;
use deno_bench_util::bencher::Bencher;
use deno_core::serde_json::json;
use deno_core::serde_json::Value;
use deno_core::serde_json::json;
use test_util::lsp::LspClient;
use test_util::lsp::LspClientBuilder;

12
cli/cache/cache_db.rs vendored
View file

@ -33,6 +33,10 @@ impl CacheDBHash {
.finish(),
)
}
pub fn inner(&self) -> u64 {
self.0
}
}
impl rusqlite::types::ToSql for CacheDBHash {
@ -423,7 +427,11 @@ fn open_connection(
// Failed, try deleting it
let is_tty = std::io::stderr().is_terminal();
log::log!(
if is_tty { log::Level::Warn } else { log::Level::Trace },
if is_tty {
log::Level::Warn
} else {
log::Level::Trace
},
"Could not initialize cache database '{}', deleting and retrying... ({err:?})",
path.to_string_lossy()
);
@ -601,9 +609,9 @@ mod tests {
}
fn assert_same_serialize_deserialize(original_hash: CacheDBHash) {
use rusqlite::ToSql;
use rusqlite::types::FromSql;
use rusqlite::types::ValueRef;
use rusqlite::ToSql;
let value = original_hash.to_sql().unwrap();
match value {

View file

@ -178,14 +178,16 @@ mod test {
let conn = CacheDB::in_memory(&CODE_CACHE_DB, "1.0.0");
let cache = CodeCacheInner::new(conn);
assert!(cache
.get_sync(
"file:///foo/bar.js",
code_cache::CodeCacheType::EsModule,
CacheDBHash::new(1),
)
.unwrap()
.is_none());
assert!(
cache
.get_sync(
"file:///foo/bar.js",
code_cache::CodeCacheType::EsModule,
CacheDBHash::new(1),
)
.unwrap()
.is_none()
);
let data_esm = vec![1, 2, 3];
cache
.set_sync(
@ -207,14 +209,16 @@ mod test {
data_esm
);
assert!(cache
.get_sync(
"file:///foo/bar.js",
code_cache::CodeCacheType::Script,
CacheDBHash::new(1),
)
.unwrap()
.is_none());
assert!(
cache
.get_sync(
"file:///foo/bar.js",
code_cache::CodeCacheType::Script,
CacheDBHash::new(1),
)
.unwrap()
.is_none()
);
let data_script = vec![4, 5, 6];
cache
.set_sync(

View file

@ -6,8 +6,8 @@ use std::path::PathBuf;
use deno_core::error::AnyError;
use deno_core::parking_lot::Mutex;
use deno_core::unsync::spawn;
use deno_core::unsync::JoinHandle;
use deno_core::unsync::spawn;
use deno_runtime::deno_webstorage::rusqlite::params;
use super::cache_db::CacheDB;

15
cli/cache/mod.rs vendored
View file

@ -4,14 +4,13 @@ mod cache_db;
mod caches;
mod check;
mod code_cache;
mod deno_dir;
mod disk_cache;
mod emit;
mod fast_check;
mod incremental;
mod module_info;
mod node;
mod parsed_source;
pub type DenoDir = deno_resolver::cache::DenoDir<CliSys>;
pub type DenoDirProvider = deno_resolver::cache::DenoDirProvider<CliSys>;
pub use cache_db::CacheDBHash;
pub use caches::Caches;
@ -19,16 +18,10 @@ pub use check::TypeCheckCache;
pub use code_cache::CodeCache;
/// Permissions used to save a file in the disk caches.
pub use deno_cache_dir::CACHE_PERM;
pub use deno_dir::DenoDir;
pub use deno_dir::DenoDirProvider;
pub use disk_cache::DiskCache;
pub use emit::EmitCache;
pub use fast_check::FastCheckCache;
pub use incremental::IncrementalCache;
pub use module_info::ModuleInfoCache;
pub use node::NodeAnalysisCache;
pub use parsed_source::LazyGraphSourceParser;
pub use parsed_source::ParsedSourceCache;
pub use node::SqliteNodeAnalysisCache;
use crate::sys::CliSys;

View file

@ -9,13 +9,13 @@ use deno_core::serde_json;
use deno_error::JsErrorBox;
use deno_graph::analysis::ModuleInfo;
use deno_graph::ast::ParserModuleAnalyzer;
use deno_resolver::cache::ParsedSourceCache;
use deno_runtime::deno_webstorage::rusqlite::params;
use super::cache_db::CacheDB;
use super::cache_db::CacheDBConfiguration;
use super::cache_db::CacheDBHash;
use super::cache_db::CacheFailure;
use super::ParsedSourceCache;
const SELECT_MODULE_INFO: &str = "
SELECT
@ -316,9 +316,9 @@ fn serialize_media_type(media_type: MediaType) -> i64 {
#[cfg(test)]
mod test {
use deno_graph::PositionRange;
use deno_graph::analysis::JsDocImportInfo;
use deno_graph::analysis::SpecifierWithRange;
use deno_graph::PositionRange;
use super::*;

80
cli/cache/node.rs vendored
View file

@ -2,13 +2,15 @@
use deno_core::error::AnyError;
use deno_core::serde_json;
use deno_resolver::cjs::analyzer::DenoCjsAnalysis;
use deno_resolver::cjs::analyzer::NodeAnalysisCache;
use deno_resolver::cjs::analyzer::NodeAnalysisCacheSourceHash;
use deno_runtime::deno_webstorage::rusqlite::params;
use super::CacheDBHash;
use super::cache_db::CacheDB;
use super::cache_db::CacheDBConfiguration;
use super::cache_db::CacheFailure;
use super::CacheDBHash;
use crate::node::CliCjsAnalysis;
pub static NODE_ANALYSIS_CACHE_DB: CacheDBConfiguration =
CacheDBConfiguration {
@ -25,11 +27,11 @@ pub static NODE_ANALYSIS_CACHE_DB: CacheDBConfiguration =
};
#[derive(Clone)]
pub struct NodeAnalysisCache {
pub struct SqliteNodeAnalysisCache {
inner: NodeAnalysisCacheInner,
}
impl NodeAnalysisCache {
impl SqliteNodeAnalysisCache {
pub fn new(db: CacheDB) -> Self {
Self {
inner: NodeAnalysisCacheInner::new(db),
@ -52,27 +54,35 @@ impl NodeAnalysisCache {
}
}
}
}
pub fn get_cjs_analysis(
impl NodeAnalysisCache for SqliteNodeAnalysisCache {
fn compute_source_hash(&self, source: &str) -> NodeAnalysisCacheSourceHash {
NodeAnalysisCacheSourceHash(CacheDBHash::from_hashable(source).inner())
}
fn get_cjs_analysis(
&self,
specifier: &str,
expected_source_hash: CacheDBHash,
) -> Option<CliCjsAnalysis> {
specifier: &deno_ast::ModuleSpecifier,
source_hash: NodeAnalysisCacheSourceHash,
) -> Option<DenoCjsAnalysis> {
Self::ensure_ok(
self.inner.get_cjs_analysis(specifier, expected_source_hash),
self
.inner
.get_cjs_analysis(specifier.as_str(), CacheDBHash::new(source_hash.0)),
)
}
pub fn set_cjs_analysis(
fn set_cjs_analysis(
&self,
specifier: &str,
source_hash: CacheDBHash,
cjs_analysis: &CliCjsAnalysis,
specifier: &deno_ast::ModuleSpecifier,
source_hash: NodeAnalysisCacheSourceHash,
analysis: &DenoCjsAnalysis,
) {
Self::ensure_ok(self.inner.set_cjs_analysis(
specifier,
source_hash,
cjs_analysis,
specifier.as_str(),
CacheDBHash::new(source_hash.0),
analysis,
));
}
}
@ -91,7 +101,7 @@ impl NodeAnalysisCacheInner {
&self,
specifier: &str,
expected_source_hash: CacheDBHash,
) -> Result<Option<CliCjsAnalysis>, AnyError> {
) -> Result<Option<DenoCjsAnalysis>, AnyError> {
let query = "
SELECT
data
@ -116,7 +126,7 @@ impl NodeAnalysisCacheInner {
&self,
specifier: &str,
source_hash: CacheDBHash,
cjs_analysis: &CliCjsAnalysis,
cjs_analysis: &DenoCjsAnalysis,
) -> Result<(), AnyError> {
let sql = "
INSERT OR REPLACE INTO
@ -137,7 +147,7 @@ impl NodeAnalysisCacheInner {
#[cfg(test)]
mod test {
use deno_ast::ModuleExportsAndReExports;
use deno_resolver::cjs::analyzer::ModuleExportsAndReExports;
use super::*;
@ -146,21 +156,25 @@ mod test {
let conn = CacheDB::in_memory(&NODE_ANALYSIS_CACHE_DB, "1.0.0");
let cache = NodeAnalysisCacheInner::new(conn);
assert!(cache
.get_cjs_analysis("file.js", CacheDBHash::new(2))
.unwrap()
.is_none());
let cjs_analysis = CliCjsAnalysis::Cjs(ModuleExportsAndReExports {
assert!(
cache
.get_cjs_analysis("file.js", CacheDBHash::new(2))
.unwrap()
.is_none()
);
let cjs_analysis = DenoCjsAnalysis::Cjs(ModuleExportsAndReExports {
exports: vec!["export1".to_string()],
reexports: vec!["re-export1".to_string()],
});
cache
.set_cjs_analysis("file.js", CacheDBHash::new(2), &cjs_analysis)
.unwrap();
assert!(cache
.get_cjs_analysis("file.js", CacheDBHash::new(3))
.unwrap()
.is_none()); // different hash
assert!(
cache
.get_cjs_analysis("file.js", CacheDBHash::new(3))
.unwrap()
.is_none()
); // different hash
let actual_cjs_analysis = cache
.get_cjs_analysis("file.js", CacheDBHash::new(2))
.unwrap()
@ -184,9 +198,11 @@ mod test {
// now changing the cli version should clear it
let conn = cache.conn.recreate_with_version("2.0.0");
let cache = NodeAnalysisCacheInner::new(conn);
assert!(cache
.get_cjs_analysis("file.js", CacheDBHash::new(2))
.unwrap()
.is_none());
assert!(
cache
.get_cjs_analysis("file.js", CacheDBHash::new(2))
.unwrap()
.is_none()
);
}
}

View file

@ -6,8 +6,8 @@ use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use deno_cache_dir::npm::NpmCacheDir;
use deno_cache_dir::GlobalOrLocalHttpCache;
use deno_cache_dir::npm::NpmCacheDir;
use deno_config::workspace::WorkspaceDirectory;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
@ -15,46 +15,47 @@ use deno_core::futures::FutureExt;
use deno_core::serde_json;
use deno_core::url::Url;
use deno_error::JsErrorBox;
use deno_lib::args::CaData;
use deno_lib::args::get_root_cert_store;
use deno_lib::args::npm_process_state;
use deno_lib::args::CaData;
use deno_lib::loader::NpmModuleLoader;
use deno_lib::npm::create_npm_process_state_provider;
use deno_lib::npm::NpmRegistryReadPermissionChecker;
use deno_lib::npm::NpmRegistryReadPermissionCheckerMode;
use deno_lib::npm::create_npm_process_state_provider;
use deno_lib::worker::LibMainWorkerFactory;
use deno_lib::worker::LibMainWorkerOptions;
use deno_lib::worker::LibWorkerFactoryRoots;
use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm_cache::NpmCacheSetting;
use deno_npm_installer::NpmInstallerFactoryOptions;
use deno_npm_installer::lifecycle_scripts::LifecycleScriptsExecutor;
use deno_npm_installer::lifecycle_scripts::NullLifecycleScriptsExecutor;
use deno_npm_installer::process_state::NpmProcessStateKind;
use deno_npm_installer::NpmInstallerFactoryOptions;
use deno_resolver::cache::ParsedSourceCache;
use deno_resolver::cjs::IsCjsResolutionMode;
use deno_resolver::deno_json::CompilerOptionsOverrides;
use deno_resolver::deno_json::CompilerOptionsResolver;
use deno_resolver::factory::ConfigDiscoveryOption;
use deno_resolver::factory::DenoDirPathProviderOptions;
use deno_resolver::factory::NpmProcessStateOptions;
use deno_resolver::factory::ResolverFactoryOptions;
use deno_resolver::factory::SpecifiedImportMapProvider;
use deno_resolver::factory::WorkspaceDirectoryProvider;
use deno_resolver::import_map::WorkspaceExternalImportMapLoader;
use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_resolver::workspace::WorkspaceResolver;
use deno_runtime::FeatureChecker;
use deno_runtime::deno_fs;
use deno_runtime::deno_fs::RealFs;
use deno_runtime::deno_permissions::Permissions;
use deno_runtime::deno_permissions::PermissionsContainer;
use deno_runtime::deno_permissions::UnstableSubdomainWildcards;
use deno_runtime::deno_tls::rustls::RootCertStore;
use deno_runtime::deno_tls::RootCertStoreProvider;
use deno_runtime::deno_tls::rustls::RootCertStore;
use deno_runtime::deno_web::BlobStore;
use deno_runtime::inspector_server::InspectorServer;
use deno_runtime::permissions::RuntimePermissionDescriptorParser;
use deno_runtime::FeatureChecker;
use node_resolver::analyze::NodeCodeTranslator;
use node_resolver::cache::NodeResolutionThreadLocalCache;
use node_resolver::NodeConditionOptions;
use node_resolver::NodeResolverOptions;
use node_resolver::cache::NodeResolutionThreadLocalCache;
use once_cell::sync::OnceCell;
use sys_traits::EnvCurrentDir;
@ -62,7 +63,6 @@ use crate::args::BundleFlags;
use crate::args::BundlePlatform;
use crate::args::CliLockfile;
use crate::args::CliOptions;
use crate::args::CliTsConfigResolver;
use crate::args::ConfigFlag;
use crate::args::DenoSubcommand;
use crate::args::Flags;
@ -70,28 +70,22 @@ use crate::args::InstallFlags;
use crate::cache::Caches;
use crate::cache::CodeCache;
use crate::cache::DenoDir;
use crate::cache::DenoDirProvider;
use crate::cache::EmitCache;
use crate::cache::GlobalHttpCache;
use crate::cache::ModuleInfoCache;
use crate::cache::NodeAnalysisCache;
use crate::cache::ParsedSourceCache;
use crate::emit::Emitter;
use crate::file_fetcher::create_cli_file_fetcher;
use crate::cache::SqliteNodeAnalysisCache;
use crate::file_fetcher::CliFileFetcher;
use crate::file_fetcher::CreateCliFileFetcherOptions;
use crate::file_fetcher::TextDecodedFile;
use crate::file_fetcher::create_cli_file_fetcher;
use crate::graph_container::MainModuleGraphContainer;
use crate::graph_util::FileWatcherReporter;
use crate::graph_util::ModuleGraphBuilder;
use crate::graph_util::ModuleGraphCreator;
use crate::http_util::HttpClientProvider;
use crate::module_loader::CliEmitter;
use crate::module_loader::CliModuleLoaderFactory;
use crate::module_loader::EszipModuleLoader;
use crate::module_loader::ModuleLoadPreparer;
use crate::node::CliCjsCodeAnalyzer;
use crate::node::CliCjsModuleExportAnalyzer;
use crate::node::CliNodeCodeTranslator;
use crate::node::CliNodeResolver;
use crate::node::CliPackageJsonResolver;
use crate::npm::CliNpmCache;
@ -101,12 +95,13 @@ use crate::npm::CliNpmInstaller;
use crate::npm::CliNpmInstallerFactory;
use crate::npm::CliNpmResolver;
use crate::npm::DenoTaskLifeCycleScriptsExecutor;
use crate::resolver::on_resolve_diagnostic;
use crate::resolver::CliCjsTracker;
use crate::resolver::CliResolver;
use crate::resolver::on_resolve_diagnostic;
use crate::standalone::binary::DenoCompileBinaryWriter;
use crate::sys::CliSys;
use crate::tools::coverage::CoverageCollector;
use crate::tools::installer::BinNameResolver;
use crate::tools::lint::LintRuleProvider;
use crate::tools::run::hmr::HmrRunner;
use crate::tsc::TypeCheckingCjsTracker;
@ -248,9 +243,6 @@ impl SpecifiedImportMapProvider for CliSpecifiedImportMapProvider {
}
pub type CliWorkspaceFactory = deno_resolver::factory::WorkspaceFactory<CliSys>;
pub type CliDenoDirPathProvider =
deno_resolver::factory::DenoDirPathProvider<CliSys>;
pub type CliResolverFactory = deno_resolver::factory::ResolverFactory<CliSys>;
pub struct Deferred<T>(once_cell::unsync::OnceCell<T>);
@ -303,13 +295,8 @@ impl<T> Deferred<T> {
struct CliFactoryServices {
blob_store: Deferred<Arc<BlobStore>>,
caches: Deferred<Arc<Caches>>,
cjs_module_export_analyzer: Deferred<Arc<CliCjsModuleExportAnalyzer>>,
cli_options: Deferred<Arc<CliOptions>>,
code_cache: Deferred<Arc<CodeCache>>,
deno_dir_path_provider: Deferred<Arc<CliDenoDirPathProvider>>,
deno_dir_provider: Deferred<Arc<DenoDirProvider>>,
emit_cache: Deferred<Arc<EmitCache>>,
emitter: Deferred<Arc<Emitter>>,
eszip_module_loader_provider: Deferred<Arc<EszipModuleLoaderProvider>>,
feature_checker: Deferred<Arc<FeatureChecker>>,
file_fetcher: Deferred<Arc<CliFileFetcher>>,
@ -322,9 +309,7 @@ struct CliFactoryServices {
module_graph_creator: Deferred<Arc<ModuleGraphCreator>>,
module_info_cache: Deferred<Arc<ModuleInfoCache>>,
module_load_preparer: Deferred<Arc<ModuleLoadPreparer>>,
node_code_translator: Deferred<Arc<CliNodeCodeTranslator>>,
npm_installer_factory: Deferred<CliNpmInstallerFactory>,
parsed_source_cache: Deferred<Arc<ParsedSourceCache>>,
permission_desc_parser:
Deferred<Arc<RuntimePermissionDescriptorParser<CliSys>>>,
resolver_factory: Deferred<Arc<CliResolverFactory>>,
@ -397,34 +382,21 @@ impl CliFactory {
})
}
pub fn deno_dir_path_provider(&self) -> &Arc<CliDenoDirPathProvider> {
self.services.deno_dir_path_provider.get_or_init(|| {
Arc::new(CliDenoDirPathProvider::new(
self.sys(),
DenoDirPathProviderOptions {
maybe_custom_root: self.flags.internal.cache_path.clone(),
},
))
})
}
pub fn deno_dir_provider(&self) -> &Arc<DenoDirProvider> {
self.services.deno_dir_provider.get_or_init(|| {
Arc::new(DenoDirProvider::new(
self.sys(),
self.deno_dir_path_provider().clone(),
))
})
}
pub fn deno_dir(&self) -> Result<&DenoDir, AnyError> {
Ok(self.deno_dir_provider().get_or_create()?)
Ok(
self
.workspace_factory()?
.deno_dir_provider()
.get_or_create()?,
)
}
pub fn caches(&self) -> Result<&Arc<Caches>, AnyError> {
self.services.caches.get_or_try_init(|| {
let cli_options = self.cli_options()?;
let caches = Arc::new(Caches::new(self.deno_dir_provider().clone()));
let caches = Arc::new(Caches::new(
self.workspace_factory()?.deno_dir_provider().clone(),
));
// Warm up the caches we know we'll likely need based on the CLI mode
match cli_options.sub_command() {
DenoSubcommand::Run(_)
@ -452,6 +424,12 @@ impl CliFactory {
self.services.blob_store.get_or_init(Default::default)
}
pub fn bin_name_resolver(&self) -> Result<BinNameResolver<'_>, AnyError> {
let http_client = self.http_client_provider();
let npm_api = self.npm_installer_factory()?.registry_info_provider()?;
Ok(BinNameResolver::new(http_client, npm_api.as_ref()))
}
pub fn root_cert_store_provider(&self) -> &Arc<dyn RootCertStoreProvider> {
self.services.root_cert_store_provider.get_or_init(|| {
Arc::new(CliRootCertStoreProvider::new(
@ -616,11 +594,7 @@ impl CliFactory {
.env_current_dir()
.with_context(|| "Failed getting cwd.")?,
};
let options = new_workspace_factory_options(
&initial_cwd,
&self.flags,
self.deno_dir_path_provider().clone(),
);
let options = new_workspace_factory_options(&initial_cwd, &self.flags);
let mut factory =
CliWorkspaceFactory::new(self.sys(), initial_cwd, options);
if let Some(workspace_dir) = &self.overrides.workspace_directory {
@ -653,17 +627,11 @@ impl CliFactory {
.get_or_init(|| maybe_file_watcher_reporter)
}
pub fn emit_cache(&self) -> Result<&Arc<EmitCache>, AnyError> {
self.services.emit_cache.get_or_try_init(|| {
Ok(Arc::new(EmitCache::new(self.deno_dir()?.gen_cache.clone())))
})
}
pub fn module_info_cache(&self) -> Result<&Arc<ModuleInfoCache>, AnyError> {
self.services.module_info_cache.get_or_try_init(|| {
Ok(Arc::new(ModuleInfoCache::new(
self.caches()?.dep_analysis_db(),
self.parsed_source_cache().clone(),
self.resolver_factory()?.parsed_source_cache().clone(),
)))
})
}
@ -674,22 +642,14 @@ impl CliFactory {
})
}
pub fn parsed_source_cache(&self) -> &Arc<ParsedSourceCache> {
self
.services
.parsed_source_cache
.get_or_init(Default::default)
pub fn parsed_source_cache(
&self,
) -> Result<&Arc<ParsedSourceCache>, AnyError> {
Ok(self.resolver_factory()?.parsed_source_cache())
}
pub fn emitter(&self) -> Result<&Arc<Emitter>, AnyError> {
self.services.emitter.get_or_try_init(|| {
Ok(Arc::new(Emitter::new(
self.cjs_tracker()?.clone(),
self.emit_cache()?.clone(),
self.parsed_source_cache().clone(),
self.tsconfig_resolver()?.clone(),
)))
})
pub fn emitter(&self) -> Result<&Arc<CliEmitter>, AnyError> {
self.resolver_factory()?.emitter()
}
pub async fn lint_rule_provider(&self) -> Result<LintRuleProvider, AnyError> {
@ -710,74 +670,16 @@ impl CliFactory {
.await
}
pub async fn cjs_module_export_analyzer(
&self,
) -> Result<&Arc<CliCjsModuleExportAnalyzer>, AnyError> {
self
.services
.cjs_module_export_analyzer
.get_or_try_init_async(async {
let node_resolver = self.node_resolver().await?.clone();
let cjs_code_analyzer = self.create_cjs_code_analyzer()?;
Ok(Arc::new(CliCjsModuleExportAnalyzer::new(
cjs_code_analyzer,
self.in_npm_pkg_checker()?.clone(),
node_resolver,
self.npm_resolver().await?.clone(),
self.pkg_json_resolver()?.clone(),
self.sys(),
)))
})
.await
}
pub async fn node_code_translator(
&self,
) -> Result<&Arc<CliNodeCodeTranslator>, AnyError> {
self
.services
.node_code_translator
.get_or_try_init_async(
async {
let module_export_analyzer =
self.cjs_module_export_analyzer().await?;
Ok(Arc::new(NodeCodeTranslator::new(
module_export_analyzer.clone(),
match self.cli_options()?.sub_command() {
DenoSubcommand::Bundle(_) => {
node_resolver::analyze::NodeCodeTranslatorMode::Bundling
}
_ => node_resolver::analyze::NodeCodeTranslatorMode::ModuleLoader,
},
)))
}
.boxed_local(),
)
.await
}
fn create_cjs_code_analyzer(&self) -> Result<CliCjsCodeAnalyzer, AnyError> {
let caches = self.caches()?;
let node_analysis_cache = NodeAnalysisCache::new(caches.node_analysis_db());
Ok(CliCjsCodeAnalyzer::new(
node_analysis_cache,
self.cjs_tracker()?.clone(),
self.fs().clone(),
Some(self.parsed_source_cache().clone()),
))
}
pub fn pkg_json_resolver(
&self,
) -> Result<&Arc<CliPackageJsonResolver>, AnyError> {
Ok(self.resolver_factory()?.pkg_json_resolver())
}
pub fn tsconfig_resolver(
pub fn compiler_options_resolver(
&self,
) -> Result<&Arc<CliTsConfigResolver>, AnyError> {
Ok(self.workspace_factory()?.tsconfig_resolver()?)
) -> Result<&Arc<CompilerOptionsResolver>, AnyError> {
self.resolver_factory()?.compiler_options_resolver()
}
pub async fn type_checker(&self) -> Result<&Arc<TypeChecker>, AnyError> {
@ -798,7 +700,8 @@ impl CliFactory {
self.node_resolver().await?.clone(),
self.npm_resolver().await?.clone(),
self.sys(),
self.tsconfig_resolver()?.clone(),
self.workspace_directory_provider()?.clone(),
self.compiler_options_resolver()?.clone(),
if cli_options.code_cache_enabled() {
Some(self.code_cache()?.clone())
} else {
@ -833,11 +736,11 @@ impl CliFactory {
self.npm_graph_resolver().await?.clone(),
self.npm_installer_if_managed().await?.cloned(),
self.npm_resolver().await?.clone(),
self.parsed_source_cache().clone(),
self.resolver_factory()?.parsed_source_cache().clone(),
self.resolver().await?.clone(),
self.root_permissions_container()?.clone(),
self.sys(),
self.tsconfig_resolver()?.clone(),
self.compiler_options_resolver()?.clone(),
)))
}
.boxed_local(),
@ -926,14 +829,7 @@ impl CliFactory {
&self,
) -> Result<&Arc<RuntimePermissionDescriptorParser<CliSys>>, AnyError> {
self.services.permission_desc_parser.get_or_try_init(|| {
Ok(Arc::new(RuntimePermissionDescriptorParser::new(
self.sys(),
if self.cli_options()?.unstable_subdomain_wildcards() {
UnstableSubdomainWildcards::Enabled
} else {
UnstableSubdomainWildcards::Disabled
},
)))
Ok(Arc::new(RuntimePermissionDescriptorParser::new(self.sys())))
})
}
@ -958,11 +854,12 @@ impl CliFactory {
) -> Result<DenoCompileBinaryWriter, AnyError> {
let cli_options = self.cli_options()?;
Ok(DenoCompileBinaryWriter::new(
self.cjs_module_export_analyzer().await?,
self.resolver_factory()?.cjs_module_export_analyzer()?,
self.cjs_tracker()?,
self.cli_options()?,
self.deno_dir()?,
self.emitter()?,
self.file_fetcher()?,
self.http_client_provider(),
self.npm_resolver().await?,
self.workspace_resolver().await?.as_ref(),
@ -986,6 +883,12 @@ impl CliFactory {
})
}
fn workspace_directory_provider(
&self,
) -> Result<&Arc<WorkspaceDirectoryProvider>, AnyError> {
Ok(self.workspace_factory()?.workspace_directory_provider()?)
}
fn workspace_external_import_map_loader(
&self,
) -> Result<&Arc<WorkspaceExternalImportMapLoader<CliSys>>, AnyError> {
@ -1010,11 +913,12 @@ impl CliFactory {
let cli_options = self.cli_options()?;
let cli_npm_resolver = self.npm_resolver().await?.clone();
let in_npm_pkg_checker = self.in_npm_pkg_checker()?;
let node_code_translator = self.node_code_translator().await?;
let cjs_tracker = self.cjs_tracker()?.clone();
let workspace_factory = self.workspace_factory()?;
let resolver_factory = self.resolver_factory()?;
let node_code_translator = resolver_factory.node_code_translator()?;
let cjs_tracker = self.cjs_tracker()?.clone();
let npm_registry_permission_checker = {
let mode = if self.resolver_factory()?.use_byonm()? {
let mode = if resolver_factory.use_byonm()? {
NpmRegistryReadPermissionCheckerMode::Byonm
} else if let Some(node_modules_dir) =
workspace_factory.node_modules_dir_path()?
@ -1041,10 +945,10 @@ impl CliFactory {
None
},
self.emitter()?.clone(),
self.file_fetcher()?.clone(),
in_npm_pkg_checker.clone(),
self.main_module_graph_container().await?.clone(),
self.module_load_preparer().await?.clone(),
node_code_translator.clone(),
NpmModuleLoader::new(
self.cjs_tracker()?.clone(),
node_code_translator.clone(),
@ -1052,7 +956,8 @@ impl CliFactory {
),
npm_registry_permission_checker,
cli_npm_resolver.clone(),
self.parsed_source_cache().clone(),
resolver_factory.parsed_source_cache().clone(),
resolver_factory.prepared_module_loader()?.clone(),
self.resolver().await?.clone(),
self.sys(),
maybe_eszip_loader,
@ -1152,6 +1057,7 @@ impl CliFactory {
otel_config: cli_options.otel_config(),
no_legacy_abort: cli_options.no_legacy_abort(),
startup_snapshot: deno_snapshots::CLI_SNAPSHOT,
enable_raw_imports: cli_options.unstable_raw_imports(),
tunnel: self.flags.connected.is_some(),
})
}
@ -1197,9 +1103,17 @@ impl CliFactory {
pub fn resolver_factory(&self) -> Result<&Arc<CliResolverFactory>, AnyError> {
self.services.resolver_factory.get_or_try_init(|| {
let options = self.cli_options()?;
let caches = self.caches()?;
let node_analysis_cache =
Arc::new(SqliteNodeAnalysisCache::new(caches.node_analysis_db()));
Ok(Arc::new(CliResolverFactory::new(
self.workspace_factory()?.clone(),
ResolverFactoryOptions {
compiler_options_overrides: CompilerOptionsOverrides {
no_transpile: false,
source_map_base: None,
preserve_jsx: false,
},
is_cjs_resolution_mode: if options.is_node_main()
|| options.unstable_detect_cjs()
{
@ -1209,6 +1123,7 @@ impl CliFactory {
} else {
IsCjsResolutionMode::Disabled
},
node_analysis_cache: Some(node_analysis_cache),
node_resolver_options: NodeResolverOptions {
conditions: NodeConditionOptions {
conditions: options
@ -1246,6 +1161,12 @@ impl CliFactory {
})
),
},
node_code_translator_mode: match options.sub_command() {
DenoSubcommand::Bundle(_) => {
node_resolver::analyze::NodeCodeTranslatorMode::Bundling
}
_ => node_resolver::analyze::NodeCodeTranslatorMode::ModuleLoader,
},
node_resolution_cache: Some(Arc::new(NodeResolutionThreadLocalCache)),
npm_system_info: self.flags.subcommand.npm_system_info(),
specified_import_map: Some(Box::new(CliSpecifiedImportMapProvider {
@ -1258,8 +1179,8 @@ impl CliFactory {
.workspace_external_import_map_loader()?
.clone(),
})),
bare_node_builtins: self.flags.unstable_config.bare_node_builtins,
unstable_sloppy_imports: self.flags.unstable_config.sloppy_imports,
bare_node_builtins: options.unstable_bare_node_builtins(),
unstable_sloppy_imports: options.unstable_sloppy_imports(),
on_mapped_resolution_diagnostic: Some(Arc::new(
on_resolve_diagnostic,
)),
@ -1283,8 +1204,7 @@ impl CliFactory {
fn new_workspace_factory_options(
initial_cwd: &Path,
flags: &Flags,
deno_dir_path_provider: Arc<CliDenoDirPathProvider>,
) -> deno_resolver::factory::WorkspaceFactoryOptions<CliSys> {
) -> deno_resolver::factory::WorkspaceFactoryOptions {
deno_resolver::factory::WorkspaceFactoryOptions {
additional_config_file_names: if matches!(
flags.subcommand,
@ -1307,7 +1227,7 @@ fn new_workspace_factory_options(
}
ConfigFlag::Disabled => ConfigDiscoveryOption::Disabled,
},
deno_dir_path_provider: Some(deno_dir_path_provider),
maybe_custom_deno_dir_root: flags.internal.cache_path.clone(),
// For `deno install/add/remove/init` we want to force the managed
// resolver so it can set up the `node_modules/` directory.
is_package_manager_subcommand: matches!(

View file

@ -3,24 +3,24 @@
use std::sync::Arc;
use deno_ast::MediaType;
use deno_cache_dir::GlobalOrLocalHttpCache;
use deno_cache_dir::file_fetcher::BlobData;
use deno_cache_dir::file_fetcher::CacheSetting;
use deno_cache_dir::file_fetcher::File;
use deno_cache_dir::file_fetcher::SendError;
use deno_cache_dir::file_fetcher::SendResponse;
use deno_cache_dir::GlobalOrLocalHttpCache;
use deno_core::ModuleSpecifier;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::url::Url;
use deno_core::ModuleSpecifier;
use deno_resolver::file_fetcher::PermissionedFileFetcherOptions;
use deno_runtime::deno_web::BlobStore;
use http::HeaderMap;
use http::StatusCode;
use crate::colors;
use crate::http_util::get_response_body_with_progress;
use crate::http_util::HttpClientProvider;
use crate::http_util::get_response_body_with_progress;
use crate::sys::CliSys;
use crate::util::progress_bar::ProgressBar;
@ -242,8 +242,8 @@ impl deno_cache_dir::file_fetcher::HttpClient for HttpClientAdapter {
mod tests {
use std::collections::HashMap;
use deno_cache_dir::file_fetcher::HttpClient;
use deno_cache_dir::HttpCache;
use deno_cache_dir::file_fetcher::HttpClient;
use deno_core::resolve_url;
use deno_resolver::file_fetcher::FetchErrorKind;
use deno_resolver::file_fetcher::FetchPermissionsOptionRef;
@ -869,7 +869,10 @@ mod tests {
deno_cache_dir::file_fetcher::FetchNoFollowErrorKind::NoRemote {
..
} => {
assert_eq!(err.to_string(), "A remote specifier was requested: \"http://localhost:4545/run/002_hello.ts\", but --no-remote is specified.");
assert_eq!(
err.to_string(),
"A remote specifier was requested: \"http://localhost:4545/run/002_hello.ts\", but --no-remote is specified."
);
}
_ => unreachable!(),
}
@ -924,7 +927,10 @@ mod tests {
deno_cache_dir::file_fetcher::FetchNoFollowErrorKind::NotCached {
..
} => {
assert_eq!(err.to_string(), "Specifier not found in cache: \"http://localhost:4545/run/002_hello.ts\", --cached-only is specified.");
assert_eq!(
err.to_string(),
"Specifier not found in cache: \"http://localhost:4545/run/002_hello.ts\", --cached-only is specified."
);
}
_ => unreachable!(),
}

View file

@ -1,57 +1,58 @@
// Copyright 2018-2025 the Deno authors. MIT license.
use std::collections::HashSet;
use std::error::Error;
use std::path::PathBuf;
use std::sync::Arc;
use deno_ast::MediaType;
use deno_config::deno_json;
use deno_config::deno_json::CompilerOptionTypesDeserializeError;
use deno_config::deno_json::NodeModulesDirMode;
use deno_config::workspace::JsrPackageConfig;
use deno_config::workspace::ToMaybeJsxImportSourceConfigError;
use deno_core::ModuleSpecifier;
use deno_core::error::AnyError;
use deno_core::parking_lot::Mutex;
use deno_core::serde_json;
use deno_core::ModuleSpecifier;
use deno_error::JsErrorBox;
use deno_error::JsErrorClass;
use deno_graph::source::Loader;
use deno_graph::source::ResolveError;
use deno_graph::CheckJsOption;
use deno_graph::FillFromLockfileOptions;
use deno_graph::GraphKind;
use deno_graph::JsrLoadError;
use deno_graph::ModuleError;
use deno_graph::ModuleErrorKind;
use deno_graph::ModuleGraph;
use deno_graph::ModuleGraphError;
use deno_graph::ModuleLoadError;
use deno_graph::ResolutionError;
use deno_graph::SpecifierError;
use deno_graph::WorkspaceFastCheckOption;
use deno_npm_installer::graph::NpmCachingStrategy;
use deno_graph::source::Loader;
use deno_graph::source::ResolveError;
use deno_npm_installer::PackageCaching;
use deno_npm_installer::graph::NpmCachingStrategy;
use deno_path_util::url_to_file_path;
use deno_resolver::cache::ParsedSourceCache;
use deno_resolver::deno_json::CompilerOptionsResolver;
use deno_resolver::deno_json::JsxImportSourceConfigResolver;
use deno_resolver::graph::EnhanceGraphErrorMode;
use deno_resolver::graph::enhance_graph_error;
use deno_resolver::graph::enhanced_integrity_error_message;
use deno_resolver::graph::format_deno_graph_error;
use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_resolver::workspace::sloppy_imports_resolve;
use deno_resolver::workspace::ScopedJsxImportSourceConfig;
use deno_runtime::deno_node;
use deno_runtime::deno_permissions::PermissionsContainer;
use deno_semver::jsr::JsrDepPackageReq;
use deno_semver::SmallStackString;
use deno_semver::jsr::JsrDepPackageReq;
use indexmap::IndexMap;
use sys_traits::FsMetadata;
use crate::args::config_to_deno_graph_workspace_member;
use crate::args::jsr_url;
use crate::args::CliLockfile;
use crate::args::CliOptions;
use crate::args::CliTsConfigResolver;
use crate::args::DenoSubcommand;
use crate::args::config_to_deno_graph_workspace_member;
use crate::args::jsr_url;
use crate::cache;
use crate::cache::GlobalHttpCache;
use crate::cache::ModuleInfoCache;
use crate::cache::ParsedSourceCache;
use crate::colors;
use crate::file_fetcher::CliDenoGraphLoader;
use crate::file_fetcher::CliFileFetcher;
@ -109,17 +110,18 @@ pub fn graph_valid(
allow_unknown_jsr_exports: options.allow_unknown_jsr_exports,
},
);
if let Some(error) = errors.next() {
Err(error)
} else {
// finally surface the npm resolution result
if let Err(err) = &graph.npm_dep_graph_result {
return Err(JsErrorBox::new(
err.get_class(),
format_deno_graph_error(err),
));
match errors.next() {
Some(error) => Err(error),
_ => {
// finally surface the npm resolution result
if let Err(err) = &graph.npm_dep_graph_result {
return Err(JsErrorBox::new(
err.get_class(),
format_deno_graph_error(err),
));
}
Ok(())
}
Ok(())
}
}
@ -184,7 +186,7 @@ pub fn graph_walk_errors<'a>(
should_ignore_resolution_error_for_types(err)
}
ModuleGraphError::ModuleError(module_error) => {
matches!(module_error, ModuleError::Missing { .. })
matches!(module_error.as_kind(), ModuleErrorKind::Missing { .. })
}
}
}
@ -198,8 +200,8 @@ pub fn graph_walk_errors<'a>(
) -> bool {
if (graph_kind == GraphKind::TypesOnly || allow_unknown_media_types)
&& matches!(
error,
ModuleGraphError::ModuleError(ModuleError::UnsupportedMediaType { .. })
error.as_module_error_kind(),
Some(ModuleErrorKind::UnsupportedMediaType { .. })
)
{
return true;
@ -248,8 +250,8 @@ pub fn graph_walk_errors<'a>(
if is_root
&& options.allow_unknown_jsr_exports
&& matches!(
error,
ModuleGraphError::ModuleError(ModuleError::Load {
error.as_module_error_kind(),
Some(ModuleErrorKind::Load {
err: ModuleLoadError::Jsr(JsrLoadError::UnknownExport { .. }),
..
})
@ -297,15 +299,15 @@ pub fn module_error_for_tsc_diagnostic<'a>(
sys: &CliSys,
error: &'a ModuleError,
) -> Option<ModuleNotFoundGraphErrorRef<'a>> {
match error {
ModuleError::Missing {
match error.as_kind() {
ModuleErrorKind::Missing {
specifier,
maybe_referrer,
} => Some(ModuleNotFoundGraphErrorRef {
specifier,
maybe_range: maybe_referrer.as_ref(),
}),
ModuleError::Load {
ModuleErrorKind::Load {
specifier,
maybe_referrer,
err: ModuleLoadError::Loader(_),
@ -356,45 +358,6 @@ pub fn resolution_error_for_tsc_diagnostic(
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum EnhanceGraphErrorMode {
ShowRange,
HideRange,
}
pub fn enhance_graph_error(
sys: &CliSys,
error: &ModuleGraphError,
mode: EnhanceGraphErrorMode,
) -> String {
let mut message = match &error {
ModuleGraphError::ResolutionError(resolution_error) => {
enhanced_resolution_error_message(resolution_error)
}
ModuleGraphError::TypesResolutionError(resolution_error) => {
format!(
"Failed resolving types. {}",
enhanced_resolution_error_message(resolution_error)
)
}
ModuleGraphError::ModuleError(error) => {
enhanced_integrity_error_message(error)
.or_else(|| enhanced_sloppy_imports_error_message(sys, error))
.unwrap_or_else(|| format_deno_graph_error(error))
}
};
if let Some(range) = error.maybe_range() {
if mode == EnhanceGraphErrorMode::ShowRange
&& !range.specifier.as_str().contains("/$deno$eval")
{
message.push_str("\n at ");
message.push_str(&format_range_with_colors(range));
}
}
message
}
pub fn graph_exit_integrity_errors(graph: &ModuleGraph) {
for error in graph.module_errors() {
exit_for_integrity_error(error);
@ -653,7 +616,9 @@ pub enum BuildGraphWithNpmResolutionError {
#[error(transparent)]
Other(#[from] JsErrorBox),
#[class(generic)]
#[error("Resolving npm specifier entrypoints this way is currently not supported with \"nodeModules\": \"manual\". In the meantime, try with --node-modules-dir=auto instead")]
#[error(
"Resolving npm specifier entrypoints this way is currently not supported with \"nodeModules\": \"manual\". In the meantime, try with --node-modules-dir=auto instead"
)]
UnsupportedNpmSpecifierEntrypointResolutionWay,
}
@ -687,7 +652,7 @@ pub struct ModuleGraphBuilder {
resolver: Arc<CliResolver>,
root_permissions_container: PermissionsContainer,
sys: CliSys,
tsconfig_resolver: Arc<CliTsConfigResolver>,
compiler_options_resolver: Arc<CompilerOptionsResolver>,
}
impl ModuleGraphBuilder {
@ -709,7 +674,7 @@ impl ModuleGraphBuilder {
resolver: Arc<CliResolver>,
root_permissions_container: PermissionsContainer,
sys: CliSys,
tsconfig_resolver: Arc<CliTsConfigResolver>,
compiler_options_resolver: Arc<CompilerOptionsResolver>,
) -> Self {
Self {
caches,
@ -728,7 +693,7 @@ impl ModuleGraphBuilder {
resolver,
root_permissions_container,
sys,
tsconfig_resolver,
compiler_options_resolver,
}
}
@ -758,12 +723,14 @@ impl ModuleGraphBuilder {
MutLoaderRef::Owned(self.create_graph_loader_with_root_permissions())
}
};
let scoped_jsx_config = ScopedJsxImportSourceConfig::from_workspace_dir(
&self.cli_options.start_dir,
)?;
let graph_resolver = self
.resolver
.as_graph_resolver(self.cjs_tracker.as_ref(), &scoped_jsx_config);
let jsx_import_source_config_resolver =
JsxImportSourceConfigResolver::from_compiler_options_resolver(
&self.compiler_options_resolver,
)?;
let graph_resolver = self.resolver.as_graph_resolver(
self.cjs_tracker.as_ref(),
&jsx_import_source_config_resolver,
);
let maybe_file_watcher_reporter = self
.maybe_file_watcher_reporter
.as_ref()
@ -788,6 +755,8 @@ impl ModuleGraphBuilder {
reporter: maybe_file_watcher_reporter,
resolver: Some(&graph_resolver),
locker: locker.as_mut().map(|l| l as _),
unstable_bytes_imports: self.cli_options.unstable_raw_imports(),
unstable_text_imports: self.cli_options.unstable_raw_imports(),
},
options.npm_caching,
)
@ -850,19 +819,39 @@ impl ModuleGraphBuilder {
return Err(BuildGraphWithNpmResolutionError::UnsupportedNpmSpecifierEntrypointResolutionWay);
}
let imports = if graph.graph_kind().include_types() {
// Resolve all the imports from every deno.json. We'll separate
// Resolve all the imports from every config file. We'll separate
// them later based on the folder we're type checking.
let mut imports = Vec::new();
for deno_json in self.cli_options.workspace().deno_jsons() {
let maybe_imports = deno_json.to_compiler_option_types()?;
imports.extend(maybe_imports.into_iter().map(
|(referrer, imports)| deno_graph::ReferrerImports {
referrer,
imports,
},
));
let mut imports_by_referrer = IndexMap::<_, Vec<_>>::with_capacity(
self.compiler_options_resolver.size(),
);
for (referrer, files) in self
.compiler_options_resolver
.ts_configs()
.iter()
.filter_map(|t| t.files())
{
imports_by_referrer
.entry(referrer)
.or_default()
.extend(files.iter().map(|f| f.relative_specifier.clone()));
}
imports
for (referrer, types) in self
.compiler_options_resolver
.all()
.flat_map(|d| d.compiler_options_types().as_ref())
{
imports_by_referrer
.entry(referrer)
.or_default()
.extend(types.clone());
}
imports_by_referrer
.into_iter()
.map(|(referrer, imports)| deno_graph::ReferrerImports {
referrer: referrer.clone(),
imports,
})
.collect()
} else {
Vec::new()
};
@ -934,12 +923,14 @@ impl ModuleGraphBuilder {
None
};
let parser = self.parsed_source_cache.as_capturing_parser();
let scoped_jsx_config = ScopedJsxImportSourceConfig::from_workspace_dir(
&self.cli_options.start_dir,
)?;
let graph_resolver = self
.resolver
.as_graph_resolver(self.cjs_tracker.as_ref(), &scoped_jsx_config);
let jsx_import_source_config_resolver =
JsxImportSourceConfigResolver::from_compiler_options_resolver(
&self.compiler_options_resolver,
)?;
let graph_resolver = self.resolver.as_graph_resolver(
self.cjs_tracker.as_ref(),
&jsx_import_source_config_resolver,
);
graph.build_fast_check_type_graph(
deno_graph::BuildFastCheckTypeGraphOptions {
@ -1008,7 +999,9 @@ impl ModuleGraphBuilder {
} else {
GraphKind::CodeOnly
},
check_js: CheckJsOption::Custom(self.tsconfig_resolver.as_ref()),
check_js: CheckJsOption::Custom(
self.compiler_options_resolver.as_ref(),
),
exit_integrity_errors: true,
allow_unknown_media_types,
ignore_graph_errors: matches!(
@ -1021,229 +1014,6 @@ impl ModuleGraphBuilder {
}
}
/// Adds more explanatory information to a resolution error.
pub fn enhanced_resolution_error_message(error: &ResolutionError) -> String {
let mut message = format_deno_graph_error(error);
let maybe_hint = if let Some(specifier) =
get_resolution_error_bare_node_specifier(error)
{
Some(format!("If you want to use a built-in Node module, add a \"node:\" prefix (ex. \"node:{specifier}\")."))
} else {
get_import_prefix_missing_error(error).map(|specifier| {
format!(
"If you want to use a JSR or npm package, try running `deno add jsr:{}` or `deno add npm:{}`",
specifier, specifier
)
})
};
if let Some(hint) = maybe_hint {
message.push_str(&format!("\n {} {}", colors::cyan("hint:"), hint));
}
message
}
static RUN_WITH_SLOPPY_IMPORTS_MSG: &str =
"or run with --unstable-sloppy-imports";
fn enhanced_sloppy_imports_error_message(
sys: &CliSys,
error: &ModuleError,
) -> Option<String> {
match error {
ModuleError::Load { specifier, err: ModuleLoadError::Loader(_), .. } // ex. "Is a directory" error
| ModuleError::Missing { specifier, .. } => {
let additional_message = maybe_additional_sloppy_imports_message(sys, specifier)?;
Some(format!(
"{} {}",
error,
additional_message,
))
}
_ => None,
}
}
pub fn maybe_additional_sloppy_imports_message(
sys: &CliSys,
specifier: &ModuleSpecifier,
) -> Option<String> {
let (resolved, sloppy_reason) = sloppy_imports_resolve(
specifier,
deno_resolver::workspace::ResolutionKind::Execution,
sys.clone(),
)?;
Some(format!(
"{} {}",
sloppy_reason.suggestion_message_for_specifier(&resolved),
RUN_WITH_SLOPPY_IMPORTS_MSG
))
}
fn enhanced_integrity_error_message(err: &ModuleError) -> Option<String> {
match err {
ModuleError::Load {
specifier,
err: ModuleLoadError::Jsr(JsrLoadError::ContentChecksumIntegrity(
checksum_err,
)),
..
} => {
Some(format!(
concat!(
"Integrity check failed in package. The package may have been tampered with.\n\n",
" Specifier: {}\n",
" Actual: {}\n",
" Expected: {}\n\n",
"If you modified your global cache, run again with the --reload flag to restore ",
"its state. If you want to modify dependencies locally run again with the ",
"--vendor flag or specify `\"vendor\": true` in a deno.json then modify the contents ",
"of the vendor/ folder."
),
specifier,
checksum_err.actual,
checksum_err.expected,
))
}
ModuleError::Load {
err: ModuleLoadError::Jsr(
JsrLoadError::PackageVersionManifestChecksumIntegrity(
package_nv,
checksum_err,
),
),
..
} => {
Some(format!(
concat!(
"Integrity check failed for package. The source code is invalid, as it does not match the expected hash in the lock file.\n\n",
" Package: {}\n",
" Actual: {}\n",
" Expected: {}\n\n",
"This could be caused by:\n",
" * the lock file may be corrupt\n",
" * the source itself may be corrupt\n\n",
"Investigate the lockfile; delete it to regenerate the lockfile or --reload to reload the source code from the server."
),
package_nv,
checksum_err.actual,
checksum_err.expected,
))
}
ModuleError::Load {
specifier,
err: ModuleLoadError::HttpsChecksumIntegrity(checksum_err),
..
} => {
Some(format!(
concat!(
"Integrity check failed for remote specifier. The source code is invalid, as it does not match the expected hash in the lock file.\n\n",
" Specifier: {}\n",
" Actual: {}\n",
" Expected: {}\n\n",
"This could be caused by:\n",
" * the lock file may be corrupt\n",
" * the source itself may be corrupt\n\n",
"Investigate the lockfile; delete it to regenerate the lockfile or --reload to reload the source code from the server."
),
specifier,
checksum_err.actual,
checksum_err.expected,
))
}
_ => None,
}
}
pub fn get_resolution_error_bare_node_specifier(
error: &ResolutionError,
) -> Option<&str> {
get_resolution_error_bare_specifier(error)
.filter(|specifier| deno_node::is_builtin_node_module(specifier))
}
fn get_resolution_error_bare_specifier(
error: &ResolutionError,
) -> Option<&str> {
if let ResolutionError::InvalidSpecifier {
error: SpecifierError::ImportPrefixMissing { specifier, .. },
..
} = error
{
Some(specifier.as_str())
} else if let ResolutionError::ResolverError { error, .. } = error {
if let ResolveError::ImportMap(error) = (*error).as_ref() {
if let import_map::ImportMapErrorKind::UnmappedBareSpecifier(
specifier,
_,
) = error.as_kind()
{
Some(specifier.as_str())
} else {
None
}
} else {
None
}
} else {
None
}
}
fn get_import_prefix_missing_error(error: &ResolutionError) -> Option<&str> {
// not exact, but ok because this is just a hint
let media_type =
MediaType::from_specifier_and_headers(&error.range().specifier, None);
if media_type == MediaType::Wasm {
return None;
}
let mut maybe_specifier = None;
if let ResolutionError::InvalidSpecifier {
error: SpecifierError::ImportPrefixMissing { specifier, .. },
range,
} = error
{
if range.specifier.scheme() == "file" {
maybe_specifier = Some(specifier);
}
} else if let ResolutionError::ResolverError { error, range, .. } = error {
if range.specifier.scheme() == "file" {
match error.as_ref() {
ResolveError::Specifier(specifier_error) => {
if let SpecifierError::ImportPrefixMissing { specifier, .. } =
specifier_error
{
maybe_specifier = Some(specifier);
}
}
ResolveError::Other(other_error) => {
if let Some(SpecifierError::ImportPrefixMissing {
specifier, ..
}) = other_error.as_any().downcast_ref::<SpecifierError>()
{
maybe_specifier = Some(specifier);
}
}
ResolveError::ImportMap(_) => {}
}
}
}
// NOTE(bartlomieju): For now, return None if a specifier contains a dot or a space. This is because
// suggesting to `deno add bad-module.ts` makes no sense and is worse than not providing
// a suggestion at all. This should be improved further in the future
if let Some(specifier) = maybe_specifier {
if specifier.contains('.') || specifier.contains(' ') {
return None;
}
}
maybe_specifier.map(|s| s.as_str())
}
/// Gets if any of the specified root's "file:" dependents are in the
/// provided changed set.
pub fn has_graph_root_local_dependent_changed(
@ -1319,15 +1089,6 @@ impl deno_graph::source::Reporter for FileWatcherReporter {
}
}
pub fn format_range_with_colors(referrer: &deno_graph::Range) -> String {
format!(
"{}:{}:{}",
colors::cyan(referrer.specifier.as_str()),
colors::yellow(&(referrer.range.start.line + 1).to_string()),
colors::yellow(&(referrer.range.start.character + 1).to_string())
)
}
#[derive(Debug, Default, Clone, Copy)]
pub struct CliJsrUrlProvider;
@ -1336,100 +1097,3 @@ impl deno_graph::source::JsrUrlProvider for CliJsrUrlProvider {
jsr_url()
}
}
fn format_deno_graph_error(err: &dyn Error) -> String {
use std::fmt::Write;
let mut message = format!("{}", err);
let mut maybe_source = err.source();
if maybe_source.is_some() {
let mut past_message = message.clone();
let mut count = 0;
let mut display_count = 0;
while let Some(source) = maybe_source {
let current_message = format!("{}", source);
maybe_source = source.source();
// sometimes an error might be repeated due to
// being boxed multiple times in another AnyError
if current_message != past_message {
write!(message, "\n {}: ", display_count,).unwrap();
for (i, line) in current_message.lines().enumerate() {
if i > 0 {
write!(message, "\n {}", line).unwrap();
} else {
write!(message, "{}", line).unwrap();
}
}
display_count += 1;
}
if count > 8 {
write!(message, "\n {}: ...", count).unwrap();
break;
}
past_message = current_message;
count += 1;
}
}
message
}
#[cfg(test)]
mod test {
use std::sync::Arc;
use deno_ast::ModuleSpecifier;
use deno_graph::source::ResolveError;
use deno_graph::PositionRange;
use deno_graph::Range;
use deno_graph::ResolutionError;
use deno_graph::SpecifierError;
use super::*;
#[test]
fn import_map_node_resolution_error() {
let cases = vec![("fs", Some("fs")), ("other", None)];
for (input, output) in cases {
let import_map = import_map::ImportMap::new(
ModuleSpecifier::parse("file:///deno.json").unwrap(),
);
let specifier = ModuleSpecifier::parse("file:///file.ts").unwrap();
let err = import_map.resolve(input, &specifier).err().unwrap();
let err = ResolutionError::ResolverError {
error: Arc::new(ResolveError::ImportMap(err)),
specifier: input.to_string(),
range: Range {
specifier,
resolution_mode: None,
range: PositionRange::zeroed(),
},
};
assert_eq!(get_resolution_error_bare_node_specifier(&err), output);
}
}
#[test]
fn bare_specifier_node_resolution_error() {
let cases = vec![("process", Some("process")), ("other", None)];
for (input, output) in cases {
let specifier = ModuleSpecifier::parse("file:///file.ts").unwrap();
let err = ResolutionError::InvalidSpecifier {
range: Range {
specifier,
resolution_mode: None,
range: PositionRange::zeroed(),
},
error: SpecifierError::ImportPrefixMissing {
specifier: input.to_string(),
referrer: None,
},
};
assert_eq!(get_resolution_error_bare_node_specifier(&err), output,);
}
}
}

View file

@ -16,15 +16,15 @@ use deno_error::JsError;
use deno_error::JsErrorBox;
use deno_lib::version::DENO_VERSION_INFO;
use deno_runtime::deno_fetch;
use deno_runtime::deno_fetch::create_http_client;
use deno_runtime::deno_fetch::CreateHttpClientOptions;
use deno_runtime::deno_fetch::ResBody;
use deno_runtime::deno_fetch::create_http_client;
use deno_runtime::deno_tls::RootCertStoreProvider;
use http::header::HeaderName;
use http::header::HeaderValue;
use http::header::CONTENT_LENGTH;
use http::HeaderMap;
use http::StatusCode;
use http::header::CONTENT_LENGTH;
use http::header::HeaderName;
use http::header::HeaderValue;
use http_body_util::BodyExt;
use thiserror::Error;
@ -508,10 +508,10 @@ mod test {
create_http_client(
DENO_VERSION_INFO.user_agent,
CreateHttpClientOptions {
ca_certs: vec![std::fs::read(
test_util::testdata_path().join("tls/RootCA.pem"),
)
.unwrap()],
ca_certs: vec![
std::fs::read(test_util::testdata_path().join("tls/RootCA.pem"))
.unwrap(),
],
..Default::default()
},
)
@ -574,7 +574,9 @@ mod test {
return;
}
panic!("None of the expected public URLs were available but internet appears to be available");
panic!(
"None of the expected public URLs were available but internet appears to be available"
);
}
#[tokio::test]
@ -614,12 +616,14 @@ mod test {
create_http_client(
DENO_VERSION_INFO.user_agent,
CreateHttpClientOptions {
ca_certs: vec![std::fs::read(
test_util::testdata_path()
.join("tls/RootCA.pem")
.to_string(),
)
.unwrap()],
ca_certs: vec![
std::fs::read(
test_util::testdata_path()
.join("tls/RootCA.pem")
.to_string(),
)
.unwrap(),
],
..Default::default()
},
)
@ -647,12 +651,14 @@ mod test {
create_http_client(
DENO_VERSION_INFO.user_agent,
CreateHttpClientOptions {
ca_certs: vec![std::fs::read(
test_util::testdata_path()
.join("tls/RootCA.pem")
.to_string(),
)
.unwrap()],
ca_certs: vec![
std::fs::read(
test_util::testdata_path()
.join("tls/RootCA.pem")
.to_string(),
)
.unwrap(),
],
..Default::default()
},
)
@ -688,12 +694,14 @@ mod test {
create_http_client(
DENO_VERSION_INFO.user_agent,
CreateHttpClientOptions {
ca_certs: vec![std::fs::read(
test_util::testdata_path()
.join("tls/RootCA.pem")
.to_string(),
)
.unwrap()],
ca_certs: vec![
std::fs::read(
test_util::testdata_path()
.join("tls/RootCA.pem")
.to_string(),
)
.unwrap(),
],
..Default::default()
},
)

View file

@ -2,7 +2,7 @@
[package]
name = "deno_lib"
version = "0.26.0"
version = "0.27.0"
authors.workspace = true
edition.workspace = true
license.workspace = true

View file

@ -4,20 +4,20 @@ use std::io::BufReader;
use std::io::Cursor;
use std::path::PathBuf;
use base64::prelude::Engine;
use base64::prelude::BASE64_STANDARD;
use base64::prelude::Engine;
use deno_npm::resolution::PackageIdNotFoundError;
use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
use deno_npm_installer::process_state::NpmProcessState;
use deno_npm_installer::process_state::NpmProcessStateFromEnvVarSys;
use deno_npm_installer::process_state::NpmProcessStateKind;
use deno_runtime::UNSTABLE_ENV_VAR_NAMES;
use deno_runtime::colors;
use deno_runtime::deno_tls::deno_native_certs::load_native_certs;
use deno_runtime::deno_tls::rustls;
use deno_runtime::deno_tls::rustls::RootCertStore;
use deno_runtime::deno_tls::rustls_pemfile;
use deno_runtime::deno_tls::webpki_roots;
use deno_runtime::UNSTABLE_ENV_VAR_NAMES;
use deno_semver::npm::NpmPackageReqReference;
use serde::Deserialize;
use serde::Serialize;
@ -170,7 +170,11 @@ pub fn npm_process_state(
.get_or_init(|| {
use deno_runtime::deno_process::NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME;
let fd_or_path = std::env::var_os(NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME)?;
std::env::remove_var(NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME);
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
std::env::remove_var(NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME)
};
if fd_or_path.is_empty() {
return None;
}
@ -201,10 +205,10 @@ pub fn resolve_npm_resolution_snapshot(
pub struct UnstableConfig {
// TODO(bartlomieju): remove in Deno 2.5
pub legacy_flag_enabled: bool, // --unstable
pub subdomain_wildcards: bool,
pub bare_node_builtins: bool,
pub detect_cjs: bool,
pub lazy_dynamic_imports: bool,
pub raw_imports: bool,
pub sloppy_imports: bool,
pub npm_lazy_caching: bool,
pub features: Vec<String>, // --unstabe-kv --unstable-cron
@ -218,10 +222,6 @@ impl UnstableConfig {
}
}
maybe_set(
&mut self.subdomain_wildcards,
UNSTABLE_ENV_VAR_NAMES.subdomain_wildcards,
);
maybe_set(
&mut self.bare_node_builtins,
UNSTABLE_ENV_VAR_NAMES.bare_node_builtins,
@ -234,9 +234,16 @@ impl UnstableConfig {
&mut self.npm_lazy_caching,
UNSTABLE_ENV_VAR_NAMES.npm_lazy_caching,
);
maybe_set(&mut self.raw_imports, UNSTABLE_ENV_VAR_NAMES.raw_imports);
maybe_set(
&mut self.sloppy_imports,
UNSTABLE_ENV_VAR_NAMES.sloppy_imports,
);
}
pub fn enable_node_compat(&mut self) {
self.bare_node_builtins = true;
self.sloppy_imports = true;
self.detect_cjs = true;
}
}

View file

@ -8,11 +8,12 @@ use deno_media_type::MediaType;
use deno_resolver::cjs::CjsTracker;
use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_runtime::deno_core::ModuleSourceCode;
use node_resolver::analyze::CjsCodeAnalyzer;
use node_resolver::analyze::NodeCodeTranslator;
use deno_runtime::deno_core::ModuleType;
use node_resolver::InNpmPackageChecker;
use node_resolver::IsBuiltInNodeModuleChecker;
use node_resolver::NpmPackageFolderResolver;
use node_resolver::analyze::CjsCodeAnalyzer;
use node_resolver::analyze::NodeCodeTranslator;
use thiserror::Error;
use url::Url;
@ -22,7 +23,7 @@ use crate::util::text_encoding::from_utf8_lossy_cow;
pub struct ModuleCodeStringSource {
pub code: ModuleSourceCode,
pub found_url: Url,
pub media_type: MediaType,
pub module_type: ModuleType,
}
#[derive(Debug, Error, deno_error::JsError)]
@ -120,12 +121,12 @@ pub struct NpmModuleLoader<
}
impl<
TCjsCodeAnalyzer: CjsCodeAnalyzer,
TInNpmPackageChecker: InNpmPackageChecker,
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver: NpmPackageFolderResolver,
TSys: DenoLibSys,
>
TCjsCodeAnalyzer: CjsCodeAnalyzer,
TInNpmPackageChecker: InNpmPackageChecker,
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver: NpmPackageFolderResolver,
TSys: DenoLibSys,
>
NpmModuleLoader<
TCjsCodeAnalyzer,
TInNpmPackageChecker,
@ -211,7 +212,17 @@ impl<
Ok(ModuleCodeStringSource {
code,
found_url: specifier.clone(),
media_type: MediaType::from_specifier(specifier),
module_type: module_type_from_media_type(MediaType::from_specifier(
specifier,
)),
})
}
}
pub fn module_type_from_media_type(media_type: MediaType) -> ModuleType {
match media_type {
MediaType::Json => ModuleType::Json,
MediaType::Wasm => ModuleType::Wasm,
_ => ModuleType::JavaScript,
}
}

View file

@ -62,7 +62,7 @@ impl ReleaseChannel {
"rc" => Self::Rc,
"lts" => Self::Lts,
unknown => {
return Err(UnrecognizedReleaseChannelError(unknown.to_string()))
return Err(UnrecognizedReleaseChannelError(unknown.to_string()));
}
})
}

View file

@ -136,9 +136,11 @@ pub enum CjsExportAnalysisEntry {
const HAS_TRANSPILED_FLAG: u8 = 1 << 0;
const HAS_SOURCE_MAP_FLAG: u8 = 1 << 1;
const HAS_CJS_EXPORT_ANALYSIS_FLAG: u8 = 1 << 2;
const HAS_VALID_UTF8_FLAG: u8 = 1 << 3;
pub struct RemoteModuleEntry<'a> {
pub media_type: MediaType,
pub is_valid_utf8: bool,
pub data: Cow<'a, [u8]>,
pub maybe_transpiled: Option<Cow<'a, [u8]>>,
pub maybe_source_map: Option<Cow<'a, [u8]>>,
@ -161,6 +163,9 @@ impl<'a> DenoRtSerializable<'a> for RemoteModuleEntry<'a> {
}
let mut has_data_flags = 0;
if self.is_valid_utf8 {
has_data_flags |= HAS_VALID_UTF8_FLAG;
}
if self.maybe_transpiled.is_some() {
has_data_flags |= HAS_TRANSPILED_FLAG;
}
@ -203,6 +208,7 @@ impl<'a> DenoRtDeserializable<'a> for RemoteModuleEntry<'a> {
deserialize_data_if_has_flag(input, has_data_flags, HAS_TRANSPILED_FLAG)?;
let (input, maybe_source_map) =
deserialize_data_if_has_flag(input, has_data_flags, HAS_SOURCE_MAP_FLAG)?;
let is_valid_utf8 = has_data_flags & HAS_VALID_UTF8_FLAG != 0;
let (input, maybe_cjs_export_analysis) = deserialize_data_if_has_flag(
input,
has_data_flags,
@ -213,6 +219,7 @@ impl<'a> DenoRtDeserializable<'a> for RemoteModuleEntry<'a> {
Self {
media_type,
data: Cow::Borrowed(data),
is_valid_utf8,
maybe_transpiled,
maybe_source_map,
maybe_cjs_export_analysis,
@ -270,7 +277,7 @@ impl<'a> DenoRtDeserializable<'a> for MediaType {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("Unknown media type value: {value}"),
))
));
}
};
Ok((input, value))

View file

@ -1,10 +1,10 @@
// Copyright 2018-2025 the Deno authors. MIT license.
use std::cmp::Ordering;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::collections::HashSet;
use std::collections::VecDeque;
use std::collections::hash_map::Entry;
use std::fmt;
use std::io::Read;
use std::path::Path;
@ -14,17 +14,19 @@ use std::time::SystemTime;
use deno_path_util::normalize_path;
use deno_path_util::strip_unc_prefix;
use deno_runtime::colors;
use deno_runtime::deno_core::anyhow::bail;
use deno_runtime::deno_core::anyhow::Context;
use deno_runtime::deno_core::anyhow::bail;
use deno_runtime::deno_core::error::AnyError;
use indexmap::IndexSet;
use serde::de;
use serde::de::SeqAccess;
use serde::de::Visitor;
use serde::Deserialize;
use serde::Deserializer;
use serde::Serialize;
use serde::Serializer;
use serde::de;
use serde::de::SeqAccess;
use serde::de::Visitor;
use crate::util::text_encoding::is_valid_utf8;
#[derive(Debug, PartialEq, Eq)]
pub enum WindowsSystemRootablePath {
@ -257,6 +259,8 @@ pub struct VirtualFile {
pub name: String,
#[serde(rename = "o")]
pub offset: OffsetWithLength,
#[serde(default, rename = "u", skip_serializing_if = "is_false")]
pub is_valid_utf8: bool,
#[serde(rename = "m", skip_serializing_if = "Option::is_none")]
pub transpiled_offset: Option<OffsetWithLength>,
#[serde(rename = "c", skip_serializing_if = "Option::is_none")]
@ -267,6 +271,10 @@ pub struct VirtualFile {
pub mtime: Option<u128>, // mtime in milliseconds
}
fn is_false(value: &bool) -> bool {
!value
}
#[derive(Debug, Serialize, Deserialize)]
pub struct VirtualSymlinkParts(Vec<String>);
@ -414,7 +422,7 @@ impl FilesData {
if data.is_empty() {
return OffsetWithLength { offset: 0, len: 0 };
}
let checksum = crate::util::checksum::gen(&[&data]);
let checksum = crate::util::checksum::r#gen(&[&data]);
match self.file_offsets.entry((checksum, data.len())) {
Entry::Occupied(occupied_entry) => {
let offset_and_len = *occupied_entry.get();
@ -766,6 +774,7 @@ impl VfsBuilder {
log::debug!("Adding file '{}'", path.display());
let case_sensitivity = self.case_sensitivity;
let is_valid_utf8 = is_valid_utf8(&options.data);
let offset_and_len = self.files.add_data(options.data);
let transpiled_offset = options
.maybe_transpiled
@ -790,6 +799,7 @@ impl VfsBuilder {
|| {
VfsEntry::File(VirtualFile {
name: name.to_string(),
is_valid_utf8,
offset: offset_and_len,
transpiled_offset,
cjs_export_analysis_offset,

View file

@ -4,7 +4,7 @@ use aws_lc_rs::digest::Context;
use aws_lc_rs::digest::SHA256;
/// Generate a SHA256 checksum of a slice of byte-slice-like things.
pub fn gen(v: &[impl AsRef<[u8]>]) -> String {
pub fn r#gen(v: &[impl AsRef<[u8]>]) -> String {
let mut ctx = Context::new(&SHA256);
for src in v {
ctx.update(src.as_ref());
@ -18,7 +18,7 @@ mod tests {
#[test]
fn test_gen() {
let actual = gen(&[b"hello world"]);
let actual = r#gen(&[b"hello world"]);
assert_eq!(
actual,
"b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"

View file

@ -3,6 +3,10 @@
use std::borrow::Cow;
use std::sync::Arc;
pub fn is_valid_utf8(bytes: &[u8]) -> bool {
matches!(String::from_utf8_lossy(bytes), Cow::Borrowed(_))
}
#[inline(always)]
pub fn from_utf8_lossy_owned(bytes: Vec<u8>) -> String {
match String::from_utf8_lossy(&bytes) {

View file

@ -1 +1 @@
2.3.7
2.4.0

View file

@ -11,17 +11,22 @@ use deno_path_util::url_from_file_path;
use deno_path_util::url_to_file_path;
use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_resolver::npm::NpmResolver;
use deno_runtime::BootstrapOptions;
use deno_runtime::FeatureChecker;
use deno_runtime::UNSTABLE_FEATURES;
use deno_runtime::WorkerExecutionMode;
use deno_runtime::WorkerLogLevel;
use deno_runtime::colors;
use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel;
use deno_runtime::deno_core;
use deno_runtime::deno_core::error::CoreError;
use deno_runtime::deno_core::v8;
use deno_runtime::deno_core::CompiledWasmModuleStore;
use deno_runtime::deno_core::Extension;
use deno_runtime::deno_core::JsRuntime;
use deno_runtime::deno_core::LocalInspectorSession;
use deno_runtime::deno_core::ModuleLoader;
use deno_runtime::deno_core::SharedArrayBufferStore;
use deno_runtime::deno_core::error::CoreError;
use deno_runtime::deno_core::v8;
use deno_runtime::deno_fs;
use deno_runtime::deno_napi::DenoRtNativeAddonLoaderRc;
use deno_runtime::deno_node::NodeExtInitServices;
@ -41,13 +46,8 @@ use deno_runtime::web_worker::WebWorkerServiceOptions;
use deno_runtime::worker::MainWorker;
use deno_runtime::worker::WorkerOptions;
use deno_runtime::worker::WorkerServiceOptions;
use deno_runtime::BootstrapOptions;
use deno_runtime::FeatureChecker;
use deno_runtime::WorkerExecutionMode;
use deno_runtime::WorkerLogLevel;
use deno_runtime::UNSTABLE_FEATURES;
use node_resolver::errors::ResolvePkgJsonBinExportError;
use node_resolver::UrlOrPath;
use node_resolver::errors::ResolvePkgJsonBinExportError;
use url::Url;
use crate::args::has_trace_permissions_enabled;
@ -323,6 +323,7 @@ pub struct LibMainWorkerOptions {
pub argv: Vec<String>,
pub log_level: WorkerLogLevel,
pub enable_op_summary_metrics: bool,
pub enable_raw_imports: bool,
pub enable_testing_features: bool,
pub has_node_modules_dir: bool,
pub inspect_brk: bool,
@ -425,7 +426,7 @@ impl<TSys: DenoLibSys> LibWorkerFactorySharedState<TSys> {
.resolve_storage_key(&args.main_module);
let cache_storage_dir = maybe_storage_key.map(|key| {
// TODO(@satyarohith): storage quota management
get_cache_storage_dir().join(checksum::gen(&[key.as_bytes()]))
get_cache_storage_dir().join(checksum::r#gen(&[key.as_bytes()]))
});
// TODO(bartlomieju): this is cruft, update FeatureChecker to spit out
@ -506,6 +507,7 @@ impl<TSys: DenoLibSys> LibWorkerFactorySharedState<TSys> {
strace_ops: shared.options.strace_ops.clone(),
close_on_idle: args.close_on_idle,
maybe_worker_metadata: args.maybe_worker_metadata,
enable_raw_imports: shared.options.enable_raw_imports,
enable_stack_trace_arg_in_ops: has_trace_permissions_enabled(),
};
@ -568,10 +570,12 @@ impl<TSys: DenoLibSys> LibMainWorkerFactory<TSys> {
mode: WorkerExecutionMode,
permissions: PermissionsContainer,
main_module: Url,
preload_modules: Vec<Url>,
) -> Result<LibMainWorker, CoreError> {
self.create_custom_worker(
mode,
main_module,
preload_modules,
permissions,
vec![],
Default::default(),
@ -580,10 +584,12 @@ impl<TSys: DenoLibSys> LibMainWorkerFactory<TSys> {
}
#[allow(clippy::result_large_err)]
#[allow(clippy::too_many_arguments)]
pub fn create_custom_worker(
&self,
mode: WorkerExecutionMode,
main_module: Url,
preload_modules: Vec<Url>,
permissions: PermissionsContainer,
custom_extensions: Vec<Extension>,
stdio: deno_runtime::deno_io::Stdio,
@ -612,11 +618,11 @@ impl<TSys: DenoLibSys> LibMainWorkerFactory<TSys> {
.origin_data_folder_path
.as_ref()
.unwrap() // must be set if storage key resolver returns a value
.join(checksum::gen(&[key.as_bytes()]))
.join(checksum::r#gen(&[key.as_bytes()]))
});
let cache_storage_dir = maybe_storage_key.map(|key| {
// TODO(@satyarohith): storage quota management
get_cache_storage_dir().join(checksum::gen(&[key.as_bytes()]))
get_cache_storage_dir().join(checksum::r#gen(&[key.as_bytes()]))
});
let services = WorkerServiceOptions {
@ -690,6 +696,7 @@ impl<TSys: DenoLibSys> LibMainWorkerFactory<TSys> {
origin_storage_dir,
stdio,
skip_op_registration: shared.options.skip_op_registration,
enable_raw_imports: shared.options.enable_raw_imports,
enable_stack_trace_arg_in_ops: has_trace_permissions_enabled(),
unconfigured_runtime,
};
@ -700,6 +707,7 @@ impl<TSys: DenoLibSys> LibMainWorkerFactory<TSys> {
Ok(LibMainWorker {
main_module,
preload_modules,
worker,
})
}
@ -786,6 +794,7 @@ impl<TSys: DenoLibSys> LibMainWorkerFactory<TSys> {
pub struct LibMainWorker {
main_module: Url,
preload_modules: Vec<Url>,
worker: MainWorker,
}
@ -847,9 +856,21 @@ impl LibMainWorker {
self.worker.evaluate_module(id).await
}
pub async fn execute_preload_modules(&mut self) -> Result<(), CoreError> {
for preload_module_url in self.preload_modules.iter() {
let id = self.worker.preload_side_module(preload_module_url).await?;
self.worker.evaluate_module(id).await?;
self.worker.run_event_loop(false).await?;
}
Ok(())
}
pub async fn run(&mut self) -> Result<i32, CoreError> {
log::debug!("main_module {}", self.main_module);
// Run preload modules first if they were defined
self.execute_preload_modules().await?;
self.execute_main_module().await?;
self.worker.dispatch_load_event()?;

View file

@ -10,6 +10,7 @@ use std::sync::Arc;
use deno_ast::SourceRange;
use deno_ast::SourceRangedForSpanned;
use deno_ast::SourceTextInfo;
use deno_core::ModuleSpecifier;
use deno_core::anyhow::anyhow;
use deno_core::error::AnyError;
use deno_core::resolve_url;
@ -18,13 +19,15 @@ use deno_core::serde::Serialize;
use deno_core::serde_json;
use deno_core::serde_json::json;
use deno_core::url::Url;
use deno_core::ModuleSpecifier;
use deno_error::JsErrorBox;
use deno_lint::diagnostic::LintDiagnosticRange;
use deno_npm::NpmPackageId;
use deno_path_util::url_to_file_path;
use deno_resolver::npm::managed::NpmResolutionCell;
use deno_runtime::deno_node::PathClean;
use deno_semver::SmallStackString;
use deno_semver::StackString;
use deno_semver::Version;
use deno_semver::jsr::JsrPackageNvReference;
use deno_semver::jsr::JsrPackageReqReference;
use deno_semver::npm::NpmPackageReqReference;
@ -32,9 +35,6 @@ use deno_semver::package::PackageNv;
use deno_semver::package::PackageNvReference;
use deno_semver::package::PackageReq;
use deno_semver::package::PackageReqReference;
use deno_semver::SmallStackString;
use deno_semver::StackString;
use deno_semver::Version;
use import_map::ImportMap;
use lsp_types::Uri;
use node_resolver::InNpmPackageChecker;
@ -632,11 +632,7 @@ fn maybe_reverse_definitely_typed(
.filter_map(|(req, nv)| (*nv.name == package_name).then_some(req))
.collect::<Vec<_>>();
if reqs.is_empty() {
None
} else {
Some(reqs)
}
if reqs.is_empty() { None } else { Some(reqs) }
}
fn try_reverse_map_package_json_exports(

View file

@ -6,8 +6,8 @@ use std::path::Path;
use std::sync::Arc;
use std::time::SystemTime;
use deno_core::url::Url;
use deno_core::ModuleSpecifier;
use deno_core::url::Url;
use deno_path_util::url_to_file_path;
use crate::cache::DenoDir;

View file

@ -37,8 +37,8 @@ fn code_action_capabilities(
.unwrap_or(CodeActionProviderCapability::Simple(true))
}
pub fn semantic_tokens_registration_options(
) -> SemanticTokensRegistrationOptions {
pub fn semantic_tokens_registration_options()
-> SemanticTokensRegistrationOptions {
const LANGUAGES: [&str; 4] = [
"javascript",
"javascriptreact",

View file

@ -12,8 +12,8 @@ use lsp_types::Uri;
use tower_lsp::lsp_types as lsp;
use tower_lsp::lsp_types::ConfigurationItem;
use super::config::WorkspaceSettings;
use super::config::SETTINGS_SECTION;
use super::config::WorkspaceSettings;
use super::lsp_custom;
use super::testing::lsp_custom as testing_lsp_custom;
use crate::lsp::repl::get_repl_workspace_settings;

View file

@ -5,18 +5,18 @@ use std::collections::HashSet;
use std::rc::Rc;
use std::sync::Arc;
use deno_ast::swc::ast;
use deno_ast::swc::ecma_visit::Visit;
use deno_ast::swc::ecma_visit::VisitWith;
use deno_ast::ParsedSource;
use deno_ast::SourceRange;
use deno_ast::SourceRangedForSpanned;
use deno_ast::swc::ast;
use deno_ast::swc::ecma_visit::Visit;
use deno_ast::swc::ecma_visit::VisitWith;
use deno_core::ModuleSpecifier;
use deno_core::error::AnyError;
use deno_core::serde::Deserialize;
use deno_core::serde::Serialize;
use deno_core::serde_json;
use deno_core::serde_json::json;
use deno_core::ModuleSpecifier;
use lazy_regex::lazy_regex;
use lsp_types::Uri;
use once_cell::sync::Lazy;

View file

@ -2,13 +2,13 @@
use deno_ast::LineAndColumnIndex;
use deno_ast::SourceTextInfo;
use deno_core::ModuleSpecifier;
use deno_core::resolve_path;
use deno_core::resolve_url;
use deno_core::serde::Deserialize;
use deno_core::serde::Serialize;
use deno_core::serde_json::json;
use deno_core::url::Position;
use deno_core::ModuleSpecifier;
use deno_path_util::url_to_file_path;
use deno_runtime::deno_node::SUPPORTED_BUILTIN_NODE_MODULES;
use deno_semver::jsr::JsrPackageReqReference;
@ -180,7 +180,7 @@ pub async fn get_import_completions(
NodeResolutionKind::Execution,
)
.ok();
if let Some(completion_list) = get_jsr_completions(
match get_jsr_completions(
&module.specifier,
text,
&range,
@ -190,85 +190,128 @@ pub async fn get_import_completions(
)
.await
{
Some(lsp::CompletionResponse::List(completion_list))
} else if let Some(completion_list) =
get_npm_completions(&module.specifier, text, &range, npm_search_api).await
{
Some(lsp::CompletionResponse::List(completion_list))
} else if let Some(completion_list) = get_node_completions(text, &range) {
Some(lsp::CompletionResponse::List(completion_list))
} else if let Some(completion_list) = get_import_map_completions(
&module.specifier,
text,
&range,
maybe_import_map,
) {
// completions for import map specifiers
Some(lsp::CompletionResponse::List(completion_list))
} else if let Some(completion_list) = get_local_completions(
&module.specifier,
resolution_mode,
text,
&range,
resolver,
) {
// completions for local relative modules
Some(lsp::CompletionResponse::List(completion_list))
} else if !text.is_empty() {
// completion of modules from a module registry or cache
check_auto_config_registry(
text,
config.workspace_settings_for_specifier(&module.specifier),
client,
module_registries,
)
.await;
let maybe_list = module_registries
.get_completions(text, &range, resolved.as_ref(), |s| {
document_modules.specifier_exists(s, module.scope.as_deref())
})
.await;
let maybe_list = maybe_list
.or_else(|| module_registries.get_origin_completions(text, &range));
let list = maybe_list.unwrap_or_else(|| CompletionList {
items: get_remote_completions(module, text, &range, document_modules),
is_incomplete: false,
});
Some(lsp::CompletionResponse::List(list))
} else {
// the import specifier is empty, so provide all possible specifiers we are
// aware of
let mut items: Vec<lsp::CompletionItem> = LOCAL_PATHS
.iter()
.map(|s| lsp::CompletionItem {
label: s.to_string(),
kind: Some(lsp::CompletionItemKind::FOLDER),
detail: Some("(local)".to_string()),
sort_text: Some("1".to_string()),
insert_text: Some(s.to_string()),
commit_characters: Some(
IMPORT_COMMIT_CHARS.iter().map(|&c| c.into()).collect(),
),
..Default::default()
})
.collect();
let mut is_incomplete = false;
if let Some(import_map) = maybe_import_map {
items.extend(get_base_import_map_completions(
import_map,
&module.specifier,
));
Some(completion_list) => {
Some(lsp::CompletionResponse::List(completion_list))
}
if let Some(origin_items) =
module_registries.get_origin_completions(text, &range)
{
is_incomplete = origin_items.is_incomplete;
items.extend(origin_items.items);
_ => {
match get_npm_completions(&module.specifier, text, &range, npm_search_api)
.await
{
Some(completion_list) => {
Some(lsp::CompletionResponse::List(completion_list))
}
_ => {
match get_node_completions(text, &range) {
Some(completion_list) => {
Some(lsp::CompletionResponse::List(completion_list))
}
_ => {
match get_import_map_completions(
&module.specifier,
text,
&range,
maybe_import_map,
) {
Some(completion_list) => {
// completions for import map specifiers
Some(lsp::CompletionResponse::List(completion_list))
}
_ => {
match get_local_completions(
&module.specifier,
resolution_mode,
text,
&range,
resolver,
) {
Some(completion_list) => {
// completions for local relative modules
Some(lsp::CompletionResponse::List(completion_list))
}
_ => {
if !text.is_empty() {
// completion of modules from a module registry or cache
check_auto_config_registry(
text,
config.workspace_settings_for_specifier(
&module.specifier,
),
client,
module_registries,
)
.await;
let maybe_list = module_registries
.get_completions(
text,
&range,
resolved.as_ref(),
|s| {
document_modules
.specifier_exists(s, module.scope.as_deref())
},
)
.await;
let maybe_list = maybe_list.or_else(|| {
module_registries.get_origin_completions(text, &range)
});
let list =
maybe_list.unwrap_or_else(|| CompletionList {
items: get_remote_completions(
module,
text,
&range,
document_modules,
),
is_incomplete: false,
});
Some(lsp::CompletionResponse::List(list))
} else {
// the import specifier is empty, so provide all possible specifiers we are
// aware of
let mut items: Vec<lsp::CompletionItem> = LOCAL_PATHS
.iter()
.map(|s| lsp::CompletionItem {
label: s.to_string(),
kind: Some(lsp::CompletionItemKind::FOLDER),
detail: Some("(local)".to_string()),
sort_text: Some("1".to_string()),
insert_text: Some(s.to_string()),
commit_characters: Some(
IMPORT_COMMIT_CHARS
.iter()
.map(|&c| c.into())
.collect(),
),
..Default::default()
})
.collect();
let mut is_incomplete = false;
if let Some(import_map) = maybe_import_map {
items.extend(get_base_import_map_completions(
import_map,
&module.specifier,
));
}
if let Some(origin_items) =
module_registries.get_origin_completions(text, &range)
{
is_incomplete = origin_items.is_incomplete;
items.extend(origin_items.items);
}
Some(lsp::CompletionResponse::List(CompletionList {
is_incomplete,
items,
}))
}
}
}
}
}
}
}
}
}
}
Some(lsp::CompletionResponse::List(CompletionList {
is_incomplete,
items,
}))
}
}
@ -909,8 +952,10 @@ mod tests {
for item in actual.items {
match item.text_edit {
Some(lsp::CompletionTextEdit::Edit(text_edit)) => {
assert!(["./b", "./f.mjs", "./g.json"]
.contains(&text_edit.new_text.as_str()));
assert!(
["./b", "./f.mjs", "./g.json"]
.contains(&text_edit.new_text.as_str())
);
}
_ => unreachable!(),
}

View file

@ -27,27 +27,27 @@ use deno_config::workspace::WorkspaceDirLintConfig;
use deno_config::workspace::WorkspaceDirectory;
use deno_config::workspace::WorkspaceDirectoryEmptyOptions;
use deno_config::workspace::WorkspaceDiscoverOptions;
use deno_core::ModuleSpecifier;
use deno_core::anyhow::anyhow;
use deno_core::error::AnyError;
use deno_core::parking_lot::Mutex;
use deno_core::serde::de::DeserializeOwned;
use deno_core::serde::Deserialize;
use deno_core::serde::Serialize;
use deno_core::serde::de::DeserializeOwned;
use deno_core::serde_json;
use deno_core::serde_json::json;
use deno_core::serde_json::Value;
use deno_core::serde_json::json;
use deno_core::url::Url;
use deno_core::ModuleSpecifier;
use deno_lib::args::has_flag_env_var;
use deno_lib::util::hash::FastInsecureHasher;
use deno_lint::linter::LintConfig as DenoLintConfig;
use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm_cache::NpmCacheSetting;
use deno_npm_installer::graph::NpmCachingStrategy;
use deno_npm_installer::lifecycle_scripts::NullLifecycleScriptsExecutor;
use deno_npm_installer::LifecycleScriptsConfig;
use deno_npm_installer::NpmInstallerFactory;
use deno_npm_installer::NpmInstallerFactoryOptions;
use deno_npm_installer::graph::NpmCachingStrategy;
use deno_npm_installer::lifecycle_scripts::NullLifecycleScriptsExecutor;
use deno_package_json::PackageJsonCache;
use deno_path_util::url_to_file_path;
use deno_resolver::factory::ConfigDiscoveryOption;
@ -703,7 +703,9 @@ impl WorkspaceSettings {
let inlay_hints: InlayHintsSettings =
parse_or_default(inlay_hints, "settings under \"deno.inlayHints\"");
if inlay_hints.parameter_names.enabled != Default::default() {
lsp_warn!("\"deno.inlayHints.parameterNames.enabled\" is deprecated. Instead use \"javascript.inlayHints.parameterNames.enabled\" and \"typescript.inlayHints.parameterNames.enabled\".");
lsp_warn!(
"\"deno.inlayHints.parameterNames.enabled\" is deprecated. Instead use \"javascript.inlayHints.parameterNames.enabled\" and \"typescript.inlayHints.parameterNames.enabled\"."
);
settings.javascript.inlay_hints.parameter_names.enabled =
inlay_hints.parameter_names.enabled.clone();
settings.typescript.inlay_hints.parameter_names.enabled =
@ -713,7 +715,9 @@ impl WorkspaceSettings {
.parameter_names
.suppress_when_argument_matches_name
{
lsp_warn!("\"deno.inlayHints.parameterNames.suppressWhenArgumentMatchesName\" is deprecated. Instead use \"javascript.inlayHints.parameterNames.suppressWhenArgumentMatchesName\" and \"typescript.inlayHints.parameterNames.suppressWhenArgumentMatchesName\".");
lsp_warn!(
"\"deno.inlayHints.parameterNames.suppressWhenArgumentMatchesName\" is deprecated. Instead use \"javascript.inlayHints.parameterNames.suppressWhenArgumentMatchesName\" and \"typescript.inlayHints.parameterNames.suppressWhenArgumentMatchesName\"."
);
settings
.javascript
.inlay_hints
@ -730,21 +734,27 @@ impl WorkspaceSettings {
.suppress_when_argument_matches_name;
}
if inlay_hints.parameter_types.enabled {
lsp_warn!("\"deno.inlayHints.parameterTypes.enabled\" is deprecated. Instead use \"javascript.inlayHints.parameterTypes.enabled\" and \"typescript.inlayHints.parameterTypes.enabled\".");
lsp_warn!(
"\"deno.inlayHints.parameterTypes.enabled\" is deprecated. Instead use \"javascript.inlayHints.parameterTypes.enabled\" and \"typescript.inlayHints.parameterTypes.enabled\"."
);
settings.javascript.inlay_hints.parameter_types.enabled =
inlay_hints.parameter_types.enabled;
settings.typescript.inlay_hints.parameter_types.enabled =
inlay_hints.parameter_types.enabled;
}
if inlay_hints.variable_types.enabled {
lsp_warn!("\"deno.inlayHints.variableTypes.enabled\" is deprecated. Instead use \"javascript.inlayHints.variableTypes.enabled\" and \"typescript.inlayHints.variableTypes.enabled\".");
lsp_warn!(
"\"deno.inlayHints.variableTypes.enabled\" is deprecated. Instead use \"javascript.inlayHints.variableTypes.enabled\" and \"typescript.inlayHints.variableTypes.enabled\"."
);
settings.javascript.inlay_hints.variable_types.enabled =
inlay_hints.variable_types.enabled;
settings.typescript.inlay_hints.variable_types.enabled =
inlay_hints.variable_types.enabled;
}
if !inlay_hints.variable_types.suppress_when_type_matches_name {
lsp_warn!("\"deno.inlayHints.variableTypes.suppressWhenTypeMatchesName\" is deprecated. Instead use \"javascript.inlayHints.variableTypes.suppressWhenTypeMatchesName\" and \"typescript.inlayHints.variableTypes.suppressWhenTypeMatchesName\".");
lsp_warn!(
"\"deno.inlayHints.variableTypes.suppressWhenTypeMatchesName\" is deprecated. Instead use \"javascript.inlayHints.variableTypes.suppressWhenTypeMatchesName\" and \"typescript.inlayHints.variableTypes.suppressWhenTypeMatchesName\"."
);
settings
.javascript
.inlay_hints
@ -759,7 +769,9 @@ impl WorkspaceSettings {
inlay_hints.variable_types.suppress_when_type_matches_name;
}
if inlay_hints.property_declaration_types.enabled {
lsp_warn!("\"deno.inlayHints.propertyDeclarationTypes.enabled\" is deprecated. Instead use \"javascript.inlayHints.propertyDeclarationTypes.enabled\" and \"typescript.inlayHints.propertyDeclarationTypes.enabled\".");
lsp_warn!(
"\"deno.inlayHints.propertyDeclarationTypes.enabled\" is deprecated. Instead use \"javascript.inlayHints.propertyDeclarationTypes.enabled\" and \"typescript.inlayHints.propertyDeclarationTypes.enabled\"."
);
settings
.javascript
.inlay_hints
@ -772,7 +784,9 @@ impl WorkspaceSettings {
.enabled = inlay_hints.property_declaration_types.enabled;
}
if inlay_hints.function_like_return_types.enabled {
lsp_warn!("\"deno.inlayHints.functionLikeReturnTypes.enabled\" is deprecated. Instead use \"javascript.inlayHints.functionLikeReturnTypes.enabled\" and \"typescript.inlayHints.functionLikeReturnTypes.enabled\".");
lsp_warn!(
"\"deno.inlayHints.functionLikeReturnTypes.enabled\" is deprecated. Instead use \"javascript.inlayHints.functionLikeReturnTypes.enabled\" and \"typescript.inlayHints.functionLikeReturnTypes.enabled\"."
);
settings
.javascript
.inlay_hints
@ -785,7 +799,9 @@ impl WorkspaceSettings {
.enabled = inlay_hints.function_like_return_types.enabled;
}
if inlay_hints.enum_member_values.enabled {
lsp_warn!("\"deno.inlayHints.enumMemberValues.enabled\" is deprecated. Instead use \"javascript.inlayHints.enumMemberValues.enabled\" and \"typescript.inlayHints.enumMemberValues.enabled\".");
lsp_warn!(
"\"deno.inlayHints.enumMemberValues.enabled\" is deprecated. Instead use \"javascript.inlayHints.enumMemberValues.enabled\" and \"typescript.inlayHints.enumMemberValues.enabled\"."
);
settings.javascript.inlay_hints.enum_member_values.enabled =
inlay_hints.enum_member_values.enabled;
settings.typescript.inlay_hints.enum_member_values.enabled =
@ -796,24 +812,32 @@ impl WorkspaceSettings {
let suggest: CompletionSettings =
parse_or_default(suggest, "settings under \"deno.suggest\"");
if suggest.complete_function_calls {
lsp_warn!("\"deno.suggest.completeFunctionCalls\" is deprecated. Instead use \"javascript.suggest.completeFunctionCalls\" and \"typescript.suggest.completeFunctionCalls\".");
lsp_warn!(
"\"deno.suggest.completeFunctionCalls\" is deprecated. Instead use \"javascript.suggest.completeFunctionCalls\" and \"typescript.suggest.completeFunctionCalls\"."
);
settings.javascript.suggest.complete_function_calls =
suggest.complete_function_calls;
settings.typescript.suggest.complete_function_calls =
suggest.complete_function_calls;
}
if !suggest.names {
lsp_warn!("\"deno.suggest.names\" is deprecated. Instead use \"javascript.suggest.names\" and \"typescript.suggest.names\".");
lsp_warn!(
"\"deno.suggest.names\" is deprecated. Instead use \"javascript.suggest.names\" and \"typescript.suggest.names\"."
);
settings.javascript.suggest.names = suggest.names;
settings.typescript.suggest.names = suggest.names;
}
if !suggest.paths {
lsp_warn!("\"deno.suggest.paths\" is deprecated. Instead use \"javascript.suggest.paths\" and \"typescript.suggest.paths\".");
lsp_warn!(
"\"deno.suggest.paths\" is deprecated. Instead use \"javascript.suggest.paths\" and \"typescript.suggest.paths\"."
);
settings.javascript.suggest.paths = suggest.paths;
settings.typescript.suggest.paths = suggest.paths;
}
if !suggest.auto_imports {
lsp_warn!("\"deno.suggest.autoImports\" is deprecated. Instead use \"javascript.suggest.autoImports\" and \"typescript.suggest.autoImports\".");
lsp_warn!(
"\"deno.suggest.autoImports\" is deprecated. Instead use \"javascript.suggest.autoImports\" and \"typescript.suggest.autoImports\"."
);
settings.javascript.suggest.auto_imports = suggest.auto_imports;
settings.typescript.suggest.auto_imports = suggest.auto_imports;
}
@ -1451,7 +1475,7 @@ impl ConfigData {
WorkspaceFactoryOptions {
additional_config_file_names: &[],
config_discovery: ConfigDiscoveryOption::DiscoverCwd,
deno_dir_path_provider: None,
maybe_custom_deno_dir_root: None,
is_package_manager_subcommand: false,
frozen_lockfile: None,
lock_arg: None,
@ -1472,9 +1496,12 @@ impl ConfigData {
ResolverFactoryOptions {
// these default options are fine because we don't use this for
// anything other than resolving the lockfile at the moment
compiler_options_overrides: Default::default(),
is_cjs_resolution_mode: Default::default(),
npm_system_info: Default::default(),
node_code_translator_mode: Default::default(),
node_resolver_options: NodeResolverOptions::default(),
node_analysis_cache: None,
node_resolution_cache: None,
package_json_cache: None,
package_json_dep_resolution: None,

View file

@ -5,13 +5,14 @@ use std::collections::HashMap;
use std::collections::HashSet;
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::atomic::AtomicUsize;
use std::sync::Arc;
use std::sync::atomic::AtomicUsize;
use std::thread;
use deno_ast::MediaType;
use deno_config::glob::FilePatterns;
use deno_config::workspace::WorkspaceDirLintConfig;
use deno_core::ModuleSpecifier;
use deno_core::anyhow::anyhow;
use deno_core::error::AnyError;
use deno_core::parking_lot::Mutex;
@ -20,17 +21,16 @@ use deno_core::resolve_url;
use deno_core::serde::Deserialize;
use deno_core::serde_json;
use deno_core::serde_json::json;
use deno_core::unsync::JoinHandle;
use deno_core::unsync::spawn;
use deno_core::unsync::spawn_blocking;
use deno_core::unsync::JoinHandle;
use deno_core::url::Url;
use deno_core::ModuleSpecifier;
use deno_graph::source::ResolutionKind;
use deno_graph::source::ResolveError;
use deno_graph::Resolution;
use deno_graph::ResolutionError;
use deno_graph::SpecifierError;
use deno_graph::source::ResolveError;
use deno_lint::linter::LintConfig as DenoLintConfig;
use deno_resolver::graph::enhanced_resolution_error_message;
use deno_resolver::workspace::sloppy_imports_resolve;
use deno_runtime::deno_node;
use deno_runtime::tokio_util::create_basic_runtime;
@ -42,8 +42,8 @@ use import_map::ImportMapErrorKind;
use log::error;
use lsp_types::Uri;
use node_resolver::NodeResolutionKind;
use tokio::sync::mpsc;
use tokio::sync::Mutex as AsyncMutex;
use tokio::sync::mpsc;
use tokio::time::Duration;
use tokio_util::sync::CancellationToken;
use tower_lsp::lsp_types as lsp;
@ -61,8 +61,6 @@ use super::performance::Performance;
use super::tsc;
use super::tsc::MaybeAmbientModules;
use super::tsc::TsServer;
use crate::graph_util;
use crate::graph_util::enhanced_resolution_error_message;
use crate::lsp::logging::lsp_warn;
use crate::lsp::lsp_custom::DiagnosticBatchNotificationParams;
use crate::sys::CliSys;
@ -460,13 +458,13 @@ impl DeferredDiagnostics {
}
let mut regex_string = ambient_modules_to_regex_string(&value);
regex_string.push('$');
if let Ok(regex) = regex::Regex::new(&regex_string).inspect_err(|e| {
match regex::Regex::new(&regex_string).inspect_err(|e| {
lsp_warn!("failed to compile ambient modules pattern: {e} (pattern is {regex_string:?})");
}) {
}) { Ok(regex) => {
ambient.regex = Some(regex);
} else {
} _ => {
ambient.regex = None;
}
}}
}
}
}
@ -1030,15 +1028,12 @@ fn generate_document_lint_diagnostics(
.and_then(|d| d.parsed_source.as_ref())
{
Some(Ok(parsed_source)) => {
if let Ok(references) =
analysis::get_lint_references(parsed_source, linter, token)
{
references
match analysis::get_lint_references(parsed_source, linter, token) {
Ok(references) => references
.into_iter()
.map(|r| r.to_diagnostic())
.collect::<Vec<_>>()
} else {
Vec::new()
.collect::<Vec<_>>(),
_ => Vec::new(),
}
}
Some(Err(_)) => Vec::new(),
@ -1201,7 +1196,9 @@ impl DenoDiagnostic {
Self::NoExportNpm(_) => "no-export-npm",
Self::NoLocal(_) => "no-local",
Self::ResolutionError(err) => {
if graph_util::get_resolution_error_bare_node_specifier(err).is_some() {
if deno_resolver::graph::get_resolution_error_bare_node_specifier(err)
.is_some()
{
"import-node-prefix-missing"
} else {
match err {
@ -1384,7 +1381,7 @@ impl DenoDiagnostic {
return Err(anyhow!(
"Unsupported diagnostic code (\"{}\") provided.",
code
))
));
}
};
Ok(code_action)
@ -1469,7 +1466,7 @@ impl DenoDiagnostic {
(
lsp::DiagnosticSeverity::ERROR,
message,
graph_util::get_resolution_error_bare_node_specifier(err)
deno_resolver::graph::get_resolution_error_bare_node_specifier(err)
.map(|specifier| json!({ "specifier": specifier }))
)},
Self::UnknownNodeSpecifier(specifier) => (lsp::DiagnosticSeverity::ERROR, format!("No such built-in module: node:{}", specifier.path()), None),
@ -1568,7 +1565,6 @@ fn diagnose_resolution(
snapshot: &language_server::StateSnapshot,
dependency_key: &str,
resolution: &Resolution,
resolution_kind: ResolutionKind,
is_dynamic: bool,
maybe_assert_type: Option<&str>,
referrer_module: &DocumentModule,
@ -1589,100 +1585,127 @@ fn diagnose_resolution(
diagnostics.push(DenoDiagnostic::DenoWarn(message.clone()));
}
}
if let Some(module) = snapshot
match snapshot
.document_modules
.module_for_specifier(specifier, referrer_module.scope.as_deref())
{
if let Some(headers) = &module.headers {
if let Some(message) = headers.get("x-deno-warning") {
diagnostics.push(DenoDiagnostic::DenoWarn(message.clone()));
Some(module) => {
if let Some(headers) = &module.headers {
if let Some(message) = headers.get("x-deno-warning") {
diagnostics.push(DenoDiagnostic::DenoWarn(message.clone()));
}
}
if module.media_type == MediaType::Json {
match maybe_assert_type {
// The module has the correct assertion type, no diagnostic
Some("json") => (),
// The dynamic import statement is missing an attribute type, which
// we might not be able to statically detect, therefore we will
// not provide a potentially incorrect diagnostic.
None if is_dynamic => (),
// The module has an incorrect assertion type, diagnostic
Some(assert_type) => diagnostics.push(
DenoDiagnostic::InvalidAttributeType(assert_type.to_string()),
),
// The module is missing an attribute type, diagnostic
None => diagnostics.push(DenoDiagnostic::NoAttributeType),
}
}
}
if module.media_type == MediaType::Json {
match maybe_assert_type {
// The module has the correct assertion type, no diagnostic
Some("json") => (),
// The dynamic import statement is missing an attribute type, which
// we might not be able to statically detect, therefore we will
// not provide a potentially incorrect diagnostic.
None if is_dynamic => (),
// The module has an incorrect assertion type, diagnostic
Some(assert_type) => diagnostics.push(
DenoDiagnostic::InvalidAttributeType(assert_type.to_string()),
),
// The module is missing an attribute type, diagnostic
None => diagnostics.push(DenoDiagnostic::NoAttributeType),
}
}
} else if let Ok(pkg_ref) =
JsrPackageReqReference::from_specifier(specifier)
{
let req = pkg_ref.into_inner().req;
diagnostics
.push(DenoDiagnostic::NotInstalledJsr(req, specifier.clone()));
} else if let Ok(pkg_ref) =
NpmPackageReqReference::from_specifier(specifier)
{
if let Some(npm_resolver) = managed_npm_resolver {
// show diagnostics for npm package references that aren't cached
let req = pkg_ref.req();
if !npm_resolver.is_pkg_req_folder_cached(req) {
diagnostics.push(DenoDiagnostic::NotInstalledNpm(
req.clone(),
specifier.clone(),
));
} else if scoped_resolver
.npm_to_file_url(
&pkg_ref,
&referrer_module.specifier,
NodeResolutionKind::from_deno_graph(resolution_kind),
referrer_module.resolution_mode,
)
.is_none()
{
diagnostics.push(DenoDiagnostic::NoExportNpm(pkg_ref.clone()));
}
}
} else if let Some(module_name) = specifier.as_str().strip_prefix("node:")
{
if !deno_node::is_builtin_node_module(module_name) {
diagnostics
.push(DenoDiagnostic::UnknownNodeSpecifier(specifier.clone()));
} else if module_name == dependency_key {
let mut is_mapped = false;
if let Some(import_map) = import_map {
if let Resolution::Ok(resolved) = &resolution {
if import_map.resolve(module_name, &resolved.specifier).is_ok() {
is_mapped = true;
_ => {
match JsrPackageReqReference::from_specifier(specifier) {
Ok(pkg_ref) => {
let req = pkg_ref.into_inner().req;
diagnostics
.push(DenoDiagnostic::NotInstalledJsr(req, specifier.clone()));
}
_ => {
match NpmPackageReqReference::from_specifier(specifier) {
Ok(pkg_ref) => {
if let Some(npm_resolver) = managed_npm_resolver {
// show diagnostics for npm package references that aren't cached
let req = pkg_ref.req();
if !npm_resolver.is_pkg_req_folder_cached(req) {
diagnostics.push(DenoDiagnostic::NotInstalledNpm(
req.clone(),
specifier.clone(),
));
} else {
let resolution_kinds = [
NodeResolutionKind::Types,
NodeResolutionKind::Execution,
];
if resolution_kinds.into_iter().all(|k| {
scoped_resolver
.npm_to_file_url(
&pkg_ref,
&referrer_module.specifier,
k,
referrer_module.resolution_mode,
)
.is_none()
}) {
diagnostics
.push(DenoDiagnostic::NoExportNpm(pkg_ref.clone()));
}
}
}
}
_ => {
if let Some(module_name) =
specifier.as_str().strip_prefix("node:")
{
if !deno_node::is_builtin_node_module(module_name) {
diagnostics.push(DenoDiagnostic::UnknownNodeSpecifier(
specifier.clone(),
));
} else if module_name == dependency_key {
let mut is_mapped = false;
if let Some(import_map) = import_map {
if let Resolution::Ok(resolved) = &resolution {
if import_map
.resolve(module_name, &resolved.specifier)
.is_ok()
{
is_mapped = true;
}
}
}
// show diagnostics for bare node specifiers that aren't mapped by import map
if !is_mapped {
diagnostics.push(DenoDiagnostic::BareNodeSpecifier(
module_name.to_string(),
));
}
} else if let Some(npm_resolver) = managed_npm_resolver {
// check that a @types/node package exists in the resolver
let types_node_req =
PackageReq::from_str("@types/node").unwrap();
if !npm_resolver.is_pkg_req_folder_cached(&types_node_req)
{
diagnostics.push(DenoDiagnostic::NotInstalledNpm(
types_node_req,
ModuleSpecifier::parse("npm:@types/node").unwrap(),
));
}
}
} else {
// When the document is not available, it means that it cannot be found
// in the cache or locally on the disk, so we want to issue a diagnostic
// about that.
// these may be invalid, however, if this is an ambient module with
// no real source (as in the case of a virtual module).
let deno_diagnostic = match specifier.scheme() {
"file" => DenoDiagnostic::NoLocal(specifier.clone()),
_ => DenoDiagnostic::NoCache(specifier.clone()),
};
deferred_diagnostics.push(deno_diagnostic);
}
}
}
}
}
// show diagnostics for bare node specifiers that aren't mapped by import map
if !is_mapped {
diagnostics
.push(DenoDiagnostic::BareNodeSpecifier(module_name.to_string()));
}
} else if let Some(npm_resolver) = managed_npm_resolver {
// check that a @types/node package exists in the resolver
let types_node_req = PackageReq::from_str("@types/node").unwrap();
if !npm_resolver.is_pkg_req_folder_cached(&types_node_req) {
diagnostics.push(DenoDiagnostic::NotInstalledNpm(
types_node_req,
ModuleSpecifier::parse("npm:@types/node").unwrap(),
));
}
}
} else {
// When the document is not available, it means that it cannot be found
// in the cache or locally on the disk, so we want to issue a diagnostic
// about that.
// these may be invalid, however, if this is an ambient module with
// no real source (as in the case of a virtual module).
let deno_diagnostic = match specifier.scheme() {
"file" => DenoDiagnostic::NoLocal(specifier.clone()),
_ => DenoDiagnostic::NoCache(specifier.clone()),
};
deferred_diagnostics.push(deno_diagnostic);
}
}
// The specifier resolution resulted in an error, so we want to issue a
@ -1763,9 +1786,7 @@ fn diagnose_dependency(
.includes(i.specifier_range.range.start)
.is_some()
});
let resolution;
let resolution_kind;
if dependency.maybe_code.is_none()
let resolution = if dependency.maybe_code.is_none()
// If not @ts-types, diagnose the types if the code errored because
// it's likely resolving into the node_modules folder, which might be
// erroring correctly due to resolution only being for bundlers. Let this
@ -1773,17 +1794,14 @@ fn diagnose_dependency(
|| !is_types_deno_types && matches!(dependency.maybe_type, Resolution::Ok(_))
&& matches!(dependency.maybe_code, Resolution::Err(_))
{
resolution = &dependency.maybe_type;
resolution_kind = ResolutionKind::Types;
&dependency.maybe_type
} else {
resolution = &dependency.maybe_code;
resolution_kind = ResolutionKind::Execution;
&dependency.maybe_code
};
let (resolution_diagnostics, deferred) = diagnose_resolution(
snapshot,
dependency_key,
resolution,
resolution_kind,
dependency.is_dynamic,
dependency.maybe_attribute_type.as_deref(),
referrer_module,
@ -1819,7 +1837,6 @@ fn diagnose_dependency(
snapshot,
dependency_key,
&dependency.maybe_type,
ResolutionKind::Types,
dependency.is_dynamic,
dependency.maybe_attribute_type.as_deref(),
referrer_module,

View file

@ -16,19 +16,19 @@ use std::sync::Weak;
use std::time::SystemTime;
use dashmap::DashMap;
use deno_ast::swc::ecma_visit::VisitWith;
use deno_ast::MediaType;
use deno_ast::ParsedSource;
use deno_ast::SourceTextInfo;
use deno_ast::swc::ecma_visit::VisitWith;
use deno_core::ModuleSpecifier;
use deno_core::error::AnyError;
use deno_core::futures::FutureExt;
use deno_core::futures::future;
use deno_core::futures::future::Shared;
use deno_core::futures::FutureExt;
use deno_core::parking_lot::RwLock;
use deno_core::resolve_url;
use deno_core::url::Position;
use deno_core::url::Url;
use deno_core::ModuleSpecifier;
use deno_error::JsErrorBox;
use deno_graph::TypesDependency;
use deno_path_util::url_to_file_path;
@ -38,17 +38,17 @@ use deno_semver::npm::NpmPackageReqReference;
use indexmap::IndexMap;
use indexmap::IndexSet;
use lsp_types::Uri;
use node_resolver::cache::NodeResolutionThreadLocalCache;
use node_resolver::NodeResolutionKind;
use node_resolver::ResolutionMode;
use node_resolver::cache::NodeResolutionThreadLocalCache;
use once_cell::sync::Lazy;
use serde::Serialize;
use tower_lsp::lsp_types as lsp;
use weak_table::PtrWeakKeyHashMap;
use weak_table::WeakValueHashMap;
use super::cache::calculate_fs_version_at_path;
use super::cache::LspCache;
use super::cache::calculate_fs_version_at_path;
use super::config::Config;
use super::logging::lsp_warn;
use super::resolver::LspResolver;
@ -59,12 +59,12 @@ use super::testing::TestModule;
use super::text::LineIndex;
use super::tsc::ChangeKind;
use super::tsc::NavigationTree;
use super::urls::COMPONENT;
use super::urls::normalize_uri;
use super::urls::uri_is_file_like;
use super::urls::uri_to_file_path;
use super::urls::uri_to_url;
use super::urls::url_to_uri;
use super::urls::COMPONENT;
use crate::graph_util::CliJsrUrlProvider;
#[derive(Debug)]
@ -197,7 +197,7 @@ fn data_url_to_uri(url: &Url) -> Option<Uri> {
file_name_str.push('?');
file_name_str.push_str(query);
}
let hash = deno_lib::util::checksum::gen(&[file_name_str.as_bytes()]);
let hash = deno_lib::util::checksum::r#gen(&[file_name_str.as_bytes()]);
Uri::from_str(&format!("deno:/data_url/{hash}{extension}",))
.inspect_err(|err| {
lsp_warn!("Couldn't convert data url \"{url}\" to URI: {err}")
@ -410,7 +410,7 @@ pub static ASSET_DOCUMENTS: Lazy<AssetDocuments> =
inner: crate::tsc::LAZILY_LOADED_STATIC_ASSETS
.iter()
.map(|(k, v)| {
let doc = Arc::new(ServerDocument::asset(k, v.as_str()));
let doc = Arc::new(ServerDocument::asset(k, v.source.as_str()));
let uri = doc.uri.clone();
(uri, doc)
})
@ -702,12 +702,16 @@ impl Documents {
if let Some(doc) = self.server.get(&uri) {
return Some(Document::Server(doc.clone()));
}
let doc = if let Some(doc) = ServerDocument::load(&uri) {
doc
} else if let Some(data_url) = self.data_urls_by_uri.get(&uri) {
ServerDocument::data_url(&uri, data_url.value().clone())?
} else {
return None;
let doc = match ServerDocument::load(&uri) {
Some(doc) => doc,
_ => match self.data_urls_by_uri.get(&uri) {
Some(data_url) => {
ServerDocument::data_url(&uri, data_url.value().clone())?
}
_ => {
return None;
}
},
};
let doc = Arc::new(doc);
self.server.insert(uri.into_owned(), doc.clone());
@ -1221,12 +1225,11 @@ impl DocumentModules {
scope: Option<&Url>,
) -> Option<Arc<DocumentModule>> {
let scoped_resolver = self.resolver.get_scoped_resolver(scope);
let specifier = if let Ok(jsr_req_ref) =
JsrPackageReqReference::from_specifier(specifier)
{
Cow::Owned(scoped_resolver.jsr_to_resource_url(&jsr_req_ref)?)
} else {
Cow::Borrowed(specifier)
let specifier = match JsrPackageReqReference::from_specifier(specifier) {
Ok(jsr_req_ref) => {
Cow::Owned(scoped_resolver.jsr_to_resource_url(&jsr_req_ref)?)
}
_ => Cow::Borrowed(specifier),
};
let specifier = scoped_resolver.resolve_redirects(&specifier)?;
let document =
@ -1322,12 +1325,11 @@ impl DocumentModules {
scope: Option<&Url>,
) -> Option<Arc<DocumentModule>> {
let scoped_resolver = self.resolver.get_scoped_resolver(scope);
let specifier = if let Ok(jsr_req_ref) =
JsrPackageReqReference::from_specifier(specifier)
{
Cow::Owned(scoped_resolver.jsr_to_resource_url(&jsr_req_ref)?)
} else {
Cow::Borrowed(specifier)
let specifier = match JsrPackageReqReference::from_specifier(specifier) {
Ok(jsr_req_ref) => {
Cow::Owned(scoped_resolver.jsr_to_resource_url(&jsr_req_ref)?)
}
_ => Cow::Borrowed(specifier),
};
let specifier = scoped_resolver.resolve_redirects(&specifier)?;
let modules = self.modules_for_scope(scope)?;
@ -1601,21 +1603,26 @@ impl DocumentModules {
} else {
results.push(None);
}
} else if let Ok(specifier) = scoped_resolver.as_cli_resolver().resolve(
raw_specifier,
referrer,
deno_graph::Position::zeroed(),
resolution_mode,
NodeResolutionKind::Types,
) {
results.push(self.resolve_dependency(
&specifier,
referrer,
resolution_mode,
scope,
));
} else {
results.push(None);
match scoped_resolver.as_cli_resolver().resolve(
raw_specifier,
referrer,
deno_graph::Position::zeroed(),
resolution_mode,
NodeResolutionKind::Types,
) {
Ok(specifier) => {
results.push(self.resolve_dependency(
&specifier,
referrer,
resolution_mode,
scope,
));
}
_ => {
results.push(None);
}
}
}
}
results
@ -1998,11 +2005,12 @@ fn analyze_module(
}
Err(diagnostic) => (
Err(deno_graph::ModuleGraphError::ModuleError(
deno_graph::ModuleError::Parse {
deno_graph::ModuleErrorKind::Parse {
specifier,
mtime: None,
diagnostic: Arc::new(JsErrorBox::from_err(diagnostic.clone())),
},
}
.into_box(),
)),
ResolutionMode::Import,
),

View file

@ -9,15 +9,15 @@ use deno_core::anyhow::anyhow;
use deno_core::error::AnyError;
use deno_core::serde_json;
use deno_core::url::Url;
use deno_graph::ModuleSpecifier;
use deno_graph::packages::JsrPackageInfo;
use deno_graph::packages::JsrPackageInfoVersion;
use deno_graph::packages::JsrPackageVersionInfo;
use deno_graph::ModuleSpecifier;
use deno_semver::StackString;
use deno_semver::Version;
use deno_semver::jsr::JsrPackageReqReference;
use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq;
use deno_semver::StackString;
use deno_semver::Version;
use serde::Deserialize;
use super::config::ConfigData;
@ -26,8 +26,8 @@ use crate::args::jsr_api_url;
use crate::args::jsr_url;
use crate::file_fetcher::CliFileFetcher;
use crate::file_fetcher::TextDecodedFile;
use crate::jsr::partial_jsr_package_version_info_from_slice;
use crate::jsr::JsrFetchResolver;
use crate::jsr::partial_jsr_package_version_info_from_slice;
#[derive(Debug)]
struct WorkspacePackage {

View file

@ -1,5 +1,6 @@
// Copyright 2018-2025 the Deno authors. MIT license.
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::collections::HashMap;
@ -13,27 +14,27 @@ use std::str::FromStr;
use std::sync::Arc;
use deno_ast::MediaType;
use deno_cache_dir::file_fetcher::CacheSetting;
use deno_cache_dir::GlobalOrLocalHttpCache;
use deno_cache_dir::file_fetcher::CacheSetting;
use deno_core::ModuleSpecifier;
use deno_core::anyhow::anyhow;
use deno_core::error::AnyError;
use deno_core::serde_json;
use deno_core::serde_json::json;
use deno_core::serde_json::Value;
use deno_core::serde_json::json;
use deno_core::unsync::spawn;
use deno_core::url;
use deno_core::url::Url;
use deno_core::ModuleSpecifier;
use deno_graph::CheckJsOption;
use deno_graph::GraphKind;
use deno_graph::Resolution;
use deno_lib::args::get_root_cert_store;
use deno_lib::args::CaData;
use deno_lib::args::get_root_cert_store;
use deno_lib::version::DENO_VERSION_INFO;
use deno_npm_installer::graph::NpmCachingStrategy;
use deno_path_util::url_to_file_path;
use deno_runtime::deno_tls::rustls::RootCertStore;
use deno_runtime::deno_tls::RootCertStoreProvider;
use deno_runtime::deno_tls::rustls::RootCertStore;
use deno_semver::jsr::JsrPackageReqReference;
use indexmap::Equivalent;
use indexmap::IndexMap;
@ -43,20 +44,20 @@ use node_resolver::NodeResolutionKind;
use node_resolver::ResolutionMode;
use serde::Deserialize;
use serde_json::from_value;
use tokio::sync::mpsc::unbounded_channel;
use tokio::sync::mpsc::UnboundedReceiver;
use tokio::sync::mpsc::UnboundedSender;
use tokio::sync::mpsc::unbounded_channel;
use tokio_util::sync::CancellationToken;
use tower_lsp::jsonrpc::Error as LspError;
use tower_lsp::jsonrpc::Result as LspResult;
use tower_lsp::lsp_types::request::*;
use tower_lsp::lsp_types::*;
use super::analysis::fix_ts_import_changes;
use super::analysis::ts_changes_to_edit;
use super::analysis::CodeActionCollection;
use super::analysis::CodeActionData;
use super::analysis::TsResponseImportMapper;
use super::analysis::fix_ts_import_changes;
use super::analysis::ts_changes_to_edit;
use super::cache::LspCache;
use super::capabilities;
use super::capabilities::semantic_tokens_registration_options;
@ -64,9 +65,9 @@ use super::client::Client;
use super::code_lens;
use super::completions;
use super::config::Config;
use super::config::SETTINGS_SECTION;
use super::config::UpdateImportsOnFileMoveEnabled;
use super::config::WorkspaceSettings;
use super::config::SETTINGS_SECTION;
use super::diagnostics;
use super::diagnostics::DiagnosticDataSpecifier;
use super::diagnostics::DiagnosticServerUpdateMessage;
@ -99,8 +100,8 @@ use crate::args::Flags;
use crate::args::InternalFlags;
use crate::args::UnstableFmtOptions;
use crate::factory::CliFactory;
use crate::file_fetcher::create_cli_file_fetcher;
use crate::file_fetcher::CreateCliFileFetcherOptions;
use crate::file_fetcher::create_cli_file_fetcher;
use crate::graph_util;
use crate::http_util::HttpClientProvider;
use crate::lsp::config::ConfigWatchedFileType;
@ -1797,7 +1798,10 @@ impl Inner {
});
format_file(
&file_path,
&document.text(),
&crate::tools::fmt::FileContents {
text: Cow::Borrowed(document.text().as_ref()),
had_bom: false,
},
&fmt_options,
&unstable_options,
ext,
@ -1866,35 +1870,48 @@ impl Inner {
.map(|d| &d.dependency)
.unwrap_or(&Resolution::None)
});
let value = match (dep.maybe_code.is_none(), dep.maybe_type.is_none(), &dep_types_dependency) {
let value = match (
dep.maybe_code.is_none(),
dep.maybe_type.is_none(),
&dep_types_dependency,
) {
(false, false, None) => format!(
"**Resolved Dependency**\n\n**Code**: {}\n\n**Types**: {}\n",
self.resolution_to_hover_text(&dep.maybe_code, module.scope.as_deref()),
self.resolution_to_hover_text(&dep.maybe_type, module.scope.as_deref()),
self
.resolution_to_hover_text(&dep.maybe_code, module.scope.as_deref()),
self
.resolution_to_hover_text(&dep.maybe_type, module.scope.as_deref()),
),
(false, false, Some(types_dep)) if !types_dep.is_none() => format!(
"**Resolved Dependency**\n\n**Code**: {}\n**Types**: {}\n**Import Types**: {}\n",
self.resolution_to_hover_text(&dep.maybe_code, module.scope.as_deref()),
self.resolution_to_hover_text(&dep.maybe_type, module.scope.as_deref()),
self
.resolution_to_hover_text(&dep.maybe_code, module.scope.as_deref()),
self
.resolution_to_hover_text(&dep.maybe_type, module.scope.as_deref()),
self.resolution_to_hover_text(types_dep, module.scope.as_deref()),
),
(false, false, Some(_)) => format!(
"**Resolved Dependency**\n\n**Code**: {}\n\n**Types**: {}\n",
self.resolution_to_hover_text(&dep.maybe_code, module.scope.as_deref()),
self.resolution_to_hover_text(&dep.maybe_type, module.scope.as_deref()),
self
.resolution_to_hover_text(&dep.maybe_code, module.scope.as_deref()),
self
.resolution_to_hover_text(&dep.maybe_type, module.scope.as_deref()),
),
(false, true, Some(types_dep)) if !types_dep.is_none() => format!(
"**Resolved Dependency**\n\n**Code**: {}\n\n**Types**: {}\n",
self.resolution_to_hover_text(&dep.maybe_code, module.scope.as_deref()),
self
.resolution_to_hover_text(&dep.maybe_code, module.scope.as_deref()),
self.resolution_to_hover_text(types_dep, module.scope.as_deref()),
),
(false, true, _) => format!(
"**Resolved Dependency**\n\n**Code**: {}\n",
self.resolution_to_hover_text(&dep.maybe_code, module.scope.as_deref()),
self
.resolution_to_hover_text(&dep.maybe_code, module.scope.as_deref()),
),
(true, false, _) => format!(
"**Resolved Dependency**\n\n**Types**: {}\n",
self.resolution_to_hover_text(&dep.maybe_type, module.scope.as_deref()),
self
.resolution_to_hover_text(&dep.maybe_type, module.scope.as_deref()),
),
(true, true, _) => unreachable!("{}", json!(params)),
};
@ -2359,7 +2376,11 @@ impl Inner {
if token.is_cancelled() {
return Err(LspError::request_cancelled());
} else {
lsp_warn!("Unable to get refactor edit info from TypeScript: {:#}\nCode action data: {:#}", err, json!(&action_data));
lsp_warn!(
"Unable to get refactor edit info from TypeScript: {:#}\nCode action data: {:#}",
err,
json!(&action_data)
);
}
}
}
@ -4780,19 +4801,22 @@ impl Inner {
}
Some(contents)
} else if let Some(document) = self.get_document(
&params.text_document.uri,
Enabled::Ignore,
Exists::Filter,
Diagnosable::Ignore,
)? {
Some(document.text().to_string())
} else {
lsp_warn!(
"The document was not found: {}",
params.text_document.uri.as_str()
);
None
match self.get_document(
&params.text_document.uri,
Enabled::Ignore,
Exists::Filter,
Diagnosable::Ignore,
)? {
Some(document) => Some(document.text().to_string()),
_ => {
lsp_warn!(
"The document was not found: {}",
params.text_document.uri.as_str()
);
None
}
}
};
self.performance.measure(mark);
Ok(contents)

View file

@ -72,9 +72,11 @@ pub fn init_log_file(enabled: bool) {
LOG_FILE.buffer.lock().clear();
return;
};
thread::spawn(move || loop {
LOG_FILE.commit(&path);
thread::sleep(std::time::Duration::from_secs(1));
thread::spawn(move || {
loop {
LOG_FILE.commit(&path);
thread::sleep(std::time::Duration::from_secs(1));
}
});
}

View file

@ -8,8 +8,8 @@ use deno_core::error::AnyError;
use deno_core::serde_json;
use deno_core::url::Url;
use deno_npm::npm_rc::NpmRc;
use deno_semver::package::PackageNv;
use deno_semver::Version;
use deno_semver::package::PackageNv;
use once_cell::sync::Lazy;
use serde::Deserialize;

View file

@ -7,11 +7,13 @@ use std::time::Duration;
/// it will terminate the current process.
pub fn start(parent_process_id: u32) {
// use a separate thread in case the runtime gets hung up
std::thread::spawn(move || loop {
std::thread::sleep(Duration::from_secs(10));
std::thread::spawn(move || {
loop {
std::thread::sleep(Duration::from_secs(10));
if !is_process_active(parent_process_id) {
deno_runtime::exit(1);
if !is_process_active(parent_process_id) {
deno_runtime::exit(1);
}
}
});
}

View file

@ -875,13 +875,27 @@ mod tests {
);
let actual = result.unwrap();
if let Some((text, start, end)) = *expected {
assert!(actual.is_some(), "Match failure for path \"{path}\" and fixture \"{fixture}\". Expected Some got None");
assert!(
actual.is_some(),
"Match failure for path \"{path}\" and fixture \"{fixture}\". Expected Some got None"
);
let actual = actual.unwrap();
assert_eq!(actual.as_str(), text, "Match failure for path \"{}\" and fixture \"{}\". Expected \"{}\" got \"{}\".", path, fixture, text, actual.as_str());
assert_eq!(
actual.as_str(),
text,
"Match failure for path \"{}\" and fixture \"{}\". Expected \"{}\" got \"{}\".",
path,
fixture,
text,
actual.as_str()
);
assert_eq!(actual.start(), start);
assert_eq!(actual.end(), end);
} else {
assert!(actual.is_none(), "Match failure for path \"{path}\" and fixture \"{fixture}\". Expected None got {actual:?}");
assert!(
actual.is_none(),
"Match failure for path \"{path}\" and fixture \"{fixture}\". Expected None got {actual:?}"
);
}
}
}

View file

@ -6,16 +6,16 @@ use std::path::PathBuf;
use std::sync::Arc;
use deno_cache_dir::file_fetcher::CacheSetting;
use deno_core::ModuleSpecifier;
use deno_core::anyhow::anyhow;
use deno_core::error::AnyError;
use deno_core::serde::Deserialize;
use deno_core::serde_json;
use deno_core::serde_json::json;
use deno_core::serde_json::Value;
use deno_core::serde_json::json;
use deno_core::url::ParseError;
use deno_core::url::Position;
use deno_core::url::Url;
use deno_core::ModuleSpecifier;
use deno_graph::Dependency;
use deno_resolver::file_fetcher::FetchOptions;
use deno_resolver::file_fetcher::FetchPermissionsOptionRef;
@ -25,8 +25,6 @@ use tower_lsp::lsp_types as lsp;
use super::completions::IMPORT_COMMIT_CHARS;
use super::logging::lsp_log;
use super::path_to_regex::parse;
use super::path_to_regex::string_to_regex;
use super::path_to_regex::Compiler;
use super::path_to_regex::Key;
use super::path_to_regex::MatchResult;
@ -34,12 +32,14 @@ use super::path_to_regex::Matcher;
use super::path_to_regex::StringOrNumber;
use super::path_to_regex::StringOrVec;
use super::path_to_regex::Token;
use super::path_to_regex::parse;
use super::path_to_regex::string_to_regex;
use crate::cache::GlobalHttpCache;
use crate::cache::HttpCache;
use crate::file_fetcher::create_cli_file_fetcher;
use crate::file_fetcher::CliFileFetcher;
use crate::file_fetcher::CreateCliFileFetcherOptions;
use crate::file_fetcher::TextDecodedFile;
use crate::file_fetcher::create_cli_file_fetcher;
use crate::http_util::HttpClientProvider;
use crate::sys::CliSys;
@ -322,7 +322,11 @@ fn validate_config(config: &RegistryConfigurationJson) -> Result<(), AnyError> {
.map(|var| var.key.to_owned())
.any(|x| x == *key_name)
{
return Err(anyhow!("Invalid registry configuration. Registry with schema \"{}\" is missing variable declaration for key \"{}\".", registry.schema, key_name));
return Err(anyhow!(
"Invalid registry configuration. Registry with schema \"{}\" is missing variable declaration for key \"{}\".",
registry.schema,
key_name
));
}
}
@ -334,13 +338,27 @@ fn validate_config(config: &RegistryConfigurationJson) -> Result<(), AnyError> {
let limited_keys = key_names.get(0..key_index).unwrap();
for v in replacement_variables {
if variable.key == v && config.version == 1 {
return Err(anyhow!("Invalid registry configuration. Url \"{}\" (for variable \"{}\" in registry with schema \"{}\") uses variable \"{}\", which is not allowed because that would be a self reference.", variable.url, variable.key, registry.schema, v));
return Err(anyhow!(
"Invalid registry configuration. Url \"{}\" (for variable \"{}\" in registry with schema \"{}\") uses variable \"{}\", which is not allowed because that would be a self reference.",
variable.url,
variable.key,
registry.schema,
v
));
}
let key_index = limited_keys.iter().position(|key| key == &v);
if key_index.is_none() && variable.key != v {
return Err(anyhow!("Invalid registry configuration. Url \"{}\" (for variable \"{}\" in registry with schema \"{}\") uses variable \"{}\", which is not allowed because the schema defines \"{}\" to the right of \"{}\".", variable.url, variable.key, registry.schema, v, v, variable.key));
return Err(anyhow!(
"Invalid registry configuration. Url \"{}\" (for variable \"{}\" in registry with schema \"{}\") uses variable \"{}\", which is not allowed because the schema defines \"{}\" to the right of \"{}\".",
variable.url,
variable.key,
registry.schema,
v,
v,
variable.key
));
}
}
}
@ -1113,11 +1131,13 @@ mod tests {
#[test]
fn test_validate_registry_configuration() {
assert!(validate_config(&RegistryConfigurationJson {
version: 3,
registries: vec![],
})
.is_err());
assert!(
validate_config(&RegistryConfigurationJson {
version: 3,
registries: vec![],
})
.is_err()
);
let cfg = RegistryConfigurationJson {
version: 1,

View file

@ -10,6 +10,7 @@ use deno_core::error::AnyError;
use deno_core::serde_json;
use lsp_types::Uri;
use tokio_util::sync::CancellationToken;
use tower_lsp::LanguageServer;
use tower_lsp::lsp_types::ClientCapabilities;
use tower_lsp::lsp_types::ClientInfo;
use tower_lsp::lsp_types::CompletionContext;
@ -31,7 +32,6 @@ use tower_lsp::lsp_types::TextDocumentItem;
use tower_lsp::lsp_types::TextDocumentPositionParams;
use tower_lsp::lsp_types::VersionedTextDocumentIdentifier;
use tower_lsp::lsp_types::WorkDoneProgressParams;
use tower_lsp::LanguageServer;
use super::client::Client;
use super::config::ClassMemberSnippets;

View file

@ -9,8 +9,8 @@ use std::sync::Arc;
use dashmap::DashMap;
use deno_ast::MediaType;
use deno_cache_dir::npm::NpmCacheDir;
use deno_cache_dir::HttpCache;
use deno_cache_dir::npm::NpmCacheDir;
use deno_config::workspace::JsxImportSourceConfig;
use deno_core::parking_lot::Mutex;
use deno_core::url::Url;
@ -20,27 +20,27 @@ use deno_graph::ModuleSpecifier;
use deno_graph::Range;
use deno_npm::NpmSystemInfo;
use deno_npm_cache::TarballCache;
use deno_npm_installer::LifecycleScriptsConfig;
use deno_npm_installer::initializer::NpmResolutionInitializer;
use deno_npm_installer::initializer::NpmResolverManagedSnapshotOption;
use deno_npm_installer::lifecycle_scripts::NullLifecycleScriptsExecutor;
use deno_npm_installer::package_json::NpmInstallDepsProvider;
use deno_npm_installer::resolution::NpmResolutionInstaller;
use deno_npm_installer::LifecycleScriptsConfig;
use deno_path_util::url_to_file_path;
use deno_resolver::DenoResolverOptions;
use deno_resolver::NodeAndNpmResolvers;
use deno_resolver::cjs::IsCjsResolutionMode;
use deno_resolver::graph::FoundPackageJsonDepFlag;
use deno_resolver::npm::managed::ManagedInNpmPkgCheckerCreateOptions;
use deno_resolver::npm::managed::ManagedNpmResolverCreateOptions;
use deno_resolver::npm::managed::NpmResolutionCell;
use deno_resolver::npm::CreateInNpmPkgCheckerOptions;
use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_resolver::npm::NpmReqResolverOptions;
use deno_resolver::npm::managed::ManagedInNpmPkgCheckerCreateOptions;
use deno_resolver::npm::managed::ManagedNpmResolverCreateOptions;
use deno_resolver::npm::managed::NpmResolutionCell;
use deno_resolver::npmrc::create_default_npmrc;
use deno_resolver::workspace::PackageJsonDepResolution;
use deno_resolver::workspace::WorkspaceNpmLinkPackages;
use deno_resolver::workspace::WorkspaceResolver;
use deno_resolver::DenoResolverOptions;
use deno_resolver::NodeAndNpmResolvers;
use deno_runtime::tokio_util::create_basic_runtime;
use deno_semver::jsr::JsrPackageReqReference;
use deno_semver::npm::NpmPackageReqReference;
@ -48,14 +48,14 @@ use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq;
use import_map::ImportMap;
use indexmap::IndexMap;
use node_resolver::cache::NodeResolutionSys;
use node_resolver::cache::NodeResolutionThreadLocalCache;
use node_resolver::DenoIsBuiltInNodeModuleChecker;
use node_resolver::NodeResolutionKind;
use node_resolver::NodeResolverOptions;
use node_resolver::PackageJson;
use node_resolver::PackageJsonThreadLocalCache;
use node_resolver::ResolutionMode;
use node_resolver::cache::NodeResolutionSys;
use node_resolver::cache::NodeResolutionThreadLocalCache;
use once_cell::sync::Lazy;
use super::cache::LspCache;
@ -78,10 +78,10 @@ use crate::npm::CliNpmInstaller;
use crate::npm::CliNpmRegistryInfoProvider;
use crate::npm::CliNpmResolver;
use crate::npm::CliNpmResolverCreateOptions;
use crate::resolver::on_resolve_diagnostic;
use crate::resolver::CliIsCjsResolver;
use crate::resolver::CliNpmReqResolver;
use crate::resolver::CliResolver;
use crate::resolver::on_resolve_diagnostic;
use crate::sys::CliSys;
use crate::tsc::into_specifier_and_media_type;
use crate::util::progress_bar::ProgressBar;
@ -950,7 +950,7 @@ impl<'a> ResolverFactory<'a> {
Arc::new(NullLifecycleScriptsExecutor),
npm_cache.clone(),
Arc::new(NpmInstallDepsProvider::empty()),
Arc::new(registry_info_provider.as_npm_registry_api()),
registry_info_provider.clone(),
self.services.npm_resolution.clone(),
npm_resolution_initializer.clone(),
npm_resolution_installer,

View file

@ -3,15 +3,15 @@
use std::sync::Arc;
use deno_core::error::AnyError;
use deno_semver::package::PackageNv;
use deno_semver::Version;
use deno_semver::package::PackageNv;
#[async_trait::async_trait(?Send)]
pub trait PackageSearchApi {
async fn search(&self, query: &str) -> Result<Arc<Vec<String>>, AnyError>;
async fn versions(&self, name: &str) -> Result<Arc<Vec<Version>>, AnyError>;
async fn exports(&self, nv: &PackageNv)
-> Result<Arc<Vec<String>>, AnyError>;
-> Result<Arc<Vec<String>>, AnyError>;
}
#[cfg(test)]

View file

@ -3,11 +3,11 @@
use std::collections::HashMap;
use std::collections::HashSet;
use deno_ast::SourceRangedForSpanned;
use deno_ast::SourceTextInfo;
use deno_ast::swc::ast;
use deno_ast::swc::ecma_visit::Visit;
use deno_ast::swc::ecma_visit::VisitWith;
use deno_ast::SourceRangedForSpanned;
use deno_ast::SourceTextInfo;
use deno_core::ModuleSpecifier;
use lsp::Range;
use tower_lsp::lsp_types as lsp;

View file

@ -3,8 +3,8 @@
use std::collections::HashMap;
use std::collections::HashSet;
use deno_core::error::AnyError;
use deno_core::ModuleSpecifier;
use deno_core::error::AnyError;
use deno_lib::util::checksum;
use lsp::Range;
use tower_lsp::lsp_types as lsp;
@ -56,7 +56,11 @@ impl TestModule {
let parent = match self.defs.get(parent_id) {
Some(d) => d,
None => {
lsp_warn!("Internal Error: parent_id \"{}\" of test \"{}\" was not registered.", parent_id, &name);
lsp_warn!(
"Internal Error: parent_id \"{}\" of test \"{}\" was not registered.",
parent_id,
&name
);
id_components.push("<unknown>".as_bytes());
break;
}
@ -66,7 +70,7 @@ impl TestModule {
}
id_components.push(self.specifier.as_str().as_bytes());
id_components.reverse();
let id = checksum::gen(&id_components);
let id = checksum::r#gen(&id_components);
if self.defs.contains_key(&id) {
return (id, false);
}

View file

@ -7,16 +7,16 @@ use std::sync::Arc;
use std::time::Duration;
use std::time::Instant;
use deno_core::ModuleSpecifier;
use deno_core::anyhow::anyhow;
use deno_core::error::AnyError;
use deno_core::error::JsError;
use deno_core::futures::StreamExt;
use deno_core::futures::future;
use deno_core::futures::stream;
use deno_core::futures::StreamExt;
use deno_core::parking_lot::RwLock;
use deno_core::unsync::spawn;
use deno_core::unsync::spawn_blocking;
use deno_core::ModuleSpecifier;
use deno_runtime::deno_permissions::Permissions;
use deno_runtime::deno_permissions::PermissionsContainer;
use deno_runtime::tokio_util::create_and_run_current_thread;
@ -28,9 +28,9 @@ use super::definitions::TestDefinition;
use super::definitions::TestModule;
use super::lsp_custom;
use super::server::TestServerTests;
use crate::args::DenoSubcommand;
use crate::args::flags_from_vec;
use crate::args::parallelism_count;
use crate::args::DenoSubcommand;
use crate::factory::CliFactory;
use crate::lsp::client::Client;
use crate::lsp::client::TestingNotification;
@ -40,10 +40,10 @@ use crate::lsp::urls::uri_parse_unencoded;
use crate::lsp::urls::uri_to_url;
use crate::lsp::urls::url_to_uri;
use crate::tools::test;
use crate::tools::test::create_test_event_channel;
use crate::tools::test::FailFastTracker;
use crate::tools::test::TestFailure;
use crate::tools::test::TestFailureFormatOptions;
use crate::tools::test::create_test_event_channel;
/// Logic to convert a test request into a set of test modules to be tested and
/// any filters to be applied to those tests
@ -316,6 +316,8 @@ impl TestRun {
worker_factory,
permissions_container,
specifier,
// Executing tests in the LSP currently doesn't support preload option
vec![],
worker_sender,
fail_fast_tracker,
test::TestSpecifierOptions {
@ -698,7 +700,10 @@ impl LspTestReporter {
let err_string = format!(
"Uncaught error from {}: {}\nThis error was not caught from a test and caused the test runner to fail on the referenced module.\nIt most likely originated from a dangling promise, event/timeout handler or top-level code.",
origin,
test::fmt::format_test_error(js_error, &TestFailureFormatOptions::default())
test::fmt::format_test_error(
js_error,
&TestFailureFormatOptions::default()
)
);
let messages = vec![lsp_custom::TestMessage {
message: lsp::MarkupContent {

View file

@ -5,12 +5,12 @@ use std::collections::HashSet;
use std::sync::Arc;
use std::thread;
use deno_core::ModuleSpecifier;
use deno_core::error::AnyError;
use deno_core::parking_lot::Mutex;
use deno_core::serde_json::json;
use deno_core::serde_json::Value;
use deno_core::serde_json::json;
use deno_core::url::Url;
use deno_core::ModuleSpecifier;
use deno_runtime::tokio_util::create_basic_runtime;
use tokio::sync::mpsc;
use tower_lsp::jsonrpc::Error as LspError;

View file

@ -1,8 +1,8 @@
// Copyright 2018-2025 the Deno authors. MIT license.
use deno_core::error::AnyError;
use dissimilar::diff;
use dissimilar::Chunk;
use dissimilar::diff;
use text_size::TextRange;
use text_size::TextSize;
use tower_lsp::jsonrpc;

View file

@ -29,15 +29,15 @@ impl fmt::Debug for TracingGuard {
#[cfg(feature = "lsp-tracing")]
mod real_tracing {
use deno_core::anyhow;
use opentelemetry::trace::TracerProvider;
pub use opentelemetry::Context;
use opentelemetry::KeyValue;
use opentelemetry::trace::TracerProvider;
use opentelemetry_otlp::WithExportConfig;
use opentelemetry_sdk::Resource;
use opentelemetry_semantic_conventions::resource::SERVICE_NAME;
pub use tracing::Span;
use tracing::level_filters::LevelFilter;
pub use tracing::span::EnteredSpan;
pub use tracing::Span;
use tracing_opentelemetry::OpenTelemetryLayer;
pub use tracing_opentelemetry::OpenTelemetrySpanExt as SpanExt;
use tracing_subscriber::fmt::format::FmtSpan;

View file

@ -12,12 +12,17 @@ use std::net::SocketAddr;
use std::ops::Range;
use std::path::Path;
use std::rc::Rc;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::thread;
use dashmap::DashMap;
use deno_ast::MediaType;
use deno_core::JsRuntime;
use deno_core::ModuleSpecifier;
use deno_core::OpState;
use deno_core::PollEventLoopOptions;
use deno_core::RuntimeOptions;
use deno_core::anyhow::anyhow;
use deno_core::convert::Smi;
use deno_core::convert::ToV8;
@ -26,20 +31,15 @@ use deno_core::futures::FutureExt;
use deno_core::op2;
use deno_core::parking_lot::Mutex;
use deno_core::resolve_url;
use deno_core::serde::de;
use deno_core::serde::Deserialize;
use deno_core::serde::Serialize;
use deno_core::serde::de;
use deno_core::serde_json;
use deno_core::serde_json::json;
use deno_core::serde_json::Value;
use deno_core::serde_json::json;
use deno_core::serde_v8;
use deno_core::url::Url;
use deno_core::v8;
use deno_core::JsRuntime;
use deno_core::ModuleSpecifier;
use deno_core::OpState;
use deno_core::PollEventLoopOptions;
use deno_core::RuntimeOptions;
use deno_lib::util::result::InfallibleResultExt;
use deno_lib::worker::create_isolate_create_params;
use deno_path_util::url_to_file_path;
@ -51,9 +51,9 @@ use indexmap::IndexSet;
use lazy_regex::lazy_regex;
use log::error;
use lsp_types::Uri;
use node_resolver::cache::NodeResolutionThreadLocalCache;
use node_resolver::NodeResolutionKind;
use node_resolver::ResolutionMode;
use node_resolver::cache::NodeResolutionThreadLocalCache;
use once_cell::sync::Lazy;
use regex::Captures;
use regex::Regex;
@ -80,22 +80,22 @@ use super::language_server::StateSnapshot;
use super::logging::lsp_log;
use super::performance::Performance;
use super::performance::PerformanceMark;
use super::refactor::RefactorCodeActionData;
use super::refactor::ALL_KNOWN_REFACTOR_ACTION_KINDS;
use super::refactor::EXTRACT_CONSTANT;
use super::refactor::EXTRACT_INTERFACE;
use super::refactor::EXTRACT_TYPE;
use super::refactor::RefactorCodeActionData;
use super::semantic_tokens;
use super::semantic_tokens::SemanticTokensBuilder;
use super::text::LineIndex;
use super::urls::uri_to_url;
use super::urls::url_to_uri;
use crate::args::jsr_url;
use crate::args::FmtOptionsConfig;
use crate::args::jsr_url;
use crate::lsp::documents::Document;
use crate::lsp::logging::lsp_warn;
use crate::tsc::ResolveArgs;
use crate::tsc::MISSING_DEPENDENCY_SPECIFIER;
use crate::tsc::ResolveArgs;
use crate::util::path::relative_specifier;
use crate::util::path::to_percent_decoded_str;
use crate::util::v8::convert;

View file

@ -3,7 +3,6 @@
mod args;
mod cache;
mod cdp;
mod emit;
mod factory;
mod file_fetcher;
mod graph_container;
@ -47,10 +46,10 @@ use deno_lib::util::result::any_and_jserrorbox_downcast_ref;
use deno_lib::worker::LibWorkerFactoryRoots;
use deno_resolver::npm::ByonmResolvePkgFolderFromDenoReqError;
use deno_resolver::npm::ResolvePkgFolderFromDenoReqError;
use deno_runtime::fmt_errors::format_js_error;
use deno_runtime::tokio_util::create_and_run_current_thread_with_maybe_metrics;
use deno_runtime::UnconfiguredRuntime;
use deno_runtime::WorkerExecutionMode;
use deno_runtime::fmt_errors::format_js_error;
use deno_runtime::tokio_util::create_and_run_current_thread_with_maybe_metrics;
use deno_telemetry::OtelConfig;
use deno_terminal::colors;
use factory::CliFactory;
@ -60,10 +59,10 @@ const UNSUPPORTED_SCHEME: &str = "Unsupported scheme";
use self::args::load_env_variables_from_env_file;
use self::util::draw_thread::DrawThread;
use crate::args::flags_from_vec;
use crate::args::get_default_v8_flags;
use crate::args::DenoSubcommand;
use crate::args::Flags;
use crate::args::flags_from_vec;
use crate::args::get_default_v8_flags;
use crate::util::display;
use crate::util::v8::get_v8_flags_from_env;
use crate::util::v8::init_v8_flags;
@ -117,25 +116,25 @@ async fn run_subcommand(
DenoSubcommand::Add(add_flags) => spawn_subcommand(async {
tools::pm::add(flags, add_flags, tools::pm::AddCommandName::Add).await
}),
DenoSubcommand::Remove(remove_flags) => spawn_subcommand(async {
tools::pm::remove(flags, remove_flags).await
}),
DenoSubcommand::Remove(remove_flags) => {
spawn_subcommand(async { tools::pm::remove(flags, remove_flags).await })
}
DenoSubcommand::Bench(bench_flags) => spawn_subcommand(async {
if bench_flags.watch.is_some() {
tools::bench::run_benchmarks_with_watch(flags, bench_flags).boxed_local().await
tools::bench::run_benchmarks_with_watch(flags, bench_flags)
.boxed_local()
.await
} else {
tools::bench::run_benchmarks(flags, bench_flags).await
}
}),
DenoSubcommand::Bundle(bundle_flags) => {
spawn_subcommand(async {
log::warn!(
"⚠️ {} is experimental and subject to changes",
colors::cyan("deno bundle")
);
tools::bundle::bundle(flags, bundle_flags).await
})
},
DenoSubcommand::Bundle(bundle_flags) => spawn_subcommand(async {
log::warn!(
"⚠️ {} is experimental and subject to changes",
colors::cyan("deno bundle")
);
tools::bundle::bundle(flags, bundle_flags).await
}),
DenoSubcommand::Deploy => {
spawn_subcommand(async { tools::deploy::deploy(Arc::unwrap_or_clone(flags)).await })
}
@ -146,23 +145,31 @@ async fn run_subcommand(
tools::run::eval_command(flags, eval_flags).await
}),
DenoSubcommand::Cache(cache_flags) => spawn_subcommand(async move {
tools::installer::install_from_entrypoints(flags, &cache_flags.files).await
}),
DenoSubcommand::Check(check_flags) => spawn_subcommand(async move {
tools::check::check(flags, check_flags).await
}),
DenoSubcommand::Clean(clean_flags) => spawn_subcommand(async move {
tools::clean::clean(flags, clean_flags).await
tools::installer::install_from_entrypoints(flags, &cache_flags.files)
.await
}),
DenoSubcommand::Check(check_flags) => {
spawn_subcommand(
async move { tools::check::check(flags, check_flags).await },
)
}
DenoSubcommand::Clean(clean_flags) => {
spawn_subcommand(
async move { tools::clean::clean(flags, clean_flags).await },
)
}
DenoSubcommand::Compile(compile_flags) => spawn_subcommand(async {
if compile_flags.eszip {
tools::compile::compile_eszip(flags, compile_flags).boxed_local().await
tools::compile::compile_eszip(flags, compile_flags)
.boxed_local()
.await
} else {
tools::compile::compile(flags, compile_flags).await
}
}),
DenoSubcommand::Coverage(coverage_flags) => spawn_subcommand(async move {
let reporter = crate::tools::coverage::reporter::create(coverage_flags.r#type.clone());
let reporter =
crate::tools::coverage::reporter::create(coverage_flags.r#type.clone());
tools::coverage::cover_files(
flags,
coverage_flags.files.include,
@ -170,7 +177,7 @@ async fn run_subcommand(
coverage_flags.include,
coverage_flags.exclude,
coverage_flags.output,
&[&*reporter]
&[&*reporter],
)
}),
DenoSubcommand::Fmt(fmt_flags) => {
@ -179,9 +186,7 @@ async fn run_subcommand(
)
}
DenoSubcommand::Init(init_flags) => {
spawn_subcommand(async {
tools::init::init_project(init_flags).await
})
spawn_subcommand(async { tools::init::init_project(init_flags).await })
}
DenoSubcommand::Info(info_flags) => {
spawn_subcommand(async { tools::info::info(flags, info_flags).await })
@ -189,9 +194,13 @@ async fn run_subcommand(
DenoSubcommand::Install(install_flags) => spawn_subcommand(async {
tools::installer::install_command(flags, install_flags).await
}),
DenoSubcommand::JSONReference(json_reference) => spawn_subcommand(async move {
display::write_to_stdout_ignore_sigpipe(&deno_core::serde_json::to_vec_pretty(&json_reference.json).unwrap())
}),
DenoSubcommand::JSONReference(json_reference) => {
spawn_subcommand(async move {
display::write_to_stdout_ignore_sigpipe(
&deno_core::serde_json::to_vec_pretty(&json_reference.json).unwrap(),
)
})
}
DenoSubcommand::Jupyter(jupyter_flags) => spawn_subcommand(async {
tools::jupyter::kernel(flags, jupyter_flags).await
}),
@ -223,9 +232,9 @@ async fn run_subcommand(
}
}),
DenoSubcommand::Outdated(update_flags) => {
spawn_subcommand(async move {
tools::pm::outdated(flags, update_flags).await
})
spawn_subcommand(
async move { tools::pm::outdated(flags, update_flags).await },
)
}
DenoSubcommand::Repl(repl_flags) => {
spawn_subcommand(async move { tools::repl::run(flags, repl_flags).await })
@ -233,38 +242,77 @@ async fn run_subcommand(
DenoSubcommand::Run(run_flags) => spawn_subcommand(async move {
if run_flags.is_stdin() {
// these futures are boxed to prevent stack overflows on Windows
tools::run::run_from_stdin(flags.clone(), unconfigured_runtime, roots).boxed_local().await
tools::run::run_from_stdin(flags.clone(), unconfigured_runtime, roots)
.boxed_local()
.await
} else if flags.eszip {
tools::run::run_eszip(flags, run_flags, unconfigured_runtime, roots).boxed_local().await
tools::run::run_eszip(flags, run_flags, unconfigured_runtime, roots)
.boxed_local()
.await
} else {
let result = tools::run::run_script(WorkerExecutionMode::Run, flags.clone(), run_flags.watch, unconfigured_runtime, roots.clone()).await;
let result = tools::run::run_script(
WorkerExecutionMode::Run,
flags.clone(),
run_flags.watch,
unconfigured_runtime,
roots.clone(),
)
.await;
match result {
Ok(v) => Ok(v),
Err(script_err) => {
if let Some(worker::CreateCustomWorkerError::ResolvePkgFolderFromDenoReq(ResolvePkgFolderFromDenoReqError::Byonm(ByonmResolvePkgFolderFromDenoReqError::UnmatchedReq(_)))) = any_and_jserrorbox_downcast_ref::<worker::CreateCustomWorkerError>(&script_err) {
if let Some(
worker::CreateCustomWorkerError::ResolvePkgFolderFromDenoReq(
ResolvePkgFolderFromDenoReqError::Byonm(
ByonmResolvePkgFolderFromDenoReqError::UnmatchedReq(_),
),
),
) = any_and_jserrorbox_downcast_ref::<
worker::CreateCustomWorkerError,
>(&script_err)
{
if flags.node_modules_dir.is_none() {
let mut flags = flags.deref().clone();
let watch = match &flags.subcommand {
DenoSubcommand::Run(run_flags) => run_flags.watch.clone(),
_ => unreachable!(),
};
flags.node_modules_dir = Some(deno_config::deno_json::NodeModulesDirMode::None);
flags.node_modules_dir =
Some(deno_config::deno_json::NodeModulesDirMode::None);
// use the current lockfile, but don't write it out
if flags.frozen_lockfile.is_none() {
flags.internal.lockfile_skip_write = true;
}
return tools::run::run_script(WorkerExecutionMode::Run, Arc::new(flags), watch, None, roots).boxed_local().await;
return tools::run::run_script(
WorkerExecutionMode::Run,
Arc::new(flags),
watch,
None,
roots,
)
.boxed_local()
.await;
}
}
let script_err_msg = script_err.to_string();
if script_err_msg.starts_with(MODULE_NOT_FOUND) || script_err_msg.starts_with(UNSUPPORTED_SCHEME) {
if script_err_msg.starts_with(MODULE_NOT_FOUND)
|| script_err_msg.starts_with(UNSUPPORTED_SCHEME)
{
if run_flags.bare {
let mut cmd = args::clap_root();
cmd.build();
let command_names = cmd.get_subcommands().map(|command| command.get_name()).collect::<Vec<_>>();
let suggestions = args::did_you_mean(&run_flags.script, command_names);
let command_names = cmd
.get_subcommands()
.map(|command| command.get_name())
.collect::<Vec<_>>();
let suggestions =
args::did_you_mean(&run_flags.script, command_names);
if !suggestions.is_empty() && !run_flags.script.contains('.') {
let mut error = clap::error::Error::<clap::error::DefaultFormatter>::new(clap::error::ErrorKind::InvalidSubcommand).with_cmd(&cmd);
let mut error =
clap::error::Error::<clap::error::DefaultFormatter>::new(
clap::error::ErrorKind::InvalidSubcommand,
)
.with_cmd(&cmd);
error.insert(
clap::error::ContextKind::SuggestedSubcommand,
clap::error::ContextValue::Strings(suggestions),
@ -285,7 +333,11 @@ async fn run_subcommand(
eval: false,
};
new_flags.subcommand = DenoSubcommand::Task(task_flags.clone());
let result = tools::task::execute_script(Arc::new(new_flags), task_flags.clone()).await;
let result = tools::task::execute_script(
Arc::new(new_flags),
task_flags.clone(),
)
.await;
match result {
Ok(v) => Ok(v),
Err(_) => {
@ -318,10 +370,14 @@ async fn run_subcommand(
.with_context(|| format!("Failed creating: {coverage_dir}"))?;
// this is set in order to ensure spawned processes use the same
// coverage directory
env::set_var(
"DENO_COVERAGE_DIR",
PathBuf::from(coverage_dir).canonicalize()?,
);
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
env::set_var(
"DENO_COVERAGE_DIR",
PathBuf::from(coverage_dir).canonicalize()?,
)
};
}
if test_flags.watch.is_some() {
@ -349,18 +405,24 @@ async fn run_subcommand(
"This deno was built without the \"upgrade\" feature. Please upgrade using the installation method originally used to install Deno.",
1,
),
DenoSubcommand::Vendor => exit_with_message("⚠️ `deno vendor` was removed in Deno 2.\n\nSee the Deno 1.x to 2.x Migration Guide for migration instructions: https://docs.deno.com/runtime/manual/advanced/migrate_deprecations", 1),
DenoSubcommand::Vendor => exit_with_message(
"⚠️ `deno vendor` was removed in Deno 2.\n\nSee the Deno 1.x to 2.x Migration Guide for migration instructions: https://docs.deno.com/runtime/manual/advanced/migrate_deprecations",
1,
),
DenoSubcommand::Publish(publish_flags) => spawn_subcommand(async {
tools::publish::publish(flags, publish_flags).await
}),
DenoSubcommand::Help(help_flags) => spawn_subcommand(async move {
use std::io::Write;
let mut stream = anstream::AutoStream::new(std::io::stdout(), if colors::use_color() {
anstream::ColorChoice::Auto
} else {
anstream::ColorChoice::Never
});
let mut stream = anstream::AutoStream::new(
std::io::stdout(),
if colors::use_color() {
anstream::ColorChoice::Auto
} else {
anstream::ColorChoice::Never
},
);
match stream.write_all(help_flags.help.ansi().to_string().as_bytes()) {
Ok(()) => Ok(()),
@ -548,6 +610,17 @@ async fn resolve_flags_and_init(
load_env_variables_from_env_file(flags.env_file.as_ref(), flags.log_level);
flags.unstable_config.fill_with_env();
if std::env::var("DENO_COMPAT").is_ok() {
flags.unstable_config.enable_node_compat();
}
if flags.node_conditions.is_empty() {
if let Ok(conditions) = std::env::var("DENO_CONDITIONS") {
flags.node_conditions = conditions
.split(",")
.map(|c| c.trim().to_string())
.collect();
}
}
// Tunnel is initialized before OTEL since
// OTEL data is submitted via the tunnel.
@ -636,11 +709,15 @@ fn wait_for_start(
Option<(UnconfiguredRuntime, Vec<std::ffi::OsString>)>,
AnyError,
>,
>,
> + use<>,
> {
let startup_snapshot = deno_snapshots::CLI_SNAPSHOT?;
let addr = std::env::var("DENO_UNSTABLE_CONTROL_SOCK").ok()?;
std::env::remove_var("DENO_UNSTABLE_CONTROL_SOCK");
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
std::env::remove_var("DENO_UNSTABLE_CONTROL_SOCK")
};
let argv0 = args[0].clone();
@ -663,15 +740,18 @@ fn wait_for_start(
deno_resolver::npm::DenoInNpmPackageChecker,
crate::npm::CliNpmResolver,
crate::sys::CliSys,
>(
>(deno_runtime::UnconfiguredRuntimeOptions {
startup_snapshot,
deno_lib::worker::create_isolate_create_params(
create_params: deno_lib::worker::create_isolate_create_params(
&crate::sys::CliSys::default(),
),
Some(roots.shared_array_buffer_store.clone()),
Some(roots.compiled_wasm_module_store.clone()),
vec![],
);
shared_array_buffer_store: Some(roots.shared_array_buffer_store.clone()),
compiled_wasm_module_store: Some(
roots.compiled_wasm_module_store.clone(),
),
additional_extensions: vec![],
enable_raw_imports: false,
});
let (rx, mut tx): (
Box<dyn AsyncRead + Unpin>,
@ -737,7 +817,10 @@ fn wait_for_start(
std::env::set_current_dir(cmd.cwd)?;
for (k, v) in cmd.env {
std::env::set_var(k, v);
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
std::env::set_var(k, v)
};
}
let args = [argv0]

View file

@ -10,26 +10,16 @@ use std::path::PathBuf;
use std::pin::Pin;
use std::rc::Rc;
use std::str;
use std::sync::Arc;
use std::sync::atomic::AtomicU16;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::time::SystemTime;
use boxed_error::Boxed;
use deno_ast::MediaType;
use deno_ast::ModuleKind;
use deno_core::anyhow::bail;
use deno_core::anyhow::Context as _;
use deno_core::error::AnyError;
use deno_core::error::ModuleLoaderError;
use deno_core::futures::future::FutureExt;
use deno_core::futures::io::BufReader;
use deno_core::futures::stream::FuturesOrdered;
use deno_core::futures::StreamExt;
use deno_core::parking_lot::Mutex;
use deno_core::resolve_url;
use deno_core::resolve_url_or_path;
use deno_core::serde_json;
use deno_core::ModuleCodeString;
use deno_cache_dir::file_fetcher::FetchLocalOptions;
use deno_core::FastString;
use deno_core::ModuleLoader;
use deno_core::ModuleSource;
use deno_core::ModuleSourceCode;
@ -37,60 +27,72 @@ use deno_core::ModuleSpecifier;
use deno_core::ModuleType;
use deno_core::RequestedModuleType;
use deno_core::SourceCodeCacheInfo;
use deno_core::anyhow::Context as _;
use deno_core::anyhow::bail;
use deno_core::error::AnyError;
use deno_core::error::ModuleLoaderError;
use deno_core::futures::StreamExt;
use deno_core::futures::future::FutureExt;
use deno_core::futures::io::BufReader;
use deno_core::futures::stream::FuturesOrdered;
use deno_core::parking_lot::Mutex;
use deno_core::resolve_url;
use deno_core::resolve_url_or_path;
use deno_core::serde_json;
use deno_error::JsErrorBox;
use deno_graph::GraphKind;
use deno_graph::JsModule;
use deno_graph::JsonModule;
use deno_graph::ModuleGraph;
use deno_graph::ModuleGraphError;
use deno_graph::WalkOptions;
use deno_graph::WasmModule;
use deno_lib::loader::ModuleCodeStringSource;
use deno_lib::loader::NpmModuleLoadError;
use deno_lib::loader::StrippingTypesNodeModulesError;
use deno_lib::loader::module_type_from_media_type;
use deno_lib::npm::NpmRegistryReadPermissionChecker;
use deno_lib::util::hash::FastInsecureHasher;
use deno_lib::worker::CreateModuleLoaderResult;
use deno_lib::worker::ModuleLoaderFactory;
use deno_resolver::cache::ParsedSourceCache;
use deno_resolver::file_fetcher::FetchOptions;
use deno_resolver::file_fetcher::FetchPermissionsOptionRef;
use deno_resolver::graph::ResolveWithGraphErrorKind;
use deno_resolver::graph::ResolveWithGraphOptions;
use deno_resolver::loader::LoadPreparedModuleError;
use deno_resolver::loader::PreparedModuleOrAsset;
use deno_resolver::loader::PreparedModuleSource;
use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_resolver::npm::ResolveNpmReqRefError;
use deno_runtime::code_cache;
use deno_runtime::deno_node::NodeRequireLoader;
use deno_runtime::deno_node::create_host_defined_options;
use deno_runtime::deno_node::ops::require::UnableToGetCwdError;
use deno_runtime::deno_node::NodeRequireLoader;
use deno_runtime::deno_permissions::CheckSpecifierKind;
use deno_runtime::deno_permissions::PermissionsContainer;
use deno_semver::npm::NpmPackageReqReference;
use eszip::EszipV2;
use node_resolver::errors::ClosestPkgJsonError;
use node_resolver::DenoIsBuiltInNodeModuleChecker;
use node_resolver::InNpmPackageChecker;
use node_resolver::NodeResolutionKind;
use node_resolver::ResolutionMode;
use node_resolver::errors::ClosestPkgJsonError;
use sys_traits::FsMetadata;
use sys_traits::FsMetadataValue;
use sys_traits::FsRead;
use tokio_util::compat::TokioAsyncReadCompatExt;
use crate::args::jsr_url;
use crate::args::CliLockfile;
use crate::args::CliOptions;
use crate::args::DenoSubcommand;
use crate::args::TsTypeLib;
use crate::args::jsr_url;
use crate::cache::CodeCache;
use crate::cache::ParsedSourceCache;
use crate::emit::Emitter;
use crate::file_fetcher::CliFileFetcher;
use crate::graph_container::MainModuleGraphContainer;
use crate::graph_container::ModuleGraphContainer;
use crate::graph_container::ModuleGraphUpdatePermit;
use crate::graph_util::enhance_graph_error;
use crate::graph_util::BuildGraphRequest;
use crate::graph_util::BuildGraphWithNpmOptions;
use crate::graph_util::EnhanceGraphErrorMode;
use crate::graph_util::ModuleGraphBuilder;
use crate::node::CliCjsCodeAnalyzer;
use crate::node::CliNodeCodeTranslator;
use crate::npm::CliNpmResolver;
use crate::resolver::CliCjsTracker;
use crate::resolver::CliResolver;
@ -109,6 +111,10 @@ pub type CliNpmModuleLoader = deno_lib::loader::NpmModuleLoader<
CliNpmResolver,
CliSys,
>;
pub type CliEmitter =
deno_resolver::emit::Emitter<DenoInNpmPackageChecker, CliSys>;
pub type CliPreparedModuleLoader =
deno_resolver::loader::PreparedModuleLoader<DenoInNpmPackageChecker, CliSys>;
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum PrepareModuleLoadError {
@ -325,16 +331,17 @@ struct SharedCliModuleLoaderState {
is_repl: bool,
cjs_tracker: Arc<CliCjsTracker>,
code_cache: Option<Arc<CodeCache>>,
emitter: Arc<Emitter>,
emitter: Arc<CliEmitter>,
file_fetcher: Arc<CliFileFetcher>,
in_npm_pkg_checker: DenoInNpmPackageChecker,
main_module_graph_container: Arc<MainModuleGraphContainer>,
module_load_preparer: Arc<ModuleLoadPreparer>,
node_code_translator: Arc<CliNodeCodeTranslator>,
npm_module_loader: CliNpmModuleLoader,
npm_registry_permission_checker:
Arc<NpmRegistryReadPermissionChecker<CliSys>>,
npm_resolver: CliNpmResolver,
parsed_source_cache: Arc<ParsedSourceCache>,
prepared_module_loader: Arc<CliPreparedModuleLoader>,
resolver: Arc<CliResolver>,
sys: CliSys,
in_flight_loads_tracker: InFlightModuleLoadsTracker,
@ -386,17 +393,18 @@ impl CliModuleLoaderFactory {
options: &CliOptions,
cjs_tracker: Arc<CliCjsTracker>,
code_cache: Option<Arc<CodeCache>>,
emitter: Arc<Emitter>,
emitter: Arc<CliEmitter>,
file_fetcher: Arc<CliFileFetcher>,
in_npm_pkg_checker: DenoInNpmPackageChecker,
main_module_graph_container: Arc<MainModuleGraphContainer>,
module_load_preparer: Arc<ModuleLoadPreparer>,
node_code_translator: Arc<CliNodeCodeTranslator>,
npm_module_loader: CliNpmModuleLoader,
npm_registry_permission_checker: Arc<
NpmRegistryReadPermissionChecker<CliSys>,
>,
npm_resolver: CliNpmResolver,
parsed_source_cache: Arc<ParsedSourceCache>,
prepared_module_loader: Arc<CliPreparedModuleLoader>,
resolver: Arc<CliResolver>,
sys: CliSys,
maybe_eszip_loader: Option<Arc<EszipModuleLoader>>,
@ -415,14 +423,15 @@ impl CliModuleLoaderFactory {
cjs_tracker,
code_cache,
emitter,
file_fetcher,
in_npm_pkg_checker,
main_module_graph_container,
module_load_preparer,
node_code_translator,
npm_module_loader,
npm_registry_permission_checker,
npm_resolver,
parsed_source_cache,
prepared_module_loader,
resolver,
sys,
in_flight_loads_tracker: InFlightModuleLoadsTracker {
@ -450,9 +459,6 @@ impl CliModuleLoaderFactory {
parent_permissions,
permissions,
graph_container: graph_container.clone(),
node_code_translator: self.shared.node_code_translator.clone(),
emitter: self.shared.emitter.clone(),
parsed_source_cache: self.shared.parsed_source_cache.clone(),
shared: self.shared.clone(),
loaded_files: Default::default(),
})));
@ -518,9 +524,6 @@ impl CliModuleLoaderFactory {
parent_permissions: root_permissions.clone(),
permissions: root_permissions,
graph_container: (*self.shared.main_module_graph_container).clone(),
node_code_translator: self.shared.node_code_translator.clone(),
emitter: self.shared.emitter.clone(),
parsed_source_cache: self.shared.parsed_source_cache.clone(),
shared: self.shared.clone(),
loaded_files: Default::default(),
}))
@ -535,41 +538,6 @@ pub struct LoadUnpreparedModuleError {
maybe_referrer: Option<ModuleSpecifier>,
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
#[error("{message}")]
#[class(inherit)]
pub struct EnhancedGraphError {
#[inherit]
pub error: deno_graph::ModuleError,
pub message: String,
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum LoadPreparedModuleError {
#[class(inherit)]
#[error(transparent)]
NpmModuleLoad(#[from] crate::emit::EmitParsedSourceHelperError),
#[class(inherit)]
#[error(transparent)]
LoadMaybeCjs(#[from] LoadMaybeCjsError),
#[class(inherit)]
#[error(transparent)]
Graph(#[from] Box<EnhancedGraphError>),
#[class(inherit)]
#[error(transparent)]
Other(#[from] JsErrorBox),
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum LoadMaybeCjsError {
#[class(inherit)]
#[error(transparent)]
NpmModuleLoad(#[from] crate::emit::EmitParsedSourceHelperError),
#[class(inherit)]
#[error(transparent)]
TranslateCjsToEsm(#[from] node_resolver::analyze::TranslateCjsToEsmError),
}
struct CliModuleLoaderInner<TGraphContainer: ModuleGraphContainer> {
lib: TsTypeLib,
is_worker: bool,
@ -579,23 +547,13 @@ struct CliModuleLoaderInner<TGraphContainer: ModuleGraphContainer> {
parent_permissions: PermissionsContainer,
permissions: PermissionsContainer,
shared: Arc<SharedCliModuleLoaderState>,
emitter: Arc<Emitter>,
node_code_translator: Arc<CliNodeCodeTranslator>,
parsed_source_cache: Arc<ParsedSourceCache>,
graph_container: TGraphContainer,
loaded_files: RefCell<HashSet<ModuleSpecifier>>,
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
#[derive(Debug, deno_error::JsError, Boxed)]
#[class(inherit)]
#[error(transparent)]
pub struct LoadCodeSourceError(#[from] pub Box<LoadCodeSourceErrorKind>);
impl LoadCodeSourceError {
pub fn from_err<E: Into<LoadCodeSourceErrorKind>>(err: E) -> Self {
Self(Box::new(err.into()))
}
}
pub struct LoadCodeSourceError(pub Box<LoadCodeSourceErrorKind>);
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum LoadCodeSourceErrorKind {
@ -617,6 +575,9 @@ pub enum LoadCodeSourceErrorKind {
#[class(inherit)]
#[error(transparent)]
NpmReqRef(#[from] ResolveNpmReqRefError),
#[class(inherit)]
#[error(transparent)]
Fetch(#[from] deno_resolver::file_fetcher::FetchError),
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
@ -628,7 +589,9 @@ pub enum CliModuleLoaderError {
#[error(transparent)]
LoadPreparedModule(#[from] Box<LoadPreparedModuleError>),
#[class(generic)]
#[error("Attempted to load JSON module without specifying \"type\": \"json\" attribute in the import statement.")]
#[error(
"Attempted to load JSON module without specifying \"type\": \"json\" attribute in the import statement."
)]
MissingJsonAttribute,
#[class(inherit)]
#[error(transparent)]
@ -643,7 +606,7 @@ impl<TGraphContainer: ModuleGraphContainer> CliModuleLoader<TGraphContainer> {
&self,
specifier: &ModuleSpecifier,
maybe_referrer: Option<&ModuleSpecifier>,
requested_module_type: RequestedModuleType,
requested_module_type: &RequestedModuleType,
) -> Result<ModuleSource, CliModuleLoaderError> {
self
.0
@ -659,26 +622,22 @@ impl<TGraphContainer: ModuleGraphContainer>
&self,
specifier: &ModuleSpecifier,
maybe_referrer: Option<&ModuleSpecifier>,
requested_module_type: RequestedModuleType,
requested_module_type: &RequestedModuleType,
) -> Result<ModuleSource, CliModuleLoaderError> {
let code_source = self.load_code_source(specifier, maybe_referrer).await?;
let module_type = match code_source.media_type {
MediaType::Json => ModuleType::Json,
MediaType::Wasm => ModuleType::Wasm,
_ => ModuleType::JavaScript,
};
let code_source = self
.load_code_source(specifier, maybe_referrer, requested_module_type)
.await?;
// If we loaded a JSON file, but the "requested_module_type" (that is computed from
// import attributes) is not JSON we need to fail.
if module_type == ModuleType::Json
&& requested_module_type != RequestedModuleType::Json
if code_source.module_type == ModuleType::Json
&& *requested_module_type != RequestedModuleType::Json
{
return Err(CliModuleLoaderError::MissingJsonAttribute);
}
Ok(ModuleSource::new_with_redirect(
module_type,
code_source.module_type,
code_source.code,
specifier,
&code_source.found_url,
@ -690,27 +649,22 @@ impl<TGraphContainer: ModuleGraphContainer>
&self,
specifier: &ModuleSpecifier,
maybe_referrer: Option<&ModuleSpecifier>,
requested_module_type: RequestedModuleType,
requested_module_type: &RequestedModuleType,
) -> Result<ModuleSource, ModuleLoaderError> {
let code_source = self
.load_code_source(specifier, maybe_referrer)
.load_code_source(specifier, maybe_referrer, requested_module_type)
.await
.map_err(JsErrorBox::from_err)?;
let module_type = match code_source.media_type {
MediaType::Json => ModuleType::Json,
MediaType::Wasm => ModuleType::Wasm,
_ => ModuleType::JavaScript,
};
// If we loaded a JSON file, but the "requested_module_type" (that is computed from
// import attributes) is not JSON we need to fail.
if module_type == ModuleType::Json
&& requested_module_type != RequestedModuleType::Json
if code_source.module_type == ModuleType::Json
&& *requested_module_type != RequestedModuleType::Json
{
return Err(JsErrorBox::generic("Attempted to load JSON module without specifying \"type\": \"json\" attribute in the import statement.").into());
}
let code = if self.shared.is_inspecting
|| code_source.media_type == MediaType::Wasm
|| code_source.module_type == ModuleType::Wasm
{
// we need the code with the source map in order for
// it to work with --inspect or --inspect-brk
@ -720,7 +674,7 @@ impl<TGraphContainer: ModuleGraphContainer>
code_without_source_map(code_source.code)
};
let code_cache = if module_type == ModuleType::JavaScript {
let code_cache = if code_source.module_type == ModuleType::JavaScript {
self.shared.code_cache.as_ref().map(|cache| {
let code_hash = FastInsecureHasher::new_deno_versioned()
.write_hashable(&code)
@ -744,7 +698,7 @@ impl<TGraphContainer: ModuleGraphContainer>
};
Ok(ModuleSource::new_with_redirect(
module_type,
code_source.module_type,
code,
specifier,
&code_source.found_url,
@ -756,13 +710,74 @@ impl<TGraphContainer: ModuleGraphContainer>
&self,
specifier: &ModuleSpecifier,
maybe_referrer: Option<&ModuleSpecifier>,
requested_module_type: &RequestedModuleType,
) -> Result<ModuleCodeStringSource, LoadCodeSourceError> {
fn as_deno_resolver_requested_module_type(
value: &RequestedModuleType,
) -> deno_resolver::loader::RequestedModuleType<'_> {
match value {
RequestedModuleType::None => {
deno_resolver::loader::RequestedModuleType::None
}
RequestedModuleType::Json => {
deno_resolver::loader::RequestedModuleType::Json
}
RequestedModuleType::Text => {
deno_resolver::loader::RequestedModuleType::Text
}
RequestedModuleType::Bytes => {
deno_resolver::loader::RequestedModuleType::Bytes
}
RequestedModuleType::Other(text) => {
deno_resolver::loader::RequestedModuleType::Other(text)
}
}
}
let graph = self.graph_container.graph();
match self
.load_prepared_module(specifier)
.shared
.prepared_module_loader
.load_prepared_module(
&graph,
specifier,
&as_deno_resolver_requested_module_type(requested_module_type),
)
.await
.map_err(LoadCodeSourceError::from_err)?
.map_err(LoadCodeSourceError::from)?
{
Some(code) => Ok(code),
Some(module_or_asset) => match module_or_asset {
PreparedModuleOrAsset::Module(prepared_module) => {
Ok(ModuleCodeStringSource {
code: match prepared_module.source {
PreparedModuleSource::ArcStr(text) => {
ModuleSourceCode::String(text.into())
}
PreparedModuleSource::ArcBytes(bytes) => {
ModuleSourceCode::Bytes(bytes.into())
}
},
found_url: prepared_module.specifier.clone(),
module_type: match requested_module_type {
RequestedModuleType::Json => ModuleType::Json,
RequestedModuleType::Text => ModuleType::Text,
RequestedModuleType::Bytes => ModuleType::Bytes,
RequestedModuleType::None | RequestedModuleType::Other(_) => {
module_type_from_media_type(prepared_module.media_type)
}
},
})
}
PreparedModuleOrAsset::ExternalAsset { specifier } => {
self.load_asset(
specifier,
/* do not use dynamic import permissions because this was statically analyzable */ CheckSpecifierKind::Static,
requested_module_type
)
.await
.map_err(|err| LoadCodeSourceErrorKind::Fetch(err).into_box())
}
},
None => {
let specifier = if let Ok(reference) =
NpmPackageReqReference::from_specifier(specifier)
@ -776,7 +791,7 @@ impl<TGraphContainer: ModuleGraphContainer>
None => Cow::Owned(
self
.resolve_referrer("")
.map_err(LoadCodeSourceError::from_err)?,
.map_err(LoadCodeSourceError::from)?,
),
};
Cow::Owned(
@ -789,10 +804,10 @@ impl<TGraphContainer: ModuleGraphContainer>
ResolutionMode::Import,
NodeResolutionKind::Execution,
)
.map_err(LoadCodeSourceError::from_err)?
.map_err(LoadCodeSourceError::from)?
.unwrap()
.into_url()
.map_err(LoadCodeSourceError::from_err)?,
.map_err(LoadCodeSourceError::from)?,
)
} else {
Cow::Borrowed(specifier)
@ -803,16 +818,70 @@ impl<TGraphContainer: ModuleGraphContainer>
.npm_module_loader
.load(&specifier, maybe_referrer)
.await
.map_err(LoadCodeSourceError::from_err);
.map_err(LoadCodeSourceError::from);
}
match requested_module_type {
RequestedModuleType::Text | RequestedModuleType::Bytes => self
.load_asset(
&specifier,
/* force using permissions because this was not statically analyzable */ CheckSpecifierKind::Dynamic,
requested_module_type
)
.await
.map_err(LoadCodeSourceError::from),
_ => Err(LoadCodeSourceError::from(LoadUnpreparedModuleError {
specifier: specifier.into_owned(),
maybe_referrer: maybe_referrer.cloned(),
})),
}
Err(LoadCodeSourceError::from_err(LoadUnpreparedModuleError {
specifier: specifier.into_owned(),
maybe_referrer: maybe_referrer.cloned(),
}))
}
}
}
async fn load_asset(
&self,
specifier: &ModuleSpecifier,
check_specifier_kind: CheckSpecifierKind,
requested_module_type: &RequestedModuleType,
) -> Result<ModuleCodeStringSource, deno_resolver::file_fetcher::FetchError>
{
let file = self
.shared
.file_fetcher
.fetch_with_options(
specifier,
FetchPermissionsOptionRef::Restricted(
match check_specifier_kind {
CheckSpecifierKind::Static => &self.permissions,
CheckSpecifierKind::Dynamic => &self.parent_permissions,
},
check_specifier_kind,
),
FetchOptions {
local: FetchLocalOptions {
include_mtime: false,
},
maybe_auth: None,
maybe_accept: None,
maybe_cache_setting: Some(
&deno_cache_dir::file_fetcher::CacheSetting::Use,
),
},
)
.await?;
Ok(ModuleCodeStringSource {
code: ModuleSourceCode::Bytes(file.source.into()),
found_url: file.url,
module_type: match requested_module_type {
RequestedModuleType::Text => ModuleType::Text,
RequestedModuleType::Bytes => ModuleType::Bytes,
_ => unreachable!(),
},
})
}
async fn maybe_reload_dynamic(
&self,
graph: &ModuleGraph,
@ -869,7 +938,10 @@ impl<TGraphContainer: ModuleGraphContainer>
self.has_module_changed_on_file_system(specifier, module.mtime())
}
deno_graph::ModuleEntryRef::Err(err) => {
if matches!(err, deno_graph::ModuleError::Missing { .. }) {
if matches!(
err.as_kind(),
deno_graph::ModuleErrorKind::Missing { .. }
) {
self.mtime_of_specifier(specifier).is_some() // it exists now
} else {
self.has_module_changed_on_file_system(specifier, err.mtime())
@ -955,7 +1027,10 @@ impl<TGraphContainer: ModuleGraphContainer>
&& !specifier.as_str().starts_with(jsr_url().as_str())
&& matches!(specifier.scheme(), "http" | "https")
{
return Err(JsErrorBox::generic(format!("Importing {} blocked. JSR packages cannot import non-JSR remote modules for security reasons.", specifier)));
return Err(JsErrorBox::generic(format!(
"Importing {} blocked. JSR packages cannot import non-JSR remote modules for security reasons.",
specifier
)));
}
Ok(())
}
@ -1012,255 +1087,6 @@ impl<TGraphContainer: ModuleGraphContainer>
Ok(specifier)
}
async fn load_prepared_module(
&self,
specifier: &ModuleSpecifier,
) -> Result<Option<ModuleCodeStringSource>, LoadPreparedModuleError> {
// Note: keep this in sync with the sync version below
let graph = self.graph_container.graph();
match self.load_prepared_module_or_defer_emit(&graph, specifier)? {
Some(CodeOrDeferredEmit::Code(code_source)) => Ok(Some(code_source)),
Some(CodeOrDeferredEmit::DeferredEmit {
specifier,
media_type,
source,
}) => {
let transpile_result = self
.emitter
.emit_parsed_source(specifier, media_type, ModuleKind::Esm, source)
.await?;
// at this point, we no longer need the parsed source in memory, so free it
self.parsed_source_cache.free(specifier);
Ok(Some(ModuleCodeStringSource {
// note: it's faster to provide a string if we know it's a string
code: ModuleSourceCode::String(transpile_result.into()),
found_url: specifier.clone(),
media_type,
}))
}
Some(CodeOrDeferredEmit::Cjs {
specifier,
media_type,
source,
}) => self
.load_maybe_cjs(specifier, media_type, source)
.await
.map(Some)
.map_err(LoadPreparedModuleError::LoadMaybeCjs),
None => Ok(None),
}
}
fn load_prepared_module_for_source_map_sync(
&self,
specifier: &ModuleSpecifier,
) -> Result<Option<ModuleCodeStringSource>, AnyError> {
// Note: keep this in sync with the async version above
let graph = self.graph_container.graph();
match self.load_prepared_module_or_defer_emit(&graph, specifier)? {
Some(CodeOrDeferredEmit::Code(code_source)) => Ok(Some(code_source)),
Some(CodeOrDeferredEmit::DeferredEmit {
specifier,
media_type,
source,
}) => {
let transpile_result = self.emitter.emit_parsed_source_sync(
specifier,
media_type,
ModuleKind::Esm,
source,
)?;
// at this point, we no longer need the parsed source in memory, so free it
self.parsed_source_cache.free(specifier);
Ok(Some(ModuleCodeStringSource {
// note: it's faster to provide a string if we know it's a string
code: ModuleSourceCode::String(transpile_result.into()),
found_url: specifier.clone(),
media_type,
}))
}
Some(CodeOrDeferredEmit::Cjs { .. }) => {
self.parsed_source_cache.free(specifier);
// todo(dsherret): to make this work, we should probably just
// rely on the CJS export cache. At the moment this is hard because
// cjs export analysis is only async
Ok(None)
}
None => Ok(None),
}
}
fn load_prepared_module_or_defer_emit<'graph>(
&self,
graph: &'graph ModuleGraph,
specifier: &ModuleSpecifier,
) -> Result<Option<CodeOrDeferredEmit<'graph>>, LoadPreparedModuleError> {
if specifier.scheme() == "node" {
// Node built-in modules should be handled internally.
unreachable!("Deno bug. {} was misconfigured internally.", specifier);
}
let maybe_module = graph.try_get(specifier).map_err(|err| {
Box::new(EnhancedGraphError {
message: enhance_graph_error(
&self.shared.sys,
&ModuleGraphError::ModuleError(err.clone()),
EnhanceGraphErrorMode::ShowRange,
),
error: err.clone(),
})
})?;
match maybe_module {
Some(deno_graph::Module::Json(JsonModule {
source,
media_type,
specifier,
..
})) => Ok(Some(CodeOrDeferredEmit::Code(ModuleCodeStringSource {
code: ModuleSourceCode::String(source.clone().into()),
found_url: specifier.clone(),
media_type: *media_type,
}))),
Some(deno_graph::Module::Js(JsModule {
source,
media_type,
specifier,
is_script,
..
})) => {
if self
.shared
.cjs_tracker
.is_cjs_with_known_is_script(specifier, *media_type, *is_script)
.map_err(JsErrorBox::from_err)?
{
return Ok(Some(CodeOrDeferredEmit::Cjs {
specifier,
media_type: *media_type,
source,
}));
}
let code: ModuleCodeString = match media_type {
MediaType::JavaScript
| MediaType::Unknown
| MediaType::Mjs
| MediaType::Json => source.clone().into(),
MediaType::Dts | MediaType::Dcts | MediaType::Dmts => {
Default::default()
}
MediaType::Cjs | MediaType::Cts => {
return Ok(Some(CodeOrDeferredEmit::Cjs {
specifier,
media_type: *media_type,
source,
}));
}
MediaType::TypeScript
| MediaType::Mts
| MediaType::Jsx
| MediaType::Tsx => {
return Ok(Some(CodeOrDeferredEmit::DeferredEmit {
specifier,
media_type: *media_type,
source,
}));
}
MediaType::Css
| MediaType::Html
| MediaType::Sql
| MediaType::Wasm
| MediaType::SourceMap => {
panic!("Unexpected media type {media_type} for {specifier}")
}
};
// at this point, we no longer need the parsed source in memory, so free it
self.parsed_source_cache.free(specifier);
Ok(Some(CodeOrDeferredEmit::Code(ModuleCodeStringSource {
code: ModuleSourceCode::String(code),
found_url: specifier.clone(),
media_type: *media_type,
})))
}
Some(deno_graph::Module::Wasm(WasmModule {
source, specifier, ..
})) => Ok(Some(CodeOrDeferredEmit::Code(ModuleCodeStringSource {
code: ModuleSourceCode::Bytes(source.clone().into()),
found_url: specifier.clone(),
media_type: MediaType::Wasm,
}))),
Some(
deno_graph::Module::External(_)
| deno_graph::Module::Node(_)
| deno_graph::Module::Npm(_),
)
| None => Ok(None),
}
}
async fn load_maybe_cjs(
&self,
specifier: &ModuleSpecifier,
media_type: MediaType,
original_source: &Arc<str>,
) -> Result<ModuleCodeStringSource, LoadMaybeCjsError> {
let js_source = if media_type.is_emittable() {
Cow::Owned(
self
.emitter
.emit_parsed_source(
specifier,
media_type,
ModuleKind::Cjs,
original_source,
)
.await?,
)
} else {
Cow::Borrowed(original_source.as_ref())
};
let text = self
.node_code_translator
.translate_cjs_to_esm(specifier, Some(js_source))
.await?;
// at this point, we no longer need the parsed source in memory, so free it
self.parsed_source_cache.free(specifier);
Ok(ModuleCodeStringSource {
code: match text {
// perf: if the text is borrowed, that means it didn't make any changes
// to the original source, so we can just provide that instead of cloning
// the borrowed text
Cow::Borrowed(_) => {
ModuleSourceCode::String(original_source.clone().into())
}
Cow::Owned(text) => ModuleSourceCode::String(text.into()),
},
found_url: specifier.clone(),
media_type,
})
}
}
enum CodeOrDeferredEmit<'a> {
Code(ModuleCodeStringSource),
DeferredEmit {
specifier: &'a ModuleSpecifier,
media_type: MediaType,
source: &'a Arc<str>,
},
Cjs {
specifier: &'a ModuleSpecifier,
media_type: MediaType,
source: &'a Arc<str>,
},
}
#[derive(Clone)]
@ -1330,7 +1156,7 @@ impl<TGraphContainer: ModuleGraphContainer> ModuleLoader
.load_inner(
&specifier,
maybe_referrer.as_ref(),
requested_module_type,
&requested_module_type,
)
.await
}
@ -1343,8 +1169,19 @@ impl<TGraphContainer: ModuleGraphContainer> ModuleLoader
specifier: &ModuleSpecifier,
_maybe_referrer: Option<String>,
is_dynamic: bool,
requested_module_type: RequestedModuleType,
) -> Pin<Box<dyn Future<Output = Result<(), ModuleLoaderError>>>> {
// always call this first unconditionally because it will be
// decremented unconditionally in "finish_load"
self.0.shared.in_flight_loads_tracker.increase();
if matches!(
requested_module_type,
RequestedModuleType::Text | RequestedModuleType::Bytes
) {
return Box::pin(deno_core::futures::future::ready(Ok(())));
}
if self.0.shared.in_npm_pkg_checker.in_npm_package(specifier) {
return Box::pin(deno_core::futures::future::ready(Ok(())));
}
@ -1480,11 +1317,14 @@ impl<TGraphContainer: ModuleGraphContainer> ModuleLoader
"wasm" | "file" | "http" | "https" | "data" | "blob" => (),
_ => return None,
}
let graph = self.0.graph_container.graph();
let source = self
.0
.load_prepared_module_for_source_map_sync(&specifier)
.shared
.prepared_module_loader
.load_prepared_module_for_source_map_sync(&graph, &specifier)
.ok()??;
source_map_from_code(source.code.as_bytes()).map(Cow::Owned)
source_map_from_code(source.source.as_bytes()).map(Cow::Owned)
}
fn get_source_mapped_source_line(
@ -1494,8 +1334,8 @@ impl<TGraphContainer: ModuleGraphContainer> ModuleLoader
) -> Option<String> {
let graph = self.0.graph_container.graph();
let code = match graph.get(&resolve_url(file_name).ok()?) {
Some(deno_graph::Module::Js(module)) => &module.source,
Some(deno_graph::Module::Json(module)) => &module.source,
Some(deno_graph::Module::Js(module)) => &module.source.text,
Some(deno_graph::Module::Json(module)) => &module.source.text,
_ => return None,
};
// Do NOT use .lines(): it skips the terminating empty line.
@ -1504,7 +1344,8 @@ impl<TGraphContainer: ModuleGraphContainer> ModuleLoader
if line_number >= lines.len() {
Some(format!(
"{} Couldn't format source line: Line {} is out of bounds (source may have changed at runtime)",
crate::colors::yellow("Warning"), line_number + 1,
crate::colors::yellow("Warning"),
line_number + 1,
))
} else {
Some(lines[line_number].to_string())
@ -1566,7 +1407,7 @@ impl ModuleGraphUpdatePermit for WorkerModuleGraphUpdatePermit {
#[derive(Debug)]
struct CliNodeRequireLoader<TGraphContainer: ModuleGraphContainer> {
cjs_tracker: Arc<CliCjsTracker>,
emitter: Arc<Emitter>,
emitter: Arc<CliEmitter>,
npm_resolver: CliNpmResolver,
sys: CliSys,
graph_container: TGraphContainer,
@ -1598,7 +1439,7 @@ impl<TGraphContainer: ModuleGraphContainer> NodeRequireLoader
fn load_text_file_lossy(
&self,
path: &Path,
) -> Result<Cow<'static, str>, JsErrorBox> {
) -> Result<FastString, JsErrorBox> {
// todo(dsherret): use the preloaded module from the graph if available?
let media_type = MediaType::from_path(path);
let text = self
@ -1613,9 +1454,9 @@ impl<TGraphContainer: ModuleGraphContainer> NodeRequireLoader
specifier,
}));
}
self
let text = self
.emitter
.emit_parsed_source_sync(
.maybe_emit_source_sync(
&specifier,
media_type,
// this is probably not super accurate due to require esm, but probably ok.
@ -1624,10 +1465,13 @@ impl<TGraphContainer: ModuleGraphContainer> NodeRequireLoader
ModuleKind::Cjs,
&text.into(),
)
.map(Cow::Owned)
.map_err(JsErrorBox::from_err)
.map_err(JsErrorBox::from_err)?;
Ok(text.into())
} else {
Ok(text)
Ok(match text {
Cow::Borrowed(s) => FastString::from_static(s),
Cow::Owned(s) => s.into(),
})
}
}
@ -1756,7 +1600,7 @@ mod tests {
let source = "const a = 'hello';";
let parsed_source_cache = Arc::new(ParsedSourceCache::default());
let parsed_source = parsed_source_cache
.remove_or_parse_module(&specifier, source.into(), MediaType::JavaScript)
.remove_or_parse_module(&specifier, MediaType::JavaScript, source.into())
.unwrap();
parsed_source_cache.set_parsed_source(specifier, parsed_source);

View file

@ -1,32 +1,15 @@
// Copyright 2018-2025 the Deno authors. MIT license.
use std::borrow::Cow;
use std::sync::Arc;
use deno_ast::MediaType;
use deno_ast::ModuleExportsAndReExports;
use deno_ast::ModuleSpecifier;
use deno_error::JsErrorBox;
use deno_graph::ast::ParsedSourceStore;
use deno_resolver::cjs::analyzer::DenoCjsCodeAnalyzer;
use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_runtime::deno_fs;
use node_resolver::analyze::CjsAnalysis as ExtNodeCjsAnalysis;
use node_resolver::analyze::CjsAnalysisExports;
use node_resolver::analyze::CjsCodeAnalyzer;
use node_resolver::analyze::CjsModuleExportAnalyzer;
use node_resolver::analyze::EsmAnalysisMode;
use node_resolver::analyze::NodeCodeTranslator;
use node_resolver::DenoIsBuiltInNodeModuleChecker;
use serde::Deserialize;
use serde::Serialize;
use node_resolver::analyze::CjsModuleExportAnalyzer;
use crate::cache::CacheDBHash;
use crate::cache::NodeAnalysisCache;
use crate::cache::ParsedSourceCache;
use crate::npm::CliNpmResolver;
use crate::resolver::CliCjsTracker;
use crate::sys::CliSys;
pub type CliCjsCodeAnalyzer = DenoCjsCodeAnalyzer<CliSys>;
pub type CliCjsModuleExportAnalyzer = CjsModuleExportAnalyzer<
CliCjsCodeAnalyzer,
DenoInNpmPackageChecker,
@ -34,187 +17,9 @@ pub type CliCjsModuleExportAnalyzer = CjsModuleExportAnalyzer<
CliNpmResolver,
CliSys,
>;
pub type CliNodeCodeTranslator = NodeCodeTranslator<
CliCjsCodeAnalyzer,
DenoInNpmPackageChecker,
DenoIsBuiltInNodeModuleChecker,
CliNpmResolver,
CliSys,
>;
pub type CliNodeResolver = deno_runtime::deno_node::NodeResolver<
DenoInNpmPackageChecker,
CliNpmResolver,
CliSys,
>;
pub type CliPackageJsonResolver = node_resolver::PackageJsonResolver<CliSys>;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum CliCjsAnalysis {
/// The module was found to be an ES module.
Esm,
/// The module was found to be an ES module and
/// it was analyzed for imports and exports.
EsmAnalysis(ModuleExportsAndReExports),
/// The module was CJS.
Cjs(ModuleExportsAndReExports),
}
pub struct CliCjsCodeAnalyzer {
cache: NodeAnalysisCache,
cjs_tracker: Arc<CliCjsTracker>,
fs: deno_fs::FileSystemRc,
parsed_source_cache: Option<Arc<ParsedSourceCache>>,
}
impl CliCjsCodeAnalyzer {
pub fn new(
cache: NodeAnalysisCache,
cjs_tracker: Arc<CliCjsTracker>,
fs: deno_fs::FileSystemRc,
parsed_source_cache: Option<Arc<ParsedSourceCache>>,
) -> Self {
Self {
cache,
cjs_tracker,
fs,
parsed_source_cache,
}
}
async fn inner_cjs_analysis(
&self,
specifier: &ModuleSpecifier,
source: &str,
esm_analysis_mode: EsmAnalysisMode,
) -> Result<CliCjsAnalysis, JsErrorBox> {
let source = source.strip_prefix('\u{FEFF}').unwrap_or(source); // strip BOM
let source_hash = CacheDBHash::from_hashable(source);
if let Some(analysis) =
self.cache.get_cjs_analysis(specifier.as_str(), source_hash)
{
return Ok(analysis);
}
let media_type = MediaType::from_specifier(specifier);
if media_type == MediaType::Json {
return Ok(CliCjsAnalysis::Cjs(Default::default()));
}
let cjs_tracker = self.cjs_tracker.clone();
let is_maybe_cjs = cjs_tracker
.is_maybe_cjs(specifier, media_type)
.map_err(JsErrorBox::from_err)?;
let analysis = if is_maybe_cjs
|| esm_analysis_mode == EsmAnalysisMode::SourceImportsAndExports
{
let maybe_parsed_source = self
.parsed_source_cache
.as_ref()
.and_then(|c| c.remove_parsed_source(specifier));
deno_core::unsync::spawn_blocking({
let specifier = specifier.clone();
let source: Arc<str> = source.into();
move || -> Result<_, JsErrorBox> {
let parsed_source = maybe_parsed_source
.map(Ok)
.unwrap_or_else(|| {
deno_ast::parse_program(deno_ast::ParseParams {
specifier,
text: source,
media_type,
capture_tokens: true,
scope_analysis: false,
maybe_syntax: None,
})
})
.map_err(JsErrorBox::from_err)?;
let is_script = is_maybe_cjs && parsed_source.compute_is_script();
let is_cjs = is_maybe_cjs
&& cjs_tracker
.is_cjs_with_known_is_script(
parsed_source.specifier(),
media_type,
is_script,
)
.map_err(JsErrorBox::from_err)?;
if is_cjs {
let analysis = parsed_source.analyze_cjs();
Ok(CliCjsAnalysis::Cjs(analysis))
} else {
match esm_analysis_mode {
EsmAnalysisMode::SourceOnly => Ok(CliCjsAnalysis::Esm),
EsmAnalysisMode::SourceImportsAndExports => {
Ok(CliCjsAnalysis::EsmAnalysis(
parsed_source.analyze_es_runtime_exports(),
))
}
}
}
}
})
.await
.unwrap()?
} else {
CliCjsAnalysis::Esm
};
self
.cache
.set_cjs_analysis(specifier.as_str(), source_hash, &analysis);
Ok(analysis)
}
}
#[async_trait::async_trait(?Send)]
impl CjsCodeAnalyzer for CliCjsCodeAnalyzer {
async fn analyze_cjs<'a>(
&self,
specifier: &ModuleSpecifier,
source: Option<Cow<'a, str>>,
esm_analysis_mode: EsmAnalysisMode,
) -> Result<ExtNodeCjsAnalysis<'a>, JsErrorBox> {
let source = match source {
Some(source) => source,
None => {
if let Ok(path) = specifier.to_file_path() {
if let Ok(source_from_file) =
self.fs.read_text_file_lossy_async(path, None).await
{
source_from_file
} else {
return Ok(ExtNodeCjsAnalysis::Cjs(CjsAnalysisExports {
exports: vec![],
reexports: vec![],
}));
}
} else {
return Ok(ExtNodeCjsAnalysis::Cjs(CjsAnalysisExports {
exports: vec![],
reexports: vec![],
}));
}
}
};
let analysis = self
.inner_cjs_analysis(specifier, &source, esm_analysis_mode)
.await?;
match analysis {
CliCjsAnalysis::Esm => Ok(ExtNodeCjsAnalysis::Esm(source, None)),
CliCjsAnalysis::EsmAnalysis(analysis) => Ok(ExtNodeCjsAnalysis::Esm(
source,
Some(CjsAnalysisExports {
exports: analysis.exports,
reexports: analysis.reexports,
}),
)),
CliCjsAnalysis::Cjs(analysis) => {
Ok(ExtNodeCjsAnalysis::Cjs(CjsAnalysisExports {
exports: analysis.exports,
reexports: analysis.reexports,
}))
}
}
}
}

View file

@ -12,23 +12,25 @@ use deno_core::serde_json;
use deno_core::url::Url;
use deno_error::JsErrorBox;
use deno_lib::version::DENO_VERSION_INFO;
use deno_npm::NpmResolutionPackage;
use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm::registry::NpmPackageInfo;
use deno_npm::resolution::NpmResolutionSnapshot;
use deno_npm::NpmResolutionPackage;
use deno_npm_cache::NpmCacheHttpClientBytesResponse;
use deno_npm_cache::NpmCacheHttpClientResponse;
use deno_npm_installer::lifecycle_scripts::is_broken_default_install_script;
use deno_npm_installer::lifecycle_scripts::LifecycleScriptsExecutor;
use deno_npm_installer::lifecycle_scripts::LifecycleScriptsExecutorOptions;
use deno_npm_installer::lifecycle_scripts::PackageWithScript;
use deno_npm_installer::lifecycle_scripts::LIFECYCLE_SCRIPTS_RUNNING_ENV_VAR;
use deno_npm_installer::BinEntries;
use deno_npm_installer::CachedNpmPackageExtraInfoProvider;
use deno_npm_installer::ExpectedExtraInfo;
use deno_npm_installer::lifecycle_scripts::LIFECYCLE_SCRIPTS_RUNNING_ENV_VAR;
use deno_npm_installer::lifecycle_scripts::LifecycleScriptsExecutor;
use deno_npm_installer::lifecycle_scripts::LifecycleScriptsExecutorOptions;
use deno_npm_installer::lifecycle_scripts::PackageWithScript;
use deno_npm_installer::lifecycle_scripts::is_broken_default_install_script;
use deno_resolver::npm::ByonmNpmResolverCreateOptions;
use deno_resolver::npm::ManagedNpmResolverRc;
use deno_runtime::deno_io::FromRawIoHandle;
use deno_semver::Version;
use deno_semver::VersionReq;
use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq;
use deno_task_shell::KillSignal;
@ -179,18 +181,8 @@ impl NpmFetchResolver {
let maybe_get_nv = || async {
let name = req.name.clone();
let package_info = self.package_info(&name).await?;
if let Some(dist_tag) = req.version_req.tag() {
let version = package_info.dist_tags.get(dist_tag)?.clone();
return Some(PackageNv { name, version });
}
// Find the first matching version of the package.
let mut versions = package_info.versions.keys().collect::<Vec<_>>();
versions.sort();
let version = versions
.into_iter()
.rev()
.find(|v| req.version_req.tag().is_none() && req.version_req.matches(v))
.cloned()?;
let version =
version_from_package_info(&package_info, &req.version_req)?.clone();
Some(PackageNv { name, version })
};
let nv = maybe_get_nv().await;
@ -233,6 +225,22 @@ impl NpmFetchResolver {
}
}
pub fn version_from_package_info<'a>(
package_info: &'a NpmPackageInfo,
version_req: &VersionReq,
) -> Option<&'a Version> {
if let Some(dist_tag) = version_req.tag() {
return package_info.dist_tags.get(dist_tag);
}
// Find the first matching version of the package.
let mut versions = package_info.versions.keys().collect::<Vec<_>>();
versions.sort();
versions
.into_iter()
.rev()
.find(|v| version_req.tag().is_none() && version_req.matches(v))
}
pub static NPM_CONFIG_USER_AGENT_ENV_VAR: &str = "npm_config_user_agent";
pub fn get_npm_config_user_agent() -> String {

View file

@ -3,10 +3,10 @@
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use deno_core::op2;
use deno_core::v8;
use deno_core::ModuleSpecifier;
use deno_core::OpState;
use deno_core::op2;
use deno_core::v8;
use deno_error::JsErrorBox;
use deno_runtime::deno_permissions::ChildPermissionsArg;
use deno_runtime::deno_permissions::PermissionsContainer;
@ -77,16 +77,19 @@ pub fn op_restore_test_permissions(
state: &mut OpState,
#[serde] token: Uuid,
) -> Result<(), JsErrorBox> {
if let Some(permissions_holder) = state.try_take::<PermissionsHolder>() {
if token != permissions_holder.0 {
panic!("restore test permissions token does not match the stored token");
}
match state.try_take::<PermissionsHolder>() {
Some(permissions_holder) => {
if token != permissions_holder.0 {
panic!(
"restore test permissions token does not match the stored token"
);
}
let permissions = permissions_holder.1;
state.put::<PermissionsContainer>(permissions);
Ok(())
} else {
Err(JsErrorBox::generic("no permissions to restore"))
let permissions = permissions_holder.1;
state.put::<PermissionsContainer>(permissions);
Ok(())
}
_ => Err(JsErrorBox::generic("no permissions to restore")),
}
}

View file

@ -8,11 +8,11 @@ use std::cell::RefCell;
use std::rc::Rc;
use std::sync::Arc;
use deno_core::OpState;
use deno_core::error::AnyError;
use deno_core::op2;
use deno_core::parking_lot::Mutex;
use deno_core::serde_json;
use deno_core::OpState;
use deno_error::JsErrorBox;
use jupyter_runtime::InputRequest;
use jupyter_runtime::JupyterMessage;
@ -329,7 +329,7 @@ pub fn op_jupyter_create_png_from_texture(
return Err(JsErrorBox::type_error(format!(
"Unsupported texture format '{}'",
texture.format.as_str()
)))
)));
}
};

View file

@ -6,8 +6,8 @@ use deno_ast::ParseDiagnostic;
use deno_ast::SourceRange;
use deno_ast::SourceTextInfo;
use deno_ast::SourceTextProvider;
use deno_core::op2;
use deno_core::OpState;
use deno_core::op2;
use deno_lint::diagnostic::LintDiagnostic;
use deno_lint::diagnostic::LintDiagnosticDetails;
use deno_lint::diagnostic::LintDiagnosticRange;
@ -236,7 +236,9 @@ struct LintReportFix {
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum LintReportError {
#[class(type)]
#[error("Invalid range [{start}, {end}], the source has a range of [0, {source_end}]")]
#[error(
"Invalid range [{start}, {end}], the source has a range of [0, {source_end}]"
)]
IncorrectRange {
start: usize,
end: usize,

View file

@ -3,10 +3,10 @@
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use deno_core::op2;
use deno_core::v8;
use deno_core::ModuleSpecifier;
use deno_core::OpState;
use deno_core::op2;
use deno_core::v8;
use deno_error::JsErrorBox;
use deno_runtime::deno_permissions::ChildPermissionsArg;
use deno_runtime::deno_permissions::PermissionsContainer;
@ -72,16 +72,19 @@ pub fn op_restore_test_permissions(
state: &mut OpState,
#[serde] token: Uuid,
) -> Result<(), JsErrorBox> {
if let Some(permissions_holder) = state.try_take::<PermissionsHolder>() {
if token != permissions_holder.0 {
panic!("restore test permissions token does not match the stored token");
}
match state.try_take::<PermissionsHolder>() {
Some(permissions_holder) => {
if token != permissions_holder.0 {
panic!(
"restore test permissions token does not match the stored token"
);
}
let permissions = permissions_holder.1;
state.put::<PermissionsContainer>(permissions);
Ok(())
} else {
Err(JsErrorBox::generic("no permissions to restore"))
let permissions = permissions_holder.1;
state.put::<PermissionsContainer>(permissions);
Ok(())
}
_ => Err(JsErrorBox::generic("no permissions to restore")),
}
}

View file

@ -2,7 +2,7 @@
[package]
name = "denort"
version = "2.3.7"
version = "2.4.0"
authors.workspace = true
default-run = "denort"
edition.workspace = true

View file

@ -8,34 +8,35 @@ use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use deno_core::anyhow::bail;
use deno_core::FastString;
use deno_core::ModuleCodeBytes;
use deno_core::ModuleSourceCode;
use deno_core::ModuleType;
use deno_core::anyhow::Context;
use deno_core::anyhow::bail;
use deno_core::error::AnyError;
use deno_core::serde_json;
use deno_core::url::Url;
use deno_core::FastString;
use deno_core::ModuleSourceCode;
use deno_core::ModuleType;
use deno_error::JsError;
use deno_error::JsErrorBox;
use deno_lib::standalone::binary::DenoRtDeserializable;
use deno_lib::standalone::binary::MAGIC_BYTES;
use deno_lib::standalone::binary::Metadata;
use deno_lib::standalone::binary::RemoteModuleEntry;
use deno_lib::standalone::binary::SpecifierDataStore;
use deno_lib::standalone::binary::SpecifierId;
use deno_lib::standalone::binary::MAGIC_BYTES;
use deno_lib::standalone::virtual_fs::VirtualDirectory;
use deno_lib::standalone::virtual_fs::VirtualDirectoryEntries;
use deno_media_type::MediaType;
use deno_npm::NpmPackageId;
use deno_npm::resolution::SerializedNpmResolutionSnapshot;
use deno_npm::resolution::SerializedNpmResolutionSnapshotPackage;
use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
use deno_npm::NpmPackageId;
use deno_runtime::deno_fs::FileSystem;
use deno_runtime::deno_fs::RealFs;
use deno_runtime::deno_io::fs::FsError;
use deno_semver::package::PackageReq;
use deno_semver::StackString;
use deno_semver::package::PackageReq;
use indexmap::IndexMap;
use thiserror::Error;
@ -348,12 +349,14 @@ impl StandaloneModules {
let mut transpiled = None;
let mut source_map = None;
let mut cjs_export_analysis = None;
let mut is_valid_utf8 = false;
let bytes = match self.vfs.file_entry(&path) {
Ok(entry) => {
let bytes = self
.vfs
.read_file_all(entry)
.map_err(JsErrorBox::from_err)?;
is_valid_utf8 = entry.is_valid_utf8;
transpiled = entry
.transpiled_offset
.and_then(|t| self.vfs.read_file_offset_with_len(t).ok());
@ -369,7 +372,7 @@ impl StandaloneModules {
match RealFs.read_file_sync(&path, None) {
Ok(bytes) => bytes,
Err(FsError::Io(err)) if err.kind() == ErrorKind::NotFound => {
return Ok(None)
return Ok(None);
}
Err(err) => return Err(JsErrorBox::from_err(err)),
}
@ -379,6 +382,7 @@ impl StandaloneModules {
Ok(Some(DenoCompileModuleData {
media_type: MediaType::from_specifier(specifier),
specifier,
is_valid_utf8,
data: bytes,
transpiled,
source_map,
@ -393,6 +397,7 @@ impl StandaloneModules {
pub struct DenoCompileModuleData<'a> {
pub specifier: &'a Url,
pub media_type: MediaType,
pub is_valid_utf8: bool,
pub data: Cow<'static, [u8]>,
pub transpiled: Option<Cow<'static, [u8]>>,
pub source_map: Option<Cow<'static, [u8]>>,
@ -401,12 +406,18 @@ pub struct DenoCompileModuleData<'a> {
impl<'a> DenoCompileModuleData<'a> {
pub fn into_parts(self) -> (&'a Url, ModuleType, DenoCompileModuleSource) {
fn into_string_unsafe(data: Cow<'static, [u8]>) -> DenoCompileModuleSource {
fn into_string_unsafe(
is_valid_utf8: bool,
data: Cow<'static, [u8]>,
) -> DenoCompileModuleSource {
match data {
Cow::Borrowed(d) => DenoCompileModuleSource::String(
// SAFETY: we know this is a valid utf8 string
unsafe { std::str::from_utf8_unchecked(d) },
),
Cow::Borrowed(d) if is_valid_utf8 => {
DenoCompileModuleSource::String(
// SAFETY: we know this is a valid utf8 string
unsafe { std::str::from_utf8_unchecked(d) },
)
}
Cow::Borrowed(_) => DenoCompileModuleSource::Bytes(data),
Cow::Owned(d) => DenoCompileModuleSource::Bytes(Cow::Owned(d)),
}
}
@ -423,8 +434,14 @@ impl<'a> DenoCompileModuleData<'a> {
| MediaType::Dts
| MediaType::Dmts
| MediaType::Dcts
| MediaType::Tsx => (ModuleType::JavaScript, into_string_unsafe(data)),
MediaType::Json => (ModuleType::Json, into_string_unsafe(data)),
| MediaType::Tsx => (
ModuleType::JavaScript,
into_string_unsafe(self.is_valid_utf8, data),
),
MediaType::Json => (
ModuleType::Json,
into_string_unsafe(self.is_valid_utf8, data),
),
MediaType::Wasm => {
(ModuleType::Wasm, DenoCompileModuleSource::Bytes(data))
}
@ -441,6 +458,7 @@ impl<'a> DenoCompileModuleData<'a> {
}
}
#[derive(Debug)]
pub enum DenoCompileModuleSource {
String(&'static str),
Bytes(Cow<'static, [u8]>),
@ -448,21 +466,28 @@ pub enum DenoCompileModuleSource {
impl DenoCompileModuleSource {
pub fn into_for_v8(self) -> ModuleSourceCode {
fn into_bytes(data: Cow<'static, [u8]>) -> ModuleSourceCode {
ModuleSourceCode::Bytes(match data {
Cow::Borrowed(d) => d.into(),
Cow::Owned(d) => d.into_boxed_slice().into(),
})
}
match self {
// todo(https://github.com/denoland/deno_core/pull/943): store whether
// the string is ascii or not ahead of time so we can avoid the is_ascii()
// check in FastString::from_static
Self::String(s) => ModuleSourceCode::String(FastString::from_static(s)),
Self::Bytes(b) => into_bytes(b),
Self::Bytes(b) => ModuleSourceCode::Bytes(module_source_into_bytes(b)),
}
}
pub fn into_bytes_for_v8(self) -> ModuleCodeBytes {
match self {
DenoCompileModuleSource::String(text) => text.as_bytes().into(),
DenoCompileModuleSource::Bytes(b) => module_source_into_bytes(b),
}
}
}
fn module_source_into_bytes(data: Cow<'static, [u8]>) -> ModuleCodeBytes {
match data {
Cow::Borrowed(d) => d.into(),
Cow::Owned(d) => d.into_boxed_slice().into(),
}
}
#[derive(Debug, Error, JsError)]
@ -558,6 +583,7 @@ impl RemoteModulesStore {
self.specifiers.get_specifier(specifier).unwrap()
},
media_type: entry.media_type,
is_valid_utf8: entry.is_valid_utf8,
data: handle_cow_ref(&entry.data),
transpiled: entry.maybe_transpiled.as_ref().map(handle_cow_ref),
source_map: entry.maybe_source_map.as_ref().map(handle_cow_ref),

View file

@ -461,12 +461,16 @@ mod test {
// first run
{
let code_cache = DenoCompileCodeCache::new(file_path.clone(), 1234);
assert!(code_cache
.get_sync(&url1, CodeCacheType::EsModule, 0)
.is_none());
assert!(code_cache
.get_sync(&url2, CodeCacheType::EsModule, 1)
.is_none());
assert!(
code_cache
.get_sync(&url1, CodeCacheType::EsModule, 0)
.is_none()
);
assert!(
code_cache
.get_sync(&url2, CodeCacheType::EsModule, 1)
.is_none()
);
assert!(code_cache.enabled());
code_cache.set_sync(url1.clone(), CodeCacheType::EsModule, 0, &[1, 2, 3]);
assert!(code_cache.enabled());
@ -494,12 +498,16 @@ mod test {
// new cache key first run
{
let code_cache = DenoCompileCodeCache::new(file_path.clone(), 54321);
assert!(code_cache
.get_sync(&url1, CodeCacheType::EsModule, 0)
.is_none());
assert!(code_cache
.get_sync(&url2, CodeCacheType::EsModule, 1)
.is_none());
assert!(
code_cache
.get_sync(&url1, CodeCacheType::EsModule, 0)
.is_none()
);
assert!(
code_cache
.get_sync(&url2, CodeCacheType::EsModule, 1)
.is_none()
);
code_cache.set_sync(url1.clone(), CodeCacheType::EsModule, 0, &[2, 2, 3]);
code_cache.set_sync(url2.clone(), CodeCacheType::EsModule, 1, &[3, 2, 3]);
}
@ -510,9 +518,11 @@ mod test {
.get_sync(&url1, CodeCacheType::EsModule, 0)
.unwrap();
assert_eq!(result1, vec![2, 2, 3]);
assert!(code_cache
.get_sync(&url2, CodeCacheType::EsModule, 5) // different hash will cause none
.is_none());
assert!(
code_cache
.get_sync(&url2, CodeCacheType::EsModule, 5) // different hash will cause none
.is_none()
);
}
}
}

View file

@ -39,11 +39,11 @@ use deno_runtime::deno_napi::DenoRtNativeAddonLoader;
use deno_runtime::deno_napi::DenoRtNativeAddonLoaderRc;
#[cfg(windows)]
use deno_subprocess_windows::Stdio as StdStdio;
use sys_traits::FsCopy;
use sys_traits::boxed::BoxedFsDirEntry;
use sys_traits::boxed::BoxedFsMetadataValue;
use sys_traits::boxed::FsMetadataBoxed;
use sys_traits::boxed::FsReadDirBoxed;
use sys_traits::FsCopy;
use url::Url;
#[derive(Debug, Clone)]
@ -195,6 +195,16 @@ impl FileSystem for DenoRtSys {
RealFs.chown_async(path, uid, gid).await
}
fn lchmod_sync(&self, path: &Path, mode: u32) -> FsResult<()> {
self.error_if_in_vfs(path)?;
RealFs.lchmod_sync(path, mode)
}
async fn lchmod_async(&self, path: PathBuf, mode: u32) -> FsResult<()> {
self.error_if_in_vfs(&path)?;
RealFs.lchmod_async(path, mode).await
}
fn lchown_sync(
&self,
path: &Path,
@ -1080,7 +1090,10 @@ impl FileBackedVfsFile {
if offset >= 0 {
*current_pos += offset as u64;
} else if -offset as u64 > *current_pos {
return Err(std::io::Error::new(std::io::ErrorKind::PermissionDenied, "An attempt was made to move the file pointer before the beginning of the file."));
return Err(std::io::Error::new(
std::io::ErrorKind::PermissionDenied,
"An attempt was made to move the file pointer before the beginning of the file.",
));
} else {
*current_pos -= -offset as u64;
}
@ -1397,7 +1410,7 @@ impl FileBackedVfs {
pub fn read_dir_with_metadata(
&self,
path: &Path,
) -> std::io::Result<impl Iterator<Item = FileBackedVfsDirEntry>> {
) -> std::io::Result<impl Iterator<Item = FileBackedVfsDirEntry> + use<>> {
let dir = self.dir_entry(path)?;
let path = path.to_path_buf();
Ok(
@ -1528,8 +1541,8 @@ mod test {
use std::io::Write;
use deno_lib::standalone::virtual_fs::VfsBuilder;
use test_util::assert_contains;
use test_util::TempDir;
use test_util::assert_contains;
use super::*;
@ -1763,10 +1776,7 @@ mod test {
file.read_to_buf(&mut buf).unwrap();
assert_eq!(buf, b"23");
assert_eq!(
file
.seek(SeekFrom::Current(-5))
.unwrap_err()
.to_string(),
file.seek(SeekFrom::Current(-5)).unwrap_err().to_string(),
"An attempt was made to move the file pointer before the beginning of the file."
);
// go beyond the file length, then back

View file

@ -60,7 +60,10 @@ fn unwrap_or_exit<T>(result: Result<T, AnyError>) -> T {
fn load_env_vars(env_vars: &IndexMap<String, String>) {
env_vars.iter().for_each(|env_var| {
if env::var(env_var.0).is_err() {
std::env::set_var(env_var.0, env_var.1);
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
std::env::set_var(env_var.0, env_var.1)
};
}
})
}

View file

@ -11,11 +11,11 @@ use deno_media_type::MediaType;
use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_resolver::npm::NpmReqResolver;
use deno_runtime::deno_fs::FileSystem;
use node_resolver::DenoIsBuiltInNodeModuleChecker;
use node_resolver::analyze::CjsAnalysis;
use node_resolver::analyze::CjsAnalysisExports;
use node_resolver::analyze::EsmAnalysisMode;
use node_resolver::analyze::NodeCodeTranslator;
use node_resolver::DenoIsBuiltInNodeModuleChecker;
use crate::binary::StandaloneModules;
use crate::file_system::DenoRtSys;

View file

@ -8,12 +8,6 @@ use std::sync::OnceLock;
use deno_cache_dir::npm::NpmCacheDir;
use deno_config::workspace::ResolverWorkspaceJsrPackage;
use deno_core::error::AnyError;
use deno_core::error::ModuleLoaderError;
use deno_core::futures::future::LocalBoxFuture;
use deno_core::futures::FutureExt;
use deno_core::url::Url;
use deno_core::v8_set_flags;
use deno_core::FastString;
use deno_core::ModuleLoader;
use deno_core::ModuleSourceCode;
@ -21,15 +15,21 @@ use deno_core::ModuleType;
use deno_core::RequestedModuleType;
use deno_core::ResolutionKind;
use deno_core::SourceCodeCacheInfo;
use deno_core::error::AnyError;
use deno_core::error::ModuleLoaderError;
use deno_core::futures::FutureExt;
use deno_core::futures::future::LocalBoxFuture;
use deno_core::url::Url;
use deno_core::v8_set_flags;
use deno_error::JsErrorBox;
use deno_lib::args::get_root_cert_store;
use deno_lib::args::npm_pkg_req_ref_to_binary_command;
use deno_lib::args::CaData;
use deno_lib::args::RootCertStoreLoadError;
use deno_lib::args::get_root_cert_store;
use deno_lib::args::npm_pkg_req_ref_to_binary_command;
use deno_lib::loader::NpmModuleLoader;
use deno_lib::npm::create_npm_process_state_provider;
use deno_lib::npm::NpmRegistryReadPermissionChecker;
use deno_lib::npm::NpmRegistryReadPermissionCheckerMode;
use deno_lib::npm::create_npm_process_state_provider;
use deno_lib::standalone::binary::NodeModules;
use deno_lib::util::hash::FastInsecureHasher;
use deno_lib::util::text_encoding::from_utf8_lossy_cow;
@ -44,11 +44,9 @@ use deno_media_type::MediaType;
use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm::resolution::NpmResolutionSnapshot;
use deno_package_json::PackageJsonDepValue;
use deno_resolver::DenoResolveErrorKind;
use deno_resolver::cjs::CjsTracker;
use deno_resolver::cjs::IsCjsResolutionMode;
use deno_resolver::npm::managed::ManagedInNpmPkgCheckerCreateOptions;
use deno_resolver::npm::managed::ManagedNpmResolverCreateOptions;
use deno_resolver::npm::managed::NpmResolutionCell;
use deno_resolver::npm::ByonmNpmResolverCreateOptions;
use deno_resolver::npm::CreateInNpmPkgCheckerOptions;
use deno_resolver::npm::DenoInNpmPackageChecker;
@ -56,35 +54,36 @@ use deno_resolver::npm::NpmReqResolver;
use deno_resolver::npm::NpmReqResolverOptions;
use deno_resolver::npm::NpmResolver;
use deno_resolver::npm::NpmResolverCreateOptions;
use deno_resolver::npm::managed::ManagedInNpmPkgCheckerCreateOptions;
use deno_resolver::npm::managed::ManagedNpmResolverCreateOptions;
use deno_resolver::npm::managed::NpmResolutionCell;
use deno_resolver::workspace::MappedResolution;
use deno_resolver::workspace::SloppyImportsOptions;
use deno_resolver::workspace::WorkspaceResolver;
use deno_resolver::DenoResolveErrorKind;
use deno_runtime::code_cache::CodeCache;
use deno_runtime::deno_fs::FileSystem;
use deno_runtime::deno_node::create_host_defined_options;
use deno_runtime::deno_node::NodeRequireLoader;
use deno_runtime::deno_permissions::Permissions;
use deno_runtime::deno_permissions::PermissionsContainer;
use deno_runtime::deno_permissions::UnstableSubdomainWildcards;
use deno_runtime::deno_tls::rustls::RootCertStore;
use deno_runtime::deno_tls::RootCertStoreProvider;
use deno_runtime::deno_web::BlobStore;
use deno_runtime::permissions::RuntimePermissionDescriptorParser;
use deno_runtime::FeatureChecker;
use deno_runtime::WorkerExecutionMode;
use deno_runtime::WorkerLogLevel;
use deno_runtime::code_cache::CodeCache;
use deno_runtime::deno_fs::FileSystem;
use deno_runtime::deno_node::NodeRequireLoader;
use deno_runtime::deno_node::create_host_defined_options;
use deno_runtime::deno_permissions::Permissions;
use deno_runtime::deno_permissions::PermissionsContainer;
use deno_runtime::deno_tls::RootCertStoreProvider;
use deno_runtime::deno_tls::rustls::RootCertStore;
use deno_runtime::deno_web::BlobStore;
use deno_runtime::permissions::RuntimePermissionDescriptorParser;
use deno_semver::npm::NpmPackageReqReference;
use node_resolver::analyze::CjsModuleExportAnalyzer;
use node_resolver::analyze::NodeCodeTranslator;
use node_resolver::cache::NodeResolutionSys;
use node_resolver::errors::ClosestPkgJsonError;
use node_resolver::DenoIsBuiltInNodeModuleChecker;
use node_resolver::NodeResolutionKind;
use node_resolver::NodeResolver;
use node_resolver::PackageJsonResolver;
use node_resolver::PackageJsonThreadLocalCache;
use node_resolver::ResolutionMode;
use node_resolver::analyze::CjsModuleExportAnalyzer;
use node_resolver::analyze::NodeCodeTranslator;
use node_resolver::cache::NodeResolutionSys;
use node_resolver::errors::ClosestPkgJsonError;
use crate::binary::DenoCompileModuleSource;
use crate::binary::StandaloneData;
@ -372,7 +371,7 @@ impl ModuleLoader for EmbeddedModuleLoader {
original_specifier: &Url,
maybe_referrer: Option<&Url>,
_is_dynamic: bool,
_requested_module_type: RequestedModuleType,
requested_module_type: RequestedModuleType,
) -> deno_core::ModuleLoadResponse {
if original_specifier.scheme() == "data" {
let data_url_text =
@ -412,10 +411,7 @@ impl ModuleLoader for EmbeddedModuleLoader {
code_source.code.as_bytes(),
);
Ok(deno_core::ModuleSource::new_with_redirect(
match code_source.media_type {
MediaType::Json => ModuleType::Json,
_ => ModuleType::JavaScript,
},
code_source.module_type,
code_source.code,
&original_specifier,
&code_source.found_url,
@ -428,6 +424,36 @@ impl ModuleLoader for EmbeddedModuleLoader {
match self.shared.modules.read(original_specifier) {
Ok(Some(module)) => {
match requested_module_type {
RequestedModuleType::Text | RequestedModuleType::Bytes => {
let module_source = DenoCompileModuleSource::Bytes(module.data);
return deno_core::ModuleLoadResponse::Sync(Ok(
deno_core::ModuleSource::new_with_redirect(
match requested_module_type {
RequestedModuleType::Text => ModuleType::Text,
RequestedModuleType::Bytes => ModuleType::Bytes,
_ => unreachable!(),
},
match requested_module_type {
RequestedModuleType::Text => module_source.into_for_v8(),
RequestedModuleType::Bytes => {
ModuleSourceCode::Bytes(module_source.into_bytes_for_v8())
}
_ => unreachable!(),
},
original_specifier,
module.specifier,
None,
),
));
}
RequestedModuleType::Other(_)
| RequestedModuleType::None
| RequestedModuleType::Json => {
// ignore
}
}
let media_type = module.media_type;
let (module_specifier, module_type, module_source) =
module.into_parts();
@ -552,7 +578,8 @@ impl ModuleLoader for EmbeddedModuleLoader {
if line_number >= lines.len() {
Some(format!(
"{} Couldn't format source line: Line {} is out of bounds (source may have changed at runtime)",
crate::colors::yellow("Warning"), line_number + 1,
crate::colors::yellow("Warning"),
line_number + 1,
))
} else {
Some(lines[line_number].to_string())
@ -581,7 +608,7 @@ impl NodeRequireLoader for EmbeddedModuleLoader {
fn load_text_file_lossy(
&self,
path: &std::path::Path,
) -> Result<Cow<'static, str>, JsErrorBox> {
) -> Result<FastString, JsErrorBox> {
let file_entry = self
.shared
.vfs
@ -594,7 +621,10 @@ impl NodeRequireLoader for EmbeddedModuleLoader {
file_entry.transpiled_offset.unwrap_or(file_entry.offset),
)
.map_err(JsErrorBox::from_err)?;
Ok(from_utf8_lossy_cow(file_bytes))
Ok(match from_utf8_lossy_cow(file_bytes) {
Cow::Borrowed(s) => FastString::from_static(s),
Cow::Owned(s) => s.into(),
})
}
fn is_maybe_cjs(&self, specifier: &Url) -> Result<bool, ClosestPkgJsonError> {
@ -933,14 +963,8 @@ pub async fn run(
}
}
let desc_parser = Arc::new(RuntimePermissionDescriptorParser::new(
sys.clone(),
if metadata.unstable_config.subdomain_wildcards {
UnstableSubdomainWildcards::Enabled
} else {
UnstableSubdomainWildcards::Disabled
},
));
let desc_parser =
Arc::new(RuntimePermissionDescriptorParser::new(sys.clone()));
let permissions =
Permissions::from_options(desc_parser.as_ref(), &permissions)?;
PermissionsContainer::new(desc_parser, permissions)
@ -984,6 +1008,7 @@ pub async fn run(
otel_config: metadata.otel_config,
no_legacy_abort: false,
startup_snapshot: deno_snapshots::CLI_SNAPSHOT,
enable_raw_imports: metadata.unstable_config.raw_imports,
tunnel: false,
};
let worker_factory = LibMainWorkerFactory::new(
@ -1033,6 +1058,8 @@ pub async fn run(
WorkerExecutionMode::Run,
permissions,
main_module,
// TODO(bartlomieju): support preload modules in `deno compile`
vec![],
)?;
let exit_code = worker.run().await?;

View file

@ -699,6 +699,7 @@
"kv",
"net",
"node-globals",
"raw-imports",
"sloppy-imports",
"temporal",
"unsafe-proto",

View file

@ -2,7 +2,7 @@
[package]
name = "deno_snapshots"
version = "0.23.0"
version = "0.24.0"
authors.workspace = true
edition.workspace = true
license.workspace = true

View file

@ -17,8 +17,8 @@ use deno_ast::MediaType;
use deno_ast::ModuleKind;
use deno_ast::ModuleSpecifier;
use deno_cache_dir::CACHE_PERM;
use deno_core::anyhow::bail;
use deno_core::anyhow::Context;
use deno_core::anyhow::bail;
use deno_core::error::AnyError;
use deno_core::serde_json;
use deno_core::url::Url;
@ -27,6 +27,7 @@ use deno_lib::args::CaData;
use deno_lib::args::UnstableConfig;
use deno_lib::shared::ReleaseChannel;
use deno_lib::standalone::binary::CjsExportAnalysisEntry;
use deno_lib::standalone::binary::MAGIC_BYTES;
use deno_lib::standalone::binary::Metadata;
use deno_lib::standalone::binary::NodeModules;
use deno_lib::standalone::binary::RemoteModuleEntry;
@ -35,33 +36,37 @@ use deno_lib::standalone::binary::SerializedWorkspaceResolver;
use deno_lib::standalone::binary::SerializedWorkspaceResolverImportMap;
use deno_lib::standalone::binary::SpecifierDataStore;
use deno_lib::standalone::binary::SpecifierId;
use deno_lib::standalone::binary::MAGIC_BYTES;
use deno_lib::standalone::virtual_fs::BuiltVfs;
use deno_lib::standalone::virtual_fs::DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME;
use deno_lib::standalone::virtual_fs::VfsBuilder;
use deno_lib::standalone::virtual_fs::VfsEntry;
use deno_lib::standalone::virtual_fs::VirtualDirectory;
use deno_lib::standalone::virtual_fs::VirtualDirectoryEntries;
use deno_lib::standalone::virtual_fs::WindowsSystemRootablePath;
use deno_lib::standalone::virtual_fs::DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME;
use deno_lib::util::hash::FastInsecureHasher;
use deno_lib::util::text_encoding::is_valid_utf8;
use deno_lib::util::v8::construct_v8_flags;
use deno_lib::version::DENO_VERSION_INFO;
use deno_npm::resolution::SerializedNpmResolutionSnapshot;
use deno_npm::NpmSystemInfo;
use deno_npm::resolution::SerializedNpmResolutionSnapshot;
use deno_path_util::fs::atomic_write_file_with_retries;
use deno_path_util::url_from_directory_path;
use deno_path_util::url_to_file_path;
use deno_resolver::file_fetcher::FetchLocalOptions;
use deno_resolver::file_fetcher::FetchOptions;
use deno_resolver::file_fetcher::FetchPermissionsOptionRef;
use deno_resolver::workspace::WorkspaceResolver;
use indexmap::IndexMap;
use node_resolver::analyze::ResolvedCjsAnalysis;
use super::virtual_fs::output_vfs;
use crate::args::get_default_v8_flags;
use crate::args::CliOptions;
use crate::args::CompileFlags;
use crate::args::get_default_v8_flags;
use crate::cache::DenoDir;
use crate::emit::Emitter;
use crate::file_fetcher::CliFileFetcher;
use crate::http_util::HttpClientProvider;
use crate::module_loader::CliEmitter;
use crate::node::CliCjsModuleExportAnalyzer;
use crate::npm::CliNpmResolver;
use crate::resolver::CliCjsTracker;
@ -196,7 +201,8 @@ pub struct DenoCompileBinaryWriter<'a> {
cjs_tracker: &'a CliCjsTracker,
cli_options: &'a CliOptions,
deno_dir: &'a DenoDir,
emitter: &'a Emitter,
emitter: &'a CliEmitter,
file_fetcher: &'a CliFileFetcher,
http_client_provider: &'a HttpClientProvider,
npm_resolver: &'a CliNpmResolver,
workspace_resolver: &'a WorkspaceResolver<CliSys>,
@ -210,7 +216,8 @@ impl<'a> DenoCompileBinaryWriter<'a> {
cjs_tracker: &'a CliCjsTracker,
cli_options: &'a CliOptions,
deno_dir: &'a DenoDir,
emitter: &'a Emitter,
emitter: &'a CliEmitter,
file_fetcher: &'a CliFileFetcher,
http_client_provider: &'a HttpClientProvider,
npm_resolver: &'a CliNpmResolver,
workspace_resolver: &'a WorkspaceResolver<CliSys>,
@ -222,6 +229,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
cli_options,
deno_dir,
emitter,
file_fetcher,
http_client_provider,
npm_resolver,
workspace_resolver,
@ -409,6 +417,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
let mut specifier_store = SpecifierStore::with_capacity(specifiers_count);
let mut remote_modules_store =
SpecifierDataStore::with_capacity(specifiers_count);
let mut asset_module_urls = graph.asset_module_urls();
// todo(dsherret): transpile and analyze CJS in parallel
for module in graph.modules() {
if module.specifier().scheme() == "data" {
@ -420,7 +429,10 @@ impl<'a> DenoCompileBinaryWriter<'a> {
let (maybe_original_source, media_type) = match module {
deno_graph::Module::Js(m) => {
let specifier = &m.specifier;
let original_bytes = m.source.as_bytes();
let original_bytes = match m.source.try_get_original_bytes() {
Some(bytes) => bytes,
None => self.load_asset_bypass_permissions(specifier).await?.source,
};
if self.cjs_tracker.is_maybe_cjs(specifier, m.media_type)? {
if self.cjs_tracker.is_cjs_with_known_is_script(
specifier,
@ -431,7 +443,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
.cjs_module_export_analyzer
.analyze_all_exports(
module.specifier(),
Some(Cow::Borrowed(m.source.as_ref())),
Some(Cow::Borrowed(m.source.text.as_ref())),
)
.await?;
maybe_cjs_analysis = Some(match cjs_analysis {
@ -452,13 +464,13 @@ impl<'a> DenoCompileBinaryWriter<'a> {
_ => ModuleKind::Esm,
};
let (source, source_map) =
self.emitter.emit_parsed_source_for_deno_compile(
self.emitter.emit_source_for_deno_compile(
&m.specifier,
m.media_type,
module_kind,
&m.source,
&m.source.text,
)?;
if source != m.source.as_ref() {
if source != m.source.text.as_ref() {
maybe_source_map = Some(source_map.into_bytes());
maybe_transpiled = Some(source.into_bytes());
}
@ -466,16 +478,26 @@ impl<'a> DenoCompileBinaryWriter<'a> {
(Some(original_bytes), m.media_type)
}
deno_graph::Module::Json(m) => {
(Some(m.source.as_bytes()), m.media_type)
let original_bytes = match m.source.try_get_original_bytes() {
Some(bytes) => bytes,
None => {
self
.load_asset_bypass_permissions(&m.specifier)
.await?
.source
}
};
(Some(original_bytes), m.media_type)
}
deno_graph::Module::Wasm(m) => {
(Some(m.source.as_ref()), MediaType::Wasm)
(Some(m.source.clone()), MediaType::Wasm)
}
deno_graph::Module::Npm(_)
| deno_graph::Module::Node(_)
| deno_graph::Module::External(_) => (None, MediaType::Unknown),
};
if let Some(original_source) = maybe_original_source {
asset_module_urls.swap_remove(module.specifier());
let maybe_cjs_export_analysis = maybe_cjs_analysis
.as_ref()
.map(bincode::serialize)
@ -505,7 +527,8 @@ impl<'a> DenoCompileBinaryWriter<'a> {
specifier_id,
RemoteModuleEntry {
media_type,
data: Cow::Borrowed(original_source),
is_valid_utf8: is_valid_utf8(&original_source),
data: Cow::Owned(original_source.to_vec()),
maybe_transpiled: maybe_transpiled.map(Cow::Owned),
maybe_source_map: maybe_source_map.map(Cow::Owned),
maybe_cjs_export_analysis: maybe_cjs_export_analysis
@ -516,6 +539,42 @@ impl<'a> DenoCompileBinaryWriter<'a> {
}
}
for url in asset_module_urls {
if graph.try_get(url).is_err() {
// skip because there was an error loading this module
continue;
}
match url.scheme() {
"file" => {
let file_path = deno_path_util::url_to_file_path(url)?;
vfs.add_file_at_path(&file_path)?;
}
"http" | "https" => {
let specifier_id = specifier_store.get_or_add(url);
if !remote_modules_store.contains(specifier_id) {
// it's ok to bypass permissions here because we verified the module
// loaded successfully in the graph
let file = self.load_asset_bypass_permissions(url).await?;
remote_modules_store.add(
specifier_id,
RemoteModuleEntry {
media_type: MediaType::from_specifier_and_headers(
&file.url,
file.maybe_headers.as_ref(),
),
is_valid_utf8: is_valid_utf8(&file.source),
data: Cow::Owned(file.source.to_vec()),
maybe_cjs_export_analysis: None,
maybe_source_map: None,
maybe_transpiled: None,
},
);
}
}
_ => {}
}
}
let mut redirects_store =
SpecifierDataStore::with_capacity(graph.redirects.len());
for (from, to) in &graph.redirects {
@ -638,7 +697,11 @@ impl<'a> DenoCompileBinaryWriter<'a> {
Some(env_filenames) => {
let mut aggregated_env_vars = IndexMap::new();
for env_filename in env_filenames.iter().rev() {
log::info!("{} Environment variables from the file \"{}\" were embedded in the generated executable file", crate::colors::yellow("Warning"), env_filename);
log::info!(
"{} Environment variables from the file \"{}\" were embedded in the generated executable file",
crate::colors::yellow("Warning"),
env_filename
);
let env_vars = get_file_env_vars(env_filename.to_string())?;
aggregated_env_vars.extend(env_vars);
@ -709,7 +772,6 @@ impl<'a> DenoCompileBinaryWriter<'a> {
node_modules,
unstable_config: UnstableConfig {
legacy_flag_enabled: false,
subdomain_wildcards: self.cli_options.unstable_subdomain_wildcards(),
bare_node_builtins: self.cli_options.unstable_bare_node_builtins(),
detect_cjs: self.cli_options.unstable_detect_cjs(),
features: self
@ -720,6 +782,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
.collect(),
lazy_dynamic_imports: self.cli_options.unstable_lazy_dynamic_imports(),
npm_lazy_caching: self.cli_options.unstable_npm_lazy_caching(),
raw_imports: self.cli_options.unstable_raw_imports(),
sloppy_imports: self.cli_options.unstable_sloppy_imports(),
},
otel_config: self.cli_options.otel_config(),
@ -756,10 +819,39 @@ impl<'a> DenoCompileBinaryWriter<'a> {
.context("Writing binary bytes")
}
async fn load_asset_bypass_permissions(
&self,
specifier: &ModuleSpecifier,
) -> Result<
deno_cache_dir::file_fetcher::File,
deno_resolver::file_fetcher::FetchError,
> {
self
.file_fetcher
.fetch_with_options(
specifier,
FetchPermissionsOptionRef::AllowAll,
FetchOptions {
local: FetchLocalOptions {
include_mtime: false,
},
maybe_auth: None,
maybe_accept: None,
maybe_cache_setting: Some(
&deno_cache_dir::file_fetcher::CacheSetting::Use,
),
},
)
.await
}
fn fill_npm_vfs(&self, builder: &mut VfsBuilder) -> Result<(), AnyError> {
fn maybe_warn_different_system(system_info: &NpmSystemInfo) {
if system_info != &NpmSystemInfo::default() {
log::warn!("{} The node_modules directory may be incompatible with the target system.", crate::colors::yellow("Warning"));
log::warn!(
"{} The node_modules directory may be incompatible with the target system.",
crate::colors::yellow("Warning")
);
}
}

View file

@ -5,6 +5,7 @@ use std::collections::HashSet;
use std::path::PathBuf;
use deno_lib::standalone::virtual_fs::BuiltVfs;
use deno_lib::standalone::virtual_fs::DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME;
use deno_lib::standalone::virtual_fs::OffsetWithLength;
use deno_lib::standalone::virtual_fs::VfsEntry;
use deno_lib::standalone::virtual_fs::VirtualDirectory;
@ -12,7 +13,6 @@ use deno_lib::standalone::virtual_fs::VirtualDirectoryEntries;
use deno_lib::standalone::virtual_fs::VirtualFile;
use deno_lib::standalone::virtual_fs::VirtualSymlinkParts;
use deno_lib::standalone::virtual_fs::WindowsSystemRootablePath;
use deno_lib::standalone::virtual_fs::DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME;
use deno_resolver::display::DisplayTreeNode;
use crate::util::display::human_size;

View file

@ -290,7 +290,6 @@ impl ShellCommand for NodeCommand {
"-A".into(),
"--unstable-bare-node-builtins".into(),
"--unstable-detect-cjs".into(),
"--unstable-node-globals".into(),
"--unstable-sloppy-imports".into(),
"--unstable-unsafe-proto".into(),
]);
@ -324,7 +323,10 @@ impl ShellCommand for NodeGypCommand {
.resolve_command_path(OsStr::new("node-gyp"))
.is_err()
{
log::warn!("{} node-gyp was used in a script, but was not listed as a dependency. Either add it as a dependency or install it globally (e.g. `npm install -g node-gyp`)", crate::colors::yellow("Warning"));
log::warn!(
"{} node-gyp was used in a script, but was not listed as a dependency. Either add it as a dependency or install it globally (e.g. `npm install -g node-gyp`)",
crate::colors::yellow("Warning")
);
}
ExecutableCommand::new(
"node-gyp".to_string(),
@ -342,25 +344,28 @@ impl ShellCommand for NpxCommand {
mut context: ShellCommandContext,
) -> LocalBoxFuture<'static, ExecuteResult> {
if let Some(first_arg) = context.args.first().cloned() {
if let Some(command) = context.state.resolve_custom_command(&first_arg) {
let context = ShellCommandContext {
args: context.args.into_iter().skip(1).collect::<Vec<_>>(),
..context
};
command.execute(context)
} else {
// can't find the command, so fallback to running the real npx command
let npx_path =
match context.state.resolve_command_path(OsStr::new("npx")) {
Ok(npx) => npx,
Err(err) => {
let _ = context.stderr.write_line(&format!("{}", err));
return Box::pin(std::future::ready(
ExecuteResult::from_exit_code(err.exit_code()),
));
}
match context.state.resolve_custom_command(&first_arg) {
Some(command) => {
let context = ShellCommandContext {
args: context.args.into_iter().skip(1).collect::<Vec<_>>(),
..context
};
ExecutableCommand::new("npx".to_string(), npx_path).execute(context)
command.execute(context)
}
_ => {
// can't find the command, so fallback to running the real npx command
let npx_path =
match context.state.resolve_command_path(OsStr::new("npx")) {
Ok(npx) => npx,
Err(err) => {
let _ = context.stderr.write_line(&format!("{}", err));
return Box::pin(std::future::ready(
ExecuteResult::from_exit_code(err.exit_code()),
));
}
};
ExecutableCommand::new("npx".to_string(), npx_path).execute(context)
}
}
} else {
let _ = context.stderr.write_line("npx: missing command");

View file

@ -6,33 +6,33 @@ use std::sync::Arc;
use std::time::Duration;
use deno_config::glob::WalkEntry;
use deno_core::ModuleSpecifier;
use deno_core::PollEventLoopOptions;
use deno_core::anyhow::anyhow;
use deno_core::error::AnyError;
use deno_core::error::CoreError;
use deno_core::error::JsError;
use deno_core::futures::StreamExt;
use deno_core::futures::future;
use deno_core::futures::stream;
use deno_core::futures::StreamExt;
use deno_core::serde_v8;
use deno_core::unsync::spawn;
use deno_core::unsync::spawn_blocking;
use deno_core::v8;
use deno_core::ModuleSpecifier;
use deno_core::PollEventLoopOptions;
use deno_error::JsErrorBox;
use deno_npm_installer::graph::NpmCachingStrategy;
use deno_runtime::WorkerExecutionMode;
use deno_runtime::deno_permissions::Permissions;
use deno_runtime::deno_permissions::PermissionsContainer;
use deno_runtime::permissions::RuntimePermissionDescriptorParser;
use deno_runtime::tokio_util::create_and_run_current_thread;
use deno_runtime::WorkerExecutionMode;
use indexmap::IndexMap;
use indexmap::IndexSet;
use log::Level;
use serde::Deserialize;
use serde::Serialize;
use tokio::sync::mpsc::unbounded_channel;
use tokio::sync::mpsc::UnboundedSender;
use tokio::sync::mpsc::unbounded_channel;
use crate::args::BenchFlags;
use crate::args::Flags;
@ -43,8 +43,8 @@ use crate::graph_container::CheckSpecifiersOptions;
use crate::graph_util::has_graph_root_local_dependent_changed;
use crate::ops;
use crate::sys::CliSys;
use crate::tools::test::format_test_error;
use crate::tools::test::TestFilter;
use crate::tools::test::format_test_error;
use crate::util::file_watcher;
use crate::util::fs::collect_specifiers;
use crate::util::path::is_script_ext;
@ -154,6 +154,7 @@ async fn bench_specifier(
worker_factory: Arc<CliMainWorkerFactory>,
permissions_container: PermissionsContainer,
specifier: ModuleSpecifier,
preload_modules: Vec<ModuleSpecifier>,
sender: UnboundedSender<BenchEvent>,
filter: TestFilter,
) -> Result<(), AnyError> {
@ -161,6 +162,7 @@ async fn bench_specifier(
worker_factory,
permissions_container,
specifier.clone(),
preload_modules,
&sender,
filter,
)
@ -183,6 +185,7 @@ async fn bench_specifier_inner(
worker_factory: Arc<CliMainWorkerFactory>,
permissions_container: PermissionsContainer,
specifier: ModuleSpecifier,
preload_modules: Vec<ModuleSpecifier>,
sender: &UnboundedSender<BenchEvent>,
filter: TestFilter,
) -> Result<(), CreateCustomWorkerError> {
@ -190,6 +193,7 @@ async fn bench_specifier_inner(
.create_custom_worker(
WorkerExecutionMode::Bench,
specifier.clone(),
preload_modules,
permissions_container,
vec![ops::bench::deno_bench::init(sender.clone())],
Default::default(),
@ -197,6 +201,7 @@ async fn bench_specifier_inner(
)
.await?;
worker.execute_preload_modules().await?;
// We execute the main module as a side module so that import.meta.main is not set.
worker.execute_side_module().await?;
@ -289,6 +294,7 @@ async fn bench_specifiers(
permissions: &Permissions,
permissions_desc_parser: &Arc<RuntimePermissionDescriptorParser<CliSys>>,
specifiers: Vec<ModuleSpecifier>,
preload_modules: Vec<ModuleSpecifier>,
options: BenchSpecifierOptions,
) -> Result<(), AnyError> {
let (sender, mut receiver) = unbounded_channel::<BenchEvent>();
@ -303,11 +309,13 @@ async fn bench_specifiers(
);
let sender = sender.clone();
let options = option_for_handles.clone();
let preload_modules = preload_modules.clone();
spawn_blocking(move || {
let future = bench_specifier(
worker_factory,
permissions_container,
specifier,
preload_modules,
sender,
options.filter,
);
@ -478,6 +486,7 @@ pub async fn run_benchmarks(
return Ok(());
}
let preload_modules = cli_options.preload_modules()?;
let log_level = cli_options.log_level();
let worker_factory =
Arc::new(factory.create_cli_main_worker_factory().await?);
@ -486,6 +495,7 @@ pub async fn run_benchmarks(
&permissions,
&permission_desc_parser,
specifiers,
preload_modules,
BenchSpecifierOptions {
filter: TestFilter::from_flag(&workspace_bench_options.filter),
json: workspace_bench_options.json,
@ -618,11 +628,13 @@ pub async fn run_benchmarks_with_watch(
}
let log_level = cli_options.log_level();
let preload_modules = cli_options.preload_modules()?;
bench_specifiers(
worker_factory,
&permissions,
&permission_desc_parser,
specifiers,
preload_modules,
BenchSpecifierOptions {
filter: TestFilter::from_flag(&workspace_bench_options.filter),
json: workspace_bench_options.json,

View file

@ -233,7 +233,13 @@ impl BenchReporter for ConsoleReporter {
);
if !stats.high_precision && stats.used_explicit_timers {
println!("{}", colors::yellow(format!("Warning: start() and end() calls in \"{}\" are ignored because it averages less\nthan 10µs per iteration. Remove them for better results.", &desc.name)));
println!(
"{}",
colors::yellow(format!(
"Warning: start() and end() calls in \"{}\" are ignored because it averages less\nthan 10µs per iteration. Remove them for better results.",
&desc.name
))
);
}
self.group_measurements.push((desc, stats.clone()));
@ -306,8 +312,12 @@ impl BenchReporter for ConsoleReporter {
colors::red_bold("error"),
format_test_error(&error, &TestFailureFormatOptions::default())
);
println!("This error was not caught from a benchmark and caused the bench runner to fail on the referenced module.");
println!("It most likely originated from a dangling promise, event/timeout handler or top-level code.");
println!(
"This error was not caught from a benchmark and caused the bench runner to fail on the referenced module."
);
println!(
"It most likely originated from a dangling promise, event/timeout handler or top-level code."
);
println!();
}
}

View file

@ -39,7 +39,7 @@ fn esbuild_platform() -> &'static str {
pub async fn ensure_esbuild(
deno_dir: &DenoDir,
npmrc: &ResolvedNpmRc,
npm_registry_info: &Arc<CliNpmRegistryInfoProvider>,
api: &Arc<CliNpmRegistryInfoProvider>,
workspace_link_packages: &Arc<WorkspaceNpmLinkPackages>,
tarball_cache: &Arc<TarballCache<CliNpmCacheHttpClient, CliSys>>,
npm_cache: &CliNpmCache,
@ -60,7 +60,6 @@ pub async fn ensure_esbuild(
let pkg_name = format!("@esbuild/{}", target);
let nv =
PackageNv::from_str(&format!("{}@{}", pkg_name, ESBUILD_VERSION)).unwrap();
let api = npm_registry_info.as_npm_registry_api();
let mut info = api.package_info(&pkg_name).await?;
let version_info = match info.version_info(&nv, &workspace_link_packages.0) {
Ok(version_info) => version_info,

View file

@ -4,40 +4,43 @@ mod esbuild;
mod externals;
mod transform;
use std::borrow::Cow;
use std::cell::RefCell;
use std::path::Path;
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::Arc;
use std::sync::LazyLock;
use std::time::Duration;
use deno_ast::EmitOptions;
use deno_ast::MediaType;
use deno_ast::ModuleSpecifier;
use deno_config::deno_json::TsTypeLib;
use deno_config::workspace::TsTypeLib;
use deno_core::RequestedModuleType;
use deno_core::error::AnyError;
use deno_core::futures::FutureExt as _;
use deno_core::resolve_url_or_path;
use deno_core::serde_json;
use deno_core::url::Url;
use deno_core::RequestedModuleType;
use deno_error::JsError;
use deno_graph::ModuleError;
use deno_graph::ModuleErrorKind;
use deno_graph::Position;
use deno_resolver::graph::ResolveWithGraphError;
use deno_resolver::graph::ResolveWithGraphOptions;
use deno_resolver::loader::LoadPreparedModuleError;
use deno_resolver::npm::managed::ResolvePkgFolderFromDenoModuleError;
use deno_runtime::deno_permissions::PermissionsContainer;
use deno_semver::npm::NpmPackageReqReference;
use esbuild_client::protocol;
use esbuild_client::protocol::BuildResponse;
use esbuild_client::EsbuildFlags;
use esbuild_client::EsbuildFlagsBuilder;
use esbuild_client::EsbuildService;
use esbuild_client::protocol;
use esbuild_client::protocol::BuildResponse;
use indexmap::IndexMap;
use node_resolver::errors::PackageSubpathResolveError;
use node_resolver::NodeResolutionKind;
use node_resolver::ResolutionMode;
use node_resolver::errors::PackageSubpathResolveError;
use sys_traits::EnvCurrentDir;
use crate::args::BundleFlags;
@ -51,10 +54,8 @@ use crate::graph_container::ModuleGraphContainer;
use crate::graph_container::ModuleGraphUpdatePermit;
use crate::module_loader::CliModuleLoader;
use crate::module_loader::CliModuleLoaderError;
use crate::module_loader::EnhancedGraphError;
use crate::module_loader::LoadCodeSourceError;
use crate::module_loader::LoadCodeSourceErrorKind;
use crate::module_loader::LoadPreparedModuleError;
use crate::module_loader::ModuleLoadPreparer;
use crate::module_loader::PrepareModuleLoadOptions;
use crate::node::CliNodeResolver;
@ -153,22 +154,18 @@ pub async fn bundle(
let response = bundler.build().await?;
if bundle_flags.watch {
return bundle_watch(flags, bundler).await;
return bundle_watch(flags, bundler, bundle_flags.minify).await;
}
handle_esbuild_errors_and_warnings(&response, &init_cwd);
if response.errors.is_empty() {
process_result(&response, *DISABLE_HACK)?;
let metafile = metafile_from_response(&response)?;
let output_infos =
process_result(&response, &init_cwd, *DISABLE_HACK, bundle_flags.minify)?;
if bundle_flags.output_dir.is_some() || bundle_flags.output_path.is_some() {
log::info!(
"{}",
deno_terminal::colors::green(format!(
"bundled in {}",
crate::display::human_elapsed(start.elapsed().as_millis()),
))
);
print_finished_message(&metafile, &output_infos, start.elapsed())?;
}
}
@ -179,9 +176,20 @@ pub async fn bundle(
Ok(())
}
fn metafile_from_response(
response: &BuildResponse,
) -> Result<esbuild_client::Metafile, AnyError> {
Ok(serde_json::from_str::<esbuild_client::Metafile>(
response.metafile.as_deref().ok_or_else(|| {
deno_core::anyhow::anyhow!("expected a metafile to be present")
})?,
)?)
}
async fn bundle_watch(
flags: Arc<Flags>,
bundler: EsbuildBundler,
minified: bool,
) -> Result<(), AnyError> {
let initial_roots = bundler
.roots
@ -218,14 +226,10 @@ async fn bundle_watch(
let response = bundler.rebuild().await?;
handle_esbuild_errors_and_warnings(&response, &bundler.cwd);
if response.errors.is_empty() {
process_result(&response, *DISABLE_HACK)?;
log::info!(
"{}",
deno_terminal::colors::green(format!(
"bundled in {}",
crate::display::human_elapsed(start.elapsed().as_millis()),
))
);
let metafile = metafile_from_response(&response)?;
let output_infos =
process_result(&response, &bundler.cwd, *DISABLE_HACK, minified)?;
print_finished_message(&metafile, &output_infos, start.elapsed())?;
let new_watched = get_input_paths_for_watch(&response);
*current_roots.borrow_mut() = new_watched.clone();
@ -360,8 +364,17 @@ impl EsbuildBundler {
// TODO(nathanwhit): MASSIVE HACK
// See tests::specs::bundle::requires_node_builtin for why this is needed.
// Without this hack, that test would fail with "Dynamic require of "util" is not supported"
fn replace_require_shim(contents: &str) -> String {
contents.replace(
fn replace_require_shim(contents: &str, minified: bool) -> String {
if minified {
let re = lazy_regex::regex!(
r#"var (\w+)\s*=\((\w+)\s*=>typeof require<"u"\?require:typeof Proxy<"u"\?new Proxy\((\w+)\,\{get:\(\w+,\w+\)=>\(typeof require<"u"\?require:\w+\)\[l\]\}\):(\w+)\)\(function\(\w+\)\{if\(typeof require<"u"\)return require\.apply\(this\,arguments\);throw Error\('Dynamic require of "'\+\w+\+'" is not supported'\)\}\);"#
);
re.replace(contents, |c: &regex::Captures<'_>| {
let var_name = c.get(1).unwrap().as_str();
format!("import{{createRequire}} from \"node:module\";var {var_name}=createRequire(import.meta.url);")
}).into_owned()
} else {
contents.replace(
r#"var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
}) : x)(function(x) {
@ -372,6 +385,7 @@ fn replace_require_shim(contents: &str) -> String {
var __require = createRequire(import.meta.url);
"#,
)
}
}
fn format_message(
@ -445,6 +459,8 @@ fn requested_type_from_map(
let type_ = map.get("type").map(|s| s.as_str());
match type_ {
Some("json") => RequestedModuleType::Json,
Some("bytes") => RequestedModuleType::Bytes,
Some("text") => RequestedModuleType::Text,
Some(other) => RequestedModuleType::Other(other.to_string().into()),
None => RequestedModuleType::None,
}
@ -536,7 +552,7 @@ impl esbuild_client::PluginHandler for DenoPluginHandler {
args: esbuild_client::OnLoadArgs,
) -> Result<Option<esbuild_client::OnLoadResult>, AnyError> {
let result = self
.bundle_load(&args.path, requested_type_from_map(&args.with))
.bundle_load(&args.path, &requested_type_from_map(&args.with))
.await;
let result = match result {
Ok(r) => r,
@ -636,16 +652,13 @@ impl BundleLoadError {
pub fn is_unsupported_media_type(&self) -> bool {
match self {
BundleLoadError::CliModuleLoader(
CliModuleLoaderError::LoadCodeSource(LoadCodeSourceError(ref e)),
CliModuleLoaderError::LoadCodeSource(LoadCodeSourceError(e)),
) => match &**e {
LoadCodeSourceErrorKind::LoadPreparedModule(
LoadPreparedModuleError::Graph(ref e),
LoadPreparedModuleError::Graph(e),
) => matches!(
&**e,
EnhancedGraphError {
error: ModuleError::UnsupportedMediaType { .. },
..
}
e.error.as_kind(),
ModuleErrorKind::UnsupportedMediaType { .. },
),
_ => false,
},
@ -729,7 +742,7 @@ impl DenoPluginHandler {
Position::new(0, 0),
ResolveWithGraphOptions {
mode: import_kind_to_resolution_mode(kind),
kind: NodeResolutionKind::Execution,
kind: NodeResolutionKind::Bundling,
maintain_npm_specifiers: false,
},
);
@ -778,7 +791,7 @@ impl DenoPluginHandler {
async fn bundle_load(
&self,
specifier: &str,
requested_type: RequestedModuleType,
requested_type: &RequestedModuleType,
) -> Result<Option<(Vec<u8>, esbuild_client::BuiltinLoader)>, BundleLoadError>
{
log::debug!(
@ -793,7 +806,19 @@ impl DenoPluginHandler {
Path::new(""), // should be absolute already, feels kind of hacky though
)?;
let (specifier, media_type, loader) =
if let Some((specifier, media_type, loader)) =
if let RequestedModuleType::Bytes = requested_type {
(
specifier,
MediaType::Unknown,
esbuild_client::BuiltinLoader::Binary,
)
} else if let RequestedModuleType::Text = requested_type {
(
specifier,
MediaType::Unknown,
esbuild_client::BuiltinLoader::Text,
)
} else if let Some((specifier, media_type, loader)) =
self.specifier_and_type_from_graph(&specifier)?
{
(specifier, media_type, loader)
@ -1028,19 +1053,20 @@ fn resolve_roots(
let mut roots = Vec::with_capacity(entrypoints.len());
for url in entrypoints {
let root = if let Ok(v) = NpmPackageReqReference::from_specifier(&url) {
let referrer =
ModuleSpecifier::from_directory_path(sys.env_current_dir().unwrap())
let root = match NpmPackageReqReference::from_specifier(&url) {
Ok(v) => {
let referrer =
ModuleSpecifier::from_directory_path(sys.env_current_dir().unwrap())
.unwrap();
let package_folder = npm_resolver
.resolve_pkg_folder_from_deno_module_req(v.req(), &referrer)
.unwrap();
let package_folder = npm_resolver
.resolve_pkg_folder_from_deno_module_req(v.req(), &referrer)
.unwrap();
let main_module = node_resolver
.resolve_binary_export(&package_folder, v.sub_path())
.unwrap();
Url::from_file_path(&main_module).unwrap()
} else {
url
let main_module = node_resolver
.resolve_binary_export(&package_folder, v.sub_path())
.unwrap();
Url::from_file_path(&main_module).unwrap()
}
_ => url,
};
roots.push(root)
}
@ -1076,7 +1102,7 @@ fn configure_esbuild_flags(bundle_flags: &BundleFlags) -> EsbuildFlags {
let mut builder = EsbuildFlagsBuilder::default();
builder
.bundle(bundle_flags.one_file)
.bundle(bundle_flags.inline_imports)
.minify(bundle_flags.minify)
.splitting(bundle_flags.code_splitting)
.external(bundle_flags.external.clone())
@ -1104,9 +1130,7 @@ fn configure_esbuild_flags(bundle_flags: &BundleFlags) -> EsbuildFlags {
} else if let Some(output_path) = bundle_flags.output_path.clone() {
builder.outfile(output_path);
}
if bundle_flags.watch {
builder.metafile(true);
}
builder.metafile(true);
match bundle_flags.platform {
crate::args::BundlePlatform::Browser => {
@ -1139,38 +1163,117 @@ fn handle_esbuild_errors_and_warnings(
}
}
fn is_js(path: &Path) -> bool {
if let Some(ext) = path.extension() {
matches!(
ext.to_string_lossy().as_ref(),
"js" | "mjs" | "cjs" | "jsx" | "ts" | "tsx" | "mts" | "cts" | "dts"
)
} else {
false
}
}
struct OutputFileInfo {
relative_path: PathBuf,
size: usize,
is_js: bool,
}
fn process_result(
response: &BuildResponse,
// init_cwd: &Path,
cwd: &Path,
should_replace_require_shim: bool,
) -> Result<(), AnyError> {
if let Some(output_files) = response.output_files.as_ref() {
let mut exists_cache = std::collections::HashSet::new();
for file in output_files.iter() {
minified: bool,
) -> Result<Vec<OutputFileInfo>, AnyError> {
let mut exists_cache = std::collections::HashSet::new();
let output_files = response
.output_files
.as_ref()
.map(Cow::Borrowed)
.unwrap_or_default();
let mut output_infos = Vec::new();
for file in output_files.iter() {
let path = Path::new(&file.path);
let relative_path =
pathdiff::diff_paths(path, cwd).unwrap_or_else(|| path.to_path_buf());
let is_js = is_js(path);
let bytes = if is_js || file.path.ends_with("<stdout>") {
let string = String::from_utf8(file.contents.clone())?;
let string = if should_replace_require_shim {
replace_require_shim(&string)
replace_require_shim(&string, minified)
} else {
string
};
Cow::Owned(string.into_bytes())
} else {
Cow::Borrowed(&file.contents)
};
if file.path == "<stdout>" {
crate::display::write_to_stdout_ignore_sigpipe(string.as_bytes())?;
continue;
}
let path = PathBuf::from(&file.path);
if let Some(parent) = path.parent() {
if !exists_cache.contains(parent) {
if !parent.exists() {
std::fs::create_dir_all(parent)?;
}
exists_cache.insert(parent.to_path_buf());
}
}
std::fs::write(&file.path, string)?;
if file.path.ends_with("<stdout>") {
crate::display::write_to_stdout_ignore_sigpipe(bytes.as_slice())?;
continue;
}
if let Some(parent) = path.parent() {
if !exists_cache.contains(parent) {
if !parent.exists() {
std::fs::create_dir_all(parent)?;
}
exists_cache.insert(parent.to_path_buf());
}
}
output_infos.push(OutputFileInfo {
relative_path,
size: bytes.len(),
is_js,
});
std::fs::write(path, bytes.as_ref())?;
}
Ok(output_infos)
}
fn print_finished_message(
metafile: &esbuild_client::Metafile,
output_infos: &[OutputFileInfo],
duration: Duration,
) -> Result<(), AnyError> {
let mut output = String::new();
output.push_str(&format!(
"{} {} module{} in {}",
deno_terminal::colors::green("Bundled"),
metafile.inputs.len(),
if metafile.inputs.len() == 1 { "" } else { "s" },
crate::display::human_elapsed(duration.as_millis()),
));
let longest = output_infos
.iter()
.map(|info| info.relative_path.to_string_lossy().len())
.max()
.unwrap_or(0);
for info in output_infos {
output.push_str(&format!(
"\n {} {}",
if info.is_js {
deno_terminal::colors::cyan(format!(
"{:<longest$}",
info.relative_path.display()
))
} else {
deno_terminal::colors::magenta(format!(
"{:<longest$}",
info.relative_path.display()
))
},
deno_terminal::colors::gray(
crate::display::human_size(info.size as f64,)
)
));
}
output.push('\n');
log::info!("{}", output);
Ok(())
}

View file

@ -9,12 +9,12 @@ use std::path::PathBuf;
use std::sync::Arc;
use deno_cache_dir::GlobalOrLocalHttpCache;
use deno_core::anyhow::bail;
use deno_core::anyhow::Context;
use deno_core::anyhow::bail;
use deno_core::error::AnyError;
use deno_core::url::Url;
use deno_graph::packages::PackageSpecifiers;
use deno_graph::ModuleGraph;
use deno_graph::packages::PackageSpecifiers;
use deno_npm_installer::graph::NpmCachingStrategy;
use sys_traits::FsCanonicalize;
use sys_traits::FsCreateDirAll;
@ -527,7 +527,7 @@ fn clean_node_modules(
"failed to clean node_modules directory at {}",
dir.display()
)
})
});
}
};
@ -646,22 +646,23 @@ fn remove_file(
}
state.files_removed += 1;
state.update_progress();
if let Err(e) = std::fs::remove_file(path)
match std::fs::remove_file(path)
.with_context(|| format!("Failed to remove file: {}", path.display()))
{
if cfg!(windows) {
if let Ok(meta) = path.symlink_metadata() {
if meta.is_symlink() {
std::fs::remove_dir(path).with_context(|| {
format!("Failed to remove symlink: {}", path.display())
})?;
return Ok(());
Err(e) => {
if cfg!(windows) {
if let Ok(meta) = path.symlink_metadata() {
if meta.is_symlink() {
std::fs::remove_dir(path).with_context(|| {
format!("Failed to remove symlink: {}", path.display())
})?;
return Ok(());
}
}
}
Err(e)
}
Err(e)
} else {
Ok(())
_ => Ok(()),
}
}

View file

@ -9,9 +9,9 @@ use std::sync::Arc;
use deno_ast::MediaType;
use deno_ast::ModuleSpecifier;
use deno_core::anyhow::Context;
use deno_core::anyhow::anyhow;
use deno_core::anyhow::bail;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::resolve_url_or_path;
use deno_graph::GraphKind;
@ -21,13 +21,12 @@ use deno_path_util::url_to_file_path;
use deno_terminal::colors;
use rand::Rng;
use super::installer::infer_name_from_url;
use super::installer::BinNameResolver;
use crate::args::CompileFlags;
use crate::args::Flags;
use crate::factory::CliFactory;
use crate::http_util::HttpClientProvider;
use crate::standalone::binary::is_standalone_binary;
use crate::standalone::binary::WriteBinOptions;
use crate::standalone::binary::is_standalone_binary;
pub async fn compile(
flags: Arc<Flags>,
@ -37,10 +36,10 @@ pub async fn compile(
let cli_options = factory.cli_options()?;
let module_graph_creator = factory.module_graph_creator().await?;
let binary_writer = factory.create_compile_binary_writer().await?;
let http_client = factory.http_client_provider();
let entrypoint = cli_options.resolve_main_module()?;
let bin_name_resolver = factory.bin_name_resolver()?;
let output_path = resolve_compile_executable_output_path(
http_client,
&bin_name_resolver,
&compile_flags,
cli_options.initial_cwd(),
)
@ -84,7 +83,7 @@ pub async fn compile(
temp_filename.push(format!(
".tmp-{}",
faster_hex::hex_encode(
&rand::thread_rng().gen::<[u8; 8]>(),
&rand::thread_rng().r#gen::<[u8; 8]>(),
&mut [0u8; 16]
)
.unwrap()
@ -163,12 +162,12 @@ pub async fn compile_eszip(
let factory = CliFactory::from_flags(flags);
let cli_options = factory.cli_options()?;
let module_graph_creator = factory.module_graph_creator().await?;
let parsed_source_cache = factory.parsed_source_cache();
let tsconfig_resolver = factory.tsconfig_resolver()?;
let http_client = factory.http_client_provider();
let parsed_source_cache = factory.parsed_source_cache()?;
let compiler_options_resolver = factory.compiler_options_resolver()?;
let bin_name_resolver = factory.bin_name_resolver()?;
let entrypoint = cli_options.resolve_main_module()?;
let mut output_path = resolve_compile_executable_output_path(
http_client,
&bin_name_resolver,
&compile_flags,
cli_options.initial_cwd(),
)
@ -204,8 +203,9 @@ pub async fn compile_eszip(
graph
};
let transpile_and_emit_options = tsconfig_resolver
.transpile_and_emit_options(cli_options.workspace().root_dir())?;
let transpile_and_emit_options = compiler_options_resolver
.for_specifier(cli_options.workspace().root_dir())
.transpile_options()?;
let transpile_options = transpile_and_emit_options.transpile.clone();
let emit_options = transpile_and_emit_options.emit.clone();
@ -307,13 +307,13 @@ fn validate_output_path(output_path: &Path) -> Result<(), AnyError> {
let output_base = &output_path.parent().unwrap();
if output_base.exists() && output_base.is_file() {
bail!(
concat!(
"Could not compile to file '{}' because its parent directory ",
"is an existing file. You can use the `--output <file-path>` flag to ",
"provide an alternative name.",
),
output_base.display(),
);
concat!(
"Could not compile to file '{}' because its parent directory ",
"is an existing file. You can use the `--output <file-path>` flag to ",
"provide an alternative name.",
),
output_base.display(),
);
}
std::fs::create_dir_all(output_base)?;
}
@ -420,7 +420,7 @@ fn get_module_roots_and_include_paths(
}
async fn resolve_compile_executable_output_path(
http_client_provider: &HttpClientProvider,
bin_name_resolver: &BinNameResolver<'_>,
compile_flags: &CompileFlags,
current_dir: &Path,
) -> Result<PathBuf, AnyError> {
@ -431,10 +431,10 @@ async fn resolve_compile_executable_output_path(
let mut output_path = if let Some(out) = output_flag.as_ref() {
let mut out_path = PathBuf::from(out);
if out.ends_with('/') || out.ends_with('\\') {
if let Some(infer_file_name) =
infer_name_from_url(http_client_provider, &module_specifier)
.await
.map(PathBuf::from)
if let Some(infer_file_name) = bin_name_resolver
.infer_name_from_url(&module_specifier)
.await
.map(PathBuf::from)
{
out_path = out_path.join(infer_file_name);
}
@ -447,7 +447,8 @@ async fn resolve_compile_executable_output_path(
};
if output_flag.is_none() {
output_path = infer_name_from_url(http_client_provider, &module_specifier)
output_path = bin_name_resolver
.infer_name_from_url(&module_specifier)
.await
.map(PathBuf::from)
}
@ -481,13 +482,18 @@ fn get_os_specific_filepath(
#[cfg(test)]
mod test {
use deno_npm::registry::TestNpmRegistryApi;
pub use super::*;
use crate::http_util::HttpClientProvider;
#[tokio::test]
async fn resolve_compile_executable_output_path_target_linux() {
let http_client = HttpClientProvider::new(None, None);
let npm_api = TestNpmRegistryApi::default();
let bin_name_resolver = BinNameResolver::new(&http_client, &npm_api);
let path = resolve_compile_executable_output_path(
&http_client,
&bin_name_resolver,
&CompileFlags {
source_file: "mod.ts".to_string(),
output: Some(String::from("./file")),
@ -513,8 +519,10 @@ mod test {
#[tokio::test]
async fn resolve_compile_executable_output_path_target_windows() {
let http_client = HttpClientProvider::new(None, None);
let npm_api = TestNpmRegistryApi::default();
let bin_name_resolver = BinNameResolver::new(&http_client, &npm_api);
let path = resolve_compile_executable_output_path(
&http_client,
&bin_name_resolver,
&CompileFlags {
source_file: "mod.ts".to_string(),
output: Some(String::from("./file")),

View file

@ -2,9 +2,9 @@
use std::collections::HashSet;
use deno_ast::swc::common::comments::CommentKind;
use deno_ast::MediaType;
use deno_ast::TextLines;
use deno_ast::swc::common::comments::CommentKind;
use deno_core::url::Url;
static COVERAGE_IGNORE_START_DIRECTIVE: &str = "deno-coverage-ignore-start";

View file

@ -209,7 +209,7 @@ impl<'a> Iterator for StartEventQueue<'a> {
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
let pending_offset: Option<usize> = match &self.pending {
Some(ref start_event) if !start_event.trees.is_empty() => {
Some(start_event) if !start_event.trees.is_empty() => {
Some(start_event.offset)
}
_ => None,
@ -299,7 +299,7 @@ fn merge_range_tree_children<'a>(
}
None => {
let mut open_range_end: usize = event.offset + 1;
for (_, ref tree) in &event.trees {
for (_, tree) in &event.trees {
open_range_end = if tree.end > open_range_end {
tree.end
} else {

View file

@ -15,14 +15,14 @@ use deno_config::glob::FileCollector;
use deno_config::glob::FilePatterns;
use deno_config::glob::PathOrPattern;
use deno_config::glob::PathOrPatternSet;
use deno_core::anyhow::anyhow;
use deno_core::LocalInspectorSession;
use deno_core::anyhow::Context;
use deno_core::anyhow::anyhow;
use deno_core::error::AnyError;
use deno_core::error::CoreError;
use deno_core::serde_json;
use deno_core::sourcemap::SourceMap;
use deno_core::url::Url;
use deno_core::LocalInspectorSession;
use deno_error::JsErrorBox;
use deno_resolver::npm::DenoInNpmPackageChecker;
use node_resolver::InNpmPackageChecker;
@ -579,6 +579,7 @@ fn filter_coverages(
|| e.url.starts_with("data:")
|| e.url.ends_with("__anonymous__")
|| e.url.ends_with("$deno$test.mjs")
|| e.url.ends_with("$deno$stdin.mts")
|| e.url.ends_with(".snap")
|| is_supported_test_path(Path::new(e.url.as_str()))
|| doc_test_re.is_match(e.url.as_str())

View file

@ -13,8 +13,8 @@ use deno_core::error::AnyError;
use deno_core::url::Url;
use deno_lib::version::DENO_VERSION_INFO;
use super::util;
use super::CoverageReport;
use super::util;
use crate::args::CoverageType;
use crate::colors;

View file

@ -7,24 +7,24 @@ use std::sync::Arc;
use deno_ast::diagnostics::Diagnostic;
use deno_config::glob::FilePatterns;
use deno_config::glob::PathOrPatternSet;
use deno_core::anyhow::bail;
use deno_core::anyhow::Context;
use deno_core::anyhow::bail;
use deno_core::error::AnyError;
use deno_core::serde_json;
use deno_doc as doc;
use deno_doc::html::UrlResolveKind;
use deno_doc::html::UsageComposer;
use deno_doc::html::UsageComposerEntry;
use deno_graph::analysis::ModuleAnalyzer;
use deno_graph::ast::EsParser;
use deno_graph::source::NullFileSystem;
use deno_graph::CheckJsOption;
use deno_graph::GraphKind;
use deno_graph::ModuleSpecifier;
use deno_graph::analysis::ModuleAnalyzer;
use deno_graph::ast::EsParser;
use deno_graph::source::NullFileSystem;
use deno_lib::version::DENO_VERSION_INFO;
use deno_npm_installer::graph::NpmCachingStrategy;
use doc::html::ShortPath;
use doc::DocDiagnostic;
use doc::html::ShortPath;
use indexmap::IndexMap;
use crate::args::DocFlags;
@ -34,9 +34,9 @@ use crate::args::Flags;
use crate::colors;
use crate::display;
use crate::factory::CliFactory;
use crate::graph_util::GraphWalkErrorsOptions;
use crate::graph_util::graph_exit_integrity_errors;
use crate::graph_util::graph_walk_errors;
use crate::graph_util::GraphWalkErrorsOptions;
use crate::sys::CliSys;
use crate::tsc::get_types_declaration_file_text;
use crate::util::fs::collect_specifiers;
@ -85,6 +85,8 @@ async fn generate_doc_nodes_for_builtin_types(
npm_resolver: None,
reporter: None,
resolver: None,
unstable_bytes_imports: false,
unstable_text_imports: false,
},
)
.await;
@ -107,7 +109,7 @@ pub async fn doc(
let factory = CliFactory::from_flags(flags);
let cli_options = factory.cli_options()?;
let module_info_cache = factory.module_info_cache()?;
let parsed_source_cache = factory.parsed_source_cache();
let parsed_source_cache = factory.parsed_source_cache()?;
let capturing_parser = parsed_source_cache.as_capturing_parser();
let analyzer = module_info_cache.as_module_analyzer();

View file

@ -9,29 +9,28 @@
use std::borrow::Cow;
use std::fs;
use std::io::stdin;
use std::io::stdout;
use std::io::Read;
use std::io::Write;
use std::io::stdin;
use std::io::stdout;
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use async_trait::async_trait;
use deno_ast::ParsedSource;
use deno_config::glob::FileCollector;
use deno_config::glob::FilePatterns;
use deno_core::anyhow::Context;
use deno_core::anyhow::anyhow;
use deno_core::anyhow::bail;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::futures;
use deno_core::parking_lot::Mutex;
use deno_core::unsync::spawn_blocking;
use deno_core::url::Url;
use deno_media_type::MediaType;
use log::debug;
use log::info;
use log::warn;
@ -301,7 +300,7 @@ fn format_markdown(
"css" | "scss" | "sass" | "less" => {
format_css(&fake_filename, text, fmt_options)
}
"html" => {
"html" | "svg" | "xml" => {
format_html(&fake_filename, text, fmt_options, unstable_options)
}
"svelte" | "vue" | "astro" | "vto" | "njk" => {
@ -538,15 +537,16 @@ pub fn format_html(
fn create_external_formatter_for_typescript(
unstable_options: &UnstableFmtOptions,
) -> impl Fn(
MediaType,
&str,
String,
&dprint_plugin_typescript::configuration::Configuration,
) -> deno_core::anyhow::Result<Option<String>> {
) -> deno_core::anyhow::Result<Option<String>>
+ use<> {
let unstable_sql = unstable_options.sql;
move |media_type, text, config| match media_type {
MediaType::Css => format_embedded_css(&text, config),
MediaType::Html => format_embedded_html(&text, config),
MediaType::Sql => {
move |lang, text, config| match lang {
"css" => format_embedded_css(&text, config),
"html" | "xml" | "svg" => format_embedded_html(lang, &text, config),
"sql" => {
if unstable_sql {
format_embedded_sql(&text, config)
} else {
@ -617,6 +617,8 @@ fn format_embedded_css(
selector_override_comment_directive: "malva-selector-override".into(),
ignore_comment_directive: "malva-ignore".into(),
ignore_file_comment_directive: "malva-ignore-file".into(),
declaration_order_group_by:
config::DeclarationOrderGroupBy::NonDeclaration,
},
};
// Wraps the text in a css block of `a { ... ;}`
@ -662,10 +664,17 @@ fn format_embedded_css(
/// Formats the embedded HTML code blocks in JavaScript and TypeScript.
fn format_embedded_html(
lang: &str,
text: &str,
config: &dprint_plugin_typescript::configuration::Configuration,
) -> deno_core::anyhow::Result<Option<String>> {
use markup_fmt::config;
let language = match lang {
"xml" | "svg" => markup_fmt::Language::Xml,
_ => markup_fmt::Language::Html,
};
let options = config::FormatOptions {
layout: config::LayoutOptions {
indent_width: config.indent_width as usize,
@ -725,12 +734,9 @@ fn format_embedded_html(
ignore_file_comment_directive: "deno-fmt-ignore-file".into(),
},
};
let text = markup_fmt::format_text(
text,
markup_fmt::Language::Html,
&options,
|code, _| Ok::<_, std::convert::Infallible>(code.into()),
)?;
let text = markup_fmt::format_text(text, language, &options, |code, _| {
Ok::<_, std::convert::Infallible>(code.into())
})?;
Ok(Some(text.to_string()))
}
@ -802,7 +808,7 @@ pub fn format_sql(
/// Formats a single TS, TSX, JS, JSX, JSONC, JSON, MD, IPYNB or SQL file.
pub fn format_file(
file_path: &Path,
file_text: &str,
file: &FileContents,
fmt_options: &FmtOptionsConfig,
unstable_options: &UnstableFmtOptions,
ext: Option<String>,
@ -811,34 +817,40 @@ pub fn format_file(
.or_else(|| get_extension(file_path))
.unwrap_or("ts".to_string());
match ext.as_str() {
let maybe_result = match ext.as_str() {
"md" | "mkd" | "mkdn" | "mdwn" | "mdown" | "markdown" => {
format_markdown(file_text, fmt_options, unstable_options)
format_markdown(&file.text, fmt_options, unstable_options)?
}
"json" | "jsonc" => format_json(file_path, file_text, fmt_options),
"json" | "jsonc" => format_json(file_path, &file.text, fmt_options)?,
"css" | "scss" | "sass" | "less" => {
format_css(file_path, file_text, fmt_options)
format_css(file_path, &file.text, fmt_options)?
}
"html" => format_html(file_path, file_text, fmt_options, unstable_options),
"svelte" | "vue" | "astro" | "vto" | "njk" => {
"html" | "xml" | "svg" => {
format_html(file_path, &file.text, fmt_options, unstable_options)?
}
"svelte" | "vue" | "astro" | "vto" | "njk" | "mustache" => {
if unstable_options.component {
format_html(file_path, file_text, fmt_options, unstable_options)
format_html(file_path, &file.text, fmt_options, unstable_options)?
} else {
Ok(None)
None
}
}
"yml" | "yaml" => format_yaml(file_text, fmt_options),
"yml" | "yaml" => format_yaml(&file.text, fmt_options)?,
"ipynb" => dprint_plugin_jupyter::format_text(
file_text,
&file.text,
|file_path: &Path, file_text: String| {
format_file(file_path, &file_text, fmt_options, unstable_options, None)
let file = FileContents {
had_bom: false,
text: file_text.into(),
};
format_file(file_path, &file, fmt_options, unstable_options, None)
},
),
)?,
"sql" => {
if unstable_options.sql {
format_sql(file_text, fmt_options)
format_sql(&file.text, fmt_options)?
} else {
Ok(None)
None
}
}
_ => {
@ -847,15 +859,24 @@ pub fn format_file(
dprint_plugin_typescript::FormatTextOptions {
path: file_path,
extension: Some(&ext),
text: file_text.to_string(),
text: file.text.to_string(),
config: &config,
external_formatter: Some(&create_external_formatter_for_typescript(
unstable_options,
)),
},
)
)?
}
}
};
Ok(match maybe_result {
Some(result) => Some(result),
None if file.had_bom => {
// return back the text without the BOM
Some(file.text.to_string())
}
None => None,
})
}
pub fn format_parsed_source(
@ -908,16 +929,18 @@ impl Formatter for CheckFormatter {
let checked_files_count = self.checked_files_count.clone();
move |file_path| {
checked_files_count.fetch_add(1, Ordering::Relaxed);
let file_text = read_file_contents(&file_path)?.text;
let file = read_file_contents(&file_path)?;
// skip checking the file if we know it's formatted
if incremental_cache.is_file_same(&file_path, &file_text) {
if !file.had_bom
&& incremental_cache.is_file_same(&file_path, &file.text)
{
return Ok(());
}
match format_file(
&file_path,
&file_text,
&file,
&fmt_options,
&unstable_options,
ext.clone(),
@ -926,9 +949,12 @@ impl Formatter for CheckFormatter {
not_formatted_files_count.fetch_add(1, Ordering::Relaxed);
let _g = output_lock.lock();
let diff =
deno_resolver::display::diff(&file_text, &formatted_text);
deno_resolver::display::diff(&file.text, &formatted_text);
info!("");
info!("{} {}:", colors::bold("from"), file_path.display());
if file.had_bom {
info!(" {}", colors::gray("File has strippable UTF-8 BOM."));
}
info!("{}", diff);
}
Ok(None) => {
@ -937,7 +963,7 @@ impl Formatter for CheckFormatter {
// formatting here. Additionally, ensure this is done during check
// so that CIs that cache the DENO_DIR will get the benefit of
// incremental formatting
incremental_cache.update_file(&file_path, &file_text);
incremental_cache.update_file(&file_path, &file.text);
}
Err(e) => {
not_formatted_files_count.fetch_add(1, Ordering::Relaxed);
@ -1010,41 +1036,33 @@ impl Formatter for RealFormatter {
let checked_files_count = self.checked_files_count.clone();
move |file_path| {
checked_files_count.fetch_add(1, Ordering::Relaxed);
let file_contents = read_file_contents(&file_path)?;
let file = read_file_contents(&file_path)?;
// skip formatting the file if we know it's formatted
if incremental_cache.is_file_same(&file_path, &file_contents.text) {
if !file.had_bom
&& incremental_cache.is_file_same(&file_path, &file.text)
{
return Ok(());
}
match format_ensure_stable(
&file_path,
&file_contents.text,
|file_path, file_text| {
format_file(
file_path,
file_text,
&fmt_options,
&unstable_options,
ext.clone(),
)
},
) {
match format_ensure_stable(&file_path, &file, |file_path, file| {
format_file(
file_path,
file,
&fmt_options,
&unstable_options,
ext.clone(),
)
}) {
Ok(Some(formatted_text)) => {
incremental_cache.update_file(&file_path, &formatted_text);
write_file_contents(
&file_path,
FileContents {
had_bom: file_contents.had_bom,
text: formatted_text,
},
)?;
write_file_contents(&file_path, &formatted_text)?;
formatted_files_count.fetch_add(1, Ordering::Relaxed);
let _g = output_lock.lock();
info!("{}", file_path.to_string_lossy());
}
Ok(None) => {
incremental_cache.update_file(&file_path, &file_contents.text);
incremental_cache.update_file(&file_path, &file.text);
}
Err(e) => {
failed_files_count.fetch_add(1, Ordering::Relaxed);
@ -1098,16 +1116,22 @@ impl Formatter for RealFormatter {
/// a user formats their code locally and it fails on the CI afterwards.
fn format_ensure_stable(
file_path: &Path,
file_text: &str,
fmt_func: impl Fn(&Path, &str) -> Result<Option<String>, AnyError>,
file: &FileContents,
fmt_func: impl Fn(&Path, &FileContents) -> Result<Option<String>, AnyError>,
) -> Result<Option<String>, AnyError> {
let formatted_text = fmt_func(file_path, file_text)?;
let formatted_text = fmt_func(file_path, file)?;
match formatted_text {
Some(mut current_text) => {
let mut count = 0;
loop {
match fmt_func(file_path, &current_text) {
match fmt_func(
file_path,
&FileContents {
had_bom: false,
text: (&current_text).into(),
},
) {
Ok(Some(next_pass_text)) => {
// just in case
if next_pass_text == current_text {
@ -1159,10 +1183,14 @@ fn format_stdin(
if stdin().read_to_string(&mut source).is_err() {
bail!("Failed to read from stdin");
}
let file = FileContents {
had_bom: false,
text: source.into(),
};
let file_path = PathBuf::from(format!("_stdin.{ext}"));
let formatted_text = format_file(
&file_path,
&source,
&file,
&fmt_options.options,
&fmt_options.unstable,
None,
@ -1173,17 +1201,18 @@ fn format_stdin(
println!("Not formatted stdin");
}
} else {
stdout().write_all(formatted_text.unwrap_or(source).as_bytes())?;
stdout().write_all(
formatted_text
.as_ref()
.map(|t| t.as_bytes())
.unwrap_or(file.text.as_bytes()),
)?;
}
Ok(())
}
fn files_str(len: usize) -> &'static str {
if len == 1 {
"file"
} else {
"files"
}
if len == 1 { "file" } else { "files" }
}
fn get_typescript_config_builder(
@ -1478,6 +1507,7 @@ fn get_resolved_malva_config(
selector_override_comment_directive: "deno-fmt-selector-override".into(),
ignore_comment_directive: "deno-fmt-ignore".into(),
ignore_file_comment_directive: "deno-fmt-ignore-file".into(),
declaration_order_group_by: DeclarationOrderGroupBy::NonDeclaration,
};
FormatOptions {
@ -1584,40 +1614,37 @@ fn get_resolved_yaml_config(
}
}
struct FileContents {
text: String,
had_bom: bool,
pub struct FileContents<'a> {
pub text: Cow<'a, str>,
pub had_bom: bool,
}
fn read_file_contents(file_path: &Path) -> Result<FileContents, AnyError> {
let file_bytes = fs::read(file_path)
.with_context(|| format!("Error reading {}", file_path.display()))?;
let had_bom = file_bytes.starts_with(&[0xEF, 0xBB, 0xBF]);
// will have the BOM stripped
let charset =
deno_media_type::encoding::detect_charset_local_file(&file_bytes);
let text =
deno_media_type::encoding::decode_owned_source(charset, file_bytes)
.with_context(|| {
anyhow!("{} is not a valid UTF-8 file", file_path.display())
})?;
let text = deno_media_type::encoding::decode_owned_source(
charset,
file_bytes.to_vec(),
)
.with_context(|| {
anyhow!("{} is not a valid UTF-8 file", file_path.display())
})?;
Ok(FileContents { text, had_bom })
Ok(FileContents {
text: Cow::Owned(text),
had_bom,
})
}
fn write_file_contents(
file_path: &Path,
mut file_contents: FileContents,
file_contents: &str,
) -> Result<(), AnyError> {
let file_text = if file_contents.had_bom {
// add back the BOM
file_contents.text.insert(0, '\u{FEFF}');
file_contents.text
} else {
file_contents.text
};
Ok(fs::write(file_path, file_text)?)
Ok(fs::write(file_path, file_contents)?)
}
pub async fn run_parallelized<F>(
@ -1656,10 +1683,9 @@ where
.and_then(|handle_result| handle_result.err())
});
if let Some(e) = errors.next() {
Err(e)
} else {
Ok(())
match errors.next() {
Some(e) => Err(e),
_ => Ok(()),
}
}
@ -1699,6 +1725,9 @@ fn is_supported_ext_fmt(path: &Path) -> bool {
| "yaml"
| "ipynb"
| "sql"
| "xml"
| "svg"
| "mustache"
)
})
}
@ -1768,11 +1797,15 @@ mod test {
#[test]
fn test_format_ensure_stable_unstable_format() {
let err =
format_ensure_stable(&PathBuf::from("mod.ts"), "1", |_, file_text| {
Ok(Some(format!("1{file_text}")))
})
.unwrap_err();
let err = format_ensure_stable(
&PathBuf::from("mod.ts"),
&FileContents {
had_bom: false,
text: "1".into(),
},
|_, file| Ok(Some(format!("1{}", file.text))),
)
.unwrap_err();
assert_starts_with!(
err.to_string(),
"Formatting not stable. Bailed after 5 tries."
@ -1781,9 +1814,14 @@ mod test {
#[test]
fn test_format_ensure_stable_error_first() {
let err = format_ensure_stable(&PathBuf::from("mod.ts"), "1", |_, _| {
bail!("Error formatting.")
})
let err = format_ensure_stable(
&PathBuf::from("mod.ts"),
&FileContents {
had_bom: false,
text: "1".into(),
},
|_, _| bail!("Error formatting."),
)
.unwrap_err();
assert_eq!(err.to_string(), "Error formatting.");
@ -1791,15 +1829,21 @@ mod test {
#[test]
fn test_format_ensure_stable_error_second() {
let err =
format_ensure_stable(&PathBuf::from("mod.ts"), "1", |_, file_text| {
if file_text == "1" {
let err = format_ensure_stable(
&PathBuf::from("mod.ts"),
&FileContents {
had_bom: false,
text: "1".into(),
},
|_, file| {
if file.text == "1" {
Ok(Some("11".to_string()))
} else {
bail!("Error formatting.")
}
})
.unwrap_err();
},
)
.unwrap_err();
assert_starts_with!(
err.to_string(),
"Formatting succeeded initially, but failed when"
@ -1808,17 +1852,23 @@ mod test {
#[test]
fn test_format_stable_after_two() {
let result =
format_ensure_stable(&PathBuf::from("mod.ts"), "1", |_, file_text| {
if file_text == "1" {
let result = format_ensure_stable(
&PathBuf::from("mod.ts"),
&FileContents {
had_bom: false,
text: "1".into(),
},
|_, file| {
if file.text == "1" {
Ok(Some("11".to_string()))
} else if file_text == "11" {
} else if file.text == "11" {
Ok(None)
} else {
unreachable!();
}
})
.unwrap();
},
)
.unwrap();
assert_eq!(result, Some("11".to_string()));
}
@ -1827,7 +1877,10 @@ mod test {
fn test_single_quote_true_prefers_single_quote() {
let file_text = format_file(
&PathBuf::from("test.ts"),
"console.log(\"there's\");\nconsole.log('hi');\nconsole.log(\"bye\")\n",
&FileContents {
had_bom: false,
text: "console.log(\"there's\");\nconsole.log('hi');\nconsole.log(\"bye\")\n".into(),
},
&FmtOptionsConfig {
single_quote: Some(true),
..Default::default()
@ -1843,4 +1896,24 @@ mod test {
"console.log(\"there's\");\nconsole.log('hi');\nconsole.log('bye');\n",
);
}
#[test]
fn test_formated_removes_utf8_bom() {
let file_text = format_file(
&PathBuf::from("test.ts"),
&FileContents {
had_bom: true,
text: "let a = 1;".into(),
},
&FmtOptionsConfig {
single_quote: Some(true),
..Default::default()
},
&UnstableFmtOptions::default(),
None,
)
.unwrap()
.unwrap();
assert_eq!(file_text, "let a = 1;\n",);
}
}

View file

@ -16,17 +16,18 @@ use deno_graph::Dependency;
use deno_graph::GraphKind;
use deno_graph::Module;
use deno_graph::ModuleError;
use deno_graph::ModuleErrorKind;
use deno_graph::ModuleGraph;
use deno_graph::Resolution;
use deno_lib::util::checksum;
use deno_lib::version::DENO_VERSION_INFO;
use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm::resolution::NpmResolutionSnapshot;
use deno_npm::NpmPackageId;
use deno_npm::NpmResolutionPackage;
use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm::resolution::NpmResolutionSnapshot;
use deno_npm_installer::graph::NpmCachingStrategy;
use deno_resolver::display::DisplayTreeNode;
use deno_resolver::DenoResolveErrorKind;
use deno_resolver::display::DisplayTreeNode;
use deno_semver::npm::NpmPackageNvReference;
use deno_semver::npm::NpmPackageReqReference;
use deno_semver::package::PackageNv;
@ -59,12 +60,12 @@ pub async fn info(
let cwd_url =
url::Url::from_directory_path(cli_options.initial_cwd()).unwrap();
let maybe_import_specifier = if let Ok(resolved) = resolver.resolve(
let maybe_import_specifier = match resolver.resolve(
&specifier,
&cwd_url,
deno_resolver::workspace::ResolutionKind::Execution,
) {
match resolved {
Ok(resolved) => match resolved {
deno_resolver::workspace::MappedResolution::Normal {
specifier,
..
@ -134,9 +135,8 @@ pub async fn info(
))?)
}
},
}
} else {
None
},
_ => None,
};
let specifier = match maybe_import_specifier {
@ -221,7 +221,7 @@ fn print_cache_info(
if let Some(location) = &location {
origin_dir =
origin_dir.join(checksum::gen(&[location.to_string().as_bytes()]));
origin_dir.join(checksum::r#gen(&[location.to_string().as_bytes()]));
}
let local_storage_dir = origin_dir.join("local_storage");
@ -550,7 +550,7 @@ impl<'a> GraphDisplayContext<'a> {
Ok(())
}
Err(err) => {
if let ModuleError::Missing { .. } = *err {
if let ModuleErrorKind::Missing { .. } = err.as_kind() {
bail!("module could not be found");
} else {
bail!("{:#}", err);
@ -700,11 +700,11 @@ impl<'a> GraphDisplayContext<'a> {
specifier: &ModuleSpecifier,
) -> DisplayTreeNode {
self.seen.insert(specifier.to_string());
match err {
ModuleError::InvalidTypeAssertion { .. } => {
match err.as_kind() {
ModuleErrorKind::InvalidTypeAssertion { .. } => {
self.build_error_msg(specifier, "(invalid import attribute)")
}
ModuleError::Load { err, .. } => {
ModuleErrorKind::Load { err, .. } => {
use deno_graph::ModuleLoadError::*;
let message = match err {
HttpsChecksumIntegrity(_) => "(checksum integrity error)",
@ -722,16 +722,17 @@ impl<'a> GraphDisplayContext<'a> {
};
self.build_error_msg(specifier, message.as_ref())
}
ModuleError::Parse { .. } | ModuleError::WasmParse { .. } => {
ModuleErrorKind::Parse { .. } | ModuleErrorKind::WasmParse { .. } => {
self.build_error_msg(specifier, "(parsing error)")
}
ModuleError::UnsupportedImportAttributeType { .. } => {
ModuleErrorKind::UnsupportedImportAttributeType { .. } => {
self.build_error_msg(specifier, "(unsupported import attribute)")
}
ModuleError::UnsupportedMediaType { .. } => {
ModuleErrorKind::UnsupportedMediaType { .. } => {
self.build_error_msg(specifier, "(unsupported)")
}
ModuleError::Missing { .. } | ModuleError::MissingDynamic { .. } => {
ModuleErrorKind::Missing { .. }
| ModuleErrorKind::MissingDynamic { .. } => {
self.build_error_msg(specifier, "(missing)")
}
}

View file

@ -299,13 +299,22 @@ async fn init_npm(name: &str, args: Vec<String>) -> Result<i32, AnyError> {
let script_name = npm_name_to_create_package(name);
fn print_manual_usage(script_name: &str, args: &[String]) -> i32 {
log::info!("{}", cformat!("You can initialize project manually by running <u>deno run {} {}</> and applying desired permissions.", script_name, args.join(" ")));
log::info!(
"{}",
cformat!(
"You can initialize project manually by running <u>deno run {} {}</> and applying desired permissions.",
script_name,
args.join(" ")
)
);
1
}
if std::io::stdin().is_terminal() {
log::info!(
cstr!("⚠️ Do you fully trust <y>{}</> package? Deno will invoke code from it with all permissions. Do you want to continue? <p(245)>[y/n]</>"),
cstr!(
"⚠️ Do you fully trust <y>{}</> package? Deno will invoke code from it with all permissions. Do you want to continue? <p(245)>[y/n]</>"
),
script_name
);
loop {

View file

@ -0,0 +1,308 @@
// Copyright 2018-2025 the Deno authors. MIT license.
use std::path::PathBuf;
use deno_core::error::AnyError;
use deno_core::url::Url;
use deno_npm::registry::NpmPackageInfo;
use deno_npm::registry::NpmRegistryApi;
use deno_semver::npm::NpmPackageReqReference;
use crate::http_util::HttpClientProvider;
pub struct BinNameResolver<'a> {
http_client_provider: &'a HttpClientProvider,
npm_registry_api: &'a dyn NpmRegistryApi,
}
impl<'a> BinNameResolver<'a> {
pub fn new(
http_client_provider: &'a HttpClientProvider,
npm_registry_api: &'a dyn NpmRegistryApi,
) -> Self {
Self {
http_client_provider,
npm_registry_api,
}
}
pub async fn infer_name_from_url(&self, url: &Url) -> Option<String> {
// If there's an absolute url with no path, eg. https://my-cli.com
// perform a request, and see if it redirects another file instead.
let mut url = url.clone();
if matches!(url.scheme(), "http" | "https") && url.path() == "/" {
if let Ok(client) = self.http_client_provider.get_or_create() {
if let Ok(redirected_url) = client
.get_redirected_url(url.clone(), &Default::default())
.await
{
url = redirected_url;
}
}
}
if let Ok(npm_ref) = NpmPackageReqReference::from_specifier(&url) {
if let Some(sub_path) = npm_ref.sub_path() {
if !sub_path.contains('/') {
return Some(sub_path.to_string());
}
}
match self.resolve_name_from_npm(&npm_ref).await {
Ok(Some(value)) => return Some(value),
Ok(None) => {}
Err(err) => {
log::warn!(
"{} Failed resolving npm specifier information. {:#}",
deno_runtime::colors::yellow("Warning"),
err
);
}
}
if !npm_ref.req().name.contains('/') {
return Some(npm_ref.into_inner().req.name.into_string());
}
if let Some(scope_and_pkg) = npm_ref.req().name.strip_prefix('@') {
if let Some((scope, package)) = scope_and_pkg.split_once('/') {
if package == "cli" {
return Some(scope.to_string());
}
}
}
return None;
}
let percent_decode =
percent_encoding::percent_decode(url.path().as_bytes());
#[cfg(unix)]
let path = {
use std::os::unix::prelude::OsStringExt;
PathBuf::from(std::ffi::OsString::from_vec(
percent_decode.collect::<Vec<u8>>(),
))
};
#[cfg(windows)]
let path = PathBuf::from(percent_decode.decode_utf8_lossy().as_ref());
let mut stem = path.file_stem()?.to_string_lossy();
if matches!(stem.as_ref(), "main" | "mod" | "index" | "cli") {
if let Some(parent_name) = path.parent().and_then(|p| p.file_name()) {
stem = parent_name.to_string_lossy();
}
}
// if atmark symbol appears in the index other than 0 (e.g. `foo@bar`) we use
// the former part as the inferred name because the latter part is most likely
// a version number.
match stem.find('@') {
Some(at_index) if at_index > 0 => {
stem = stem.split_at(at_index).0.to_string().into();
}
_ => {}
}
Some(stem.to_string())
}
async fn resolve_name_from_npm(
&self,
npm_ref: &NpmPackageReqReference,
) -> Result<Option<String>, AnyError> {
let package_info = self
.npm_registry_api
.package_info(&npm_ref.req().name)
.await?;
Ok(self.resolve_name_from_npm_package_info(&package_info, npm_ref))
}
fn resolve_name_from_npm_package_info(
&self,
package_info: &NpmPackageInfo,
npm_ref: &NpmPackageReqReference,
) -> Option<String> {
let version = crate::npm::version_from_package_info(
package_info,
&npm_ref.req().version_req,
)?;
let version_info = package_info.versions.get(version)?;
let bin_entries = version_info.bin.as_ref()?;
match bin_entries {
deno_npm::registry::NpmPackageVersionBinEntry::String(_) => {}
deno_npm::registry::NpmPackageVersionBinEntry::Map(data) => {
if data.len() == 1 {
return Some(data.keys().next().unwrap().clone());
}
}
}
None
}
}
#[cfg(test)]
mod test {
use std::collections::HashMap;
use deno_core::url::Url;
use deno_npm::registry::TestNpmRegistryApi;
use super::BinNameResolver;
use crate::http_util::HttpClientProvider;
async fn infer_name_from_url(url: &Url) -> Option<String> {
let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
let http_client = HttpClientProvider::new(None, None);
let registry_api = TestNpmRegistryApi::default();
registry_api.with_version_info(("@google/gemini-cli", "1.0.0"), |info| {
info.bin = Some(deno_npm::registry::NpmPackageVersionBinEntry::Map(
HashMap::from([("gemini".to_string(), "./bin.js".to_string())]),
))
});
let resolver = BinNameResolver::new(&http_client, &registry_api);
resolver.infer_name_from_url(url).await
}
#[tokio::test]
async fn install_infer_name_from_url() {
assert_eq!(
infer_name_from_url(
&Url::parse("https://example.com/abc/server.ts").unwrap()
)
.await,
Some("server".to_string())
);
assert_eq!(
infer_name_from_url(
&Url::parse("https://example.com/abc/main.ts").unwrap()
)
.await,
Some("abc".to_string())
);
assert_eq!(
infer_name_from_url(
&Url::parse("https://example.com/abc/mod.ts").unwrap()
)
.await,
Some("abc".to_string())
);
assert_eq!(
infer_name_from_url(
&Url::parse("https://example.com/ab%20c/mod.ts").unwrap()
)
.await,
Some("ab c".to_string())
);
assert_eq!(
infer_name_from_url(
&Url::parse("https://example.com/abc/index.ts").unwrap()
)
.await,
Some("abc".to_string())
);
assert_eq!(
infer_name_from_url(
&Url::parse("https://example.com/abc/cli.ts").unwrap()
)
.await,
Some("abc".to_string())
);
assert_eq!(
infer_name_from_url(&Url::parse("https://example.com/main.ts").unwrap())
.await,
Some("main".to_string())
);
assert_eq!(
infer_name_from_url(&Url::parse("https://example.com").unwrap()).await,
None
);
assert_eq!(
infer_name_from_url(&Url::parse("file:///abc/server.ts").unwrap()).await,
Some("server".to_string())
);
assert_eq!(
infer_name_from_url(&Url::parse("file:///abc/main.ts").unwrap()).await,
Some("abc".to_string())
);
assert_eq!(
infer_name_from_url(&Url::parse("file:///ab%20c/main.ts").unwrap()).await,
Some("ab c".to_string())
);
assert_eq!(
infer_name_from_url(&Url::parse("file:///main.ts").unwrap()).await,
Some("main".to_string())
);
assert_eq!(
infer_name_from_url(&Url::parse("file:///").unwrap()).await,
None
);
assert_eq!(
infer_name_from_url(
&Url::parse("https://example.com/abc@0.1.0").unwrap()
)
.await,
Some("abc".to_string())
);
assert_eq!(
infer_name_from_url(
&Url::parse("https://example.com/abc@0.1.0/main.ts").unwrap()
)
.await,
Some("abc".to_string())
);
assert_eq!(
infer_name_from_url(
&Url::parse("https://example.com/abc@def@ghi").unwrap()
)
.await,
Some("abc".to_string())
);
assert_eq!(
infer_name_from_url(&Url::parse("https://example.com/@abc.ts").unwrap())
.await,
Some("@abc".to_string())
);
assert_eq!(
infer_name_from_url(
&Url::parse("https://example.com/@abc/mod.ts").unwrap()
)
.await,
Some("@abc".to_string())
);
assert_eq!(
infer_name_from_url(&Url::parse("file:///@abc.ts").unwrap()).await,
Some("@abc".to_string())
);
assert_eq!(
infer_name_from_url(&Url::parse("file:///@abc/cli.ts").unwrap()).await,
Some("@abc".to_string())
);
assert_eq!(
infer_name_from_url(&Url::parse("npm:cowsay@1.2/cowthink").unwrap())
.await,
Some("cowthink".to_string())
);
assert_eq!(
infer_name_from_url(&Url::parse("npm:cowsay@1.2/cowthink/test").unwrap())
.await,
Some("cowsay".to_string())
);
assert_eq!(
infer_name_from_url(&Url::parse("npm:cowsay@1.2").unwrap()).await,
Some("cowsay".to_string())
);
assert_eq!(
infer_name_from_url(&Url::parse("npm:@types/node@1.2").unwrap()).await,
None
);
assert_eq!(
infer_name_from_url(&Url::parse("npm:@slidev/cli@1.2").unwrap()).await,
Some("slidev".to_string())
);
assert_eq!(
infer_name_from_url(&Url::parse("npm:@google/gemini-cli").unwrap()).await,
Some("gemini".to_string())
);
}
}

Some files were not shown because too many files have changed in this diff Show more