mirror of
https://github.com/denoland/deno.git
synced 2025-01-21 21:50:00 -05:00
Merge remote-tracking branch 'upstream/main' into update-imagebitmap
This commit is contained in:
commit
dbac50db8f
864 changed files with 8469 additions and 15627 deletions
|
@ -65,7 +65,7 @@
|
||||||
"third_party"
|
"third_party"
|
||||||
],
|
],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"https://plugins.dprint.dev/typescript-0.91.6.wasm",
|
"https://plugins.dprint.dev/typescript-0.91.7.wasm",
|
||||||
"https://plugins.dprint.dev/json-0.19.3.wasm",
|
"https://plugins.dprint.dev/json-0.19.3.wasm",
|
||||||
"https://plugins.dprint.dev/markdown-0.17.8.wasm",
|
"https://plugins.dprint.dev/markdown-0.17.8.wasm",
|
||||||
"https://plugins.dprint.dev/toml-0.6.2.wasm",
|
"https://plugins.dprint.dev/toml-0.6.2.wasm",
|
||||||
|
|
2
.github/workflows/ci.generate.ts
vendored
2
.github/workflows/ci.generate.ts
vendored
|
@ -5,7 +5,7 @@ import { stringify } from "jsr:@std/yaml@^0.221/stringify";
|
||||||
// Bump this number when you want to purge the cache.
|
// Bump this number when you want to purge the cache.
|
||||||
// Note: the tools/release/01_bump_crate_versions.ts script will update this version
|
// 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.
|
// automatically via regex, so ensure that this line maintains this format.
|
||||||
const cacheVersion = 13;
|
const cacheVersion = 15;
|
||||||
|
|
||||||
const ubuntuX86Runner = "ubuntu-22.04";
|
const ubuntuX86Runner = "ubuntu-22.04";
|
||||||
const ubuntuX86XlRunner = "ubuntu-22.04-xl";
|
const ubuntuX86XlRunner = "ubuntu-22.04-xl";
|
||||||
|
|
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
|
@ -367,8 +367,8 @@ jobs:
|
||||||
path: |-
|
path: |-
|
||||||
~/.cargo/registry/index
|
~/.cargo/registry/index
|
||||||
~/.cargo/registry/cache
|
~/.cargo/registry/cache
|
||||||
key: '13-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}'
|
key: '15-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}'
|
||||||
restore-keys: '13-cargo-home-${{ matrix.os }}-${{ matrix.arch }}'
|
restore-keys: '15-cargo-home-${{ matrix.os }}-${{ matrix.arch }}'
|
||||||
if: '!(matrix.skip)'
|
if: '!(matrix.skip)'
|
||||||
- name: Restore cache build output (PR)
|
- name: Restore cache build output (PR)
|
||||||
uses: actions/cache/restore@v4
|
uses: actions/cache/restore@v4
|
||||||
|
@ -381,7 +381,7 @@ jobs:
|
||||||
!./target/*/*.zip
|
!./target/*/*.zip
|
||||||
!./target/*/*.tar.gz
|
!./target/*/*.tar.gz
|
||||||
key: never_saved
|
key: never_saved
|
||||||
restore-keys: '13-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-'
|
restore-keys: '15-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-'
|
||||||
- name: Apply and update mtime cache
|
- name: Apply and update mtime cache
|
||||||
if: '!(matrix.skip) && (!startsWith(github.ref, ''refs/tags/''))'
|
if: '!(matrix.skip) && (!startsWith(github.ref, ''refs/tags/''))'
|
||||||
uses: ./.github/mtime_cache
|
uses: ./.github/mtime_cache
|
||||||
|
@ -670,7 +670,7 @@ jobs:
|
||||||
!./target/*/gn_out
|
!./target/*/gn_out
|
||||||
!./target/*/*.zip
|
!./target/*/*.zip
|
||||||
!./target/*/*.tar.gz
|
!./target/*/*.tar.gz
|
||||||
key: '13-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}'
|
key: '15-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}'
|
||||||
publish-canary:
|
publish-canary:
|
||||||
name: publish canary
|
name: publish canary
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
|
|
508
Cargo.lock
generated
508
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
74
Cargo.toml
74
Cargo.toml
|
@ -44,47 +44,48 @@ license = "MIT"
|
||||||
repository = "https://github.com/denoland/deno"
|
repository = "https://github.com/denoland/deno"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
deno_ast = { version = "=0.41.2", features = ["transpiling"] }
|
deno_ast = { version = "=0.42.0", features = ["transpiling"] }
|
||||||
deno_core = { version = "0.306.0" }
|
deno_core = { version = "0.307.0" }
|
||||||
|
|
||||||
deno_bench_util = { version = "0.160.0", path = "./bench_util" }
|
deno_bench_util = { version = "0.162.0", path = "./bench_util" }
|
||||||
deno_lockfile = "=0.22.0"
|
deno_lockfile = "=0.23.0"
|
||||||
deno_media_type = { version = "0.1.4", features = ["module_specifier"] }
|
deno_media_type = { version = "0.1.4", features = ["module_specifier"] }
|
||||||
deno_permissions = { version = "0.26.0", path = "./runtime/permissions" }
|
deno_permissions = { version = "0.28.0", path = "./runtime/permissions" }
|
||||||
deno_runtime = { version = "0.175.0", path = "./runtime" }
|
deno_runtime = { version = "0.177.0", path = "./runtime" }
|
||||||
|
deno_semver = "=0.5.13"
|
||||||
deno_terminal = "0.2.0"
|
deno_terminal = "0.2.0"
|
||||||
napi_sym = { version = "0.96.0", path = "./cli/napi/sym" }
|
napi_sym = { version = "0.98.0", path = "./cli/napi/sym" }
|
||||||
test_util = { package = "test_server", path = "./tests/util/server" }
|
test_util = { package = "test_server", path = "./tests/util/server" }
|
||||||
|
|
||||||
denokv_proto = "0.8.1"
|
denokv_proto = "0.8.1"
|
||||||
denokv_remote = "0.8.1"
|
denokv_remote = "0.8.1"
|
||||||
# denokv_sqlite brings in bundled sqlite if we don't disable the default features
|
# denokv_sqlite brings in bundled sqlite if we don't disable the default features
|
||||||
denokv_sqlite = { default-features = false, version = "0.8.1" }
|
denokv_sqlite = { default-features = false, version = "0.8.2" }
|
||||||
|
|
||||||
# exts
|
# exts
|
||||||
deno_broadcast_channel = { version = "0.160.0", path = "./ext/broadcast_channel" }
|
deno_broadcast_channel = { version = "0.162.0", path = "./ext/broadcast_channel" }
|
||||||
deno_cache = { version = "0.98.0", path = "./ext/cache" }
|
deno_cache = { version = "0.100.0", path = "./ext/cache" }
|
||||||
deno_canvas = { version = "0.35.0", path = "./ext/canvas" }
|
deno_canvas = { version = "0.37.0", path = "./ext/canvas" }
|
||||||
deno_console = { version = "0.166.0", path = "./ext/console" }
|
deno_console = { version = "0.168.0", path = "./ext/console" }
|
||||||
deno_cron = { version = "0.46.0", path = "./ext/cron" }
|
deno_cron = { version = "0.48.0", path = "./ext/cron" }
|
||||||
deno_crypto = { version = "0.180.0", path = "./ext/crypto" }
|
deno_crypto = { version = "0.182.0", path = "./ext/crypto" }
|
||||||
deno_fetch = { version = "0.190.0", path = "./ext/fetch" }
|
deno_fetch = { version = "0.192.0", path = "./ext/fetch" }
|
||||||
deno_ffi = { version = "0.153.0", path = "./ext/ffi" }
|
deno_ffi = { version = "0.155.0", path = "./ext/ffi" }
|
||||||
deno_fs = { version = "0.76.0", path = "./ext/fs" }
|
deno_fs = { version = "0.78.0", path = "./ext/fs" }
|
||||||
deno_http = { version = "0.164.0", path = "./ext/http" }
|
deno_http = { version = "0.166.0", path = "./ext/http" }
|
||||||
deno_io = { version = "0.76.0", path = "./ext/io" }
|
deno_io = { version = "0.78.0", path = "./ext/io" }
|
||||||
deno_kv = { version = "0.74.0", path = "./ext/kv" }
|
deno_kv = { version = "0.76.0", path = "./ext/kv" }
|
||||||
deno_napi = { version = "0.97.0", path = "./ext/napi" }
|
deno_napi = { version = "0.99.0", path = "./ext/napi" }
|
||||||
deno_net = { version = "0.158.0", path = "./ext/net" }
|
deno_net = { version = "0.160.0", path = "./ext/net" }
|
||||||
deno_node = { version = "0.103.0", path = "./ext/node" }
|
deno_node = { version = "0.105.0", path = "./ext/node" }
|
||||||
deno_tls = { version = "0.153.0", path = "./ext/tls" }
|
deno_tls = { version = "0.155.0", path = "./ext/tls" }
|
||||||
deno_url = { version = "0.166.0", path = "./ext/url" }
|
deno_url = { version = "0.168.0", path = "./ext/url" }
|
||||||
deno_web = { version = "0.197.0", path = "./ext/web" }
|
deno_web = { version = "0.199.0", path = "./ext/web" }
|
||||||
deno_webgpu = { version = "0.133.0", path = "./ext/webgpu" }
|
deno_webgpu = { version = "0.135.0", path = "./ext/webgpu" }
|
||||||
deno_webidl = { version = "0.166.0", path = "./ext/webidl" }
|
deno_webidl = { version = "0.168.0", path = "./ext/webidl" }
|
||||||
deno_websocket = { version = "0.171.0", path = "./ext/websocket" }
|
deno_websocket = { version = "0.173.0", path = "./ext/websocket" }
|
||||||
deno_webstorage = { version = "0.161.0", path = "./ext/webstorage" }
|
deno_webstorage = { version = "0.163.0", path = "./ext/webstorage" }
|
||||||
node_resolver = { version = "0.5.0", path = "./ext/node_resolver" }
|
node_resolver = { version = "0.7.0", path = "./ext/node_resolver" }
|
||||||
|
|
||||||
aes = "=0.8.3"
|
aes = "=0.8.3"
|
||||||
anyhow = "1.0.57"
|
anyhow = "1.0.57"
|
||||||
|
@ -102,11 +103,11 @@ chrono = { version = "0.4", default-features = false, features = ["std", "serde"
|
||||||
console_static_text = "=0.8.1"
|
console_static_text = "=0.8.1"
|
||||||
data-encoding = "2.3.3"
|
data-encoding = "2.3.3"
|
||||||
data-url = "=0.3.0"
|
data-url = "=0.3.0"
|
||||||
deno_cache_dir = "=0.11.0"
|
deno_cache_dir = "=0.11.1"
|
||||||
deno_package_json = { version = "=0.1.1", default-features = false }
|
deno_package_json = { version = "=0.1.1", default-features = false }
|
||||||
dlopen2 = "0.6.1"
|
dlopen2 = "0.6.1"
|
||||||
ecb = "=0.1.2"
|
ecb = "=0.1.2"
|
||||||
elliptic-curve = { version = "0.13.4", features = ["alloc", "arithmetic", "ecdh", "std", "pem"] }
|
elliptic-curve = { version = "0.13.4", features = ["alloc", "arithmetic", "ecdh", "std", "pem", "jwk"] }
|
||||||
encoding_rs = "=0.8.33"
|
encoding_rs = "=0.8.33"
|
||||||
fast-socks5 = "0.9.6"
|
fast-socks5 = "0.9.6"
|
||||||
faster-hex = "0.9"
|
faster-hex = "0.9"
|
||||||
|
@ -141,8 +142,8 @@ num-bigint = { version = "0.4", features = ["rand"] }
|
||||||
once_cell = "1.17.1"
|
once_cell = "1.17.1"
|
||||||
os_pipe = { version = "=1.1.5", features = ["io_safety"] }
|
os_pipe = { version = "=1.1.5", features = ["io_safety"] }
|
||||||
p224 = { version = "0.13.0", features = ["ecdh"] }
|
p224 = { version = "0.13.0", features = ["ecdh"] }
|
||||||
p256 = { version = "0.13.2", features = ["ecdh"] }
|
p256 = { version = "0.13.2", features = ["ecdh", "jwk"] }
|
||||||
p384 = { version = "0.13.0", features = ["ecdh"] }
|
p384 = { version = "0.13.0", features = ["ecdh", "jwk"] }
|
||||||
parking_lot = "0.12.0"
|
parking_lot = "0.12.0"
|
||||||
percent-encoding = "2.3.0"
|
percent-encoding = "2.3.0"
|
||||||
phf = { version = "0.11", features = ["macros"] }
|
phf = { version = "0.11", features = ["macros"] }
|
||||||
|
@ -154,7 +155,7 @@ rand = "=0.8.5"
|
||||||
regex = "^1.7.0"
|
regex = "^1.7.0"
|
||||||
reqwest = { version = "=0.12.5", default-features = false, features = ["rustls-tls", "stream", "gzip", "brotli", "socks", "json", "http2"] } # pinned because of https://github.com/seanmonstar/reqwest/pull/1955
|
reqwest = { version = "=0.12.5", default-features = false, features = ["rustls-tls", "stream", "gzip", "brotli", "socks", "json", "http2"] } # pinned because of https://github.com/seanmonstar/reqwest/pull/1955
|
||||||
ring = "^0.17.0"
|
ring = "^0.17.0"
|
||||||
rusqlite = { version = "=0.29.0", features = ["unlock_notify", "bundled"] }
|
rusqlite = { version = "0.32.0", features = ["unlock_notify", "bundled"] }
|
||||||
rustls = { version = "0.23.11", default-features = false, features = ["logging", "std", "tls12", "ring"] }
|
rustls = { version = "0.23.11", default-features = false, features = ["logging", "std", "tls12", "ring"] }
|
||||||
rustls-pemfile = "2"
|
rustls-pemfile = "2"
|
||||||
rustls-tokio-stream = "=0.3.0"
|
rustls-tokio-stream = "=0.3.0"
|
||||||
|
@ -192,6 +193,7 @@ url = { version = "< 2.5.0", features = ["serde", "expose_internals"] }
|
||||||
uuid = { version = "1.3.0", features = ["v4"] }
|
uuid = { version = "1.3.0", features = ["v4"] }
|
||||||
webpki-roots = "0.26"
|
webpki-roots = "0.26"
|
||||||
which = "4.2.5"
|
which = "4.2.5"
|
||||||
|
yoke = { version = "0.7.4", features = ["derive"] }
|
||||||
zeromq = { version = "=0.4.0", default-features = false, features = ["tcp-transport", "tokio-runtime"] }
|
zeromq = { version = "=0.4.0", default-features = false, features = ["tcp-transport", "tokio-runtime"] }
|
||||||
zstd = "=0.12.4"
|
zstd = "=0.12.4"
|
||||||
|
|
||||||
|
|
44
Releases.md
44
Releases.md
|
@ -6,6 +6,50 @@ https://github.com/denoland/deno/releases
|
||||||
We also have one-line install commands at:
|
We also have one-line install commands at:
|
||||||
https://github.com/denoland/deno_install
|
https://github.com/denoland/deno_install
|
||||||
|
|
||||||
|
### 1.46.3 / 2024.09.04
|
||||||
|
|
||||||
|
- feat(upgrade): print info links for Deno 2 RC releases (#25225)
|
||||||
|
- fix(cli): Map error kind to `PermissionDenied` when symlinking fails due to
|
||||||
|
permissions (#25398)
|
||||||
|
- fix(cli/tools): correct `deno init --serve` template behavior (#25318)
|
||||||
|
- fix(ext/node): session close during stream setup (#25170)
|
||||||
|
- fix(publish): ensure provenance is spec compliant (#25200)
|
||||||
|
- fix(upgrade): more informative information on invalid version (#25319)
|
||||||
|
- fix: fix jupyter display function type (#25326)
|
||||||
|
|
||||||
|
### 1.46.2 / 2024.08.29
|
||||||
|
|
||||||
|
- Revert "feat(fetch): accept async iterables for body" (#25207)
|
||||||
|
- fix(bench): Fix table column alignments and NO_COLOR=1 (#25190)
|
||||||
|
- fix(ext/crypto): throw DataError for invalid EC key import (#25181)
|
||||||
|
- fix(ext/fetch): percent decode userinfo when parsing proxies (#25229)
|
||||||
|
- fix(ext/node): emit `online` event after worker thread is initialized (#25243)
|
||||||
|
- fix(ext/node): export JWK public key (#25239)
|
||||||
|
- fix(ext/node): import EC JWK keys (#25266)
|
||||||
|
- fix(ext/node): import JWK octet key pairs (#25180)
|
||||||
|
- fix(ext/node): import RSA JWK keys (#25267)
|
||||||
|
- fix(ext/node): throw when loading `cpu-features` module (#25257)
|
||||||
|
- fix(ext/node): update aead-gcm-stream to 0.3 (#25261)
|
||||||
|
- fix(ext/webgpu): allow to build on unsupported platforms (#25202)
|
||||||
|
- fix(fmt): fix incorrect quotes in components (#25249)
|
||||||
|
- fix(fmt/markdown): fix regression with multi-line footnotes and inline math
|
||||||
|
(#25222)
|
||||||
|
- fix(install): Use relative symlinks in deno install (#25164)
|
||||||
|
- fix(lsp): panic on url_to_uri() (#25238)
|
||||||
|
- fix(napi): Don't run microtasks in napi_resolve_deferred (#25246)
|
||||||
|
- fix(napi): Fix worker threads importing already-loaded NAPI addon (#25245)
|
||||||
|
- fix(node/cluster): improve stubs to make log4js work (#25146)
|
||||||
|
- fix(runtime/web_worker): populate `SnapshotOptions` for `WebWorker` when
|
||||||
|
instantiated without snapshot (#25280)
|
||||||
|
- fix(task): support tasks with colons in name in `deno run` (#25233)
|
||||||
|
- fix: handle showing warnings while the progress bar is shown (#25187)
|
||||||
|
- fix: reland async context (#25140)
|
||||||
|
- fix: removed unstable-htttp from deno help (#25216)
|
||||||
|
- fix: replace `npm install` hint with `deno install` hint (#25244)
|
||||||
|
- fix: update deno_doc (#25290)
|
||||||
|
- fix: upgrade deno_core to 0.307.0 (#25287)
|
||||||
|
- perf(ext/node): reduce some allocations in require (#25197)
|
||||||
|
|
||||||
### 1.46.1 / 2024.08.22
|
### 1.46.1 / 2024.08.22
|
||||||
|
|
||||||
- fix(ext/node): http2session ready state (#25143)
|
- fix(ext/node): http2session ready state (#25143)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "deno_bench_util"
|
name = "deno_bench_util"
|
||||||
version = "0.160.0"
|
version = "0.162.0"
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "deno"
|
name = "deno"
|
||||||
version = "1.46.1"
|
version = "2.0.0-rc.1"
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
default-run = "deno"
|
default-run = "deno"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
|
@ -65,20 +65,19 @@ winres.workspace = true
|
||||||
[dependencies]
|
[dependencies]
|
||||||
deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "proposal", "react", "sourcemap", "transforms", "typescript", "view", "visit"] }
|
deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "proposal", "react", "sourcemap", "transforms", "typescript", "view", "visit"] }
|
||||||
deno_cache_dir = { workspace = true }
|
deno_cache_dir = { workspace = true }
|
||||||
deno_config = { version = "=0.30.1", features = ["workspace", "sync"] }
|
deno_config = { version = "=0.33.2", features = ["workspace", "sync"] }
|
||||||
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] }
|
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] }
|
||||||
deno_doc = { version = "0.146.0", features = ["html", "syntect"] }
|
deno_doc = { version = "0.148.0", features = ["html", "syntect"] }
|
||||||
deno_emit = "=0.44.0"
|
deno_graph = { version = "=0.82.1" }
|
||||||
deno_graph = { version = "=0.81.3" }
|
deno_lint = { version = "=0.65.0", features = ["docs"] }
|
||||||
deno_lint = { version = "=0.63.1", features = ["docs"] }
|
|
||||||
deno_lockfile.workspace = true
|
deno_lockfile.workspace = true
|
||||||
deno_npm = "=0.24.0"
|
deno_npm = "=0.25.0"
|
||||||
deno_package_json.workspace = true
|
deno_package_json.workspace = true
|
||||||
deno_runtime = { workspace = true, features = ["include_js_files_for_snapshotting"] }
|
deno_runtime = { workspace = true, features = ["include_js_files_for_snapshotting"] }
|
||||||
deno_semver = "=0.5.10"
|
deno_semver.workspace = true
|
||||||
deno_task_shell = "=0.17.0"
|
deno_task_shell = "=0.17.0"
|
||||||
deno_terminal.workspace = true
|
deno_terminal.workspace = true
|
||||||
eszip = "=0.76.0"
|
eszip = "=0.78.0"
|
||||||
libsui = "0.3.0"
|
libsui = "0.3.0"
|
||||||
napi_sym.workspace = true
|
napi_sym.workspace = true
|
||||||
node_resolver.workspace = true
|
node_resolver.workspace = true
|
||||||
|
@ -91,8 +90,8 @@ bincode = "=1.3.3"
|
||||||
bytes.workspace = true
|
bytes.workspace = true
|
||||||
cache_control.workspace = true
|
cache_control.workspace = true
|
||||||
chrono = { workspace = true, features = ["now"] }
|
chrono = { workspace = true, features = ["now"] }
|
||||||
clap = { version = "=4.5.13", features = ["env", "string", "wrap_help"] }
|
clap = { version = "=4.5.16", features = ["env", "string", "wrap_help", "error-context"] }
|
||||||
clap_complete = "=4.5.12"
|
clap_complete = "=4.5.24"
|
||||||
clap_complete_fig = "=4.5.2"
|
clap_complete_fig = "=4.5.2"
|
||||||
color-print = "0.3.5"
|
color-print = "0.3.5"
|
||||||
console_static_text.workspace = true
|
console_static_text.workspace = true
|
||||||
|
@ -103,7 +102,7 @@ dotenvy = "0.15.7"
|
||||||
dprint-plugin-json = "=0.19.3"
|
dprint-plugin-json = "=0.19.3"
|
||||||
dprint-plugin-jupyter = "=0.1.3"
|
dprint-plugin-jupyter = "=0.1.3"
|
||||||
dprint-plugin-markdown = "=0.17.8"
|
dprint-plugin-markdown = "=0.17.8"
|
||||||
dprint-plugin-typescript = "=0.91.6"
|
dprint-plugin-typescript = "=0.91.7"
|
||||||
env_logger = "=0.10.0"
|
env_logger = "=0.10.0"
|
||||||
fancy-regex = "=0.10.0"
|
fancy-regex = "=0.10.0"
|
||||||
faster-hex.workspace = true
|
faster-hex.workspace = true
|
||||||
|
@ -115,7 +114,7 @@ http.workspace = true
|
||||||
http-body.workspace = true
|
http-body.workspace = true
|
||||||
http-body-util.workspace = true
|
http-body-util.workspace = true
|
||||||
hyper-util.workspace = true
|
hyper-util.workspace = true
|
||||||
import_map = { version = "=0.20.0", features = ["ext"] }
|
import_map = { version = "=0.20.1", features = ["ext"] }
|
||||||
indexmap.workspace = true
|
indexmap.workspace = true
|
||||||
jsonc-parser.workspace = true
|
jsonc-parser.workspace = true
|
||||||
jupyter_runtime = { package = "runtimelib", version = "=0.14.0" }
|
jupyter_runtime = { package = "runtimelib", version = "=0.14.0" }
|
||||||
|
@ -162,6 +161,7 @@ typed-arena = "=2.0.2"
|
||||||
uuid = { workspace = true, features = ["serde"] }
|
uuid = { workspace = true, features = ["serde"] }
|
||||||
walkdir = "=2.3.2"
|
walkdir = "=2.3.2"
|
||||||
which.workspace = true
|
which.workspace = true
|
||||||
|
yoke.workspace = true
|
||||||
zeromq.workspace = true
|
zeromq.workspace = true
|
||||||
zip = { version = "2.1.6", default-features = false, features = ["deflate-flate2"] }
|
zip = { version = "2.1.6", default-features = false, features = ["deflate-flate2"] }
|
||||||
zstd.workspace = true
|
zstd.workspace = true
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use deno_config::deno_json::TsConfigForEmit;
|
||||||
use deno_core::serde_json;
|
use deno_core::serde_json;
|
||||||
use deno_semver::jsr::JsrDepPackageReq;
|
use deno_semver::jsr::JsrDepPackageReq;
|
||||||
use deno_semver::jsr::JsrPackageReqReference;
|
use deno_semver::jsr::JsrPackageReqReference;
|
||||||
|
@ -105,3 +106,18 @@ fn values_to_set<'a>(
|
||||||
}
|
}
|
||||||
entries
|
entries
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn check_warn_tsconfig(ts_config: &TsConfigForEmit) {
|
||||||
|
if let Some(ignored_options) = &ts_config.maybe_ignored_options {
|
||||||
|
log::warn!("{}", ignored_options);
|
||||||
|
}
|
||||||
|
let serde_json::Value::Object(obj) = &ts_config.ts_config.0 else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if obj.get("experimentalDecorators") == Some(&serde_json::Value::Bool(true)) {
|
||||||
|
log::warn!(
|
||||||
|
"{} experimentalDecorators compiler option is deprecated and may be removed at any time",
|
||||||
|
deno_runtime::colors::yellow("Warning"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
2449
cli/args/flags.rs
2449
cli/args/flags.rs
File diff suppressed because it is too large
Load diff
|
@ -50,7 +50,7 @@ pub fn parse(paths: Vec<String>) -> clap::error::Result<Vec<String>> {
|
||||||
out.push(format!("{}:{}", host, port.0));
|
out.push(format!("{}:{}", host, port.0));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
host_and_port.parse::<NetDescriptor>().map_err(|e| {
|
NetDescriptor::parse(&host_and_port).map_err(|e| {
|
||||||
clap::Error::raw(clap::error::ErrorKind::InvalidValue, format!("{e:?}"))
|
clap::Error::raw(clap::error::ErrorKind::InvalidValue, format!("{e:?}"))
|
||||||
})?;
|
})?;
|
||||||
out.push(host_and_port)
|
out.push(host_and_port)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use std::collections::BTreeSet;
|
use std::collections::HashSet;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use deno_config::deno_json::ConfigFile;
|
use deno_config::deno_json::ConfigFile;
|
||||||
|
@ -12,6 +12,7 @@ use deno_core::parking_lot::MutexGuard;
|
||||||
use deno_lockfile::WorkspaceMemberConfig;
|
use deno_lockfile::WorkspaceMemberConfig;
|
||||||
use deno_package_json::PackageJsonDepValue;
|
use deno_package_json::PackageJsonDepValue;
|
||||||
use deno_runtime::deno_node::PackageJson;
|
use deno_runtime::deno_node::PackageJson;
|
||||||
|
use deno_semver::jsr::JsrDepPackageReq;
|
||||||
|
|
||||||
use crate::cache;
|
use crate::cache;
|
||||||
use crate::util::fs::atomic_write_file_with_retries;
|
use crate::util::fs::atomic_write_file_with_retries;
|
||||||
|
@ -98,7 +99,9 @@ impl CliLockfile {
|
||||||
flags: &Flags,
|
flags: &Flags,
|
||||||
workspace: &Workspace,
|
workspace: &Workspace,
|
||||||
) -> Result<Option<CliLockfile>, AnyError> {
|
) -> Result<Option<CliLockfile>, AnyError> {
|
||||||
fn pkg_json_deps(maybe_pkg_json: Option<&PackageJson>) -> BTreeSet<String> {
|
fn pkg_json_deps(
|
||||||
|
maybe_pkg_json: Option<&PackageJson>,
|
||||||
|
) -> HashSet<JsrDepPackageReq> {
|
||||||
let Some(pkg_json) = maybe_pkg_json else {
|
let Some(pkg_json) = maybe_pkg_json else {
|
||||||
return Default::default();
|
return Default::default();
|
||||||
};
|
};
|
||||||
|
@ -107,21 +110,21 @@ impl CliLockfile {
|
||||||
.values()
|
.values()
|
||||||
.filter_map(|dep| dep.as_ref().ok())
|
.filter_map(|dep| dep.as_ref().ok())
|
||||||
.filter_map(|dep| match dep {
|
.filter_map(|dep| match dep {
|
||||||
PackageJsonDepValue::Req(req) => Some(req),
|
PackageJsonDepValue::Req(req) => {
|
||||||
|
Some(JsrDepPackageReq::npm(req.clone()))
|
||||||
|
}
|
||||||
PackageJsonDepValue::Workspace(_) => None,
|
PackageJsonDepValue::Workspace(_) => None,
|
||||||
})
|
})
|
||||||
.map(|r| format!("npm:{}", r))
|
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deno_json_deps(
|
fn deno_json_deps(
|
||||||
maybe_deno_json: Option<&ConfigFile>,
|
maybe_deno_json: Option<&ConfigFile>,
|
||||||
) -> BTreeSet<String> {
|
) -> HashSet<JsrDepPackageReq> {
|
||||||
maybe_deno_json
|
maybe_deno_json
|
||||||
.map(|c| {
|
.map(|c| {
|
||||||
crate::args::deno_json::deno_json_deps(c)
|
crate::args::deno_json::deno_json_deps(c)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|req| req.to_string())
|
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
|
@ -157,15 +160,7 @@ impl CliLockfile {
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
});
|
});
|
||||||
|
|
||||||
let lockfile = if flags.lock_write {
|
let lockfile = Self::read_from_path(filename, frozen)?;
|
||||||
log::warn!(
|
|
||||||
"{} \"--lock-write\" flag is deprecated and will be removed in Deno 2.",
|
|
||||||
crate::colors::yellow("Warning")
|
|
||||||
);
|
|
||||||
CliLockfile::new(Lockfile::new_empty(filename, true), frozen)
|
|
||||||
} else {
|
|
||||||
Self::read_from_path(filename, frozen)?
|
|
||||||
};
|
|
||||||
|
|
||||||
// initialize the lockfile with the workspace's configuration
|
// initialize the lockfile with the workspace's configuration
|
||||||
let root_url = workspace.root_dir();
|
let root_url = workspace.root_dir();
|
||||||
|
@ -215,6 +210,7 @@ impl CliLockfile {
|
||||||
|
|
||||||
Ok(Some(lockfile))
|
Ok(Some(lockfile))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_from_path(
|
pub fn read_from_path(
|
||||||
file_path: PathBuf,
|
file_path: PathBuf,
|
||||||
frozen: bool,
|
frozen: bool,
|
||||||
|
@ -243,12 +239,6 @@ impl CliLockfile {
|
||||||
}
|
}
|
||||||
let lockfile = self.lockfile.lock();
|
let lockfile = self.lockfile.lock();
|
||||||
if lockfile.has_content_changed {
|
if lockfile.has_content_changed {
|
||||||
let suggested = if *super::DENO_FUTURE {
|
|
||||||
"`deno cache --frozen=false`, `deno install --frozen=false`,"
|
|
||||||
} else {
|
|
||||||
"`deno cache --frozen=false`"
|
|
||||||
};
|
|
||||||
|
|
||||||
let contents =
|
let contents =
|
||||||
std::fs::read_to_string(&lockfile.filename).unwrap_or_default();
|
std::fs::read_to_string(&lockfile.filename).unwrap_or_default();
|
||||||
let new_contents = lockfile.as_json_string();
|
let new_contents = lockfile.as_json_string();
|
||||||
|
@ -256,7 +246,7 @@ impl CliLockfile {
|
||||||
// has an extra newline at the end
|
// has an extra newline at the end
|
||||||
let diff = diff.trim_end();
|
let diff = diff.trim_end();
|
||||||
Err(deno_core::anyhow::anyhow!(
|
Err(deno_core::anyhow::anyhow!(
|
||||||
"The lockfile is out of date. Run {suggested} or rerun with `--frozen=false` to update it.\nchanges:\n{diff}"
|
"The lockfile is out of date. Run `deno cache --frozen=false`, `deno install --frozen=false`, or rerun with `--frozen=false` to update it.\nchanges:\n{diff}"
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
170
cli/args/mod.rs
170
cli/args/mod.rs
|
@ -8,7 +8,9 @@ mod lockfile;
|
||||||
mod package_json;
|
mod package_json;
|
||||||
|
|
||||||
use deno_ast::SourceMapOption;
|
use deno_ast::SourceMapOption;
|
||||||
|
use deno_config::deno_json::NodeModulesDirMode;
|
||||||
use deno_config::workspace::CreateResolverOptions;
|
use deno_config::workspace::CreateResolverOptions;
|
||||||
|
use deno_config::workspace::FolderConfigs;
|
||||||
use deno_config::workspace::PackageJsonDepResolution;
|
use deno_config::workspace::PackageJsonDepResolution;
|
||||||
use deno_config::workspace::VendorEnablement;
|
use deno_config::workspace::VendorEnablement;
|
||||||
use deno_config::workspace::Workspace;
|
use deno_config::workspace::Workspace;
|
||||||
|
@ -40,9 +42,10 @@ pub use deno_config::deno_json::TsConfigForEmit;
|
||||||
pub use deno_config::deno_json::TsConfigType;
|
pub use deno_config::deno_json::TsConfigType;
|
||||||
pub use deno_config::deno_json::TsTypeLib;
|
pub use deno_config::deno_json::TsTypeLib;
|
||||||
pub use deno_config::glob::FilePatterns;
|
pub use deno_config::glob::FilePatterns;
|
||||||
|
pub use deno_json::check_warn_tsconfig;
|
||||||
pub use flags::*;
|
pub use flags::*;
|
||||||
pub use lockfile::CliLockfile;
|
pub use lockfile::CliLockfile;
|
||||||
pub use package_json::PackageJsonInstallDepsProvider;
|
pub use package_json::NpmInstallDepsProvider;
|
||||||
|
|
||||||
use deno_ast::ModuleSpecifier;
|
use deno_ast::ModuleSpecifier;
|
||||||
use deno_core::anyhow::bail;
|
use deno_core::anyhow::bail;
|
||||||
|
@ -50,7 +53,6 @@ use deno_core::anyhow::Context;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::serde_json;
|
use deno_core::serde_json;
|
||||||
use deno_core::url::Url;
|
use deno_core::url::Url;
|
||||||
use deno_runtime::deno_node::PackageJson;
|
|
||||||
use deno_runtime::deno_permissions::PermissionsOptions;
|
use deno_runtime::deno_permissions::PermissionsOptions;
|
||||||
use deno_runtime::deno_tls::deno_native_certs::load_native_certs;
|
use deno_runtime::deno_tls::deno_native_certs::load_native_certs;
|
||||||
use deno_runtime::deno_tls::rustls;
|
use deno_runtime::deno_tls::rustls;
|
||||||
|
@ -63,6 +65,7 @@ use dotenvy::from_filename;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
|
@ -116,9 +119,6 @@ pub static DENO_DISABLE_PEDANTIC_NODE_WARNINGS: Lazy<bool> = Lazy::new(|| {
|
||||||
.is_some()
|
.is_some()
|
||||||
});
|
});
|
||||||
|
|
||||||
pub static DENO_FUTURE: Lazy<bool> =
|
|
||||||
Lazy::new(|| std::env::var("DENO_FUTURE").ok().is_some());
|
|
||||||
|
|
||||||
pub fn jsr_url() -> &'static Url {
|
pub fn jsr_url() -> &'static Url {
|
||||||
static JSR_URL: Lazy<Url> = Lazy::new(|| {
|
static JSR_URL: Lazy<Url> = Lazy::new(|| {
|
||||||
let env_var_name = "JSR_URL";
|
let env_var_name = "JSR_URL";
|
||||||
|
@ -370,7 +370,7 @@ pub struct WorkspaceTestOptions {
|
||||||
pub doc: bool,
|
pub doc: bool,
|
||||||
pub no_run: bool,
|
pub no_run: bool,
|
||||||
pub fail_fast: Option<NonZeroUsize>,
|
pub fail_fast: Option<NonZeroUsize>,
|
||||||
pub allow_none: bool,
|
pub permit_no_files: bool,
|
||||||
pub filter: Option<String>,
|
pub filter: Option<String>,
|
||||||
pub shuffle: Option<u64>,
|
pub shuffle: Option<u64>,
|
||||||
pub concurrent_jobs: NonZeroUsize,
|
pub concurrent_jobs: NonZeroUsize,
|
||||||
|
@ -383,7 +383,7 @@ pub struct WorkspaceTestOptions {
|
||||||
impl WorkspaceTestOptions {
|
impl WorkspaceTestOptions {
|
||||||
pub fn resolve(test_flags: &TestFlags) -> Self {
|
pub fn resolve(test_flags: &TestFlags) -> Self {
|
||||||
Self {
|
Self {
|
||||||
allow_none: test_flags.allow_none,
|
permit_no_files: test_flags.permit_no_files,
|
||||||
concurrent_jobs: test_flags
|
concurrent_jobs: test_flags
|
||||||
.concurrent_jobs
|
.concurrent_jobs
|
||||||
.unwrap_or_else(|| NonZeroUsize::new(1).unwrap()),
|
.unwrap_or_else(|| NonZeroUsize::new(1).unwrap()),
|
||||||
|
@ -781,8 +781,6 @@ pub struct CliOptions {
|
||||||
maybe_lockfile: Option<Arc<CliLockfile>>,
|
maybe_lockfile: Option<Arc<CliLockfile>>,
|
||||||
overrides: CliOptionOverrides,
|
overrides: CliOptionOverrides,
|
||||||
pub start_dir: Arc<WorkspaceDirectory>,
|
pub start_dir: Arc<WorkspaceDirectory>,
|
||||||
pub disable_deprecated_api_warning: bool,
|
|
||||||
pub verbose_deprecated_api_warning: bool,
|
|
||||||
pub deno_dir_provider: Arc<DenoDirProvider>,
|
pub deno_dir_provider: Arc<DenoDirProvider>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -813,27 +811,18 @@ impl CliOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
let maybe_lockfile = maybe_lockfile.filter(|_| !force_global_cache);
|
let maybe_lockfile = maybe_lockfile.filter(|_| !force_global_cache);
|
||||||
let root_folder = start_dir.workspace.root_folder_configs();
|
|
||||||
let deno_dir_provider =
|
let deno_dir_provider =
|
||||||
Arc::new(DenoDirProvider::new(flags.cache_path.clone()));
|
Arc::new(DenoDirProvider::new(flags.cache_path.clone()));
|
||||||
let maybe_node_modules_folder = resolve_node_modules_folder(
|
let maybe_node_modules_folder = resolve_node_modules_folder(
|
||||||
&initial_cwd,
|
&initial_cwd,
|
||||||
&flags,
|
&flags,
|
||||||
root_folder.deno_json.as_deref(),
|
&start_dir.workspace,
|
||||||
root_folder.pkg_json.as_deref(),
|
|
||||||
&deno_dir_provider,
|
&deno_dir_provider,
|
||||||
)
|
)
|
||||||
.with_context(|| "Resolving node_modules folder.")?;
|
.with_context(|| "Resolving node_modules folder.")?;
|
||||||
|
|
||||||
load_env_variables_from_env_file(flags.env_file.as_ref());
|
load_env_variables_from_env_file(flags.env_file.as_ref());
|
||||||
|
|
||||||
let disable_deprecated_api_warning = flags.log_level
|
|
||||||
== Some(log::Level::Error)
|
|
||||||
|| std::env::var("DENO_NO_DEPRECATION_WARNINGS").ok().is_some();
|
|
||||||
|
|
||||||
let verbose_deprecated_api_warning =
|
|
||||||
std::env::var("DENO_VERBOSE_WARNINGS").ok().is_some();
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
flags,
|
flags,
|
||||||
initial_cwd,
|
initial_cwd,
|
||||||
|
@ -842,8 +831,6 @@ impl CliOptions {
|
||||||
maybe_node_modules_folder,
|
maybe_node_modules_folder,
|
||||||
overrides: Default::default(),
|
overrides: Default::default(),
|
||||||
start_dir,
|
start_dir,
|
||||||
disable_deprecated_api_warning,
|
|
||||||
verbose_deprecated_api_warning,
|
|
||||||
deno_dir_provider,
|
deno_dir_provider,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1137,15 +1124,8 @@ impl CliOptions {
|
||||||
self.flags.env_file.as_ref()
|
self.flags.env_file.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_future_features(&self) -> bool {
|
|
||||||
*DENO_FUTURE
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resolve_main_module(&self) -> Result<ModuleSpecifier, AnyError> {
|
pub fn resolve_main_module(&self) -> Result<ModuleSpecifier, AnyError> {
|
||||||
let main_module = match &self.flags.subcommand {
|
let main_module = match &self.flags.subcommand {
|
||||||
DenoSubcommand::Bundle(bundle_flags) => {
|
|
||||||
resolve_url_or_path(&bundle_flags.source_file, self.initial_cwd())?
|
|
||||||
}
|
|
||||||
DenoSubcommand::Compile(compile_flags) => {
|
DenoSubcommand::Compile(compile_flags) => {
|
||||||
resolve_url_or_path(&compile_flags.source_file, self.initial_cwd())?
|
resolve_url_or_path(&compile_flags.source_file, self.initial_cwd())?
|
||||||
}
|
}
|
||||||
|
@ -1227,11 +1207,6 @@ impl CliOptions {
|
||||||
NPM_PROCESS_STATE.is_some()
|
NPM_PROCESS_STATE.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Overrides the import map specifier to use.
|
|
||||||
pub fn set_import_map_specifier(&mut self, path: Option<ModuleSpecifier>) {
|
|
||||||
self.overrides.import_map_specifier = Some(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn has_node_modules_dir(&self) -> bool {
|
pub fn has_node_modules_dir(&self) -> bool {
|
||||||
self.maybe_node_modules_folder.is_some()
|
self.maybe_node_modules_folder.is_some()
|
||||||
}
|
}
|
||||||
|
@ -1240,26 +1215,13 @@ impl CliOptions {
|
||||||
self.maybe_node_modules_folder.as_ref()
|
self.maybe_node_modules_folder.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_node_modules_dir_path(&self, path: PathBuf) -> Self {
|
pub fn node_modules_dir(
|
||||||
Self {
|
&self,
|
||||||
flags: self.flags.clone(),
|
) -> Result<Option<NodeModulesDirMode>, AnyError> {
|
||||||
initial_cwd: self.initial_cwd.clone(),
|
if let Some(flag) = self.flags.node_modules_dir {
|
||||||
maybe_node_modules_folder: Some(path),
|
return Ok(Some(flag));
|
||||||
npmrc: self.npmrc.clone(),
|
|
||||||
maybe_lockfile: self.maybe_lockfile.clone(),
|
|
||||||
start_dir: self.start_dir.clone(),
|
|
||||||
overrides: self.overrides.clone(),
|
|
||||||
disable_deprecated_api_warning: self.disable_deprecated_api_warning,
|
|
||||||
verbose_deprecated_api_warning: self.verbose_deprecated_api_warning,
|
|
||||||
deno_dir_provider: self.deno_dir_provider.clone(),
|
|
||||||
}
|
}
|
||||||
}
|
self.workspace().node_modules_dir().map_err(Into::into)
|
||||||
|
|
||||||
pub fn node_modules_dir_enablement(&self) -> Option<bool> {
|
|
||||||
self
|
|
||||||
.flags
|
|
||||||
.node_modules_dir
|
|
||||||
.or_else(|| self.workspace().node_modules_dir())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vendor_dir_path(&self) -> Option<&PathBuf> {
|
pub fn vendor_dir_path(&self) -> Option<&PathBuf> {
|
||||||
|
@ -1270,23 +1232,7 @@ impl CliOptions {
|
||||||
&self,
|
&self,
|
||||||
config_type: TsConfigType,
|
config_type: TsConfigType,
|
||||||
) -> Result<TsConfigForEmit, AnyError> {
|
) -> Result<TsConfigForEmit, AnyError> {
|
||||||
let result = self.workspace().resolve_ts_config_for_emit(config_type);
|
self.workspace().resolve_ts_config_for_emit(config_type)
|
||||||
|
|
||||||
match result {
|
|
||||||
Ok(mut ts_config_for_emit) => {
|
|
||||||
if matches!(self.flags.subcommand, DenoSubcommand::Bundle(..)) {
|
|
||||||
// For backwards compatibility, force `experimentalDecorators` setting
|
|
||||||
// to true.
|
|
||||||
*ts_config_for_emit
|
|
||||||
.ts_config
|
|
||||||
.0
|
|
||||||
.get_mut("experimentalDecorators")
|
|
||||||
.unwrap() = serde_json::Value::Bool(true);
|
|
||||||
}
|
|
||||||
Ok(ts_config_for_emit)
|
|
||||||
}
|
|
||||||
Err(err) => Err(err),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_inspector_server(
|
pub fn resolve_inspector_server(
|
||||||
|
@ -1611,9 +1557,18 @@ impl CliOptions {
|
||||||
|| self.workspace().has_unstable("bare-node-builtins")
|
|| self.workspace().has_unstable("bare-node-builtins")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn byonm_enabled(&self) -> bool {
|
||||||
|
// check if enabled via unstable
|
||||||
|
self.node_modules_dir().ok().flatten() == Some(NodeModulesDirMode::Manual)
|
||||||
|
|| NPM_PROCESS_STATE
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| matches!(s.kind, NpmProcessStateKind::Byonm))
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn use_byonm(&self) -> bool {
|
pub fn use_byonm(&self) -> bool {
|
||||||
if self.enable_future_features()
|
if self.node_modules_dir().ok().flatten().is_none()
|
||||||
&& self.node_modules_dir_enablement().is_none()
|
&& self.maybe_node_modules_folder.is_some()
|
||||||
&& self
|
&& self
|
||||||
.workspace()
|
.workspace()
|
||||||
.config_folders()
|
.config_folders()
|
||||||
|
@ -1623,13 +1578,7 @@ impl CliOptions {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if enabled via unstable
|
self.byonm_enabled()
|
||||||
self.flags.unstable_config.byonm
|
|
||||||
|| NPM_PROCESS_STATE
|
|
||||||
.as_ref()
|
|
||||||
.map(|s| matches!(s.kind, NpmProcessStateKind::Byonm))
|
|
||||||
.unwrap_or(false)
|
|
||||||
|| self.workspace().has_unstable("byonm")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unstable_sloppy_imports(&self) -> bool {
|
pub fn unstable_sloppy_imports(&self) -> bool {
|
||||||
|
@ -1651,7 +1600,7 @@ impl CliOptions {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if *DENO_FUTURE {
|
// TODO(2.0): remove this code and enable these features in `99_main.js` by default.
|
||||||
let future_features = [
|
let future_features = [
|
||||||
deno_runtime::deno_ffi::UNSTABLE_FEATURE_NAME.to_string(),
|
deno_runtime::deno_ffi::UNSTABLE_FEATURE_NAME.to_string(),
|
||||||
deno_runtime::deno_fs::UNSTABLE_FEATURE_NAME.to_string(),
|
deno_runtime::deno_fs::UNSTABLE_FEATURE_NAME.to_string(),
|
||||||
|
@ -1662,7 +1611,6 @@ impl CliOptions {
|
||||||
from_config_file.push(future_feature.to_string());
|
from_config_file.push(future_feature.to_string());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
if !from_config_file.is_empty() {
|
if !from_config_file.is_empty() {
|
||||||
// collect unstable granular flags
|
// collect unstable granular flags
|
||||||
|
@ -1761,42 +1709,55 @@ impl CliOptions {
|
||||||
fn resolve_node_modules_folder(
|
fn resolve_node_modules_folder(
|
||||||
cwd: &Path,
|
cwd: &Path,
|
||||||
flags: &Flags,
|
flags: &Flags,
|
||||||
maybe_config_file: Option<&ConfigFile>,
|
workspace: &Workspace,
|
||||||
maybe_package_json: Option<&PackageJson>,
|
|
||||||
deno_dir_provider: &Arc<DenoDirProvider>,
|
deno_dir_provider: &Arc<DenoDirProvider>,
|
||||||
) -> Result<Option<PathBuf>, AnyError> {
|
) -> Result<Option<PathBuf>, AnyError> {
|
||||||
let use_node_modules_dir = flags
|
fn resolve_from_root(root_folder: &FolderConfigs, cwd: &Path) -> PathBuf {
|
||||||
.node_modules_dir
|
root_folder
|
||||||
.or_else(|| maybe_config_file.and_then(|c| c.json.node_modules_dir))
|
.deno_json
|
||||||
|
.as_ref()
|
||||||
|
.map(|c| Cow::Owned(c.dir_path()))
|
||||||
|
.or_else(|| {
|
||||||
|
root_folder
|
||||||
|
.pkg_json
|
||||||
|
.as_ref()
|
||||||
|
.map(|c| Cow::Borrowed(c.dir_path()))
|
||||||
|
})
|
||||||
|
.unwrap_or(Cow::Borrowed(cwd))
|
||||||
|
.join("node_modules")
|
||||||
|
}
|
||||||
|
|
||||||
|
let root_folder = workspace.root_folder_configs();
|
||||||
|
let use_node_modules_dir = if let Some(mode) = flags.node_modules_dir {
|
||||||
|
Some(mode.uses_node_modules_dir())
|
||||||
|
} else {
|
||||||
|
workspace
|
||||||
|
.node_modules_dir()?
|
||||||
|
.map(|m| m.uses_node_modules_dir())
|
||||||
.or(flags.vendor)
|
.or(flags.vendor)
|
||||||
.or_else(|| maybe_config_file.and_then(|c| c.json.vendor));
|
.or_else(|| root_folder.deno_json.as_ref().and_then(|c| c.json.vendor))
|
||||||
|
};
|
||||||
let path = if use_node_modules_dir == Some(false) {
|
let path = if use_node_modules_dir == Some(false) {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
} else if let Some(state) = &*NPM_PROCESS_STATE {
|
} else if let Some(state) = &*NPM_PROCESS_STATE {
|
||||||
return Ok(state.local_node_modules_path.as_ref().map(PathBuf::from));
|
return Ok(state.local_node_modules_path.as_ref().map(PathBuf::from));
|
||||||
} else if let Some(package_json_path) = maybe_package_json.map(|c| &c.path) {
|
} else if root_folder.pkg_json.is_some() {
|
||||||
|
let node_modules_dir = resolve_from_root(root_folder, cwd);
|
||||||
if let Ok(deno_dir) = deno_dir_provider.get_or_create() {
|
if let Ok(deno_dir) = deno_dir_provider.get_or_create() {
|
||||||
// `deno_dir.root` can be symlink in macOS
|
// `deno_dir.root` can be symlink in macOS
|
||||||
if let Ok(root) = canonicalize_path_maybe_not_exists(&deno_dir.root) {
|
if let Ok(root) = canonicalize_path_maybe_not_exists(&deno_dir.root) {
|
||||||
if package_json_path.starts_with(root) {
|
if node_modules_dir.starts_with(root) {
|
||||||
// if the package.json is in deno_dir, then do not use node_modules
|
// if the package.json is in deno_dir, then do not use node_modules
|
||||||
// next to it as local node_modules dir
|
// next to it as local node_modules dir
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// auto-discover the local_node_modules_folder when a package.json exists
|
node_modules_dir
|
||||||
// and it's not in deno_dir
|
|
||||||
package_json_path.parent().unwrap().join("node_modules")
|
|
||||||
} else if use_node_modules_dir.is_none() {
|
} else if use_node_modules_dir.is_none() {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
} else if let Some(config_path) = maybe_config_file
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|c| c.specifier.to_file_path().ok())
|
|
||||||
{
|
|
||||||
config_path.parent().unwrap().join("node_modules")
|
|
||||||
} else {
|
} else {
|
||||||
cwd.join("node_modules")
|
resolve_from_root(root_folder, cwd)
|
||||||
};
|
};
|
||||||
Ok(Some(canonicalize_path_maybe_not_exists(&path)?))
|
Ok(Some(canonicalize_path_maybe_not_exists(&path)?))
|
||||||
}
|
}
|
||||||
|
@ -1886,19 +1847,18 @@ pub fn npm_pkg_req_ref_to_binary_command(
|
||||||
pub fn config_to_deno_graph_workspace_member(
|
pub fn config_to_deno_graph_workspace_member(
|
||||||
config: &ConfigFile,
|
config: &ConfigFile,
|
||||||
) -> Result<deno_graph::WorkspaceMember, AnyError> {
|
) -> Result<deno_graph::WorkspaceMember, AnyError> {
|
||||||
let nv = deno_semver::package::PackageNv {
|
let name = match &config.json.name {
|
||||||
name: match &config.json.name {
|
|
||||||
Some(name) => name.clone(),
|
Some(name) => name.clone(),
|
||||||
None => bail!("Missing 'name' field in config file."),
|
None => bail!("Missing 'name' field in config file."),
|
||||||
},
|
};
|
||||||
version: match &config.json.version {
|
let version = match &config.json.version {
|
||||||
Some(name) => deno_semver::Version::parse_standard(name)?,
|
Some(name) => Some(deno_semver::Version::parse_standard(name)?),
|
||||||
None => bail!("Missing 'version' field in config file."),
|
None => None,
|
||||||
},
|
|
||||||
};
|
};
|
||||||
Ok(deno_graph::WorkspaceMember {
|
Ok(deno_graph::WorkspaceMember {
|
||||||
base: config.specifier.join("./").unwrap(),
|
base: config.specifier.join("./").unwrap(),
|
||||||
nv,
|
name,
|
||||||
|
version,
|
||||||
exports: config.to_exports_config()?.into_map(),
|
exports: config.to_exports_config()?.into_map(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use deno_config::workspace::Workspace;
|
use deno_config::workspace::Workspace;
|
||||||
|
use deno_core::serde_json;
|
||||||
use deno_package_json::PackageJsonDepValue;
|
use deno_package_json::PackageJsonDepValue;
|
||||||
|
use deno_semver::npm::NpmPackageReqReference;
|
||||||
use deno_semver::package::PackageReq;
|
use deno_semver::package::PackageReq;
|
||||||
|
|
||||||
|
use crate::util::path::is_banned_path_char;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InstallNpmRemotePkg {
|
pub struct InstallNpmRemotePkg {
|
||||||
pub alias: String,
|
pub alias: String,
|
||||||
// todo(24419): use this when setting up the node_modules dir
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub base_dir: PathBuf,
|
pub base_dir: PathBuf,
|
||||||
pub req: PackageReq,
|
pub req: PackageReq,
|
||||||
}
|
}
|
||||||
|
@ -19,34 +22,86 @@ pub struct InstallNpmRemotePkg {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InstallNpmWorkspacePkg {
|
pub struct InstallNpmWorkspacePkg {
|
||||||
pub alias: String,
|
pub alias: String,
|
||||||
// todo(24419): use this when setting up the node_modules dir
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub base_dir: PathBuf,
|
|
||||||
pub target_dir: PathBuf,
|
pub target_dir: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct PackageJsonInstallDepsProvider {
|
pub struct NpmInstallDepsProvider {
|
||||||
remote_pkgs: Vec<InstallNpmRemotePkg>,
|
remote_pkgs: Vec<InstallNpmRemotePkg>,
|
||||||
workspace_pkgs: Vec<InstallNpmWorkspacePkg>,
|
workspace_pkgs: Vec<InstallNpmWorkspacePkg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PackageJsonInstallDepsProvider {
|
impl NpmInstallDepsProvider {
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_workspace(workspace: &Arc<Workspace>) -> Self {
|
pub fn from_workspace(workspace: &Arc<Workspace>) -> Self {
|
||||||
|
// todo(dsherret): estimate capacity?
|
||||||
let mut workspace_pkgs = Vec::new();
|
let mut workspace_pkgs = Vec::new();
|
||||||
let mut remote_pkgs = Vec::new();
|
let mut remote_pkgs = Vec::new();
|
||||||
let workspace_npm_pkgs = workspace.npm_packages();
|
let workspace_npm_pkgs = workspace.npm_packages();
|
||||||
for pkg_json in workspace.package_jsons() {
|
|
||||||
|
for (_, folder) in workspace.config_folders() {
|
||||||
|
let mut deno_json_aliases = HashSet::new();
|
||||||
|
|
||||||
|
// deal with the deno.json first because it takes precedence during resolution
|
||||||
|
if let Some(deno_json) = &folder.deno_json {
|
||||||
|
// don't bother with externally referenced import maps as users
|
||||||
|
// should inline their import map to get this behaviour
|
||||||
|
if let Some(serde_json::Value::Object(obj)) = &deno_json.json.imports {
|
||||||
|
deno_json_aliases.reserve(obj.len());
|
||||||
|
let mut pkg_pkgs = Vec::with_capacity(obj.len());
|
||||||
|
for (alias, value) in obj {
|
||||||
|
let serde_json::Value::String(specifier) = value else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let Ok(npm_req_ref) = NpmPackageReqReference::from_str(specifier)
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
// skip any aliases with banned characters
|
||||||
|
if alias.chars().any(|c| c == '\\' || is_banned_path_char(c)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
deno_json_aliases.insert(alias.to_lowercase());
|
||||||
|
let pkg_req = npm_req_ref.into_inner().req;
|
||||||
|
let workspace_pkg = workspace_npm_pkgs
|
||||||
|
.iter()
|
||||||
|
.find(|pkg| pkg.matches_req(&pkg_req));
|
||||||
|
|
||||||
|
if let Some(pkg) = workspace_pkg {
|
||||||
|
workspace_pkgs.push(InstallNpmWorkspacePkg {
|
||||||
|
alias: alias.to_string(),
|
||||||
|
target_dir: pkg.pkg_json.dir_path().to_path_buf(),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
pkg_pkgs.push(InstallNpmRemotePkg {
|
||||||
|
alias: alias.to_string(),
|
||||||
|
base_dir: deno_json.dir_path(),
|
||||||
|
req: pkg_req,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort within each package (more like npm resolution)
|
||||||
|
pkg_pkgs.sort_by(|a, b| a.alias.cmp(&b.alias));
|
||||||
|
remote_pkgs.extend(pkg_pkgs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(pkg_json) = &folder.pkg_json {
|
||||||
let deps = pkg_json.resolve_local_package_json_deps();
|
let deps = pkg_json.resolve_local_package_json_deps();
|
||||||
let mut pkg_pkgs = Vec::with_capacity(deps.len());
|
let mut pkg_pkgs = Vec::with_capacity(deps.len());
|
||||||
for (alias, dep) in deps {
|
for (alias, dep) in deps {
|
||||||
let Ok(dep) = dep else {
|
let Ok(dep) = dep else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
if deno_json_aliases.contains(&alias.to_lowercase()) {
|
||||||
|
// aliases in deno.json take precedence over package.json, so
|
||||||
|
// since this can't be resolved don't bother installing it
|
||||||
|
continue;
|
||||||
|
}
|
||||||
match dep {
|
match dep {
|
||||||
PackageJsonDepValue::Req(pkg_req) => {
|
PackageJsonDepValue::Req(pkg_req) => {
|
||||||
let workspace_pkg = workspace_npm_pkgs.iter().find(|pkg| {
|
let workspace_pkg = workspace_npm_pkgs.iter().find(|pkg| {
|
||||||
|
@ -58,7 +113,6 @@ impl PackageJsonInstallDepsProvider {
|
||||||
if let Some(pkg) = workspace_pkg {
|
if let Some(pkg) = workspace_pkg {
|
||||||
workspace_pkgs.push(InstallNpmWorkspacePkg {
|
workspace_pkgs.push(InstallNpmWorkspacePkg {
|
||||||
alias,
|
alias,
|
||||||
base_dir: pkg_json.dir_path().to_path_buf(),
|
|
||||||
target_dir: pkg.pkg_json.dir_path().to_path_buf(),
|
target_dir: pkg.pkg_json.dir_path().to_path_buf(),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -75,18 +129,19 @@ impl PackageJsonInstallDepsProvider {
|
||||||
}) {
|
}) {
|
||||||
workspace_pkgs.push(InstallNpmWorkspacePkg {
|
workspace_pkgs.push(InstallNpmWorkspacePkg {
|
||||||
alias,
|
alias,
|
||||||
base_dir: pkg_json.dir_path().to_path_buf(),
|
|
||||||
target_dir: pkg.pkg_json.dir_path().to_path_buf(),
|
target_dir: pkg.pkg_json.dir_path().to_path_buf(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// sort within each package
|
|
||||||
pkg_pkgs.sort_by(|a, b| a.alias.cmp(&b.alias));
|
|
||||||
|
|
||||||
|
// sort within each package as npm does
|
||||||
|
pkg_pkgs.sort_by(|a, b| a.alias.cmp(&b.alias));
|
||||||
remote_pkgs.extend(pkg_pkgs);
|
remote_pkgs.extend(pkg_pkgs);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
remote_pkgs.shrink_to_fit();
|
remote_pkgs.shrink_to_fit();
|
||||||
workspace_pkgs.shrink_to_fit();
|
workspace_pkgs.shrink_to_fit();
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -46,8 +46,7 @@ Deno.bench("b64_rt_short", { n: 1e6 }, () => {
|
||||||
const buf = new Uint8Array(100);
|
const buf = new Uint8Array(100);
|
||||||
const file = Deno.openSync("/dev/zero");
|
const file = Deno.openSync("/dev/zero");
|
||||||
Deno.bench("read_zero", { n: 5e5 }, () => {
|
Deno.bench("read_zero", { n: 5e5 }, () => {
|
||||||
// deno-lint-ignore no-deprecated-deno-api
|
file.readSync(buf);
|
||||||
Deno.readSync(file.rid, buf);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,29 +143,6 @@ const EXEC_TIME_BENCHMARKS: &[(&str, &[&str], Option<i32>)] = &[
|
||||||
],
|
],
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
(
|
|
||||||
"bundle",
|
|
||||||
&[
|
|
||||||
"bundle",
|
|
||||||
"--unstable",
|
|
||||||
"--config",
|
|
||||||
"tests/config/deno.json",
|
|
||||||
"tests/util/std/http/file_server_test.ts",
|
|
||||||
],
|
|
||||||
None,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"bundle_no_check",
|
|
||||||
&[
|
|
||||||
"bundle",
|
|
||||||
"--no-check",
|
|
||||||
"--unstable",
|
|
||||||
"--config",
|
|
||||||
"tests/config/deno.json",
|
|
||||||
"tests/util/std/http/file_server_test.ts",
|
|
||||||
],
|
|
||||||
None,
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const RESULT_KEYS: &[&str] =
|
const RESULT_KEYS: &[&str] =
|
||||||
|
@ -314,40 +291,6 @@ fn get_binary_sizes(target_dir: &Path) -> Result<HashMap<String, i64>> {
|
||||||
Ok(sizes)
|
Ok(sizes)
|
||||||
}
|
}
|
||||||
|
|
||||||
const BUNDLES: &[(&str, &str)] = &[
|
|
||||||
("file_server", "./tests/util/std/http/file_server.ts"),
|
|
||||||
("welcome", "./tests/testdata/welcome.ts"),
|
|
||||||
];
|
|
||||||
fn bundle_benchmark(deno_exe: &Path) -> Result<HashMap<String, i64>> {
|
|
||||||
let mut sizes = HashMap::<String, i64>::new();
|
|
||||||
|
|
||||||
for (name, url) in BUNDLES {
|
|
||||||
let path = format!("{name}.bundle.js");
|
|
||||||
test_util::run(
|
|
||||||
&[
|
|
||||||
deno_exe.to_str().unwrap(),
|
|
||||||
"bundle",
|
|
||||||
"--unstable",
|
|
||||||
"--config",
|
|
||||||
"tests/config/deno.json",
|
|
||||||
url,
|
|
||||||
&path,
|
|
||||||
],
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
let file = PathBuf::from(path);
|
|
||||||
assert!(file.is_file());
|
|
||||||
sizes.insert(name.to_string(), file.metadata()?.len() as i64);
|
|
||||||
let _ = fs::remove_file(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(sizes)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_max_mem_benchmark(deno_exe: &Path) -> Result<HashMap<String, i64>> {
|
fn run_max_mem_benchmark(deno_exe: &Path) -> Result<HashMap<String, i64>> {
|
||||||
let mut results = HashMap::<String, i64>::new();
|
let mut results = HashMap::<String, i64>::new();
|
||||||
|
|
||||||
|
@ -415,7 +358,6 @@ async fn main() -> Result<()> {
|
||||||
let mut args = env::args();
|
let mut args = env::args();
|
||||||
|
|
||||||
let mut benchmarks = vec![
|
let mut benchmarks = vec![
|
||||||
"bundle",
|
|
||||||
"exec_time",
|
"exec_time",
|
||||||
"binary_size",
|
"binary_size",
|
||||||
"cargo_deps",
|
"cargo_deps",
|
||||||
|
@ -465,11 +407,6 @@ async fn main() -> Result<()> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
if benchmarks.contains(&"bundle") {
|
|
||||||
let bundle_size = bundle_benchmark(&deno_exe)?;
|
|
||||||
new_data.bundle_size = bundle_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
if benchmarks.contains(&"exec_time") {
|
if benchmarks.contains(&"exec_time") {
|
||||||
let exec_times = run_exec_time(&deno_exe, &target_dir)?;
|
let exec_times = run_exec_time(&deno_exe, &target_dir)?;
|
||||||
new_data.benchmark = exec_times;
|
new_data.benchmark = exec_times;
|
||||||
|
|
13
cli/cache/emit.rs
vendored
13
cli/cache/emit.rs
vendored
|
@ -82,19 +82,6 @@ impl EmitCache {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the filepath which stores the emit.
|
|
||||||
pub fn get_emit_filepath(
|
|
||||||
&self,
|
|
||||||
specifier: &ModuleSpecifier,
|
|
||||||
) -> Option<PathBuf> {
|
|
||||||
Some(
|
|
||||||
self
|
|
||||||
.disk_cache
|
|
||||||
.location
|
|
||||||
.join(self.get_emit_filename(specifier)?),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_emit_filename(&self, specifier: &ModuleSpecifier) -> Option<PathBuf> {
|
fn get_emit_filename(&self, specifier: &ModuleSpecifier) -> Option<PathBuf> {
|
||||||
self
|
self
|
||||||
.disk_cache
|
.disk_cache
|
||||||
|
|
46
cli/cache/mod.rs
vendored
46
cli/cache/mod.rs
vendored
|
@ -8,6 +8,7 @@ use crate::file_fetcher::FileFetcher;
|
||||||
use crate::file_fetcher::FileOrRedirect;
|
use crate::file_fetcher::FileOrRedirect;
|
||||||
use crate::npm::CliNpmResolver;
|
use crate::npm::CliNpmResolver;
|
||||||
use crate::util::fs::atomic_write_file_with_retries;
|
use crate::util::fs::atomic_write_file_with_retries;
|
||||||
|
use crate::util::path::specifier_has_extension;
|
||||||
|
|
||||||
use deno_ast::MediaType;
|
use deno_ast::MediaType;
|
||||||
use deno_core::futures;
|
use deno_core::futures;
|
||||||
|
@ -74,6 +75,10 @@ impl deno_cache_dir::DenoCacheEnv for RealDenoCacheEnv {
|
||||||
atomic_write_file_with_retries(path, bytes, CACHE_PERM)
|
atomic_write_file_with_retries(path, bytes, CACHE_PERM)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn remove_file(&self, path: &Path) -> std::io::Result<()> {
|
||||||
|
std::fs::remove_file(path)
|
||||||
|
}
|
||||||
|
|
||||||
fn modified(&self, path: &Path) -> std::io::Result<Option<SystemTime>> {
|
fn modified(&self, path: &Path) -> std::io::Result<Option<SystemTime>> {
|
||||||
match std::fs::metadata(path) {
|
match std::fs::metadata(path) {
|
||||||
Ok(metadata) => Ok(Some(
|
Ok(metadata) => Ok(Some(
|
||||||
|
@ -102,7 +107,6 @@ pub use deno_cache_dir::HttpCache;
|
||||||
/// A "wrapper" for the FileFetcher and DiskCache for the Deno CLI that provides
|
/// A "wrapper" for the FileFetcher and DiskCache for the Deno CLI that provides
|
||||||
/// a concise interface to the DENO_DIR when building module graphs.
|
/// a concise interface to the DENO_DIR when building module graphs.
|
||||||
pub struct FetchCacher {
|
pub struct FetchCacher {
|
||||||
emit_cache: Arc<EmitCache>,
|
|
||||||
file_fetcher: Arc<FileFetcher>,
|
file_fetcher: Arc<FileFetcher>,
|
||||||
file_header_overrides: HashMap<ModuleSpecifier, HashMap<String, String>>,
|
file_header_overrides: HashMap<ModuleSpecifier, HashMap<String, String>>,
|
||||||
global_http_cache: Arc<GlobalHttpCache>,
|
global_http_cache: Arc<GlobalHttpCache>,
|
||||||
|
@ -114,7 +118,6 @@ pub struct FetchCacher {
|
||||||
|
|
||||||
impl FetchCacher {
|
impl FetchCacher {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
emit_cache: Arc<EmitCache>,
|
|
||||||
file_fetcher: Arc<FileFetcher>,
|
file_fetcher: Arc<FileFetcher>,
|
||||||
file_header_overrides: HashMap<ModuleSpecifier, HashMap<String, String>>,
|
file_header_overrides: HashMap<ModuleSpecifier, HashMap<String, String>>,
|
||||||
global_http_cache: Arc<GlobalHttpCache>,
|
global_http_cache: Arc<GlobalHttpCache>,
|
||||||
|
@ -123,7 +126,6 @@ impl FetchCacher {
|
||||||
permissions: PermissionsContainer,
|
permissions: PermissionsContainer,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
emit_cache,
|
|
||||||
file_fetcher,
|
file_fetcher,
|
||||||
file_header_overrides,
|
file_header_overrides,
|
||||||
global_http_cache,
|
global_http_cache,
|
||||||
|
@ -140,15 +142,7 @@ impl FetchCacher {
|
||||||
self.cache_info_enabled = true;
|
self.cache_info_enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEPRECATED: Where the file is stored and how it's stored should be an implementation
|
/// Only use this for `deno info`.
|
||||||
// detail of the cache.
|
|
||||||
//
|
|
||||||
// todo(dsheret): remove once implementing
|
|
||||||
// * https://github.com/denoland/deno/issues/17707
|
|
||||||
// * https://github.com/denoland/deno/issues/17703
|
|
||||||
#[deprecated(
|
|
||||||
note = "There should not be a way to do this because the file may not be cached at a local path in the future."
|
|
||||||
)]
|
|
||||||
fn get_local_path(&self, specifier: &ModuleSpecifier) -> Option<PathBuf> {
|
fn get_local_path(&self, specifier: &ModuleSpecifier) -> Option<PathBuf> {
|
||||||
// TODO(@kitsonk) fix when deno_graph does not query cache for synthetic
|
// TODO(@kitsonk) fix when deno_graph does not query cache for synthetic
|
||||||
// modules
|
// modules
|
||||||
|
@ -175,15 +169,7 @@ impl Loader for FetchCacher {
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
let local = self.get_local_path(specifier)?;
|
let local = self.get_local_path(specifier)?;
|
||||||
if local.is_file() {
|
if local.is_file() {
|
||||||
let emit = self
|
Some(CacheInfo { local: Some(local) })
|
||||||
.emit_cache
|
|
||||||
.get_emit_filepath(specifier)
|
|
||||||
.filter(|p| p.is_file());
|
|
||||||
Some(CacheInfo {
|
|
||||||
local: Some(local),
|
|
||||||
emit,
|
|
||||||
map: None,
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -196,9 +182,8 @@ impl Loader for FetchCacher {
|
||||||
) -> LoadFuture {
|
) -> LoadFuture {
|
||||||
use deno_graph::source::CacheSetting as LoaderCacheSetting;
|
use deno_graph::source::CacheSetting as LoaderCacheSetting;
|
||||||
|
|
||||||
if specifier.scheme() == "file"
|
if specifier.scheme() == "file" {
|
||||||
&& specifier.path().contains("/node_modules/")
|
if specifier.path().contains("/node_modules/") {
|
||||||
{
|
|
||||||
// The specifier might be in a completely different symlinked tree than
|
// The specifier might be in a completely different symlinked tree than
|
||||||
// what the node_modules url is in (ex. `/my-project-1/node_modules`
|
// what the node_modules url is in (ex. `/my-project-1/node_modules`
|
||||||
// symlinked to `/my-project-2/node_modules`), so first we checked if the path
|
// symlinked to `/my-project-2/node_modules`), so first we checked if the path
|
||||||
|
@ -213,6 +198,16 @@ impl Loader for FetchCacher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make local CJS modules external to the graph
|
||||||
|
if specifier_has_extension(specifier, "cjs") {
|
||||||
|
return Box::pin(futures::future::ready(Ok(Some(
|
||||||
|
LoadResponse::External {
|
||||||
|
specifier: specifier.clone(),
|
||||||
|
},
|
||||||
|
))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let file_fetcher = self.file_fetcher.clone();
|
let file_fetcher = self.file_fetcher.clone();
|
||||||
let file_header_overrides = self.file_header_overrides.clone();
|
let file_header_overrides = self.file_header_overrides.clone();
|
||||||
let permissions = self.permissions.clone();
|
let permissions = self.permissions.clone();
|
||||||
|
@ -289,6 +284,7 @@ impl Loader for FetchCacher {
|
||||||
fn cache_module_info(
|
fn cache_module_info(
|
||||||
&self,
|
&self,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
|
media_type: MediaType,
|
||||||
source: &Arc<[u8]>,
|
source: &Arc<[u8]>,
|
||||||
module_info: &deno_graph::ModuleInfo,
|
module_info: &deno_graph::ModuleInfo,
|
||||||
) {
|
) {
|
||||||
|
@ -296,7 +292,7 @@ impl Loader for FetchCacher {
|
||||||
let source_hash = CacheDBHash::from_source(source);
|
let source_hash = CacheDBHash::from_source(source);
|
||||||
let result = self.module_info_cache.set_module_info(
|
let result = self.module_info_cache.set_module_info(
|
||||||
specifier,
|
specifier,
|
||||||
MediaType::from_specifier(specifier),
|
media_type,
|
||||||
source_hash,
|
source_hash,
|
||||||
module_info,
|
module_info,
|
||||||
);
|
);
|
||||||
|
|
64
cli/emit.rs
64
cli/emit.rs
|
@ -112,8 +112,7 @@ impl Emitter {
|
||||||
let parsed_source_cache = self.parsed_source_cache.clone();
|
let parsed_source_cache = self.parsed_source_cache.clone();
|
||||||
let transpile_and_emit_options =
|
let transpile_and_emit_options =
|
||||||
self.transpile_and_emit_options.clone();
|
self.transpile_and_emit_options.clone();
|
||||||
let (should_cache, transpile_result) =
|
let transpile_result = deno_core::unsync::spawn_blocking({
|
||||||
deno_core::unsync::spawn_blocking({
|
|
||||||
let specifier = specifier.clone();
|
let specifier = specifier.clone();
|
||||||
let source = source.clone();
|
let source = source.clone();
|
||||||
move || -> Result<_, AnyError> {
|
move || -> Result<_, AnyError> {
|
||||||
|
@ -133,7 +132,6 @@ impl Emitter {
|
||||||
specifier,
|
specifier,
|
||||||
transpile_result,
|
transpile_result,
|
||||||
source_hash,
|
source_hash,
|
||||||
should_cache,
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,8 +148,7 @@ impl Emitter {
|
||||||
match helper.pre_emit_parsed_source(specifier, source) {
|
match helper.pre_emit_parsed_source(specifier, source) {
|
||||||
PreEmitResult::Cached(emitted_text) => Ok(emitted_text),
|
PreEmitResult::Cached(emitted_text) => Ok(emitted_text),
|
||||||
PreEmitResult::NotCached { source_hash } => {
|
PreEmitResult::NotCached { source_hash } => {
|
||||||
let (should_cache, transpile_result) =
|
let transpile_result = EmitParsedSourceHelper::transpile(
|
||||||
EmitParsedSourceHelper::transpile(
|
|
||||||
&self.parsed_source_cache,
|
&self.parsed_source_cache,
|
||||||
specifier,
|
specifier,
|
||||||
source.clone(),
|
source.clone(),
|
||||||
|
@ -163,7 +160,6 @@ impl Emitter {
|
||||||
specifier,
|
specifier,
|
||||||
transpile_result,
|
transpile_result,
|
||||||
source_hash,
|
source_hash,
|
||||||
should_cache,
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,16 +257,13 @@ impl<'a> EmitParsedSourceHelper<'a> {
|
||||||
media_type: MediaType,
|
media_type: MediaType,
|
||||||
transpile_options: &deno_ast::TranspileOptions,
|
transpile_options: &deno_ast::TranspileOptions,
|
||||||
emit_options: &deno_ast::EmitOptions,
|
emit_options: &deno_ast::EmitOptions,
|
||||||
) -> Result<(bool, TranspileResult), AnyError> {
|
) -> Result<TranspileResult, AnyError> {
|
||||||
// nothing else needs the parsed source at this point, so remove from
|
// nothing else needs the parsed source at this point, so remove from
|
||||||
// the cache in order to not transpile owned
|
// the cache in order to not transpile owned
|
||||||
let parsed_source = parsed_source_cache
|
let parsed_source = parsed_source_cache
|
||||||
.remove_or_parse_module(specifier, source, media_type)?;
|
.remove_or_parse_module(specifier, source, media_type)?;
|
||||||
let should_cache = !has_import_assertion(&parsed_source);
|
ensure_no_import_assertion(&parsed_source)?;
|
||||||
Ok((
|
Ok(parsed_source.transpile(transpile_options, emit_options)?)
|
||||||
should_cache,
|
|
||||||
parsed_source.transpile(transpile_options, emit_options)?,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn post_emit_parsed_source(
|
pub fn post_emit_parsed_source(
|
||||||
|
@ -278,8 +271,6 @@ impl<'a> EmitParsedSourceHelper<'a> {
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
transpile_result: TranspileResult,
|
transpile_result: TranspileResult,
|
||||||
source_hash: u64,
|
source_hash: u64,
|
||||||
// todo(dsherret): remove after Deno 2.0
|
|
||||||
should_cache: bool,
|
|
||||||
) -> ModuleCodeBytes {
|
) -> ModuleCodeBytes {
|
||||||
let transpiled_source = match transpile_result {
|
let transpiled_source = match transpile_result {
|
||||||
TranspileResult::Owned(source) => source,
|
TranspileResult::Owned(source) => source,
|
||||||
|
@ -289,44 +280,47 @@ impl<'a> EmitParsedSourceHelper<'a> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
debug_assert!(transpiled_source.source_map.is_none());
|
debug_assert!(transpiled_source.source_map.is_none());
|
||||||
if should_cache {
|
|
||||||
self.0.emit_cache.set_emit_code(
|
self.0.emit_cache.set_emit_code(
|
||||||
specifier,
|
specifier,
|
||||||
source_hash,
|
source_hash,
|
||||||
&transpiled_source.source,
|
&transpiled_source.source,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
transpiled_source.source.into_boxed_slice().into()
|
transpiled_source.source.into_boxed_slice().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_import_assertion(parsed_source: &deno_ast::ParsedSource) -> bool {
|
// todo(dsherret): this is a temporary measure until we have swc erroring for this
|
||||||
|
fn ensure_no_import_assertion(
|
||||||
|
parsed_source: &deno_ast::ParsedSource,
|
||||||
|
) -> Result<(), AnyError> {
|
||||||
fn has_import_assertion(text: &str) -> bool {
|
fn has_import_assertion(text: &str) -> bool {
|
||||||
// good enough
|
// good enough
|
||||||
text.contains(" assert ") && !text.contains(" with ")
|
text.contains(" assert ") && !text.contains(" with ")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn warn_import_attribute(
|
fn create_err(
|
||||||
parsed_source: &deno_ast::ParsedSource,
|
parsed_source: &deno_ast::ParsedSource,
|
||||||
range: SourceRange,
|
range: SourceRange,
|
||||||
) {
|
) -> AnyError {
|
||||||
let text_info = parsed_source.text_info_lazy();
|
let text_info = parsed_source.text_info_lazy();
|
||||||
let loc = text_info.line_and_column_display(range.start);
|
let loc = text_info.line_and_column_display(range.start);
|
||||||
deno_runtime::import_assertion_callback(
|
let mut msg = "Import assertions are deprecated. Use `with` keyword, instead of 'assert' keyword.".to_string();
|
||||||
deno_core::ImportAssertionsSupportCustomCallbackArgs {
|
msg.push_str("\n\n");
|
||||||
maybe_specifier: Some(parsed_source.specifier().to_string()),
|
msg.push_str(range.text_fast(text_info));
|
||||||
maybe_line_number: Some(loc.line_number),
|
msg.push_str("\n\n");
|
||||||
column_number: loc.column_number,
|
msg.push_str(&format!(
|
||||||
maybe_source_line: Some(range.text_fast(text_info).to_string()),
|
" at {}:{}:{}\n",
|
||||||
},
|
parsed_source.specifier(),
|
||||||
)
|
loc.line_number,
|
||||||
|
loc.column_number,
|
||||||
|
));
|
||||||
|
deno_core::anyhow::anyhow!("{}", msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(module) = parsed_source.program_ref().as_module() else {
|
let Some(module) = parsed_source.program_ref().as_module() else {
|
||||||
return false;
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut had_import_assertion = false;
|
|
||||||
for item in &module.body {
|
for item in &module.body {
|
||||||
match item {
|
match item {
|
||||||
deno_ast::swc::ast::ModuleItem::ModuleDecl(decl) => match decl {
|
deno_ast::swc::ast::ModuleItem::ModuleDecl(decl) => match decl {
|
||||||
|
@ -334,24 +328,21 @@ fn has_import_assertion(parsed_source: &deno_ast::ParsedSource) -> bool {
|
||||||
if n.with.is_some()
|
if n.with.is_some()
|
||||||
&& has_import_assertion(n.text_fast(parsed_source.text_info_lazy()))
|
&& has_import_assertion(n.text_fast(parsed_source.text_info_lazy()))
|
||||||
{
|
{
|
||||||
had_import_assertion = true;
|
return Err(create_err(parsed_source, n.range()));
|
||||||
warn_import_attribute(parsed_source, n.range());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deno_ast::swc::ast::ModuleDecl::ExportAll(n) => {
|
deno_ast::swc::ast::ModuleDecl::ExportAll(n) => {
|
||||||
if n.with.is_some()
|
if n.with.is_some()
|
||||||
&& has_import_assertion(n.text_fast(parsed_source.text_info_lazy()))
|
&& has_import_assertion(n.text_fast(parsed_source.text_info_lazy()))
|
||||||
{
|
{
|
||||||
had_import_assertion = true;
|
return Err(create_err(parsed_source, n.range()));
|
||||||
warn_import_attribute(parsed_source, n.range());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deno_ast::swc::ast::ModuleDecl::ExportNamed(n) => {
|
deno_ast::swc::ast::ModuleDecl::ExportNamed(n) => {
|
||||||
if n.with.is_some()
|
if n.with.is_some()
|
||||||
&& has_import_assertion(n.text_fast(parsed_source.text_info_lazy()))
|
&& has_import_assertion(n.text_fast(parsed_source.text_info_lazy()))
|
||||||
{
|
{
|
||||||
had_import_assertion = true;
|
return Err(create_err(parsed_source, n.range()));
|
||||||
warn_import_attribute(parsed_source, n.range());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deno_ast::swc::ast::ModuleDecl::ExportDecl(_)
|
deno_ast::swc::ast::ModuleDecl::ExportDecl(_)
|
||||||
|
@ -364,5 +355,6 @@ fn has_import_assertion(parsed_source: &deno_ast::ParsedSource) -> bool {
|
||||||
deno_ast::swc::ast::ModuleItem::Stmt(_) => {}
|
deno_ast::swc::ast::ModuleItem::Stmt(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
had_import_assertion
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
use crate::args::check_warn_tsconfig;
|
||||||
use crate::args::get_root_cert_store;
|
use crate::args::get_root_cert_store;
|
||||||
use crate::args::CaData;
|
use crate::args::CaData;
|
||||||
use crate::args::CliOptions;
|
use crate::args::CliOptions;
|
||||||
use crate::args::DenoSubcommand;
|
use crate::args::DenoSubcommand;
|
||||||
use crate::args::Flags;
|
use crate::args::Flags;
|
||||||
use crate::args::PackageJsonInstallDepsProvider;
|
use crate::args::NpmInstallDepsProvider;
|
||||||
use crate::args::StorageKeyResolver;
|
use crate::args::StorageKeyResolver;
|
||||||
use crate::args::TsConfigType;
|
use crate::args::TsConfigType;
|
||||||
use crate::cache::Caches;
|
use crate::cache::Caches;
|
||||||
|
@ -386,9 +387,7 @@ impl CliFactory {
|
||||||
cache_setting: cli_options.cache_setting(),
|
cache_setting: cli_options.cache_setting(),
|
||||||
text_only_progress_bar: self.text_only_progress_bar().clone(),
|
text_only_progress_bar: self.text_only_progress_bar().clone(),
|
||||||
maybe_node_modules_path: cli_options.node_modules_dir_path().cloned(),
|
maybe_node_modules_path: cli_options.node_modules_dir_path().cloned(),
|
||||||
package_json_deps_provider: Arc::new(PackageJsonInstallDepsProvider::from_workspace(
|
npm_install_deps_provider: Arc::new(NpmInstallDepsProvider::from_workspace(cli_options.workspace())),
|
||||||
cli_options.workspace(),
|
|
||||||
)),
|
|
||||||
npm_system_info: cli_options.npm_system_info(),
|
npm_system_info: cli_options.npm_system_info(),
|
||||||
npmrc: cli_options.npmrc().clone(),
|
npmrc: cli_options.npmrc().clone(),
|
||||||
lifecycle_scripts: cli_options.lifecycle_scripts_config(),
|
lifecycle_scripts: cli_options.lifecycle_scripts_config(),
|
||||||
|
@ -522,9 +521,7 @@ impl CliFactory {
|
||||||
let cli_options = self.cli_options()?;
|
let cli_options = self.cli_options()?;
|
||||||
let ts_config_result =
|
let ts_config_result =
|
||||||
cli_options.resolve_ts_config_for_emit(TsConfigType::Emit)?;
|
cli_options.resolve_ts_config_for_emit(TsConfigType::Emit)?;
|
||||||
if let Some(ignored_options) = ts_config_result.maybe_ignored_options {
|
check_warn_tsconfig(&ts_config_result);
|
||||||
warn!("{}", ignored_options);
|
|
||||||
}
|
|
||||||
let (transpile_options, emit_options) =
|
let (transpile_options, emit_options) =
|
||||||
crate::args::ts_config_to_transpile_and_emit_options(
|
crate::args::ts_config_to_transpile_and_emit_options(
|
||||||
ts_config_result.ts_config,
|
ts_config_result.ts_config,
|
||||||
|
@ -619,7 +616,6 @@ impl CliFactory {
|
||||||
self.parsed_source_cache().clone(),
|
self.parsed_source_cache().clone(),
|
||||||
cli_options.maybe_lockfile().cloned(),
|
cli_options.maybe_lockfile().cloned(),
|
||||||
self.maybe_file_watcher_reporter().clone(),
|
self.maybe_file_watcher_reporter().clone(),
|
||||||
self.emit_cache()?.clone(),
|
|
||||||
self.file_fetcher()?.clone(),
|
self.file_fetcher()?.clone(),
|
||||||
self.global_http_cache()?.clone(),
|
self.global_http_cache()?.clone(),
|
||||||
)))
|
)))
|
||||||
|
@ -793,20 +789,12 @@ impl CliFactory {
|
||||||
self.maybe_inspector_server()?.clone(),
|
self.maybe_inspector_server()?.clone(),
|
||||||
cli_options.maybe_lockfile().cloned(),
|
cli_options.maybe_lockfile().cloned(),
|
||||||
self.feature_checker()?.clone(),
|
self.feature_checker()?.clone(),
|
||||||
self.create_cli_main_worker_options()?,
|
|
||||||
cli_options.node_ipc_fd(),
|
|
||||||
cli_options.serve_port(),
|
|
||||||
cli_options.serve_host(),
|
|
||||||
cli_options.enable_future_features(),
|
|
||||||
// TODO(bartlomieju): temporarily disabled
|
|
||||||
// cli_options.disable_deprecated_api_warning,
|
|
||||||
true,
|
|
||||||
cli_options.verbose_deprecated_api_warning,
|
|
||||||
if cli_options.code_cache_enabled() {
|
if cli_options.code_cache_enabled() {
|
||||||
Some(self.code_cache()?.clone())
|
Some(self.code_cache()?.clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
|
self.create_cli_main_worker_options()?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -871,6 +859,9 @@ impl CliFactory {
|
||||||
unstable: cli_options.legacy_unstable_flag(),
|
unstable: cli_options.legacy_unstable_flag(),
|
||||||
create_hmr_runner,
|
create_hmr_runner,
|
||||||
create_coverage_collector,
|
create_coverage_collector,
|
||||||
|
node_ipc: cli_options.node_ipc_fd(),
|
||||||
|
serve_port: cli_options.serve_port(),
|
||||||
|
serve_host: cli_options.serve_host(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,13 +20,12 @@ use crate::tools::check::TypeChecker;
|
||||||
use crate::util::file_watcher::WatcherCommunicator;
|
use crate::util::file_watcher::WatcherCommunicator;
|
||||||
use crate::util::fs::canonicalize_path;
|
use crate::util::fs::canonicalize_path;
|
||||||
use deno_config::workspace::JsrPackageConfig;
|
use deno_config::workspace::JsrPackageConfig;
|
||||||
use deno_emit::LoaderChecksum;
|
use deno_graph::source::LoaderChecksum;
|
||||||
use deno_graph::JsrLoadError;
|
use deno_graph::JsrLoadError;
|
||||||
use deno_graph::ModuleLoadError;
|
use deno_graph::ModuleLoadError;
|
||||||
use deno_graph::WorkspaceFastCheckOption;
|
use deno_graph::WorkspaceFastCheckOption;
|
||||||
use deno_runtime::fs_util::specifier_to_file_path;
|
use deno_runtime::fs_util::specifier_to_file_path;
|
||||||
|
|
||||||
use deno_core::anyhow::bail;
|
|
||||||
use deno_core::error::custom_error;
|
use deno_core::error::custom_error;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::parking_lot::Mutex;
|
use deno_core::parking_lot::Mutex;
|
||||||
|
@ -35,7 +34,6 @@ use deno_graph::source::Loader;
|
||||||
use deno_graph::source::ResolutionMode;
|
use deno_graph::source::ResolutionMode;
|
||||||
use deno_graph::source::ResolveError;
|
use deno_graph::source::ResolveError;
|
||||||
use deno_graph::GraphKind;
|
use deno_graph::GraphKind;
|
||||||
use deno_graph::Module;
|
|
||||||
use deno_graph::ModuleError;
|
use deno_graph::ModuleError;
|
||||||
use deno_graph::ModuleGraph;
|
use deno_graph::ModuleGraph;
|
||||||
use deno_graph::ModuleGraphError;
|
use deno_graph::ModuleGraphError;
|
||||||
|
@ -44,10 +42,13 @@ use deno_graph::SpecifierError;
|
||||||
use deno_runtime::deno_fs::FileSystem;
|
use deno_runtime::deno_fs::FileSystem;
|
||||||
use deno_runtime::deno_node;
|
use deno_runtime::deno_node;
|
||||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||||
|
use deno_semver::jsr::JsrDepPackageReq;
|
||||||
use deno_semver::package::PackageNv;
|
use deno_semver::package::PackageNv;
|
||||||
use deno_semver::package::PackageReq;
|
use deno_semver::Version;
|
||||||
use import_map::ImportMapError;
|
use import_map::ImportMapError;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
use std::error::Error;
|
||||||
|
use std::ops::Deref;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -110,7 +111,7 @@ pub fn graph_valid(
|
||||||
ModuleGraphError::ModuleError(error) => {
|
ModuleGraphError::ModuleError(error) => {
|
||||||
enhanced_lockfile_error_message(error)
|
enhanced_lockfile_error_message(error)
|
||||||
.or_else(|| enhanced_sloppy_imports_error_message(fs, error))
|
.or_else(|| enhanced_sloppy_imports_error_message(fs, error))
|
||||||
.unwrap_or_else(|| format!("{}", error))
|
.unwrap_or_else(|| format_deno_graph_error(error))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -164,7 +165,10 @@ pub fn graph_valid(
|
||||||
} else {
|
} else {
|
||||||
// finally surface the npm resolution result
|
// finally surface the npm resolution result
|
||||||
if let Err(err) = &graph.npm_dep_graph_result {
|
if let Err(err) = &graph.npm_dep_graph_result {
|
||||||
return Err(custom_error(get_error_class_name(err), format!("{}", err)));
|
return Err(custom_error(
|
||||||
|
get_error_class_name(err),
|
||||||
|
format_deno_graph_error(err.as_ref().deref()),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -364,7 +368,6 @@ pub struct ModuleGraphBuilder {
|
||||||
parsed_source_cache: Arc<ParsedSourceCache>,
|
parsed_source_cache: Arc<ParsedSourceCache>,
|
||||||
lockfile: Option<Arc<CliLockfile>>,
|
lockfile: Option<Arc<CliLockfile>>,
|
||||||
maybe_file_watcher_reporter: Option<FileWatcherReporter>,
|
maybe_file_watcher_reporter: Option<FileWatcherReporter>,
|
||||||
emit_cache: Arc<cache::EmitCache>,
|
|
||||||
file_fetcher: Arc<FileFetcher>,
|
file_fetcher: Arc<FileFetcher>,
|
||||||
global_http_cache: Arc<GlobalHttpCache>,
|
global_http_cache: Arc<GlobalHttpCache>,
|
||||||
}
|
}
|
||||||
|
@ -381,7 +384,6 @@ impl ModuleGraphBuilder {
|
||||||
parsed_source_cache: Arc<ParsedSourceCache>,
|
parsed_source_cache: Arc<ParsedSourceCache>,
|
||||||
lockfile: Option<Arc<CliLockfile>>,
|
lockfile: Option<Arc<CliLockfile>>,
|
||||||
maybe_file_watcher_reporter: Option<FileWatcherReporter>,
|
maybe_file_watcher_reporter: Option<FileWatcherReporter>,
|
||||||
emit_cache: Arc<cache::EmitCache>,
|
|
||||||
file_fetcher: Arc<FileFetcher>,
|
file_fetcher: Arc<FileFetcher>,
|
||||||
global_http_cache: Arc<GlobalHttpCache>,
|
global_http_cache: Arc<GlobalHttpCache>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -395,7 +397,6 @@ impl ModuleGraphBuilder {
|
||||||
parsed_source_cache,
|
parsed_source_cache,
|
||||||
lockfile,
|
lockfile,
|
||||||
maybe_file_watcher_reporter,
|
maybe_file_watcher_reporter,
|
||||||
emit_cache,
|
|
||||||
file_fetcher,
|
file_fetcher,
|
||||||
global_http_cache,
|
global_http_cache,
|
||||||
}
|
}
|
||||||
|
@ -463,7 +464,7 @@ impl ModuleGraphBuilder {
|
||||||
.content
|
.content
|
||||||
.packages
|
.packages
|
||||||
.jsr
|
.jsr
|
||||||
.get(&package_nv.to_string())
|
.get(package_nv)
|
||||||
.map(|s| LoaderChecksum::new(s.integrity.clone()))
|
.map(|s| LoaderChecksum::new(s.integrity.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,7 +478,7 @@ impl ModuleGraphBuilder {
|
||||||
self
|
self
|
||||||
.0
|
.0
|
||||||
.lock()
|
.lock()
|
||||||
.insert_package(package_nv.to_string(), checksum.into_string());
|
.insert_package(package_nv.clone(), checksum.into_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,7 +536,12 @@ impl ModuleGraphBuilder {
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
// ensure an "npm install" is done if the user has explicitly
|
// ensure an "npm install" is done if the user has explicitly
|
||||||
// opted into using a node_modules directory
|
// opted into using a node_modules directory
|
||||||
if self.options.node_modules_dir_enablement() == Some(true) {
|
if self
|
||||||
|
.options
|
||||||
|
.node_modules_dir()?
|
||||||
|
.map(|m| m.uses_node_modules_dir())
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
if let Some(npm_resolver) = self.npm_resolver.as_managed() {
|
if let Some(npm_resolver) = self.npm_resolver.as_managed() {
|
||||||
npm_resolver.ensure_top_level_package_json_install().await?;
|
npm_resolver.ensure_top_level_package_json_install().await?;
|
||||||
}
|
}
|
||||||
|
@ -556,16 +562,21 @@ impl ModuleGraphBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (key, value) in &lockfile.content.packages.specifiers {
|
for (req_dep, value) in &lockfile.content.packages.specifiers {
|
||||||
if let Some(key) = key
|
match req_dep.kind {
|
||||||
.strip_prefix("jsr:")
|
deno_semver::package::PackageKind::Jsr => {
|
||||||
.and_then(|key| PackageReq::from_str(key).ok())
|
if let Ok(version) = Version::parse_standard(value) {
|
||||||
{
|
graph.packages.add_nv(
|
||||||
if let Some(value) = value
|
req_dep.req.clone(),
|
||||||
.strip_prefix("jsr:")
|
PackageNv {
|
||||||
.and_then(|value| PackageNv::from_str(value).ok())
|
name: req_dep.req.name.clone(),
|
||||||
{
|
version,
|
||||||
graph.packages.add_nv(key, value);
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deno_semver::package::PackageKind::Npm => {
|
||||||
|
// ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -603,16 +614,15 @@ impl ModuleGraphBuilder {
|
||||||
if has_jsr_package_mappings_changed {
|
if has_jsr_package_mappings_changed {
|
||||||
for (from, to) in graph.packages.mappings() {
|
for (from, to) in graph.packages.mappings() {
|
||||||
lockfile.insert_package_specifier(
|
lockfile.insert_package_specifier(
|
||||||
format!("jsr:{}", from),
|
JsrDepPackageReq::jsr(from.clone()),
|
||||||
format!("jsr:{}", to),
|
to.version.to_string(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// jsr packages
|
// jsr packages
|
||||||
if has_jsr_package_deps_changed {
|
if has_jsr_package_deps_changed {
|
||||||
for (name, deps) in graph.packages.packages_with_deps() {
|
for (nv, deps) in graph.packages.packages_with_deps() {
|
||||||
lockfile
|
lockfile.add_package_deps(nv, deps.cloned());
|
||||||
.add_package_deps(&name.to_string(), deps.map(|s| s.to_string()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -668,7 +678,6 @@ impl ModuleGraphBuilder {
|
||||||
permissions: PermissionsContainer,
|
permissions: PermissionsContainer,
|
||||||
) -> cache::FetchCacher {
|
) -> cache::FetchCacher {
|
||||||
cache::FetchCacher::new(
|
cache::FetchCacher::new(
|
||||||
self.emit_cache.clone(),
|
|
||||||
self.file_fetcher.clone(),
|
self.file_fetcher.clone(),
|
||||||
self.options.resolve_file_header_overrides(),
|
self.options.resolve_file_header_overrides(),
|
||||||
self.global_http_cache.clone(),
|
self.global_http_cache.clone(),
|
||||||
|
@ -707,33 +716,29 @@ impl ModuleGraphBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn error_for_any_npm_specifier(
|
|
||||||
graph: &ModuleGraph,
|
|
||||||
) -> Result<(), AnyError> {
|
|
||||||
for module in graph.modules() {
|
|
||||||
match module {
|
|
||||||
Module::Npm(module) => {
|
|
||||||
bail!("npm specifiers have not yet been implemented for this subcommand (https://github.com/denoland/deno/issues/15960). Found: {}", module.specifier)
|
|
||||||
}
|
|
||||||
Module::Node(module) => {
|
|
||||||
bail!("Node specifiers have not yet been implemented for this subcommand (https://github.com/denoland/deno/issues/15960). Found: node:{}", module.module_name)
|
|
||||||
}
|
|
||||||
Module::Js(_) | Module::Json(_) | Module::External(_) => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds more explanatory information to a resolution error.
|
/// Adds more explanatory information to a resolution error.
|
||||||
pub fn enhanced_resolution_error_message(error: &ResolutionError) -> String {
|
pub fn enhanced_resolution_error_message(error: &ResolutionError) -> String {
|
||||||
let mut message = format!("{error}");
|
let mut message = format_deno_graph_error(error);
|
||||||
|
|
||||||
if let Some(specifier) = get_resolution_error_bare_node_specifier(error) {
|
let maybe_hint = if let Some(specifier) =
|
||||||
|
get_resolution_error_bare_node_specifier(error)
|
||||||
|
{
|
||||||
if !*DENO_DISABLE_PEDANTIC_NODE_WARNINGS {
|
if !*DENO_DISABLE_PEDANTIC_NODE_WARNINGS {
|
||||||
message.push_str(&format!(
|
Some(format!("If you want to use a built-in Node module, add a \"node:\" prefix (ex. \"node:{specifier}\")."))
|
||||||
"\nIf you want to use a built-in Node module, add a \"node:\" prefix (ex. \"node:{specifier}\")."
|
} else {
|
||||||
));
|
None
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
get_import_prefix_missing_error(error).map(|specifier| {
|
||||||
|
format!(
|
||||||
|
"If you want to use a JSR or npm package, try running `deno add jsr:{}` or `deno add npm:{}`",
|
||||||
|
specifier, specifier
|
||||||
|
)
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(hint) = maybe_hint {
|
||||||
|
message.push_str(&format!("\n {} {}", colors::cyan("hint:"), hint));
|
||||||
}
|
}
|
||||||
|
|
||||||
message
|
message
|
||||||
|
@ -868,6 +873,50 @@ fn get_resolution_error_bare_specifier(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_import_prefix_missing_error(error: &ResolutionError) -> Option<&str> {
|
||||||
|
let mut maybe_specifier = None;
|
||||||
|
if let ResolutionError::InvalidSpecifier {
|
||||||
|
error: SpecifierError::ImportPrefixMissing { specifier, .. },
|
||||||
|
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.downcast_ref::<SpecifierError>()
|
||||||
|
{
|
||||||
|
maybe_specifier = Some(specifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(bartlomieju): For now, return None if a specifier contains a dot or a space. This is because
|
||||||
|
// suggesting to `deno add bad-module.ts` makes no sense and is worse than not providing
|
||||||
|
// a suggestion at all. This should be improved further in the future
|
||||||
|
if let Some(specifier) = maybe_specifier {
|
||||||
|
if specifier.contains('.') || specifier.contains(' ') {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
maybe_specifier.map(|s| s.as_str())
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets if any of the specified root's "file:" dependents are in the
|
/// Gets if any of the specified root's "file:" dependents are in the
|
||||||
/// provided changed set.
|
/// provided changed set.
|
||||||
pub fn has_graph_root_local_dependent_changed(
|
pub fn has_graph_root_local_dependent_changed(
|
||||||
|
@ -1022,6 +1071,49 @@ impl deno_graph::source::JsrUrlProvider for CliJsrUrlProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo(dsherret): We should change ModuleError to use thiserror so that
|
||||||
|
// we don't need to do this.
|
||||||
|
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)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
|
@ -104,12 +104,12 @@ function bench(
|
||||||
}
|
}
|
||||||
if (optionsOrFn.fn != undefined) {
|
if (optionsOrFn.fn != undefined) {
|
||||||
throw new TypeError(
|
throw new TypeError(
|
||||||
"Unexpected 'fn' field in options, bench function is already provided as the third argument.",
|
"Unexpected 'fn' field in options, bench function is already provided as the third argument",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (optionsOrFn.name != undefined) {
|
if (optionsOrFn.name != undefined) {
|
||||||
throw new TypeError(
|
throw new TypeError(
|
||||||
"Unexpected 'name' field in options, bench name is already provided as the first argument.",
|
"Unexpected 'name' field in options, bench name is already provided as the first argument",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
benchDesc = {
|
benchDesc = {
|
||||||
|
@ -141,7 +141,7 @@ function bench(
|
||||||
fn = optionsOrFn;
|
fn = optionsOrFn;
|
||||||
if (nameOrFnOrOptions.fn != undefined) {
|
if (nameOrFnOrOptions.fn != undefined) {
|
||||||
throw new TypeError(
|
throw new TypeError(
|
||||||
"Unexpected 'fn' field in options, bench function is already provided as the second argument.",
|
"Unexpected 'fn' field in options, bench function is already provided as the second argument",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
name = nameOrFnOrOptions.name ?? fn.name;
|
name = nameOrFnOrOptions.name ?? fn.name;
|
||||||
|
@ -150,7 +150,7 @@ function bench(
|
||||||
!nameOrFnOrOptions.fn || typeof nameOrFnOrOptions.fn !== "function"
|
!nameOrFnOrOptions.fn || typeof nameOrFnOrOptions.fn !== "function"
|
||||||
) {
|
) {
|
||||||
throw new TypeError(
|
throw new TypeError(
|
||||||
"Expected 'fn' field in the first argument to be a bench function.",
|
"Expected 'fn' field in the first argument to be a bench function",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
fn = nameOrFnOrOptions.fn;
|
fn = nameOrFnOrOptions.fn;
|
||||||
|
@ -385,12 +385,12 @@ function createBenchContext(desc) {
|
||||||
start() {
|
start() {
|
||||||
if (currentBenchId !== desc.id) {
|
if (currentBenchId !== desc.id) {
|
||||||
throw new TypeError(
|
throw new TypeError(
|
||||||
"The benchmark which this context belongs to is not being executed.",
|
"The benchmark which this context belongs to is not being executed",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (currentBenchUserExplicitStart != null) {
|
if (currentBenchUserExplicitStart != null) {
|
||||||
throw new TypeError(
|
throw new TypeError(
|
||||||
"BenchContext::start() has already been invoked.",
|
"BenchContext::start() has already been invoked",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
currentBenchUserExplicitStart = benchNow();
|
currentBenchUserExplicitStart = benchNow();
|
||||||
|
@ -399,11 +399,11 @@ function createBenchContext(desc) {
|
||||||
const end = benchNow();
|
const end = benchNow();
|
||||||
if (currentBenchId !== desc.id) {
|
if (currentBenchId !== desc.id) {
|
||||||
throw new TypeError(
|
throw new TypeError(
|
||||||
"The benchmark which this context belongs to is not being executed.",
|
"The benchmark which this context belongs to is not being executed",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (currentBenchUserExplicitEnd != null) {
|
if (currentBenchUserExplicitEnd != null) {
|
||||||
throw new TypeError("BenchContext::end() has already been invoked.");
|
throw new TypeError("BenchContext::end() has already been invoked");
|
||||||
}
|
}
|
||||||
currentBenchUserExplicitEnd = end;
|
currentBenchUserExplicitEnd = end;
|
||||||
},
|
},
|
||||||
|
|
|
@ -113,7 +113,7 @@ function assertExit(fn, isTest) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`${
|
`${
|
||||||
isTest ? "Test case" : "Bench"
|
isTest ? "Test case" : "Bench"
|
||||||
} finished with exit code set to ${exitCode}.`,
|
} finished with exit code set to ${exitCode}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (innerResult) {
|
if (innerResult) {
|
||||||
|
@ -242,12 +242,12 @@ function testInner(
|
||||||
}
|
}
|
||||||
if (optionsOrFn.fn != undefined) {
|
if (optionsOrFn.fn != undefined) {
|
||||||
throw new TypeError(
|
throw new TypeError(
|
||||||
"Unexpected 'fn' field in options, test function is already provided as the third argument.",
|
"Unexpected 'fn' field in options, test function is already provided as the third argument",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (optionsOrFn.name != undefined) {
|
if (optionsOrFn.name != undefined) {
|
||||||
throw new TypeError(
|
throw new TypeError(
|
||||||
"Unexpected 'name' field in options, test name is already provided as the first argument.",
|
"Unexpected 'name' field in options, test name is already provided as the first argument",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
testDesc = {
|
testDesc = {
|
||||||
|
@ -279,7 +279,7 @@ function testInner(
|
||||||
fn = optionsOrFn;
|
fn = optionsOrFn;
|
||||||
if (nameOrFnOrOptions.fn != undefined) {
|
if (nameOrFnOrOptions.fn != undefined) {
|
||||||
throw new TypeError(
|
throw new TypeError(
|
||||||
"Unexpected 'fn' field in options, test function is already provided as the second argument.",
|
"Unexpected 'fn' field in options, test function is already provided as the second argument",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
name = nameOrFnOrOptions.name ?? fn.name;
|
name = nameOrFnOrOptions.name ?? fn.name;
|
||||||
|
@ -288,7 +288,7 @@ function testInner(
|
||||||
!nameOrFnOrOptions.fn || typeof nameOrFnOrOptions.fn !== "function"
|
!nameOrFnOrOptions.fn || typeof nameOrFnOrOptions.fn !== "function"
|
||||||
) {
|
) {
|
||||||
throw new TypeError(
|
throw new TypeError(
|
||||||
"Expected 'fn' field in the first argument to be a test function.",
|
"Expected 'fn' field in the first argument to be a test function",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
fn = nameOrFnOrOptions.fn;
|
fn = nameOrFnOrOptions.fn;
|
||||||
|
@ -426,7 +426,7 @@ function createTestContext(desc) {
|
||||||
let stepDesc;
|
let stepDesc;
|
||||||
if (typeof nameOrFnOrOptions === "string") {
|
if (typeof nameOrFnOrOptions === "string") {
|
||||||
if (typeof maybeFn !== "function") {
|
if (typeof maybeFn !== "function") {
|
||||||
throw new TypeError("Expected function for second argument.");
|
throw new TypeError("Expected function for second argument");
|
||||||
}
|
}
|
||||||
stepDesc = {
|
stepDesc = {
|
||||||
name: nameOrFnOrOptions,
|
name: nameOrFnOrOptions,
|
||||||
|
@ -434,7 +434,7 @@ function createTestContext(desc) {
|
||||||
};
|
};
|
||||||
} else if (typeof nameOrFnOrOptions === "function") {
|
} else if (typeof nameOrFnOrOptions === "function") {
|
||||||
if (!nameOrFnOrOptions.name) {
|
if (!nameOrFnOrOptions.name) {
|
||||||
throw new TypeError("The step function must have a name.");
|
throw new TypeError("The step function must have a name");
|
||||||
}
|
}
|
||||||
if (maybeFn != undefined) {
|
if (maybeFn != undefined) {
|
||||||
throw new TypeError(
|
throw new TypeError(
|
||||||
|
@ -449,7 +449,7 @@ function createTestContext(desc) {
|
||||||
stepDesc = nameOrFnOrOptions;
|
stepDesc = nameOrFnOrOptions;
|
||||||
} else {
|
} else {
|
||||||
throw new TypeError(
|
throw new TypeError(
|
||||||
"Expected a test definition or name and function.",
|
"Expected a test definition or name and function",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
stepDesc.ignore ??= false;
|
stepDesc.ignore ??= false;
|
||||||
|
|
|
@ -751,7 +751,7 @@ impl CodeActionCollection {
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|d| serde_json::from_value::<Vec<DataQuickFix>>(d.clone()).ok())
|
.and_then(|d| serde_json::from_value::<Vec<DataQuickFix>>(d.clone()).ok())
|
||||||
{
|
{
|
||||||
let uri = url_to_uri(specifier);
|
let uri = url_to_uri(specifier)?;
|
||||||
for quick_fix in data_quick_fixes {
|
for quick_fix in data_quick_fixes {
|
||||||
let mut changes = HashMap::new();
|
let mut changes = HashMap::new();
|
||||||
changes.insert(
|
changes.insert(
|
||||||
|
@ -797,7 +797,7 @@ impl CodeActionCollection {
|
||||||
maybe_text_info: Option<&SourceTextInfo>,
|
maybe_text_info: Option<&SourceTextInfo>,
|
||||||
maybe_parsed_source: Option<&deno_ast::ParsedSource>,
|
maybe_parsed_source: Option<&deno_ast::ParsedSource>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let uri = url_to_uri(specifier);
|
let uri = url_to_uri(specifier)?;
|
||||||
let code = diagnostic
|
let code = diagnostic
|
||||||
.code
|
.code
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
|
|
@ -8,6 +8,7 @@ use deno_core::anyhow::bail;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::serde_json::json;
|
use deno_core::serde_json::json;
|
||||||
use deno_core::unsync::spawn;
|
use deno_core::unsync::spawn;
|
||||||
|
use lsp_types::Uri;
|
||||||
use tower_lsp::lsp_types as lsp;
|
use tower_lsp::lsp_types as lsp;
|
||||||
use tower_lsp::lsp_types::ConfigurationItem;
|
use tower_lsp::lsp_types::ConfigurationItem;
|
||||||
|
|
||||||
|
@ -17,7 +18,6 @@ use super::config::WorkspaceSettings;
|
||||||
use super::config::SETTINGS_SECTION;
|
use super::config::SETTINGS_SECTION;
|
||||||
use super::lsp_custom;
|
use super::lsp_custom;
|
||||||
use super::testing::lsp_custom as testing_lsp_custom;
|
use super::testing::lsp_custom as testing_lsp_custom;
|
||||||
use super::urls::LspClientUrl;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum TestingNotification {
|
pub enum TestingNotification {
|
||||||
|
@ -52,14 +52,11 @@ impl Client {
|
||||||
|
|
||||||
pub async fn publish_diagnostics(
|
pub async fn publish_diagnostics(
|
||||||
&self,
|
&self,
|
||||||
uri: LspClientUrl,
|
uri: Uri,
|
||||||
diags: Vec<lsp::Diagnostic>,
|
diags: Vec<lsp::Diagnostic>,
|
||||||
version: Option<i32>,
|
version: Option<i32>,
|
||||||
) {
|
) {
|
||||||
self
|
self.0.publish_diagnostics(uri, diags, version).await;
|
||||||
.0
|
|
||||||
.publish_diagnostics(uri.to_uri(), diags, version)
|
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_registry_state_notification(
|
pub fn send_registry_state_notification(
|
||||||
|
|
|
@ -5,6 +5,7 @@ use deno_config::deno_json::DenoJsonCache;
|
||||||
use deno_config::deno_json::FmtConfig;
|
use deno_config::deno_json::FmtConfig;
|
||||||
use deno_config::deno_json::FmtOptionsConfig;
|
use deno_config::deno_json::FmtOptionsConfig;
|
||||||
use deno_config::deno_json::LintConfig;
|
use deno_config::deno_json::LintConfig;
|
||||||
|
use deno_config::deno_json::NodeModulesDirMode;
|
||||||
use deno_config::deno_json::TestConfig;
|
use deno_config::deno_json::TestConfig;
|
||||||
use deno_config::deno_json::TsConfig;
|
use deno_config::deno_json::TsConfig;
|
||||||
use deno_config::fs::DenoConfigFs;
|
use deno_config::fs::DenoConfigFs;
|
||||||
|
@ -54,7 +55,6 @@ use crate::args::CliLockfile;
|
||||||
use crate::args::ConfigFile;
|
use crate::args::ConfigFile;
|
||||||
use crate::args::LintFlags;
|
use crate::args::LintFlags;
|
||||||
use crate::args::LintOptions;
|
use crate::args::LintOptions;
|
||||||
use crate::args::DENO_FUTURE;
|
|
||||||
use crate::cache::FastInsecureHasher;
|
use crate::cache::FastInsecureHasher;
|
||||||
use crate::file_fetcher::FileFetcher;
|
use crate::file_fetcher::FileFetcher;
|
||||||
use crate::lsp::logging::lsp_warn;
|
use crate::lsp::logging::lsp_warn;
|
||||||
|
@ -850,7 +850,7 @@ impl Config {
|
||||||
let mut config = Self::default();
|
let mut config = Self::default();
|
||||||
let mut folders = vec![];
|
let mut folders = vec![];
|
||||||
for root_url in root_urls {
|
for root_url in root_urls {
|
||||||
let root_uri = url_to_uri(&root_url);
|
let root_uri = url_to_uri(&root_url).unwrap();
|
||||||
let name = root_url.path_segments().and_then(|s| s.last());
|
let name = root_url.path_segments().and_then(|s| s.last());
|
||||||
let name = name.unwrap_or_default().to_string();
|
let name = name.unwrap_or_default().to_string();
|
||||||
folders.push((
|
folders.push((
|
||||||
|
@ -1084,7 +1084,6 @@ impl Default for LspTsConfig {
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"useDefineForClassFields": true,
|
"useDefineForClassFields": true,
|
||||||
"useUnknownInCatchVariables": false,
|
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
"jsxFactory": "React.createElement",
|
"jsxFactory": "React.createElement",
|
||||||
"jsxFragmentFactory": "React.Fragment",
|
"jsxFragmentFactory": "React.Fragment",
|
||||||
|
@ -1387,11 +1386,12 @@ impl ConfigData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let byonm = std::env::var("DENO_UNSTABLE_BYONM").is_ok()
|
let node_modules_dir =
|
||||||
|| member_dir.workspace.has_unstable("byonm")
|
member_dir.workspace.node_modules_dir().unwrap_or_default();
|
||||||
|| (*DENO_FUTURE
|
let byonm = match node_modules_dir {
|
||||||
&& member_dir.workspace.package_jsons().next().is_some()
|
Some(mode) => mode == NodeModulesDirMode::Manual,
|
||||||
&& member_dir.workspace.node_modules_dir().is_none());
|
None => member_dir.workspace.root_pkg_json().is_some(),
|
||||||
|
};
|
||||||
if byonm {
|
if byonm {
|
||||||
lsp_log!(" Enabled 'bring your own node_modules'.");
|
lsp_log!(" Enabled 'bring your own node_modules'.");
|
||||||
}
|
}
|
||||||
|
@ -1694,9 +1694,14 @@ impl ConfigTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_watched_file(&self, specifier: &ModuleSpecifier) -> bool {
|
pub fn is_watched_file(&self, specifier: &ModuleSpecifier) -> bool {
|
||||||
if specifier.path().ends_with("/deno.json")
|
let path = specifier.path();
|
||||||
|| specifier.path().ends_with("/deno.jsonc")
|
if path.ends_with("/deno.json")
|
||||||
|| specifier.path().ends_with("/package.json")
|
|| path.ends_with("/deno.jsonc")
|
||||||
|
|| path.ends_with("/package.json")
|
||||||
|
|| path.ends_with("/node_modules/.package-lock.json")
|
||||||
|
|| path.ends_with("/node_modules/.yarn-integrity.json")
|
||||||
|
|| path.ends_with("/node_modules/.modules.yaml")
|
||||||
|
|| path.ends_with("/node_modules/.deno/.setup-cache.bin")
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1865,13 +1870,17 @@ fn resolve_node_modules_dir(
|
||||||
// `nodeModulesDir: true` setting in the deno.json file. This is to
|
// `nodeModulesDir: true` setting in the deno.json file. This is to
|
||||||
// reduce the chance of modifying someone's node_modules directory
|
// reduce the chance of modifying someone's node_modules directory
|
||||||
// without them having asked us to do so.
|
// without them having asked us to do so.
|
||||||
let explicitly_disabled = workspace.node_modules_dir() == Some(false);
|
let node_modules_mode = workspace.node_modules_dir().ok().flatten();
|
||||||
|
let explicitly_disabled = node_modules_mode == Some(NodeModulesDirMode::None);
|
||||||
if explicitly_disabled {
|
if explicitly_disabled {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let enabled = byonm
|
let enabled = byonm
|
||||||
|| workspace.node_modules_dir() == Some(true)
|
|| node_modules_mode
|
||||||
|
.map(|m| m.uses_node_modules_dir())
|
||||||
|
.unwrap_or(false)
|
||||||
|| workspace.vendor_dir_path().is_some();
|
|| workspace.vendor_dir_path().is_some();
|
||||||
|
|
||||||
if !enabled {
|
if !enabled {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ use super::performance::Performance;
|
||||||
use super::tsc;
|
use super::tsc;
|
||||||
use super::tsc::TsServer;
|
use super::tsc::TsServer;
|
||||||
use super::urls::url_to_uri;
|
use super::urls::url_to_uri;
|
||||||
use super::urls::LspClientUrl;
|
|
||||||
use super::urls::LspUrlMap;
|
use super::urls::LspUrlMap;
|
||||||
|
|
||||||
use crate::graph_util;
|
use crate::graph_util;
|
||||||
|
@ -164,15 +163,14 @@ impl DiagnosticsPublisher {
|
||||||
.state
|
.state
|
||||||
.update(&record.specifier, version, &all_specifier_diagnostics);
|
.update(&record.specifier, version, &all_specifier_diagnostics);
|
||||||
let file_referrer = documents.get_file_referrer(&record.specifier);
|
let file_referrer = documents.get_file_referrer(&record.specifier);
|
||||||
|
let Ok(uri) =
|
||||||
|
url_map.specifier_to_uri(&record.specifier, file_referrer.as_deref())
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
self
|
self
|
||||||
.client
|
.client
|
||||||
.publish_diagnostics(
|
.publish_diagnostics(uri, all_specifier_diagnostics, version)
|
||||||
url_map
|
|
||||||
.normalize_specifier(&record.specifier, file_referrer.as_deref())
|
|
||||||
.unwrap_or(LspClientUrl::new(record.specifier)),
|
|
||||||
all_specifier_diagnostics,
|
|
||||||
version,
|
|
||||||
)
|
|
||||||
.await;
|
.await;
|
||||||
messages_sent += 1;
|
messages_sent += 1;
|
||||||
}
|
}
|
||||||
|
@ -195,15 +193,14 @@ impl DiagnosticsPublisher {
|
||||||
// clear out any diagnostics for this specifier
|
// clear out any diagnostics for this specifier
|
||||||
self.state.update(specifier, removed_value.version, &[]);
|
self.state.update(specifier, removed_value.version, &[]);
|
||||||
let file_referrer = documents.get_file_referrer(specifier);
|
let file_referrer = documents.get_file_referrer(specifier);
|
||||||
|
let Ok(uri) =
|
||||||
|
url_map.specifier_to_uri(specifier, file_referrer.as_deref())
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
self
|
self
|
||||||
.client
|
.client
|
||||||
.publish_diagnostics(
|
.publish_diagnostics(uri, Vec::new(), removed_value.version)
|
||||||
url_map
|
|
||||||
.normalize_specifier(specifier, file_referrer.as_deref())
|
|
||||||
.unwrap_or_else(|_| LspClientUrl::new(specifier.clone())),
|
|
||||||
Vec::new(),
|
|
||||||
removed_value.version,
|
|
||||||
)
|
|
||||||
.await;
|
.await;
|
||||||
messages_sent += 1;
|
messages_sent += 1;
|
||||||
}
|
}
|
||||||
|
@ -1074,7 +1071,7 @@ impl DenoDiagnostic {
|
||||||
diagnostics: Some(vec![diagnostic.clone()]),
|
diagnostics: Some(vec![diagnostic.clone()]),
|
||||||
edit: Some(lsp::WorkspaceEdit {
|
edit: Some(lsp::WorkspaceEdit {
|
||||||
changes: Some(HashMap::from([(
|
changes: Some(HashMap::from([(
|
||||||
url_to_uri(specifier),
|
url_to_uri(specifier)?,
|
||||||
vec![lsp::TextEdit {
|
vec![lsp::TextEdit {
|
||||||
new_text: format!("\"{to}\""),
|
new_text: format!("\"{to}\""),
|
||||||
range: diagnostic.range,
|
range: diagnostic.range,
|
||||||
|
@ -1091,7 +1088,7 @@ impl DenoDiagnostic {
|
||||||
diagnostics: Some(vec![diagnostic.clone()]),
|
diagnostics: Some(vec![diagnostic.clone()]),
|
||||||
edit: Some(lsp::WorkspaceEdit {
|
edit: Some(lsp::WorkspaceEdit {
|
||||||
changes: Some(HashMap::from([(
|
changes: Some(HashMap::from([(
|
||||||
url_to_uri(specifier),
|
url_to_uri(specifier)?,
|
||||||
vec![lsp::TextEdit {
|
vec![lsp::TextEdit {
|
||||||
new_text: " with { type: \"json\" }".to_string(),
|
new_text: " with { type: \"json\" }".to_string(),
|
||||||
range: lsp::Range {
|
range: lsp::Range {
|
||||||
|
@ -1142,7 +1139,7 @@ impl DenoDiagnostic {
|
||||||
diagnostics: Some(vec![diagnostic.clone()]),
|
diagnostics: Some(vec![diagnostic.clone()]),
|
||||||
edit: Some(lsp::WorkspaceEdit {
|
edit: Some(lsp::WorkspaceEdit {
|
||||||
changes: Some(HashMap::from([(
|
changes: Some(HashMap::from([(
|
||||||
url_to_uri(specifier),
|
url_to_uri(specifier)?,
|
||||||
vec![lsp::TextEdit {
|
vec![lsp::TextEdit {
|
||||||
new_text: format!(
|
new_text: format!(
|
||||||
"\"{}\"",
|
"\"{}\"",
|
||||||
|
@ -1168,7 +1165,7 @@ impl DenoDiagnostic {
|
||||||
diagnostics: Some(vec![diagnostic.clone()]),
|
diagnostics: Some(vec![diagnostic.clone()]),
|
||||||
edit: Some(lsp::WorkspaceEdit {
|
edit: Some(lsp::WorkspaceEdit {
|
||||||
changes: Some(HashMap::from([(
|
changes: Some(HashMap::from([(
|
||||||
url_to_uri(specifier),
|
url_to_uri(specifier)?,
|
||||||
vec![lsp::TextEdit {
|
vec![lsp::TextEdit {
|
||||||
new_text: format!(
|
new_text: format!(
|
||||||
"\"{}\"",
|
"\"{}\"",
|
||||||
|
@ -1194,7 +1191,7 @@ impl DenoDiagnostic {
|
||||||
diagnostics: Some(vec![diagnostic.clone()]),
|
diagnostics: Some(vec![diagnostic.clone()]),
|
||||||
edit: Some(lsp::WorkspaceEdit {
|
edit: Some(lsp::WorkspaceEdit {
|
||||||
changes: Some(HashMap::from([(
|
changes: Some(HashMap::from([(
|
||||||
url_to_uri(specifier),
|
url_to_uri(specifier)?,
|
||||||
vec![lsp::TextEdit {
|
vec![lsp::TextEdit {
|
||||||
new_text: format!("\"node:{}\"", data.specifier),
|
new_text: format!("\"node:{}\"", data.specifier),
|
||||||
range: diagnostic.range,
|
range: diagnostic.range,
|
||||||
|
@ -1642,7 +1639,7 @@ mod tests {
|
||||||
|
|
||||||
fn mock_config() -> Config {
|
fn mock_config() -> Config {
|
||||||
let root_url = resolve_url("file:///").unwrap();
|
let root_url = resolve_url("file:///").unwrap();
|
||||||
let root_uri = url_to_uri(&root_url);
|
let root_uri = url_to_uri(&root_url).unwrap();
|
||||||
Config {
|
Config {
|
||||||
settings: Arc::new(Settings {
|
settings: Arc::new(Settings {
|
||||||
unscoped: Arc::new(WorkspaceSettings {
|
unscoped: Arc::new(WorkspaceSettings {
|
||||||
|
|
|
@ -60,6 +60,9 @@ pub enum LanguageId {
|
||||||
Json,
|
Json,
|
||||||
JsonC,
|
JsonC,
|
||||||
Markdown,
|
Markdown,
|
||||||
|
Html,
|
||||||
|
Css,
|
||||||
|
Yaml,
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +76,9 @@ impl LanguageId {
|
||||||
LanguageId::Json => Some("json"),
|
LanguageId::Json => Some("json"),
|
||||||
LanguageId::JsonC => Some("jsonc"),
|
LanguageId::JsonC => Some("jsonc"),
|
||||||
LanguageId::Markdown => Some("md"),
|
LanguageId::Markdown => Some("md"),
|
||||||
|
LanguageId::Html => Some("html"),
|
||||||
|
LanguageId::Css => Some("css"),
|
||||||
|
LanguageId::Yaml => Some("yaml"),
|
||||||
LanguageId::Unknown => None,
|
LanguageId::Unknown => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,6 +91,9 @@ impl LanguageId {
|
||||||
LanguageId::Tsx => Some("text/tsx"),
|
LanguageId::Tsx => Some("text/tsx"),
|
||||||
LanguageId::Json | LanguageId::JsonC => Some("application/json"),
|
LanguageId::Json | LanguageId::JsonC => Some("application/json"),
|
||||||
LanguageId::Markdown => Some("text/markdown"),
|
LanguageId::Markdown => Some("text/markdown"),
|
||||||
|
LanguageId::Html => Some("text/html"),
|
||||||
|
LanguageId::Css => Some("text/css"),
|
||||||
|
LanguageId::Yaml => Some("application/yaml"),
|
||||||
LanguageId::Unknown => None,
|
LanguageId::Unknown => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,6 +118,9 @@ impl FromStr for LanguageId {
|
||||||
"json" => Ok(Self::Json),
|
"json" => Ok(Self::Json),
|
||||||
"jsonc" => Ok(Self::JsonC),
|
"jsonc" => Ok(Self::JsonC),
|
||||||
"markdown" => Ok(Self::Markdown),
|
"markdown" => Ok(Self::Markdown),
|
||||||
|
"html" => Ok(Self::Html),
|
||||||
|
"css" => Ok(Self::Css),
|
||||||
|
"yaml" => Ok(Self::Yaml),
|
||||||
_ => Ok(Self::Unknown),
|
_ => Ok(Self::Unknown),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1239,7 +1251,7 @@ impl Documents {
|
||||||
/// tsc when type checking.
|
/// tsc when type checking.
|
||||||
pub fn resolve(
|
pub fn resolve(
|
||||||
&self,
|
&self,
|
||||||
specifiers: &[String],
|
raw_specifiers: &[String],
|
||||||
referrer: &ModuleSpecifier,
|
referrer: &ModuleSpecifier,
|
||||||
file_referrer: Option<&ModuleSpecifier>,
|
file_referrer: Option<&ModuleSpecifier>,
|
||||||
) -> Vec<Option<(ModuleSpecifier, MediaType)>> {
|
) -> Vec<Option<(ModuleSpecifier, MediaType)>> {
|
||||||
|
@ -1250,16 +1262,16 @@ impl Documents {
|
||||||
.or(file_referrer);
|
.or(file_referrer);
|
||||||
let dependencies = document.as_ref().map(|d| d.dependencies());
|
let dependencies = document.as_ref().map(|d| d.dependencies());
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
for specifier in specifiers {
|
for raw_specifier in raw_specifiers {
|
||||||
if specifier.starts_with("asset:") {
|
if raw_specifier.starts_with("asset:") {
|
||||||
if let Ok(specifier) = ModuleSpecifier::parse(specifier) {
|
if let Ok(specifier) = ModuleSpecifier::parse(raw_specifier) {
|
||||||
let media_type = MediaType::from_specifier(&specifier);
|
let media_type = MediaType::from_specifier(&specifier);
|
||||||
results.push(Some((specifier, media_type)));
|
results.push(Some((specifier, media_type)));
|
||||||
} else {
|
} else {
|
||||||
results.push(None);
|
results.push(None);
|
||||||
}
|
}
|
||||||
} else if let Some(dep) =
|
} else if let Some(dep) =
|
||||||
dependencies.as_ref().and_then(|d| d.get(specifier))
|
dependencies.as_ref().and_then(|d| d.get(raw_specifier))
|
||||||
{
|
{
|
||||||
if let Some(specifier) = dep.maybe_type.maybe_specifier() {
|
if let Some(specifier) = dep.maybe_type.maybe_specifier() {
|
||||||
results.push(self.resolve_dependency(
|
results.push(self.resolve_dependency(
|
||||||
|
@ -1278,7 +1290,7 @@ impl Documents {
|
||||||
}
|
}
|
||||||
} else if let Ok(specifier) =
|
} else if let Ok(specifier) =
|
||||||
self.resolver.as_graph_resolver(file_referrer).resolve(
|
self.resolver.as_graph_resolver(file_referrer).resolve(
|
||||||
specifier,
|
raw_specifier,
|
||||||
&deno_graph::Range {
|
&deno_graph::Range {
|
||||||
specifier: referrer.clone(),
|
specifier: referrer.clone(),
|
||||||
start: deno_graph::Position::zeroed(),
|
start: deno_graph::Position::zeroed(),
|
||||||
|
@ -1410,11 +1422,9 @@ impl Documents {
|
||||||
if let Some(lockfile) = config_data.lockfile.as_ref() {
|
if let Some(lockfile) = config_data.lockfile.as_ref() {
|
||||||
let reqs = npm_reqs_by_scope.entry(Some(scope.clone())).or_default();
|
let reqs = npm_reqs_by_scope.entry(Some(scope.clone())).or_default();
|
||||||
let lockfile = lockfile.lock();
|
let lockfile = lockfile.lock();
|
||||||
for key in lockfile.content.packages.specifiers.keys() {
|
for dep_req in lockfile.content.packages.specifiers.keys() {
|
||||||
if let Some(key) = key.strip_prefix("npm:") {
|
if dep_req.kind == deno_semver::package::PackageKind::Npm {
|
||||||
if let Ok(req) = PackageReq::from_str(key) {
|
reqs.insert(dep_req.req.clone());
|
||||||
reqs.insert(req);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1514,12 +1524,16 @@ impl<'a> deno_graph::source::Loader for OpenDocumentsGraphLoader<'a> {
|
||||||
fn cache_module_info(
|
fn cache_module_info(
|
||||||
&self,
|
&self,
|
||||||
specifier: &deno_ast::ModuleSpecifier,
|
specifier: &deno_ast::ModuleSpecifier,
|
||||||
|
media_type: MediaType,
|
||||||
source: &Arc<[u8]>,
|
source: &Arc<[u8]>,
|
||||||
module_info: &deno_graph::ModuleInfo,
|
module_info: &deno_graph::ModuleInfo,
|
||||||
) {
|
) {
|
||||||
self
|
self.inner_loader.cache_module_info(
|
||||||
.inner_loader
|
specifier,
|
||||||
.cache_module_info(specifier, source, module_info)
|
media_type,
|
||||||
|
source,
|
||||||
|
module_info,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,20 +92,23 @@ impl JsrCacheResolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(lockfile) = config_data.and_then(|d| d.lockfile.as_ref()) {
|
if let Some(lockfile) = config_data.and_then(|d| d.lockfile.as_ref()) {
|
||||||
for (req_url, nv_url) in &lockfile.lock().content.packages.specifiers {
|
for (dep_req, version) in &lockfile.lock().content.packages.specifiers {
|
||||||
let Some(req) = req_url.strip_prefix("jsr:") else {
|
let req = match dep_req.kind {
|
||||||
|
deno_semver::package::PackageKind::Jsr => &dep_req.req,
|
||||||
|
deno_semver::package::PackageKind::Npm => {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let Ok(version) = Version::parse_standard(version) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let Some(nv) = nv_url.strip_prefix("jsr:") else {
|
nv_by_req.insert(
|
||||||
continue;
|
req.clone(),
|
||||||
};
|
Some(PackageNv {
|
||||||
let Ok(req) = PackageReq::from_str(req) else {
|
name: req.name.clone(),
|
||||||
continue;
|
version,
|
||||||
};
|
}),
|
||||||
let Ok(nv) = PackageNv::from_str(nv) else {
|
);
|
||||||
continue;
|
|
||||||
};
|
|
||||||
nv_by_req.insert(req, Some(nv));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -32,6 +32,7 @@ use std::collections::VecDeque;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fmt::Write as _;
|
use std::fmt::Write as _;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::mpsc::unbounded_channel;
|
use tokio::sync::mpsc::unbounded_channel;
|
||||||
use tokio::sync::mpsc::UnboundedReceiver;
|
use tokio::sync::mpsc::UnboundedReceiver;
|
||||||
|
@ -723,7 +724,9 @@ impl Inner {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|folder| {
|
.map(|folder| {
|
||||||
(
|
(
|
||||||
self.url_map.normalize_url(&folder.uri, LspUrlKind::Folder),
|
self
|
||||||
|
.url_map
|
||||||
|
.uri_to_specifier(&folder.uri, LspUrlKind::Folder),
|
||||||
folder,
|
folder,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -735,7 +738,7 @@ impl Inner {
|
||||||
if let Some(root_uri) = params.root_uri {
|
if let Some(root_uri) = params.root_uri {
|
||||||
if !workspace_folders.iter().any(|(_, f)| f.uri == root_uri) {
|
if !workspace_folders.iter().any(|(_, f)| f.uri == root_uri) {
|
||||||
let root_url =
|
let root_url =
|
||||||
self.url_map.normalize_url(&root_uri, LspUrlKind::Folder);
|
self.url_map.uri_to_specifier(&root_uri, LspUrlKind::Folder);
|
||||||
let name = root_url.path_segments().and_then(|s| s.last());
|
let name = root_url.path_segments().and_then(|s| s.last());
|
||||||
let name = name.unwrap_or_default().to_string();
|
let name = name.unwrap_or_default().to_string();
|
||||||
workspace_folders.insert(
|
workspace_folders.insert(
|
||||||
|
@ -963,9 +966,8 @@ impl Inner {
|
||||||
.await;
|
.await;
|
||||||
for config_file in self.config.tree.config_files() {
|
for config_file in self.config.tree.config_files() {
|
||||||
(|| {
|
(|| {
|
||||||
let compiler_options = config_file.to_compiler_options().ok()?.0;
|
let compiler_options = config_file.to_compiler_options().ok()?.options;
|
||||||
let compiler_options_obj = compiler_options.as_object()?;
|
let jsx_import_source = compiler_options.get("jsxImportSource")?;
|
||||||
let jsx_import_source = compiler_options_obj.get("jsxImportSource")?;
|
|
||||||
let jsx_import_source = jsx_import_source.as_str()?;
|
let jsx_import_source = jsx_import_source.as_str()?;
|
||||||
let referrer = config_file.specifier.clone();
|
let referrer = config_file.specifier.clone();
|
||||||
let specifier = Url::parse(&format!(
|
let specifier = Url::parse(&format!(
|
||||||
|
@ -1043,7 +1045,7 @@ impl Inner {
|
||||||
.filter(|s| self.documents.is_valid_file_referrer(s));
|
.filter(|s| self.documents.is_valid_file_referrer(s));
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document.uri, LspUrlKind::File);
|
.uri_to_specifier(¶ms.text_document.uri, LspUrlKind::File);
|
||||||
let document = self.documents.open(
|
let document = self.documents.open(
|
||||||
specifier.clone(),
|
specifier.clone(),
|
||||||
params.text_document.version,
|
params.text_document.version,
|
||||||
|
@ -1065,7 +1067,7 @@ impl Inner {
|
||||||
let mark = self.performance.mark_with_args("lsp.did_change", ¶ms);
|
let mark = self.performance.mark_with_args("lsp.did_change", ¶ms);
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document.uri, LspUrlKind::File);
|
.uri_to_specifier(¶ms.text_document.uri, LspUrlKind::File);
|
||||||
match self.documents.change(
|
match self.documents.change(
|
||||||
&specifier,
|
&specifier,
|
||||||
params.text_document.version,
|
params.text_document.version,
|
||||||
|
@ -1102,7 +1104,7 @@ impl Inner {
|
||||||
let _mark = self.performance.measure_scope("lsp.did_save");
|
let _mark = self.performance.measure_scope("lsp.did_save");
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document.uri, LspUrlKind::File);
|
.uri_to_specifier(¶ms.text_document.uri, LspUrlKind::File);
|
||||||
self.documents.save(&specifier);
|
self.documents.save(&specifier);
|
||||||
if !self
|
if !self
|
||||||
.config
|
.config
|
||||||
|
@ -1148,7 +1150,7 @@ impl Inner {
|
||||||
}
|
}
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document.uri, LspUrlKind::File);
|
.uri_to_specifier(¶ms.text_document.uri, LspUrlKind::File);
|
||||||
self.diagnostics_state.clear(&specifier);
|
self.diagnostics_state.clear(&specifier);
|
||||||
if self.is_diagnosable(&specifier) {
|
if self.is_diagnosable(&specifier) {
|
||||||
self.refresh_npm_specifiers().await;
|
self.refresh_npm_specifiers().await;
|
||||||
|
@ -1202,7 +1204,7 @@ impl Inner {
|
||||||
let changes = params
|
let changes = params
|
||||||
.changes
|
.changes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|e| (self.url_map.normalize_url(&e.uri, LspUrlKind::File), e))
|
.map(|e| (self.url_map.uri_to_specifier(&e.uri, LspUrlKind::File), e))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
if changes
|
if changes
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -1221,7 +1223,7 @@ impl Inner {
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
Some(lsp_custom::DenoConfigurationChangeEvent {
|
Some(lsp_custom::DenoConfigurationChangeEvent {
|
||||||
scope_uri: url_to_uri(t.0),
|
scope_uri: url_to_uri(t.0).ok()?,
|
||||||
file_uri: e.uri.clone(),
|
file_uri: e.uri.clone(),
|
||||||
typ: lsp_custom::DenoConfigurationChangeType::from_file_change_type(
|
typ: lsp_custom::DenoConfigurationChangeType::from_file_change_type(
|
||||||
e.typ,
|
e.typ,
|
||||||
|
@ -1256,7 +1258,7 @@ impl Inner {
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
Some(lsp_custom::DenoConfigurationChangeEvent {
|
Some(lsp_custom::DenoConfigurationChangeEvent {
|
||||||
scope_uri: url_to_uri(t.0),
|
scope_uri: url_to_uri(t.0).ok()?,
|
||||||
file_uri: e.uri.clone(),
|
file_uri: e.uri.clone(),
|
||||||
typ: lsp_custom::DenoConfigurationChangeType::from_file_change_type(
|
typ: lsp_custom::DenoConfigurationChangeType::from_file_change_type(
|
||||||
e.typ,
|
e.typ,
|
||||||
|
@ -1282,7 +1284,7 @@ impl Inner {
|
||||||
) -> LspResult<Option<DocumentSymbolResponse>> {
|
) -> LspResult<Option<DocumentSymbolResponse>> {
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document.uri, LspUrlKind::File);
|
.uri_to_specifier(¶ms.text_document.uri, LspUrlKind::File);
|
||||||
if !self.is_diagnosable(&specifier)
|
if !self.is_diagnosable(&specifier)
|
||||||
|| !self.config.specifier_enabled(&specifier)
|
|| !self.config.specifier_enabled(&specifier)
|
||||||
{
|
{
|
||||||
|
@ -1326,7 +1328,7 @@ impl Inner {
|
||||||
.filter(|s| self.documents.is_valid_file_referrer(s));
|
.filter(|s| self.documents.is_valid_file_referrer(s));
|
||||||
let mut specifier = self
|
let mut specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document.uri, LspUrlKind::File);
|
.uri_to_specifier(¶ms.text_document.uri, LspUrlKind::File);
|
||||||
// skip formatting any files ignored by the config file
|
// skip formatting any files ignored by the config file
|
||||||
if !self
|
if !self
|
||||||
.config
|
.config
|
||||||
|
@ -1441,7 +1443,7 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn hover(&self, params: HoverParams) -> LspResult<Option<Hover>> {
|
async fn hover(&self, params: HoverParams) -> LspResult<Option<Hover>> {
|
||||||
let specifier = self.url_map.normalize_url(
|
let specifier = self.url_map.uri_to_specifier(
|
||||||
¶ms.text_document_position_params.text_document.uri,
|
¶ms.text_document_position_params.text_document.uri,
|
||||||
LspUrlKind::File,
|
LspUrlKind::File,
|
||||||
);
|
);
|
||||||
|
@ -1574,7 +1576,7 @@ impl Inner {
|
||||||
) -> LspResult<Option<CodeActionResponse>> {
|
) -> LspResult<Option<CodeActionResponse>> {
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document.uri, LspUrlKind::File);
|
.uri_to_specifier(¶ms.text_document.uri, LspUrlKind::File);
|
||||||
if !self.is_diagnosable(&specifier)
|
if !self.is_diagnosable(&specifier)
|
||||||
|| !self.config.specifier_enabled(&specifier)
|
|| !self.config.specifier_enabled(&specifier)
|
||||||
{
|
{
|
||||||
|
@ -1918,7 +1920,7 @@ impl Inner {
|
||||||
) -> LspResult<Option<Vec<CodeLens>>> {
|
) -> LspResult<Option<Vec<CodeLens>>> {
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document.uri, LspUrlKind::File);
|
.uri_to_specifier(¶ms.text_document.uri, LspUrlKind::File);
|
||||||
if !self.is_diagnosable(&specifier)
|
if !self.is_diagnosable(&specifier)
|
||||||
|| !self.config.specifier_enabled(&specifier)
|
|| !self.config.specifier_enabled(&specifier)
|
||||||
{
|
{
|
||||||
|
@ -2004,7 +2006,7 @@ impl Inner {
|
||||||
&self,
|
&self,
|
||||||
params: DocumentHighlightParams,
|
params: DocumentHighlightParams,
|
||||||
) -> LspResult<Option<Vec<DocumentHighlight>>> {
|
) -> LspResult<Option<Vec<DocumentHighlight>>> {
|
||||||
let specifier = self.url_map.normalize_url(
|
let specifier = self.url_map.uri_to_specifier(
|
||||||
¶ms.text_document_position_params.text_document.uri,
|
¶ms.text_document_position_params.text_document.uri,
|
||||||
LspUrlKind::File,
|
LspUrlKind::File,
|
||||||
);
|
);
|
||||||
|
@ -2048,7 +2050,7 @@ impl Inner {
|
||||||
&self,
|
&self,
|
||||||
params: ReferenceParams,
|
params: ReferenceParams,
|
||||||
) -> LspResult<Option<Vec<Location>>> {
|
) -> LspResult<Option<Vec<Location>>> {
|
||||||
let specifier = self.url_map.normalize_url(
|
let specifier = self.url_map.uri_to_specifier(
|
||||||
¶ms.text_document_position.text_document.uri,
|
¶ms.text_document_position.text_document.uri,
|
||||||
LspUrlKind::File,
|
LspUrlKind::File,
|
||||||
);
|
);
|
||||||
|
@ -2104,7 +2106,7 @@ impl Inner {
|
||||||
&self,
|
&self,
|
||||||
params: GotoDefinitionParams,
|
params: GotoDefinitionParams,
|
||||||
) -> LspResult<Option<GotoDefinitionResponse>> {
|
) -> LspResult<Option<GotoDefinitionResponse>> {
|
||||||
let specifier = self.url_map.normalize_url(
|
let specifier = self.url_map.uri_to_specifier(
|
||||||
¶ms.text_document_position_params.text_document.uri,
|
¶ms.text_document_position_params.text_document.uri,
|
||||||
LspUrlKind::File,
|
LspUrlKind::File,
|
||||||
);
|
);
|
||||||
|
@ -2143,7 +2145,7 @@ impl Inner {
|
||||||
&self,
|
&self,
|
||||||
params: GotoTypeDefinitionParams,
|
params: GotoTypeDefinitionParams,
|
||||||
) -> LspResult<Option<GotoTypeDefinitionResponse>> {
|
) -> LspResult<Option<GotoTypeDefinitionResponse>> {
|
||||||
let specifier = self.url_map.normalize_url(
|
let specifier = self.url_map.uri_to_specifier(
|
||||||
¶ms.text_document_position_params.text_document.uri,
|
¶ms.text_document_position_params.text_document.uri,
|
||||||
LspUrlKind::File,
|
LspUrlKind::File,
|
||||||
);
|
);
|
||||||
|
@ -2189,7 +2191,7 @@ impl Inner {
|
||||||
&self,
|
&self,
|
||||||
params: CompletionParams,
|
params: CompletionParams,
|
||||||
) -> LspResult<Option<CompletionResponse>> {
|
) -> LspResult<Option<CompletionResponse>> {
|
||||||
let specifier = self.url_map.normalize_url(
|
let specifier = self.url_map.uri_to_specifier(
|
||||||
¶ms.text_document_position.text_document.uri,
|
¶ms.text_document_position.text_document.uri,
|
||||||
LspUrlKind::File,
|
LspUrlKind::File,
|
||||||
);
|
);
|
||||||
|
@ -2378,7 +2380,7 @@ impl Inner {
|
||||||
&self,
|
&self,
|
||||||
params: GotoImplementationParams,
|
params: GotoImplementationParams,
|
||||||
) -> LspResult<Option<GotoImplementationResponse>> {
|
) -> LspResult<Option<GotoImplementationResponse>> {
|
||||||
let specifier = self.url_map.normalize_url(
|
let specifier = self.url_map.uri_to_specifier(
|
||||||
¶ms.text_document_position_params.text_document.uri,
|
¶ms.text_document_position_params.text_document.uri,
|
||||||
LspUrlKind::File,
|
LspUrlKind::File,
|
||||||
);
|
);
|
||||||
|
@ -2429,7 +2431,7 @@ impl Inner {
|
||||||
) -> LspResult<Option<Vec<FoldingRange>>> {
|
) -> LspResult<Option<Vec<FoldingRange>>> {
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document.uri, LspUrlKind::File);
|
.uri_to_specifier(¶ms.text_document.uri, LspUrlKind::File);
|
||||||
if !self.is_diagnosable(&specifier)
|
if !self.is_diagnosable(&specifier)
|
||||||
|| !self.config.specifier_enabled(&specifier)
|
|| !self.config.specifier_enabled(&specifier)
|
||||||
{
|
{
|
||||||
|
@ -2476,7 +2478,7 @@ impl Inner {
|
||||||
) -> LspResult<Option<Vec<CallHierarchyIncomingCall>>> {
|
) -> LspResult<Option<Vec<CallHierarchyIncomingCall>>> {
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.item.uri, LspUrlKind::File);
|
.uri_to_specifier(¶ms.item.uri, LspUrlKind::File);
|
||||||
if !self.is_diagnosable(&specifier)
|
if !self.is_diagnosable(&specifier)
|
||||||
|| !self.config.specifier_enabled(&specifier)
|
|| !self.config.specifier_enabled(&specifier)
|
||||||
{
|
{
|
||||||
|
@ -2525,7 +2527,7 @@ impl Inner {
|
||||||
) -> LspResult<Option<Vec<CallHierarchyOutgoingCall>>> {
|
) -> LspResult<Option<Vec<CallHierarchyOutgoingCall>>> {
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.item.uri, LspUrlKind::File);
|
.uri_to_specifier(¶ms.item.uri, LspUrlKind::File);
|
||||||
if !self.is_diagnosable(&specifier)
|
if !self.is_diagnosable(&specifier)
|
||||||
|| !self.config.specifier_enabled(&specifier)
|
|| !self.config.specifier_enabled(&specifier)
|
||||||
{
|
{
|
||||||
|
@ -2570,7 +2572,7 @@ impl Inner {
|
||||||
&self,
|
&self,
|
||||||
params: CallHierarchyPrepareParams,
|
params: CallHierarchyPrepareParams,
|
||||||
) -> LspResult<Option<Vec<CallHierarchyItem>>> {
|
) -> LspResult<Option<Vec<CallHierarchyItem>>> {
|
||||||
let specifier = self.url_map.normalize_url(
|
let specifier = self.url_map.uri_to_specifier(
|
||||||
¶ms.text_document_position_params.text_document.uri,
|
¶ms.text_document_position_params.text_document.uri,
|
||||||
LspUrlKind::File,
|
LspUrlKind::File,
|
||||||
);
|
);
|
||||||
|
@ -2634,7 +2636,7 @@ impl Inner {
|
||||||
&self,
|
&self,
|
||||||
params: RenameParams,
|
params: RenameParams,
|
||||||
) -> LspResult<Option<WorkspaceEdit>> {
|
) -> LspResult<Option<WorkspaceEdit>> {
|
||||||
let specifier = self.url_map.normalize_url(
|
let specifier = self.url_map.uri_to_specifier(
|
||||||
¶ms.text_document_position.text_document.uri,
|
¶ms.text_document_position.text_document.uri,
|
||||||
LspUrlKind::File,
|
LspUrlKind::File,
|
||||||
);
|
);
|
||||||
|
@ -2683,7 +2685,7 @@ impl Inner {
|
||||||
) -> LspResult<Option<Vec<SelectionRange>>> {
|
) -> LspResult<Option<Vec<SelectionRange>>> {
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document.uri, LspUrlKind::File);
|
.uri_to_specifier(¶ms.text_document.uri, LspUrlKind::File);
|
||||||
if !self.is_diagnosable(&specifier)
|
if !self.is_diagnosable(&specifier)
|
||||||
|| !self.config.specifier_enabled(&specifier)
|
|| !self.config.specifier_enabled(&specifier)
|
||||||
{
|
{
|
||||||
|
@ -2721,7 +2723,7 @@ impl Inner {
|
||||||
) -> LspResult<Option<SemanticTokensResult>> {
|
) -> LspResult<Option<SemanticTokensResult>> {
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document.uri, LspUrlKind::File);
|
.uri_to_specifier(¶ms.text_document.uri, LspUrlKind::File);
|
||||||
if !self.is_diagnosable(&specifier) {
|
if !self.is_diagnosable(&specifier) {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
@ -2774,7 +2776,7 @@ impl Inner {
|
||||||
) -> LspResult<Option<SemanticTokensRangeResult>> {
|
) -> LspResult<Option<SemanticTokensRangeResult>> {
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document.uri, LspUrlKind::File);
|
.uri_to_specifier(¶ms.text_document.uri, LspUrlKind::File);
|
||||||
if !self.is_diagnosable(&specifier) {
|
if !self.is_diagnosable(&specifier) {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
@ -2823,7 +2825,7 @@ impl Inner {
|
||||||
&self,
|
&self,
|
||||||
params: SignatureHelpParams,
|
params: SignatureHelpParams,
|
||||||
) -> LspResult<Option<SignatureHelp>> {
|
) -> LspResult<Option<SignatureHelp>> {
|
||||||
let specifier = self.url_map.normalize_url(
|
let specifier = self.url_map.uri_to_specifier(
|
||||||
¶ms.text_document_position_params.text_document.uri,
|
¶ms.text_document_position_params.text_document.uri,
|
||||||
LspUrlKind::File,
|
LspUrlKind::File,
|
||||||
);
|
);
|
||||||
|
@ -2877,8 +2879,8 @@ impl Inner {
|
||||||
) -> LspResult<Option<WorkspaceEdit>> {
|
) -> LspResult<Option<WorkspaceEdit>> {
|
||||||
let mut changes = vec![];
|
let mut changes = vec![];
|
||||||
for rename in params.files {
|
for rename in params.files {
|
||||||
let old_specifier = self.url_map.normalize_url(
|
let old_specifier = self.url_map.uri_to_specifier(
|
||||||
&url_to_uri(&resolve_url(&rename.old_uri).unwrap()),
|
&Uri::from_str(&rename.old_uri).unwrap(),
|
||||||
LspUrlKind::File,
|
LspUrlKind::File,
|
||||||
);
|
);
|
||||||
let options = self
|
let options = self
|
||||||
|
@ -2903,8 +2905,8 @@ impl Inner {
|
||||||
.get_edits_for_file_rename(
|
.get_edits_for_file_rename(
|
||||||
self.snapshot(),
|
self.snapshot(),
|
||||||
old_specifier,
|
old_specifier,
|
||||||
self.url_map.normalize_url(
|
self.url_map.uri_to_specifier(
|
||||||
&url_to_uri(&resolve_url(&rename.new_uri).unwrap()),
|
&Uri::from_str(&rename.new_uri).unwrap(),
|
||||||
LspUrlKind::File,
|
LspUrlKind::File,
|
||||||
),
|
),
|
||||||
format_code_settings,
|
format_code_settings,
|
||||||
|
@ -3503,24 +3505,30 @@ impl Inner {
|
||||||
|
|
||||||
let mut config_events = vec![];
|
let mut config_events = vec![];
|
||||||
for (scope_url, config_data) in self.config.tree.data_by_scope().iter() {
|
for (scope_url, config_data) in self.config.tree.data_by_scope().iter() {
|
||||||
let scope_uri = url_to_uri(scope_url);
|
let Ok(scope_uri) = url_to_uri(scope_url) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
if let Some(config_file) = config_data.maybe_deno_json() {
|
if let Some(config_file) = config_data.maybe_deno_json() {
|
||||||
|
if let Ok(file_uri) = url_to_uri(&config_file.specifier) {
|
||||||
config_events.push(lsp_custom::DenoConfigurationChangeEvent {
|
config_events.push(lsp_custom::DenoConfigurationChangeEvent {
|
||||||
scope_uri: scope_uri.clone(),
|
scope_uri: scope_uri.clone(),
|
||||||
file_uri: url_to_uri(&config_file.specifier),
|
file_uri,
|
||||||
typ: lsp_custom::DenoConfigurationChangeType::Added,
|
typ: lsp_custom::DenoConfigurationChangeType::Added,
|
||||||
configuration_type: lsp_custom::DenoConfigurationType::DenoJson,
|
configuration_type: lsp_custom::DenoConfigurationType::DenoJson,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if let Some(package_json) = config_data.maybe_pkg_json() {
|
if let Some(package_json) = config_data.maybe_pkg_json() {
|
||||||
|
if let Ok(file_uri) = url_to_uri(&package_json.specifier()) {
|
||||||
config_events.push(lsp_custom::DenoConfigurationChangeEvent {
|
config_events.push(lsp_custom::DenoConfigurationChangeEvent {
|
||||||
scope_uri,
|
scope_uri,
|
||||||
file_uri: url_to_uri(&package_json.specifier()),
|
file_uri,
|
||||||
typ: lsp_custom::DenoConfigurationChangeType::Added,
|
typ: lsp_custom::DenoConfigurationChangeType::Added,
|
||||||
configuration_type: lsp_custom::DenoConfigurationType::PackageJson,
|
configuration_type: lsp_custom::DenoConfigurationType::PackageJson,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if !config_events.is_empty() {
|
if !config_events.is_empty() {
|
||||||
self.client.send_did_change_deno_configuration_notification(
|
self.client.send_did_change_deno_configuration_notification(
|
||||||
lsp_custom::DidChangeDenoConfigurationNotificationParams {
|
lsp_custom::DidChangeDenoConfigurationNotificationParams {
|
||||||
|
@ -3602,11 +3610,6 @@ impl Inner {
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|url| url.to_string())
|
.map(|url| url.to_string())
|
||||||
}),
|
}),
|
||||||
node_modules_dir: Some(
|
|
||||||
config_data
|
|
||||||
.and_then(|d| d.node_modules_dir.as_ref())
|
|
||||||
.is_some(),
|
|
||||||
),
|
|
||||||
// bit of a hack to force the lsp to cache the @types/node package
|
// bit of a hack to force the lsp to cache the @types/node package
|
||||||
type_check_mode: crate::args::TypeCheckMode::Local,
|
type_check_mode: crate::args::TypeCheckMode::Local,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -3648,7 +3651,9 @@ impl Inner {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|folder| {
|
.map(|folder| {
|
||||||
(
|
(
|
||||||
self.url_map.normalize_url(&folder.uri, LspUrlKind::Folder),
|
self
|
||||||
|
.url_map
|
||||||
|
.uri_to_specifier(&folder.uri, LspUrlKind::Folder),
|
||||||
folder,
|
folder,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -3724,7 +3729,8 @@ impl Inner {
|
||||||
result.push(TaskDefinition {
|
result.push(TaskDefinition {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
command: command.to_string(),
|
command: command.to_string(),
|
||||||
source_uri: url_to_uri(&config_file.specifier),
|
source_uri: url_to_uri(&config_file.specifier)
|
||||||
|
.map_err(|_| LspError::internal_error())?,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -3735,7 +3741,8 @@ impl Inner {
|
||||||
result.push(TaskDefinition {
|
result.push(TaskDefinition {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
command: command.clone(),
|
command: command.clone(),
|
||||||
source_uri: url_to_uri(&package_json.specifier()),
|
source_uri: url_to_uri(&package_json.specifier())
|
||||||
|
.map_err(|_| LspError::internal_error())?,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3750,7 +3757,7 @@ impl Inner {
|
||||||
) -> LspResult<Option<Vec<InlayHint>>> {
|
) -> LspResult<Option<Vec<InlayHint>>> {
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document.uri, LspUrlKind::File);
|
.uri_to_specifier(¶ms.text_document.uri, LspUrlKind::File);
|
||||||
if !self.is_diagnosable(&specifier)
|
if !self.is_diagnosable(&specifier)
|
||||||
|| !self.config.specifier_enabled(&specifier)
|
|| !self.config.specifier_enabled(&specifier)
|
||||||
|| !self.config.enabled_inlay_hints_for_specifier(&specifier)
|
|| !self.config.enabled_inlay_hints_for_specifier(&specifier)
|
||||||
|
@ -3813,7 +3820,7 @@ impl Inner {
|
||||||
.mark_with_args("lsp.virtual_text_document", ¶ms);
|
.mark_with_args("lsp.virtual_text_document", ¶ms);
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document.uri, LspUrlKind::File);
|
.uri_to_specifier(¶ms.text_document.uri, LspUrlKind::File);
|
||||||
let contents = if specifier.scheme() == "deno"
|
let contents = if specifier.scheme() == "deno"
|
||||||
&& specifier.path() == "/status.md"
|
&& specifier.path() == "/status.md"
|
||||||
{
|
{
|
||||||
|
|
|
@ -76,7 +76,7 @@ impl ReplLanguageServer {
|
||||||
.initialize(InitializeParams {
|
.initialize(InitializeParams {
|
||||||
process_id: None,
|
process_id: None,
|
||||||
root_path: None,
|
root_path: None,
|
||||||
root_uri: Some(url_to_uri(&cwd_uri)),
|
root_uri: Some(url_to_uri(&cwd_uri).unwrap()),
|
||||||
initialization_options: Some(
|
initialization_options: Some(
|
||||||
serde_json::to_value(get_repl_workspace_settings()).unwrap(),
|
serde_json::to_value(get_repl_workspace_settings()).unwrap(),
|
||||||
),
|
),
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
use crate::args::create_default_npmrc;
|
use crate::args::create_default_npmrc;
|
||||||
use crate::args::CacheSetting;
|
use crate::args::CacheSetting;
|
||||||
use crate::args::CliLockfile;
|
use crate::args::CliLockfile;
|
||||||
use crate::args::PackageJsonInstallDepsProvider;
|
use crate::args::NpmInstallDepsProvider;
|
||||||
use crate::graph_util::CliJsrUrlProvider;
|
use crate::graph_util::CliJsrUrlProvider;
|
||||||
use crate::http_util::HttpClientProvider;
|
use crate::http_util::HttpClientProvider;
|
||||||
use crate::lsp::config::Config;
|
use crate::lsp::config::Config;
|
||||||
|
@ -474,9 +474,7 @@ async fn create_npm_resolver(
|
||||||
maybe_node_modules_path: config_data
|
maybe_node_modules_path: config_data
|
||||||
.and_then(|d| d.node_modules_dir.clone()),
|
.and_then(|d| d.node_modules_dir.clone()),
|
||||||
// only used for top level install, so we can ignore this
|
// only used for top level install, so we can ignore this
|
||||||
package_json_deps_provider: Arc::new(
|
npm_install_deps_provider: Arc::new(NpmInstallDepsProvider::empty()),
|
||||||
PackageJsonInstallDepsProvider::empty(),
|
|
||||||
),
|
|
||||||
npmrc: config_data
|
npmrc: config_data
|
||||||
.and_then(|d| d.npmrc.clone())
|
.and_then(|d| d.npmrc.clone())
|
||||||
.unwrap_or_else(create_default_npmrc),
|
.unwrap_or_else(create_default_npmrc),
|
||||||
|
|
|
@ -10,6 +10,7 @@ use crate::tools::test::TestDescription;
|
||||||
use crate::tools::test::TestStepDescription;
|
use crate::tools::test::TestStepDescription;
|
||||||
use crate::util::checksum;
|
use crate::util::checksum;
|
||||||
|
|
||||||
|
use deno_core::error::AnyError;
|
||||||
use deno_core::ModuleSpecifier;
|
use deno_core::ModuleSpecifier;
|
||||||
use lsp::Range;
|
use lsp::Range;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -144,11 +145,12 @@ impl TestModule {
|
||||||
pub fn as_replace_notification(
|
pub fn as_replace_notification(
|
||||||
&self,
|
&self,
|
||||||
maybe_root_uri: Option<&ModuleSpecifier>,
|
maybe_root_uri: Option<&ModuleSpecifier>,
|
||||||
) -> TestingNotification {
|
) -> Result<TestingNotification, AnyError> {
|
||||||
let label = self.label(maybe_root_uri);
|
let label = self.label(maybe_root_uri);
|
||||||
TestingNotification::Module(lsp_custom::TestModuleNotificationParams {
|
Ok(TestingNotification::Module(
|
||||||
|
lsp_custom::TestModuleNotificationParams {
|
||||||
text_document: lsp::TextDocumentIdentifier {
|
text_document: lsp::TextDocumentIdentifier {
|
||||||
uri: url_to_uri(&self.specifier),
|
uri: url_to_uri(&self.specifier)?,
|
||||||
},
|
},
|
||||||
kind: lsp_custom::TestModuleNotificationKind::Replace,
|
kind: lsp_custom::TestModuleNotificationKind::Replace,
|
||||||
label,
|
label,
|
||||||
|
@ -158,7 +160,8 @@ impl TestModule {
|
||||||
.filter(|(_, def)| def.parent_id.is_none())
|
.filter(|(_, def)| def.parent_id.is_none())
|
||||||
.map(|(id, _)| self.get_test_data(id))
|
.map(|(id, _)| self.get_test_data(id))
|
||||||
.collect(),
|
.collect(),
|
||||||
})
|
},
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn label(&self, maybe_root_uri: Option<&ModuleSpecifier>) -> String {
|
pub fn label(&self, maybe_root_uri: Option<&ModuleSpecifier>) -> String {
|
||||||
|
|
|
@ -186,7 +186,7 @@ impl TestRun {
|
||||||
self
|
self
|
||||||
.queue
|
.queue
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| {
|
.filter_map(|s| {
|
||||||
let ids = if let Some((test_module, _)) = tests.get(s) {
|
let ids = if let Some((test_module, _)) = tests.get(s) {
|
||||||
if let Some(filter) = self.filters.get(s) {
|
if let Some(filter) = self.filters.get(s) {
|
||||||
filter.as_ids(test_module)
|
filter.as_ids(test_module)
|
||||||
|
@ -196,10 +196,12 @@ impl TestRun {
|
||||||
} else {
|
} else {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
};
|
};
|
||||||
lsp_custom::EnqueuedTestModule {
|
Some(lsp_custom::EnqueuedTestModule {
|
||||||
text_document: lsp::TextDocumentIdentifier { uri: url_to_uri(s) },
|
text_document: lsp::TextDocumentIdentifier {
|
||||||
|
uri: url_to_uri(s).ok()?,
|
||||||
|
},
|
||||||
ids,
|
ids,
|
||||||
}
|
})
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
@ -591,6 +593,9 @@ impl LspTestReporter {
|
||||||
let (test_module, _) = files
|
let (test_module, _) = files
|
||||||
.entry(specifier.clone())
|
.entry(specifier.clone())
|
||||||
.or_insert_with(|| (TestModule::new(specifier), "1".to_string()));
|
.or_insert_with(|| (TestModule::new(specifier), "1".to_string()));
|
||||||
|
let Ok(uri) = url_to_uri(&test_module.specifier) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
let (static_id, is_new) = test_module.register_dynamic(desc);
|
let (static_id, is_new) = test_module.register_dynamic(desc);
|
||||||
self.tests.insert(
|
self.tests.insert(
|
||||||
desc.id,
|
desc.id,
|
||||||
|
@ -601,9 +606,7 @@ impl LspTestReporter {
|
||||||
.client
|
.client
|
||||||
.send_test_notification(TestingNotification::Module(
|
.send_test_notification(TestingNotification::Module(
|
||||||
lsp_custom::TestModuleNotificationParams {
|
lsp_custom::TestModuleNotificationParams {
|
||||||
text_document: lsp::TextDocumentIdentifier {
|
text_document: lsp::TextDocumentIdentifier { uri },
|
||||||
uri: url_to_uri(&test_module.specifier),
|
|
||||||
},
|
|
||||||
kind: lsp_custom::TestModuleNotificationKind::Insert,
|
kind: lsp_custom::TestModuleNotificationKind::Insert,
|
||||||
label: test_module.label(self.maybe_root_uri.as_ref()),
|
label: test_module.label(self.maybe_root_uri.as_ref()),
|
||||||
tests: vec![test_module.get_test_data(&static_id)],
|
tests: vec![test_module.get_test_data(&static_id)],
|
||||||
|
@ -701,6 +704,9 @@ impl LspTestReporter {
|
||||||
let (test_module, _) = files
|
let (test_module, _) = files
|
||||||
.entry(specifier.clone())
|
.entry(specifier.clone())
|
||||||
.or_insert_with(|| (TestModule::new(specifier), "1".to_string()));
|
.or_insert_with(|| (TestModule::new(specifier), "1".to_string()));
|
||||||
|
let Ok(uri) = url_to_uri(&test_module.specifier) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
let (static_id, is_new) = test_module.register_step_dynamic(
|
let (static_id, is_new) = test_module.register_step_dynamic(
|
||||||
desc,
|
desc,
|
||||||
self.tests.get(&desc.parent_id).unwrap().static_id(),
|
self.tests.get(&desc.parent_id).unwrap().static_id(),
|
||||||
|
@ -714,9 +720,7 @@ impl LspTestReporter {
|
||||||
.client
|
.client
|
||||||
.send_test_notification(TestingNotification::Module(
|
.send_test_notification(TestingNotification::Module(
|
||||||
lsp_custom::TestModuleNotificationParams {
|
lsp_custom::TestModuleNotificationParams {
|
||||||
text_document: lsp::TextDocumentIdentifier {
|
text_document: lsp::TextDocumentIdentifier { uri },
|
||||||
uri: url_to_uri(&test_module.specifier),
|
|
||||||
},
|
|
||||||
kind: lsp_custom::TestModuleNotificationKind::Insert,
|
kind: lsp_custom::TestModuleNotificationKind::Insert,
|
||||||
label: test_module.label(self.maybe_root_uri.as_ref()),
|
label: test_module.label(self.maybe_root_uri.as_ref()),
|
||||||
tests: vec![test_module.get_test_data(&static_id)],
|
tests: vec![test_module.get_test_data(&static_id)],
|
||||||
|
@ -800,14 +804,14 @@ mod tests {
|
||||||
include: Some(vec![
|
include: Some(vec![
|
||||||
lsp_custom::TestIdentifier {
|
lsp_custom::TestIdentifier {
|
||||||
text_document: lsp::TextDocumentIdentifier {
|
text_document: lsp::TextDocumentIdentifier {
|
||||||
uri: url_to_uri(&specifier),
|
uri: url_to_uri(&specifier).unwrap(),
|
||||||
},
|
},
|
||||||
id: None,
|
id: None,
|
||||||
step_id: None,
|
step_id: None,
|
||||||
},
|
},
|
||||||
lsp_custom::TestIdentifier {
|
lsp_custom::TestIdentifier {
|
||||||
text_document: lsp::TextDocumentIdentifier {
|
text_document: lsp::TextDocumentIdentifier {
|
||||||
uri: url_to_uri(&non_test_specifier),
|
uri: url_to_uri(&non_test_specifier).unwrap(),
|
||||||
},
|
},
|
||||||
id: None,
|
id: None,
|
||||||
step_id: None,
|
step_id: None,
|
||||||
|
@ -815,7 +819,7 @@ mod tests {
|
||||||
]),
|
]),
|
||||||
exclude: vec![lsp_custom::TestIdentifier {
|
exclude: vec![lsp_custom::TestIdentifier {
|
||||||
text_document: lsp::TextDocumentIdentifier {
|
text_document: lsp::TextDocumentIdentifier {
|
||||||
uri: url_to_uri(&specifier),
|
uri: url_to_uri(&specifier).unwrap(),
|
||||||
},
|
},
|
||||||
id: Some(
|
id: Some(
|
||||||
"69d9fe87f64f5b66cb8b631d4fd2064e8224b8715a049be54276c42189ff8f9f"
|
"69d9fe87f64f5b66cb8b631d4fd2064e8224b8715a049be54276c42189ff8f9f"
|
||||||
|
|
|
@ -27,14 +27,16 @@ use tower_lsp::jsonrpc::Error as LspError;
|
||||||
use tower_lsp::jsonrpc::Result as LspResult;
|
use tower_lsp::jsonrpc::Result as LspResult;
|
||||||
use tower_lsp::lsp_types as lsp;
|
use tower_lsp::lsp_types as lsp;
|
||||||
|
|
||||||
fn as_delete_notification(url: ModuleSpecifier) -> TestingNotification {
|
fn as_delete_notification(
|
||||||
TestingNotification::DeleteModule(
|
url: &ModuleSpecifier,
|
||||||
|
) -> Result<TestingNotification, AnyError> {
|
||||||
|
Ok(TestingNotification::DeleteModule(
|
||||||
lsp_custom::TestModuleDeleteNotificationParams {
|
lsp_custom::TestModuleDeleteNotificationParams {
|
||||||
text_document: lsp::TextDocumentIdentifier {
|
text_document: lsp::TextDocumentIdentifier {
|
||||||
uri: url_to_uri(&url),
|
uri: url_to_uri(url)?,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type TestServerTests =
|
pub type TestServerTests =
|
||||||
|
@ -126,20 +128,24 @@ impl TestServer {
|
||||||
.map(|tm| tm.as_ref().clone())
|
.map(|tm| tm.as_ref().clone())
|
||||||
.unwrap_or_else(|| TestModule::new(specifier.clone()));
|
.unwrap_or_else(|| TestModule::new(specifier.clone()));
|
||||||
if !test_module.is_empty() {
|
if !test_module.is_empty() {
|
||||||
client.send_test_notification(
|
if let Ok(params) =
|
||||||
test_module.as_replace_notification(mru.as_ref()),
|
test_module.as_replace_notification(mru.as_ref())
|
||||||
);
|
{
|
||||||
|
client.send_test_notification(params);
|
||||||
|
}
|
||||||
} else if !was_empty {
|
} else if !was_empty {
|
||||||
client.send_test_notification(as_delete_notification(
|
if let Ok(params) = as_delete_notification(specifier) {
|
||||||
specifier.clone(),
|
client.send_test_notification(params);
|
||||||
));
|
}
|
||||||
}
|
}
|
||||||
tests
|
tests
|
||||||
.insert(specifier.clone(), (test_module, script_version));
|
.insert(specifier.clone(), (test_module, script_version));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for key in keys {
|
for key in &keys {
|
||||||
client.send_test_notification(as_delete_notification(key));
|
if let Ok(params) = as_delete_notification(key) {
|
||||||
|
client.send_test_notification(params);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
performance.measure(mark);
|
performance.measure(mark);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,10 @@ use super::refactor::EXTRACT_TYPE;
|
||||||
use super::semantic_tokens;
|
use super::semantic_tokens;
|
||||||
use super::semantic_tokens::SemanticTokensBuilder;
|
use super::semantic_tokens::SemanticTokensBuilder;
|
||||||
use super::text::LineIndex;
|
use super::text::LineIndex;
|
||||||
|
use super::urls::uri_to_url;
|
||||||
use super::urls::url_to_uri;
|
use super::urls::url_to_uri;
|
||||||
use super::urls::LspClientUrl;
|
|
||||||
use super::urls::INVALID_SPECIFIER;
|
use super::urls::INVALID_SPECIFIER;
|
||||||
|
use super::urls::INVALID_URI;
|
||||||
|
|
||||||
use crate::args::jsr_url;
|
use crate::args::jsr_url;
|
||||||
use crate::args::FmtOptionsConfig;
|
use crate::args::FmtOptionsConfig;
|
||||||
|
@ -2047,7 +2048,7 @@ impl DocumentSpan {
|
||||||
let file_referrer = target_asset_or_doc.file_referrer();
|
let file_referrer = target_asset_or_doc.file_referrer();
|
||||||
let target_uri = language_server
|
let target_uri = language_server
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_specifier(&target_specifier, file_referrer)
|
.specifier_to_uri(&target_specifier, file_referrer)
|
||||||
.ok()?;
|
.ok()?;
|
||||||
let (target_range, target_selection_range) =
|
let (target_range, target_selection_range) =
|
||||||
if let Some(context_span) = &self.context_span {
|
if let Some(context_span) = &self.context_span {
|
||||||
|
@ -2072,7 +2073,7 @@ impl DocumentSpan {
|
||||||
};
|
};
|
||||||
let link = lsp::LocationLink {
|
let link = lsp::LocationLink {
|
||||||
origin_selection_range,
|
origin_selection_range,
|
||||||
target_uri: target_uri.to_uri(),
|
target_uri,
|
||||||
target_range,
|
target_range,
|
||||||
target_selection_range,
|
target_selection_range,
|
||||||
};
|
};
|
||||||
|
@ -2092,11 +2093,11 @@ impl DocumentSpan {
|
||||||
let line_index = asset_or_doc.line_index();
|
let line_index = asset_or_doc.line_index();
|
||||||
let range = self.text_span.to_range(line_index);
|
let range = self.text_span.to_range(line_index);
|
||||||
let file_referrer = asset_or_doc.file_referrer();
|
let file_referrer = asset_or_doc.file_referrer();
|
||||||
let mut target = language_server
|
let target_uri = language_server
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_specifier(&specifier, file_referrer)
|
.specifier_to_uri(&specifier, file_referrer)
|
||||||
.ok()?
|
.ok()?;
|
||||||
.into_url();
|
let mut target = uri_to_url(&target_uri);
|
||||||
target.set_fragment(Some(&format!(
|
target.set_fragment(Some(&format!(
|
||||||
"L{},{}",
|
"L{},{}",
|
||||||
range.start.line + 1,
|
range.start.line + 1,
|
||||||
|
@ -2155,13 +2156,10 @@ impl NavigateToItem {
|
||||||
let file_referrer = asset_or_doc.file_referrer();
|
let file_referrer = asset_or_doc.file_referrer();
|
||||||
let uri = language_server
|
let uri = language_server
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_specifier(&specifier, file_referrer)
|
.specifier_to_uri(&specifier, file_referrer)
|
||||||
.ok()?;
|
.ok()?;
|
||||||
let range = self.text_span.to_range(line_index);
|
let range = self.text_span.to_range(line_index);
|
||||||
let location = lsp::Location {
|
let location = lsp::Location { uri, range };
|
||||||
uri: uri.to_uri(),
|
|
||||||
range,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut tags: Option<Vec<lsp::SymbolTag>> = None;
|
let mut tags: Option<Vec<lsp::SymbolTag>> = None;
|
||||||
let kind_modifiers = parse_kind_modifier(&self.kind_modifiers);
|
let kind_modifiers = parse_kind_modifier(&self.kind_modifiers);
|
||||||
|
@ -2414,12 +2412,10 @@ impl ImplementationLocation {
|
||||||
let file_referrer = language_server.documents.get_file_referrer(&specifier);
|
let file_referrer = language_server.documents.get_file_referrer(&specifier);
|
||||||
let uri = language_server
|
let uri = language_server
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_specifier(&specifier, file_referrer.as_deref())
|
.specifier_to_uri(&specifier, file_referrer.as_deref())
|
||||||
.unwrap_or_else(|_| {
|
.unwrap_or_else(|_| INVALID_URI.clone());
|
||||||
LspClientUrl::new(ModuleSpecifier::parse("deno://invalid").unwrap())
|
|
||||||
});
|
|
||||||
lsp::Location {
|
lsp::Location {
|
||||||
uri: uri.to_uri(),
|
uri,
|
||||||
range: self.document_span.text_span.to_range(line_index),
|
range: self.document_span.text_span.to_range(line_index),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2475,7 +2471,7 @@ impl RenameLocations {
|
||||||
language_server.documents.get_file_referrer(&specifier);
|
language_server.documents.get_file_referrer(&specifier);
|
||||||
let uri = language_server
|
let uri = language_server
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_specifier(&specifier, file_referrer.as_deref())?;
|
.specifier_to_uri(&specifier, file_referrer.as_deref())?;
|
||||||
let asset_or_doc = language_server.get_asset_or_document(&specifier)?;
|
let asset_or_doc = language_server.get_asset_or_document(&specifier)?;
|
||||||
|
|
||||||
// ensure TextDocumentEdit for `location.file_name`.
|
// ensure TextDocumentEdit for `location.file_name`.
|
||||||
|
@ -2484,7 +2480,7 @@ impl RenameLocations {
|
||||||
uri.clone(),
|
uri.clone(),
|
||||||
lsp::TextDocumentEdit {
|
lsp::TextDocumentEdit {
|
||||||
text_document: lsp::OptionalVersionedTextDocumentIdentifier {
|
text_document: lsp::OptionalVersionedTextDocumentIdentifier {
|
||||||
uri: uri.to_uri(),
|
uri: uri.clone(),
|
||||||
version: asset_or_doc.document_lsp_version(),
|
version: asset_or_doc.document_lsp_version(),
|
||||||
},
|
},
|
||||||
edits:
|
edits:
|
||||||
|
@ -2686,7 +2682,7 @@ impl FileTextChanges {
|
||||||
.collect();
|
.collect();
|
||||||
Ok(lsp::TextDocumentEdit {
|
Ok(lsp::TextDocumentEdit {
|
||||||
text_document: lsp::OptionalVersionedTextDocumentIdentifier {
|
text_document: lsp::OptionalVersionedTextDocumentIdentifier {
|
||||||
uri: url_to_uri(&specifier),
|
uri: url_to_uri(&specifier)?,
|
||||||
version: asset_or_doc.document_lsp_version(),
|
version: asset_or_doc.document_lsp_version(),
|
||||||
},
|
},
|
||||||
edits,
|
edits,
|
||||||
|
@ -2713,7 +2709,7 @@ impl FileTextChanges {
|
||||||
if self.is_new_file.unwrap_or(false) {
|
if self.is_new_file.unwrap_or(false) {
|
||||||
ops.push(lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(
|
ops.push(lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(
|
||||||
lsp::CreateFile {
|
lsp::CreateFile {
|
||||||
uri: url_to_uri(&specifier),
|
uri: url_to_uri(&specifier)?,
|
||||||
options: Some(lsp::CreateFileOptions {
|
options: Some(lsp::CreateFileOptions {
|
||||||
ignore_if_exists: Some(true),
|
ignore_if_exists: Some(true),
|
||||||
overwrite: None,
|
overwrite: None,
|
||||||
|
@ -2730,7 +2726,7 @@ impl FileTextChanges {
|
||||||
.collect();
|
.collect();
|
||||||
ops.push(lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
|
ops.push(lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
|
||||||
text_document: lsp::OptionalVersionedTextDocumentIdentifier {
|
text_document: lsp::OptionalVersionedTextDocumentIdentifier {
|
||||||
uri: url_to_uri(&specifier),
|
uri: url_to_uri(&specifier)?,
|
||||||
version: maybe_asset_or_document.and_then(|d| d.document_lsp_version()),
|
version: maybe_asset_or_document.and_then(|d| d.document_lsp_version()),
|
||||||
},
|
},
|
||||||
edits,
|
edits,
|
||||||
|
@ -3128,10 +3124,10 @@ impl ReferenceEntry {
|
||||||
let file_referrer = language_server.documents.get_file_referrer(&specifier);
|
let file_referrer = language_server.documents.get_file_referrer(&specifier);
|
||||||
let uri = language_server
|
let uri = language_server
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_specifier(&specifier, file_referrer.as_deref())
|
.specifier_to_uri(&specifier, file_referrer.as_deref())
|
||||||
.unwrap_or_else(|_| LspClientUrl::new(INVALID_SPECIFIER.clone()));
|
.unwrap_or_else(|_| INVALID_URI.clone());
|
||||||
lsp::Location {
|
lsp::Location {
|
||||||
uri: uri.to_uri(),
|
uri,
|
||||||
range: self.document_span.text_span.to_range(line_index),
|
range: self.document_span.text_span.to_range(line_index),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3189,12 +3185,13 @@ impl CallHierarchyItem {
|
||||||
.get_file_referrer(&target_specifier);
|
.get_file_referrer(&target_specifier);
|
||||||
let uri = language_server
|
let uri = language_server
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_specifier(&target_specifier, file_referrer.as_deref())
|
.specifier_to_uri(&target_specifier, file_referrer.as_deref())
|
||||||
.unwrap_or_else(|_| LspClientUrl::new(INVALID_SPECIFIER.clone()));
|
.unwrap_or_else(|_| INVALID_URI.clone());
|
||||||
|
|
||||||
let use_file_name = self.is_source_file_item();
|
let use_file_name = self.is_source_file_item();
|
||||||
let maybe_file_path = if uri.as_url().scheme() == "file" {
|
let maybe_file_path = if uri.scheme().is_some_and(|s| s.as_str() == "file")
|
||||||
specifier_to_file_path(uri.as_url()).ok()
|
{
|
||||||
|
specifier_to_file_path(&uri_to_url(&uri)).ok()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -3238,7 +3235,7 @@ impl CallHierarchyItem {
|
||||||
lsp::CallHierarchyItem {
|
lsp::CallHierarchyItem {
|
||||||
name,
|
name,
|
||||||
tags,
|
tags,
|
||||||
uri: uri.to_uri(),
|
uri,
|
||||||
detail: Some(detail),
|
detail: Some(detail),
|
||||||
kind: self.kind.clone().into(),
|
kind: self.kind.clone().into(),
|
||||||
range: self.span.to_range(line_index.clone()),
|
range: self.span.to_range(line_index.clone()),
|
||||||
|
|
166
cli/lsp/urls.rs
166
cli/lsp/urls.rs
|
@ -13,12 +13,18 @@ use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use super::cache::LspCache;
|
use super::cache::LspCache;
|
||||||
|
use super::logging::lsp_warn;
|
||||||
|
|
||||||
/// Used in situations where a default URL needs to be used where otherwise a
|
/// Used in situations where a default URL needs to be used where otherwise a
|
||||||
/// panic is undesired.
|
/// panic is undesired.
|
||||||
pub static INVALID_SPECIFIER: Lazy<ModuleSpecifier> =
|
pub static INVALID_SPECIFIER: Lazy<ModuleSpecifier> =
|
||||||
Lazy::new(|| ModuleSpecifier::parse("deno://invalid").unwrap());
|
Lazy::new(|| ModuleSpecifier::parse("deno://invalid").unwrap());
|
||||||
|
|
||||||
|
/// Used in situations where a default URL needs to be used where otherwise a
|
||||||
|
/// panic is undesired.
|
||||||
|
pub static INVALID_URI: Lazy<Uri> =
|
||||||
|
Lazy::new(|| Uri::from_str("deno://invalid").unwrap());
|
||||||
|
|
||||||
/// Matches the `encodeURIComponent()` encoding from JavaScript, which matches
|
/// Matches the `encodeURIComponent()` encoding from JavaScript, which matches
|
||||||
/// the component percent encoding set.
|
/// the component percent encoding set.
|
||||||
///
|
///
|
||||||
|
@ -58,7 +64,7 @@ fn hash_data_specifier(specifier: &ModuleSpecifier) -> String {
|
||||||
crate::util::checksum::gen(&[file_name_str.as_bytes()])
|
crate::util::checksum::gen(&[file_name_str.as_bytes()])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_deno_url(specifier: &Url) -> String {
|
fn to_deno_uri(specifier: &Url) -> String {
|
||||||
let mut string = String::with_capacity(specifier.as_str().len() + 6);
|
let mut string = String::with_capacity(specifier.as_str().len() + 6);
|
||||||
string.push_str("deno:/");
|
string.push_str("deno:/");
|
||||||
string.push_str(specifier.scheme());
|
string.push_str(specifier.scheme());
|
||||||
|
@ -95,64 +101,31 @@ fn from_deno_url(url: &Url) -> Option<Url> {
|
||||||
Url::parse(&string).ok()
|
Url::parse(&string).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This exists to make it a little bit harder to accidentally use a `Url`
|
|
||||||
/// in the wrong place where a client url should be used.
|
|
||||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
|
|
||||||
pub struct LspClientUrl(Url);
|
|
||||||
|
|
||||||
impl LspClientUrl {
|
|
||||||
pub fn new(url: Url) -> Self {
|
|
||||||
Self(url)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_url(&self) -> &Url {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_url(self) -> Url {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_uri(&self) -> Uri {
|
|
||||||
url_to_uri(&self.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_str(&self) -> &str {
|
|
||||||
self.0.as_str()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for LspClientUrl {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
self.0.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
struct LspUrlMapInner {
|
struct LspUrlMapInner {
|
||||||
specifier_to_url: HashMap<ModuleSpecifier, LspClientUrl>,
|
specifier_to_uri: HashMap<ModuleSpecifier, Uri>,
|
||||||
url_to_specifier: HashMap<Url, ModuleSpecifier>,
|
uri_to_specifier: HashMap<Uri, ModuleSpecifier>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LspUrlMapInner {
|
impl LspUrlMapInner {
|
||||||
fn put(&mut self, specifier: ModuleSpecifier, url: LspClientUrl) {
|
fn put(&mut self, specifier: ModuleSpecifier, uri: Uri) {
|
||||||
self
|
self.uri_to_specifier.insert(uri.clone(), specifier.clone());
|
||||||
.url_to_specifier
|
self.specifier_to_uri.insert(specifier, uri);
|
||||||
.insert(url.as_url().clone(), specifier.clone());
|
|
||||||
self.specifier_to_url.insert(specifier, url);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_url(&self, specifier: &ModuleSpecifier) -> Option<&LspClientUrl> {
|
fn get_uri(&self, specifier: &ModuleSpecifier) -> Option<&Uri> {
|
||||||
self.specifier_to_url.get(specifier)
|
self.specifier_to_uri.get(specifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_specifier(&self, url: &Url) -> Option<&ModuleSpecifier> {
|
fn get_specifier(&self, uri: &Uri) -> Option<&ModuleSpecifier> {
|
||||||
self.url_to_specifier.get(url)
|
self.uri_to_specifier.get(uri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn url_to_uri(url: &Url) -> Uri {
|
pub fn url_to_uri(url: &Url) -> Result<Uri, AnyError> {
|
||||||
Uri::from_str(url.as_str()).unwrap()
|
Ok(Uri::from_str(url.as_str()).inspect_err(|err| {
|
||||||
|
lsp_warn!("Could not convert URL \"{url}\" to URI: {err}")
|
||||||
|
})?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uri_to_url(uri: &Uri) -> Url {
|
pub fn uri_to_url(uri: &Uri) -> Url {
|
||||||
|
@ -181,24 +154,24 @@ impl LspUrlMap {
|
||||||
|
|
||||||
/// Normalize a specifier that is used internally within Deno (or tsc) to a
|
/// Normalize a specifier that is used internally within Deno (or tsc) to a
|
||||||
/// URL that can be handled as a "virtual" document by an LSP client.
|
/// URL that can be handled as a "virtual" document by an LSP client.
|
||||||
pub fn normalize_specifier(
|
pub fn specifier_to_uri(
|
||||||
&self,
|
&self,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
file_referrer: Option<&ModuleSpecifier>,
|
file_referrer: Option<&ModuleSpecifier>,
|
||||||
) -> Result<LspClientUrl, AnyError> {
|
) -> Result<Uri, AnyError> {
|
||||||
if let Some(file_url) =
|
if let Some(file_url) =
|
||||||
self.cache.vendored_specifier(specifier, file_referrer)
|
self.cache.vendored_specifier(specifier, file_referrer)
|
||||||
{
|
{
|
||||||
return Ok(LspClientUrl(file_url));
|
return url_to_uri(&file_url);
|
||||||
}
|
}
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
if let Some(url) = inner.get_url(specifier).cloned() {
|
if let Some(uri) = inner.get_uri(specifier).cloned() {
|
||||||
Ok(url)
|
Ok(uri)
|
||||||
} else {
|
} else {
|
||||||
let url = if specifier.scheme() == "file" {
|
let uri = if specifier.scheme() == "file" {
|
||||||
LspClientUrl(specifier.clone())
|
url_to_uri(specifier)?
|
||||||
} else {
|
} else {
|
||||||
let specifier_str = if specifier.scheme() == "asset" {
|
let uri_str = if specifier.scheme() == "asset" {
|
||||||
format!("deno:/asset{}", specifier.path())
|
format!("deno:/asset{}", specifier.path())
|
||||||
} else if specifier.scheme() == "data" {
|
} else if specifier.scheme() == "data" {
|
||||||
let data_url = deno_graph::source::RawDataUrl::parse(specifier)?;
|
let data_url = deno_graph::source::RawDataUrl::parse(specifier)?;
|
||||||
|
@ -214,13 +187,13 @@ impl LspUrlMap {
|
||||||
extension
|
extension
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
to_deno_url(specifier)
|
to_deno_uri(specifier)
|
||||||
};
|
};
|
||||||
let url = LspClientUrl(Url::parse(&specifier_str)?);
|
let uri = Uri::from_str(&uri_str)?;
|
||||||
inner.put(specifier.clone(), url.clone());
|
inner.put(specifier.clone(), uri.clone());
|
||||||
url
|
uri
|
||||||
};
|
};
|
||||||
Ok(url)
|
Ok(uri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,13 +205,17 @@ impl LspUrlMap {
|
||||||
/// Note: Sometimes the url provided by the client may not have a trailing slash,
|
/// Note: Sometimes the url provided by the client may not have a trailing slash,
|
||||||
/// so we need to force it to in the mapping and nee to explicitly state whether
|
/// so we need to force it to in the mapping and nee to explicitly state whether
|
||||||
/// this is a file or directory url.
|
/// this is a file or directory url.
|
||||||
pub fn normalize_url(&self, uri: &Uri, kind: LspUrlKind) -> ModuleSpecifier {
|
pub fn uri_to_specifier(
|
||||||
|
&self,
|
||||||
|
uri: &Uri,
|
||||||
|
kind: LspUrlKind,
|
||||||
|
) -> ModuleSpecifier {
|
||||||
let url = uri_to_url(uri);
|
let url = uri_to_url(uri);
|
||||||
if let Some(remote_url) = self.cache.unvendored_specifier(&url) {
|
if let Some(remote_url) = self.cache.unvendored_specifier(&url) {
|
||||||
return remote_url;
|
return remote_url;
|
||||||
}
|
}
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
if let Some(specifier) = inner.get_specifier(&url).cloned() {
|
if let Some(specifier) = inner.get_specifier(uri).cloned() {
|
||||||
return specifier;
|
return specifier;
|
||||||
}
|
}
|
||||||
let mut specifier = None;
|
let mut specifier = None;
|
||||||
|
@ -255,7 +232,7 @@ impl LspUrlMap {
|
||||||
specifier = Some(s);
|
specifier = Some(s);
|
||||||
}
|
}
|
||||||
let specifier = specifier.unwrap_or_else(|| url.clone());
|
let specifier = specifier.unwrap_or_else(|| url.clone());
|
||||||
inner.put(specifier.clone(), LspClientUrl(url));
|
inner.put(specifier.clone(), uri.clone());
|
||||||
specifier
|
specifier
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -303,15 +280,14 @@ mod tests {
|
||||||
fn test_lsp_url_map() {
|
fn test_lsp_url_map() {
|
||||||
let map = LspUrlMap::default();
|
let map = LspUrlMap::default();
|
||||||
let fixture = resolve_url("https://deno.land/x/pkg@1.0.0/mod.ts").unwrap();
|
let fixture = resolve_url("https://deno.land/x/pkg@1.0.0/mod.ts").unwrap();
|
||||||
let actual_url = map
|
let actual_uri = map
|
||||||
.normalize_specifier(&fixture, None)
|
.specifier_to_uri(&fixture, None)
|
||||||
.expect("could not handle specifier");
|
.expect("could not handle specifier");
|
||||||
let expected_url =
|
assert_eq!(
|
||||||
Url::parse("deno:/https/deno.land/x/pkg%401.0.0/mod.ts").unwrap();
|
actual_uri.as_str(),
|
||||||
assert_eq!(actual_url.as_url(), &expected_url);
|
"deno:/https/deno.land/x/pkg%401.0.0/mod.ts"
|
||||||
|
);
|
||||||
let actual_specifier =
|
let actual_specifier = map.uri_to_specifier(&actual_uri, LspUrlKind::File);
|
||||||
map.normalize_url(&actual_url.to_uri(), LspUrlKind::File);
|
|
||||||
assert_eq!(actual_specifier, fixture);
|
assert_eq!(actual_specifier, fixture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,17 +296,13 @@ mod tests {
|
||||||
let map = LspUrlMap::default();
|
let map = LspUrlMap::default();
|
||||||
let fixture =
|
let fixture =
|
||||||
Uri::from_str("deno:/https/deno.land/x/pkg%401.0.0/mod.ts").unwrap();
|
Uri::from_str("deno:/https/deno.land/x/pkg%401.0.0/mod.ts").unwrap();
|
||||||
let actual_specifier = map.normalize_url(&fixture, LspUrlKind::File);
|
let actual_specifier = map.uri_to_specifier(&fixture, LspUrlKind::File);
|
||||||
let expected_specifier =
|
let expected_specifier =
|
||||||
Url::parse("https://deno.land/x/pkg@1.0.0/mod.ts").unwrap();
|
Url::parse("https://deno.land/x/pkg@1.0.0/mod.ts").unwrap();
|
||||||
assert_eq!(&actual_specifier, &expected_specifier);
|
assert_eq!(&actual_specifier, &expected_specifier);
|
||||||
|
|
||||||
let actual_url = map
|
let actual_uri = map.specifier_to_uri(&actual_specifier, None).unwrap();
|
||||||
.normalize_specifier(&actual_specifier, None)
|
assert_eq!(actual_uri, fixture);
|
||||||
.unwrap()
|
|
||||||
.to_uri()
|
|
||||||
.clone();
|
|
||||||
assert_eq!(actual_url, fixture);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -338,14 +310,11 @@ mod tests {
|
||||||
// Test fix for #9741 - not properly encoding certain URLs
|
// Test fix for #9741 - not properly encoding certain URLs
|
||||||
let map = LspUrlMap::default();
|
let map = LspUrlMap::default();
|
||||||
let fixture = resolve_url("https://cdn.skypack.dev/-/postcss@v8.2.9-E4SktPp9c0AtxrJHp8iV/dist=es2020,mode=types/lib/postcss.d.ts").unwrap();
|
let fixture = resolve_url("https://cdn.skypack.dev/-/postcss@v8.2.9-E4SktPp9c0AtxrJHp8iV/dist=es2020,mode=types/lib/postcss.d.ts").unwrap();
|
||||||
let actual_url = map
|
let actual_uri = map
|
||||||
.normalize_specifier(&fixture, None)
|
.specifier_to_uri(&fixture, None)
|
||||||
.expect("could not handle specifier");
|
.expect("could not handle specifier");
|
||||||
let expected_url = Url::parse("deno:/https/cdn.skypack.dev/-/postcss%40v8.2.9-E4SktPp9c0AtxrJHp8iV/dist%3Des2020%2Cmode%3Dtypes/lib/postcss.d.ts").unwrap();
|
assert_eq!(actual_uri.as_str(), "deno:/https/cdn.skypack.dev/-/postcss%40v8.2.9-E4SktPp9c0AtxrJHp8iV/dist%3Des2020%2Cmode%3Dtypes/lib/postcss.d.ts");
|
||||||
assert_eq!(actual_url.as_url(), &expected_url);
|
let actual_specifier = map.uri_to_specifier(&actual_uri, LspUrlKind::File);
|
||||||
|
|
||||||
let actual_specifier =
|
|
||||||
map.normalize_url(&actual_url.to_uri(), LspUrlKind::File);
|
|
||||||
assert_eq!(actual_specifier, fixture);
|
assert_eq!(actual_specifier, fixture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,14 +322,13 @@ mod tests {
|
||||||
fn test_lsp_url_map_data() {
|
fn test_lsp_url_map_data() {
|
||||||
let map = LspUrlMap::default();
|
let map = LspUrlMap::default();
|
||||||
let fixture = resolve_url("data:application/typescript;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo=").unwrap();
|
let fixture = resolve_url("data:application/typescript;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo=").unwrap();
|
||||||
let actual_url = map
|
let actual_uri = map
|
||||||
.normalize_specifier(&fixture, None)
|
.specifier_to_uri(&fixture, None)
|
||||||
.expect("could not handle specifier");
|
.expect("could not handle specifier");
|
||||||
let expected_url = Url::parse("deno:/c21c7fc382b2b0553dc0864aa81a3acacfb7b3d1285ab5ae76da6abec213fb37/data_url.ts").unwrap();
|
let expected_url = Url::parse("deno:/c21c7fc382b2b0553dc0864aa81a3acacfb7b3d1285ab5ae76da6abec213fb37/data_url.ts").unwrap();
|
||||||
assert_eq!(actual_url.as_url(), &expected_url);
|
assert_eq!(&uri_to_url(&actual_uri), &expected_url);
|
||||||
|
|
||||||
let actual_specifier =
|
let actual_specifier = map.uri_to_specifier(&actual_uri, LspUrlKind::File);
|
||||||
map.normalize_url(&actual_url.to_uri(), LspUrlKind::File);
|
|
||||||
assert_eq!(actual_specifier, fixture);
|
assert_eq!(actual_specifier, fixture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,15 +336,11 @@ mod tests {
|
||||||
fn test_lsp_url_map_host_with_port() {
|
fn test_lsp_url_map_host_with_port() {
|
||||||
let map = LspUrlMap::default();
|
let map = LspUrlMap::default();
|
||||||
let fixture = resolve_url("http://localhost:8000/mod.ts").unwrap();
|
let fixture = resolve_url("http://localhost:8000/mod.ts").unwrap();
|
||||||
let actual_url = map
|
let actual_uri = map
|
||||||
.normalize_specifier(&fixture, None)
|
.specifier_to_uri(&fixture, None)
|
||||||
.expect("could not handle specifier");
|
.expect("could not handle specifier");
|
||||||
let expected_url =
|
assert_eq!(actual_uri.as_str(), "deno:/http/localhost%3A8000/mod.ts");
|
||||||
Url::parse("deno:/http/localhost%3A8000/mod.ts").unwrap();
|
let actual_specifier = map.uri_to_specifier(&actual_uri, LspUrlKind::File);
|
||||||
assert_eq!(actual_url.as_url(), &expected_url);
|
|
||||||
|
|
||||||
let actual_specifier =
|
|
||||||
map.normalize_url(&actual_url.to_uri(), LspUrlKind::File);
|
|
||||||
assert_eq!(actual_specifier, fixture);
|
assert_eq!(actual_specifier, fixture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,7 +352,7 @@ mod tests {
|
||||||
"file:///c%3A/Users/deno/Desktop/file%20with%20spaces%20in%20name.txt",
|
"file:///c%3A/Users/deno/Desktop/file%20with%20spaces%20in%20name.txt",
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let actual = map.normalize_url(&fixture, LspUrlKind::File);
|
let actual = map.uri_to_specifier(&fixture, LspUrlKind::File);
|
||||||
let expected =
|
let expected =
|
||||||
Url::parse("file:///C:/Users/deno/Desktop/file with spaces in name.txt")
|
Url::parse("file:///C:/Users/deno/Desktop/file with spaces in name.txt")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -403,7 +367,7 @@ mod tests {
|
||||||
"file:///Users/deno/Desktop/file%20with%20spaces%20in%20name.txt",
|
"file:///Users/deno/Desktop/file%20with%20spaces%20in%20name.txt",
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let actual = map.normalize_url(&fixture, LspUrlKind::File);
|
let actual = map.uri_to_specifier(&fixture, LspUrlKind::File);
|
||||||
let expected =
|
let expected =
|
||||||
Url::parse("file:///Users/deno/Desktop/file with spaces in name.txt")
|
Url::parse("file:///Users/deno/Desktop/file with spaces in name.txt")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -414,7 +378,7 @@ mod tests {
|
||||||
fn test_normalize_deno_status() {
|
fn test_normalize_deno_status() {
|
||||||
let map = LspUrlMap::default();
|
let map = LspUrlMap::default();
|
||||||
let fixture = Uri::from_str("deno:/status.md").unwrap();
|
let fixture = Uri::from_str("deno:/status.md").unwrap();
|
||||||
let actual = map.normalize_url(&fixture, LspUrlKind::File);
|
let actual = map.uri_to_specifier(&fixture, LspUrlKind::File);
|
||||||
assert_eq!(actual.as_str(), fixture.as_str());
|
assert_eq!(actual.as_str(), fixture.as_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
61
cli/main.rs
61
cli/main.rs
|
@ -32,8 +32,6 @@ mod worker;
|
||||||
use crate::args::flags_from_vec;
|
use crate::args::flags_from_vec;
|
||||||
use crate::args::DenoSubcommand;
|
use crate::args::DenoSubcommand;
|
||||||
use crate::args::Flags;
|
use crate::args::Flags;
|
||||||
use crate::args::DENO_FUTURE;
|
|
||||||
use crate::graph_container::ModuleGraphContainer;
|
|
||||||
use crate::util::display;
|
use crate::util::display;
|
||||||
use crate::util::v8::get_v8_flags_from_env;
|
use crate::util::v8::get_v8_flags_from_env;
|
||||||
use crate::util::v8::init_v8_flags;
|
use crate::util::v8::init_v8_flags;
|
||||||
|
@ -48,7 +46,8 @@ use deno_core::error::JsError;
|
||||||
use deno_core::futures::FutureExt;
|
use deno_core::futures::FutureExt;
|
||||||
use deno_core::unsync::JoinHandle;
|
use deno_core::unsync::JoinHandle;
|
||||||
use deno_npm::resolution::SnapshotFromLockfileError;
|
use deno_npm::resolution::SnapshotFromLockfileError;
|
||||||
use deno_runtime::fmt_errors::format_js_error;
|
use deno_runtime::fmt_errors::format_js_error_with_suggestions;
|
||||||
|
use deno_runtime::fmt_errors::FixSuggestion;
|
||||||
use deno_runtime::tokio_util::create_and_run_current_thread_with_maybe_metrics;
|
use deno_runtime::tokio_util::create_and_run_current_thread_with_maybe_metrics;
|
||||||
use deno_terminal::colors;
|
use deno_terminal::colors;
|
||||||
use factory::CliFactory;
|
use factory::CliFactory;
|
||||||
|
@ -111,9 +110,7 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
||||||
tools::bench::run_benchmarks(flags, bench_flags).await
|
tools::bench::run_benchmarks(flags, bench_flags).await
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
DenoSubcommand::Bundle(bundle_flags) => spawn_subcommand(async {
|
DenoSubcommand::Bundle => exit_with_message("⚠️ `deno bundle` 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),
|
||||||
tools::bundle::bundle(flags, bundle_flags).await
|
|
||||||
}),
|
|
||||||
DenoSubcommand::Doc(doc_flags) => {
|
DenoSubcommand::Doc(doc_flags) => {
|
||||||
spawn_subcommand(async { tools::doc::doc(flags, doc_flags).await })
|
spawn_subcommand(async { tools::doc::doc(flags, doc_flags).await })
|
||||||
}
|
}
|
||||||
|
@ -121,14 +118,7 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
||||||
tools::run::eval_command(flags, eval_flags).await
|
tools::run::eval_command(flags, eval_flags).await
|
||||||
}),
|
}),
|
||||||
DenoSubcommand::Cache(cache_flags) => spawn_subcommand(async move {
|
DenoSubcommand::Cache(cache_flags) => spawn_subcommand(async move {
|
||||||
let factory = CliFactory::from_flags(flags);
|
tools::installer::install_from_entrypoints(flags, &cache_flags.files).await
|
||||||
let emitter = factory.emitter()?;
|
|
||||||
let main_graph_container =
|
|
||||||
factory.main_module_graph_container().await?;
|
|
||||||
main_graph_container
|
|
||||||
.load_and_type_check_files(&cache_flags.files)
|
|
||||||
.await?;
|
|
||||||
emitter.cache_module_emits(&main_graph_container.graph()).await
|
|
||||||
}),
|
}),
|
||||||
DenoSubcommand::Check(check_flags) => spawn_subcommand(async move {
|
DenoSubcommand::Check(check_flags) => spawn_subcommand(async move {
|
||||||
let factory = CliFactory::from_flags(flags);
|
let factory = CliFactory::from_flags(flags);
|
||||||
|
@ -172,7 +162,7 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
||||||
tools::jupyter::kernel(flags, jupyter_flags).await
|
tools::jupyter::kernel(flags, jupyter_flags).await
|
||||||
}),
|
}),
|
||||||
DenoSubcommand::Uninstall(uninstall_flags) => spawn_subcommand(async {
|
DenoSubcommand::Uninstall(uninstall_flags) => spawn_subcommand(async {
|
||||||
tools::installer::uninstall(uninstall_flags)
|
tools::installer::uninstall(flags, uninstall_flags).await
|
||||||
}),
|
}),
|
||||||
DenoSubcommand::Lsp => spawn_subcommand(async { lsp::start().await }),
|
DenoSubcommand::Lsp => spawn_subcommand(async { lsp::start().await }),
|
||||||
DenoSubcommand::Lint(lint_flags) => spawn_subcommand(async {
|
DenoSubcommand::Lint(lint_flags) => spawn_subcommand(async {
|
||||||
|
@ -286,9 +276,7 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
||||||
"This deno was built without the \"upgrade\" feature. Please upgrade using the installation method originally used to install Deno.",
|
"This deno was built without the \"upgrade\" feature. Please upgrade using the installation method originally used to install Deno.",
|
||||||
1,
|
1,
|
||||||
),
|
),
|
||||||
DenoSubcommand::Vendor(vendor_flags) => spawn_subcommand(async {
|
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),
|
||||||
tools::vendor::vendor(flags, vendor_flags).await
|
|
||||||
}),
|
|
||||||
DenoSubcommand::Publish(publish_flags) => spawn_subcommand(async {
|
DenoSubcommand::Publish(publish_flags) => spawn_subcommand(async {
|
||||||
tools::registry::publish(flags, publish_flags).await
|
tools::registry::publish(flags, publish_flags).await
|
||||||
}),
|
}),
|
||||||
|
@ -349,12 +337,30 @@ fn exit_with_message(message: &str, code: i32) -> ! {
|
||||||
std::process::exit(code);
|
std::process::exit(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_suggestions_for_commonjs_error(e: &JsError) -> Vec<FixSuggestion> {
|
||||||
|
if e.name.as_deref() == Some("ReferenceError") {
|
||||||
|
if let Some(msg) = &e.message {
|
||||||
|
if msg.contains("module is not defined")
|
||||||
|
|| msg.contains("exports is not defined")
|
||||||
|
{
|
||||||
|
return vec![
|
||||||
|
FixSuggestion::info("Deno does not support CommonJS modules without `.cjs` extension."),
|
||||||
|
FixSuggestion::hint("Rewrite this module to ESM or change the file extension to `.cjs`."),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
|
||||||
fn exit_for_error(error: AnyError) -> ! {
|
fn exit_for_error(error: AnyError) -> ! {
|
||||||
let mut error_string = format!("{error:?}");
|
let mut error_string = format!("{error:?}");
|
||||||
let mut error_code = 1;
|
let mut error_code = 1;
|
||||||
|
|
||||||
if let Some(e) = error.downcast_ref::<JsError>() {
|
if let Some(e) = error.downcast_ref::<JsError>() {
|
||||||
error_string = format_js_error(e);
|
let suggestions = get_suggestions_for_commonjs_error(e);
|
||||||
|
error_string = format_js_error_with_suggestions(e, suggestions);
|
||||||
} else if let Some(SnapshotFromLockfileError::IntegrityCheckFailed(e)) =
|
} else if let Some(SnapshotFromLockfileError::IntegrityCheckFailed(e)) =
|
||||||
error.downcast_ref::<SnapshotFromLockfileError>()
|
error.downcast_ref::<SnapshotFromLockfileError>()
|
||||||
{
|
{
|
||||||
|
@ -454,30 +460,19 @@ fn resolve_flags_and_init(
|
||||||
// https://github.com/microsoft/vscode/blob/48d4ba271686e8072fc6674137415bc80d936bc7/extensions/typescript-language-features/src/configuration/configuration.ts#L213-L214
|
// https://github.com/microsoft/vscode/blob/48d4ba271686e8072fc6674137415bc80d936bc7/extensions/typescript-language-features/src/configuration/configuration.ts#L213-L214
|
||||||
DenoSubcommand::Lsp => vec!["--max-old-space-size=3072".to_string()],
|
DenoSubcommand::Lsp => vec!["--max-old-space-size=3072".to_string()],
|
||||||
_ => {
|
_ => {
|
||||||
if *DENO_FUTURE {
|
|
||||||
// TODO(bartlomieju): I think this can be removed as it's handled by `deno_core`
|
// TODO(bartlomieju): I think this can be removed as it's handled by `deno_core`
|
||||||
// and its settings.
|
// and its settings.
|
||||||
// deno_ast removes TypeScript `assert` keywords, so this flag only affects JavaScript
|
// deno_ast removes TypeScript `assert` keywords, so this flag only affects JavaScript
|
||||||
// TODO(petamoriken): Need to check TypeScript `assert` keywords in deno_ast
|
// TODO(petamoriken): Need to check TypeScript `assert` keywords in deno_ast
|
||||||
vec!["--no-harmony-import-assertions".to_string()]
|
vec!["--no-harmony-import-assertions".to_string()]
|
||||||
} else {
|
|
||||||
vec![
|
|
||||||
// TODO(bartlomieju): I think this can be removed as it's handled by `deno_core`
|
|
||||||
// and its settings.
|
|
||||||
// If we're still in v1.X version we want to support import assertions.
|
|
||||||
// V8 12.6 unshipped the support by default, so force it by passing a
|
|
||||||
// flag.
|
|
||||||
"--harmony-import-assertions".to_string(),
|
|
||||||
// Verify with DENO_FUTURE for now.
|
|
||||||
"--no-maglev".to_string(),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
init_v8_flags(&default_v8_flags, &flags.v8_flags, get_v8_flags_from_env());
|
init_v8_flags(&default_v8_flags, &flags.v8_flags, get_v8_flags_from_env());
|
||||||
// TODO(bartlomieju): remove last argument in Deno 2.
|
// TODO(bartlomieju): remove last argument in Deno 2.
|
||||||
deno_core::JsRuntime::init_platform(None, !*DENO_FUTURE);
|
deno_core::JsRuntime::init_platform(
|
||||||
|
None, /* import assertions enabled */ false,
|
||||||
|
);
|
||||||
util::logger::init(flags.log_level);
|
util::logger::init(flags.log_level);
|
||||||
|
|
||||||
Ok(flags)
|
Ok(flags)
|
||||||
|
|
|
@ -401,7 +401,7 @@ impl<TGraphContainer: ModuleGraphContainer>
|
||||||
|
|
||||||
fn inner_resolve(
|
fn inner_resolve(
|
||||||
&self,
|
&self,
|
||||||
specifier: &str,
|
raw_specifier: &str,
|
||||||
referrer: &ModuleSpecifier,
|
referrer: &ModuleSpecifier,
|
||||||
) -> Result<ModuleSpecifier, AnyError> {
|
) -> Result<ModuleSpecifier, AnyError> {
|
||||||
if self.shared.node_resolver.in_npm_package(referrer) {
|
if self.shared.node_resolver.in_npm_package(referrer) {
|
||||||
|
@ -409,7 +409,7 @@ impl<TGraphContainer: ModuleGraphContainer>
|
||||||
self
|
self
|
||||||
.shared
|
.shared
|
||||||
.node_resolver
|
.node_resolver
|
||||||
.resolve(specifier, referrer, NodeResolutionMode::Execution)?
|
.resolve(raw_specifier, referrer, NodeResolutionMode::Execution)?
|
||||||
.into_url(),
|
.into_url(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -418,7 +418,7 @@ impl<TGraphContainer: ModuleGraphContainer>
|
||||||
let resolution = match graph.get(referrer) {
|
let resolution = match graph.get(referrer) {
|
||||||
Some(Module::Js(module)) => module
|
Some(Module::Js(module)) => module
|
||||||
.dependencies
|
.dependencies
|
||||||
.get(specifier)
|
.get(raw_specifier)
|
||||||
.map(|d| &d.maybe_code)
|
.map(|d| &d.maybe_code)
|
||||||
.unwrap_or(&Resolution::None),
|
.unwrap_or(&Resolution::None),
|
||||||
_ => &Resolution::None,
|
_ => &Resolution::None,
|
||||||
|
@ -433,7 +433,7 @@ impl<TGraphContainer: ModuleGraphContainer>
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Resolution::None => Cow::Owned(self.shared.resolver.resolve(
|
Resolution::None => Cow::Owned(self.shared.resolver.resolve(
|
||||||
specifier,
|
raw_specifier,
|
||||||
&deno_graph::Range {
|
&deno_graph::Range {
|
||||||
specifier: referrer.clone(),
|
specifier: referrer.clone(),
|
||||||
start: deno_graph::Position::zeroed(),
|
start: deno_graph::Position::zeroed(),
|
||||||
|
|
|
@ -3307,19 +3307,30 @@ fn napi_resolve_deferred(
|
||||||
check_arg!(env, result);
|
check_arg!(env, result);
|
||||||
check_arg!(env, deferred);
|
check_arg!(env, deferred);
|
||||||
|
|
||||||
|
// Make sure microtasks don't run and call back into JS
|
||||||
|
env
|
||||||
|
.scope()
|
||||||
|
.set_microtasks_policy(v8::MicrotasksPolicy::Explicit);
|
||||||
|
|
||||||
let deferred_ptr =
|
let deferred_ptr =
|
||||||
unsafe { NonNull::new_unchecked(deferred as *mut v8::PromiseResolver) };
|
unsafe { NonNull::new_unchecked(deferred as *mut v8::PromiseResolver) };
|
||||||
let global = unsafe { v8::Global::from_raw(env.isolate(), deferred_ptr) };
|
let global = unsafe { v8::Global::from_raw(env.isolate(), deferred_ptr) };
|
||||||
let resolver = v8::Local::new(&mut env.scope(), global);
|
let resolver = v8::Local::new(&mut env.scope(), global);
|
||||||
|
|
||||||
if !resolver
|
let success = resolver
|
||||||
.resolve(&mut env.scope(), result.unwrap())
|
.resolve(&mut env.scope(), result.unwrap())
|
||||||
.unwrap_or(false)
|
.unwrap_or(false);
|
||||||
{
|
|
||||||
return napi_generic_failure;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Restore policy
|
||||||
|
env
|
||||||
|
.scope()
|
||||||
|
.set_microtasks_policy(v8::MicrotasksPolicy::Auto);
|
||||||
|
|
||||||
|
if success {
|
||||||
napi_ok
|
napi_ok
|
||||||
|
} else {
|
||||||
|
napi_generic_failure
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi_sym]
|
#[napi_sym]
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "napi_sym"
|
name = "napi_sym"
|
||||||
version = "0.96.0"
|
version = "0.98.0"
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
132
cli/npm/byonm.rs
132
cli/npm/byonm.rs
|
@ -17,6 +17,7 @@ use deno_runtime::deno_node::NodeRequireResolver;
|
||||||
use deno_runtime::deno_node::NpmProcessStateProvider;
|
use deno_runtime::deno_node::NpmProcessStateProvider;
|
||||||
use deno_runtime::deno_node::PackageJson;
|
use deno_runtime::deno_node::PackageJson;
|
||||||
use deno_semver::package::PackageReq;
|
use deno_semver::package::PackageReq;
|
||||||
|
use deno_semver::Version;
|
||||||
use node_resolver::errors::PackageFolderResolveError;
|
use node_resolver::errors::PackageFolderResolveError;
|
||||||
use node_resolver::errors::PackageFolderResolveIoError;
|
use node_resolver::errors::PackageFolderResolveIoError;
|
||||||
use node_resolver::errors::PackageJsonLoadError;
|
use node_resolver::errors::PackageJsonLoadError;
|
||||||
|
@ -29,6 +30,7 @@ use crate::args::NpmProcessStateKind;
|
||||||
use crate::util::fs::canonicalize_path_maybe_not_exists_with_fs;
|
use crate::util::fs::canonicalize_path_maybe_not_exists_with_fs;
|
||||||
use deno_runtime::fs_util::specifier_to_file_path;
|
use deno_runtime::fs_util::specifier_to_file_path;
|
||||||
|
|
||||||
|
use super::managed::normalize_pkg_name_for_node_modules_deno_folder;
|
||||||
use super::CliNpmResolver;
|
use super::CliNpmResolver;
|
||||||
use super::InnerCliNpmResolverRef;
|
use super::InnerCliNpmResolverRef;
|
||||||
|
|
||||||
|
@ -60,9 +62,7 @@ impl ByonmCliNpmResolver {
|
||||||
) -> Result<Option<Arc<PackageJson>>, PackageJsonLoadError> {
|
) -> Result<Option<Arc<PackageJson>>, PackageJsonLoadError> {
|
||||||
load_pkg_json(&DenoPkgJsonFsAdapter(self.fs.as_ref()), path)
|
load_pkg_json(&DenoPkgJsonFsAdapter(self.fs.as_ref()), path)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl ByonmCliNpmResolver {
|
|
||||||
/// Finds the ancestor package.json that contains the specified dependency.
|
/// Finds the ancestor package.json that contains the specified dependency.
|
||||||
pub fn find_ancestor_package_json_with_dep(
|
pub fn find_ancestor_package_json_with_dep(
|
||||||
&self,
|
&self,
|
||||||
|
@ -98,7 +98,7 @@ impl ByonmCliNpmResolver {
|
||||||
&self,
|
&self,
|
||||||
req: &PackageReq,
|
req: &PackageReq,
|
||||||
referrer: &ModuleSpecifier,
|
referrer: &ModuleSpecifier,
|
||||||
) -> Result<(Arc<PackageJson>, String), AnyError> {
|
) -> Result<Option<(Arc<PackageJson>, String)>, AnyError> {
|
||||||
fn resolve_alias_from_pkg_json(
|
fn resolve_alias_from_pkg_json(
|
||||||
req: &PackageReq,
|
req: &PackageReq,
|
||||||
pkg_json: &PackageJson,
|
pkg_json: &PackageJson,
|
||||||
|
@ -134,7 +134,7 @@ impl ByonmCliNpmResolver {
|
||||||
if let Some(alias) =
|
if let Some(alias) =
|
||||||
resolve_alias_from_pkg_json(req, pkg_json.as_ref())
|
resolve_alias_from_pkg_json(req, pkg_json.as_ref())
|
||||||
{
|
{
|
||||||
return Ok((pkg_json, alias));
|
return Ok(Some((pkg_json, alias)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
current_path = dir_path;
|
current_path = dir_path;
|
||||||
|
@ -148,19 +148,65 @@ impl ByonmCliNpmResolver {
|
||||||
if let Some(pkg_json) = self.load_pkg_json(&root_pkg_json_path)? {
|
if let Some(pkg_json) = self.load_pkg_json(&root_pkg_json_path)? {
|
||||||
if let Some(alias) = resolve_alias_from_pkg_json(req, pkg_json.as_ref())
|
if let Some(alias) = resolve_alias_from_pkg_json(req, pkg_json.as_ref())
|
||||||
{
|
{
|
||||||
return Ok((pkg_json, alias));
|
return Ok(Some((pkg_json, alias)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bail!(
|
Ok(None)
|
||||||
concat!(
|
}
|
||||||
"Could not find a matching package for 'npm:{}' in a package.json file. ",
|
|
||||||
"You must specify this as a package.json dependency when the ",
|
fn resolve_folder_in_root_node_modules(
|
||||||
"node_modules folder is not managed by Deno.",
|
&self,
|
||||||
),
|
req: &PackageReq,
|
||||||
req,
|
) -> Option<PathBuf> {
|
||||||
|
// now check if node_modules/.deno/ matches this constraint
|
||||||
|
let root_node_modules_dir = self.root_node_modules_dir.as_ref()?;
|
||||||
|
let node_modules_deno_dir = root_node_modules_dir.join(".deno");
|
||||||
|
let Ok(entries) = self.fs.read_dir_sync(&node_modules_deno_dir) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let search_prefix = format!(
|
||||||
|
"{}@",
|
||||||
|
normalize_pkg_name_for_node_modules_deno_folder(&req.name)
|
||||||
);
|
);
|
||||||
|
let mut best_version = None;
|
||||||
|
|
||||||
|
// example entries:
|
||||||
|
// - @denotest+add@1.0.0
|
||||||
|
// - @denotest+add@1.0.0_1
|
||||||
|
for entry in entries {
|
||||||
|
if !entry.is_directory {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let Some(version_and_copy_idx) = entry.name.strip_prefix(&search_prefix)
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let version = version_and_copy_idx
|
||||||
|
.rsplit_once('_')
|
||||||
|
.map(|(v, _)| v)
|
||||||
|
.unwrap_or(version_and_copy_idx);
|
||||||
|
let Ok(version) = Version::parse_from_npm(version) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if req.version_req.matches(&version) {
|
||||||
|
if let Some((best_version_version, _)) = &best_version {
|
||||||
|
if version > *best_version_version {
|
||||||
|
best_version = Some((version, entry.name));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
best_version = Some((version, entry.name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
best_version.map(|(_version, entry_name)| {
|
||||||
|
join_package_name(
|
||||||
|
&node_modules_deno_dir.join(entry_name).join("node_modules"),
|
||||||
|
&req.name,
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,35 +334,63 @@ impl CliNpmResolver for ByonmCliNpmResolver {
|
||||||
req: &PackageReq,
|
req: &PackageReq,
|
||||||
referrer: &ModuleSpecifier,
|
referrer: &ModuleSpecifier,
|
||||||
) -> Result<PathBuf, AnyError> {
|
) -> Result<PathBuf, AnyError> {
|
||||||
// resolve the pkg json and alias
|
fn node_resolve_dir(
|
||||||
let (pkg_json, alias) =
|
fs: &dyn FileSystem,
|
||||||
self.resolve_pkg_json_and_alias_for_req(req, referrer)?;
|
alias: &str,
|
||||||
// now try node resolution
|
start_dir: &Path,
|
||||||
for ancestor in pkg_json.path.parent().unwrap().ancestors() {
|
) -> Result<Option<PathBuf>, AnyError> {
|
||||||
|
for ancestor in start_dir.ancestors() {
|
||||||
let node_modules_folder = ancestor.join("node_modules");
|
let node_modules_folder = ancestor.join("node_modules");
|
||||||
let sub_dir = join_package_name(&node_modules_folder, &alias);
|
let sub_dir = join_package_name(&node_modules_folder, alias);
|
||||||
if self.fs.is_dir_sync(&sub_dir) {
|
if fs.is_dir_sync(&sub_dir) {
|
||||||
return Ok(canonicalize_path_maybe_not_exists_with_fs(
|
return Ok(Some(canonicalize_path_maybe_not_exists_with_fs(
|
||||||
&sub_dir,
|
&sub_dir, fs,
|
||||||
self.fs.as_ref(),
|
)?));
|
||||||
)?);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
// now attempt to resolve if it's found in any package.json
|
||||||
|
let maybe_pkg_json_and_alias =
|
||||||
|
self.resolve_pkg_json_and_alias_for_req(req, referrer)?;
|
||||||
|
match maybe_pkg_json_and_alias {
|
||||||
|
Some((pkg_json, alias)) => {
|
||||||
|
// now try node resolution
|
||||||
|
if let Some(resolved) =
|
||||||
|
node_resolve_dir(self.fs.as_ref(), &alias, pkg_json.dir_path())?
|
||||||
|
{
|
||||||
|
return Ok(resolved);
|
||||||
|
}
|
||||||
|
|
||||||
bail!(
|
bail!(
|
||||||
concat!(
|
concat!(
|
||||||
"Could not find \"{}\" in a node_modules folder. ",
|
"Could not find \"{}\" in a node_modules folder. ",
|
||||||
"Deno expects the node_modules/ directory to be up to date. ",
|
"Deno expects the node_modules/ directory to be up to date. ",
|
||||||
"Did you forget to run `{}`?"
|
"Did you forget to run `deno install`?"
|
||||||
),
|
),
|
||||||
alias,
|
alias,
|
||||||
if *crate::args::DENO_FUTURE {
|
|
||||||
"deno install"
|
|
||||||
} else {
|
|
||||||
"npm install"
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
None => {
|
||||||
|
// now check if node_modules/.deno/ matches this constraint
|
||||||
|
if let Some(folder) = self.resolve_folder_in_root_node_modules(req) {
|
||||||
|
return Ok(folder);
|
||||||
|
}
|
||||||
|
|
||||||
|
bail!(
|
||||||
|
concat!(
|
||||||
|
"Could not find a matching package for 'npm:{}' in the node_modules ",
|
||||||
|
"directory. Ensure you have all your JSR and npm dependencies listed ",
|
||||||
|
"in your deno.json or package.json, then run `deno install`. Alternatively, ",
|
||||||
|
r#"turn on auto-install by specifying `"nodeModulesDir": "auto"` in your "#,
|
||||||
|
"deno.json file."
|
||||||
|
),
|
||||||
|
req,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn check_state_hash(&self) -> Option<u64> {
|
fn check_state_hash(&self) -> Option<u64> {
|
||||||
// it is very difficult to determine the check state hash for byonm
|
// it is very difficult to determine the check state hash for byonm
|
||||||
|
|
|
@ -32,9 +32,9 @@ use resolution::AddPkgReqsResult;
|
||||||
|
|
||||||
use crate::args::CliLockfile;
|
use crate::args::CliLockfile;
|
||||||
use crate::args::LifecycleScriptsConfig;
|
use crate::args::LifecycleScriptsConfig;
|
||||||
|
use crate::args::NpmInstallDepsProvider;
|
||||||
use crate::args::NpmProcessState;
|
use crate::args::NpmProcessState;
|
||||||
use crate::args::NpmProcessStateKind;
|
use crate::args::NpmProcessStateKind;
|
||||||
use crate::args::PackageJsonInstallDepsProvider;
|
|
||||||
use crate::cache::FastInsecureHasher;
|
use crate::cache::FastInsecureHasher;
|
||||||
use crate::http_util::HttpClientProvider;
|
use crate::http_util::HttpClientProvider;
|
||||||
use crate::util::fs::canonicalize_path_maybe_not_exists_with_fs;
|
use crate::util::fs::canonicalize_path_maybe_not_exists_with_fs;
|
||||||
|
@ -45,6 +45,7 @@ use self::cache::NpmCache;
|
||||||
use self::registry::CliNpmRegistryApi;
|
use self::registry::CliNpmRegistryApi;
|
||||||
use self::resolution::NpmResolution;
|
use self::resolution::NpmResolution;
|
||||||
use self::resolvers::create_npm_fs_resolver;
|
use self::resolvers::create_npm_fs_resolver;
|
||||||
|
pub use self::resolvers::normalize_pkg_name_for_node_modules_deno_folder;
|
||||||
use self::resolvers::NpmPackageFsResolver;
|
use self::resolvers::NpmPackageFsResolver;
|
||||||
|
|
||||||
use super::CliNpmResolver;
|
use super::CliNpmResolver;
|
||||||
|
@ -71,7 +72,7 @@ pub struct CliNpmResolverManagedCreateOptions {
|
||||||
pub text_only_progress_bar: crate::util::progress_bar::ProgressBar,
|
pub text_only_progress_bar: crate::util::progress_bar::ProgressBar,
|
||||||
pub maybe_node_modules_path: Option<PathBuf>,
|
pub maybe_node_modules_path: Option<PathBuf>,
|
||||||
pub npm_system_info: NpmSystemInfo,
|
pub npm_system_info: NpmSystemInfo,
|
||||||
pub package_json_deps_provider: Arc<PackageJsonInstallDepsProvider>,
|
pub npm_install_deps_provider: Arc<NpmInstallDepsProvider>,
|
||||||
pub npmrc: Arc<ResolvedNpmRc>,
|
pub npmrc: Arc<ResolvedNpmRc>,
|
||||||
pub lifecycle_scripts: LifecycleScriptsConfig,
|
pub lifecycle_scripts: LifecycleScriptsConfig,
|
||||||
}
|
}
|
||||||
|
@ -97,7 +98,7 @@ pub async fn create_managed_npm_resolver_for_lsp(
|
||||||
npm_api,
|
npm_api,
|
||||||
npm_cache,
|
npm_cache,
|
||||||
options.npmrc,
|
options.npmrc,
|
||||||
options.package_json_deps_provider,
|
options.npm_install_deps_provider,
|
||||||
options.text_only_progress_bar,
|
options.text_only_progress_bar,
|
||||||
options.maybe_node_modules_path,
|
options.maybe_node_modules_path,
|
||||||
options.npm_system_info,
|
options.npm_system_info,
|
||||||
|
@ -122,7 +123,7 @@ pub async fn create_managed_npm_resolver(
|
||||||
npm_api,
|
npm_api,
|
||||||
npm_cache,
|
npm_cache,
|
||||||
options.npmrc,
|
options.npmrc,
|
||||||
options.package_json_deps_provider,
|
options.npm_install_deps_provider,
|
||||||
options.text_only_progress_bar,
|
options.text_only_progress_bar,
|
||||||
options.maybe_node_modules_path,
|
options.maybe_node_modules_path,
|
||||||
options.npm_system_info,
|
options.npm_system_info,
|
||||||
|
@ -139,7 +140,7 @@ fn create_inner(
|
||||||
npm_api: Arc<CliNpmRegistryApi>,
|
npm_api: Arc<CliNpmRegistryApi>,
|
||||||
npm_cache: Arc<NpmCache>,
|
npm_cache: Arc<NpmCache>,
|
||||||
npm_rc: Arc<ResolvedNpmRc>,
|
npm_rc: Arc<ResolvedNpmRc>,
|
||||||
package_json_deps_provider: Arc<PackageJsonInstallDepsProvider>,
|
npm_install_deps_provider: Arc<NpmInstallDepsProvider>,
|
||||||
text_only_progress_bar: crate::util::progress_bar::ProgressBar,
|
text_only_progress_bar: crate::util::progress_bar::ProgressBar,
|
||||||
node_modules_dir_path: Option<PathBuf>,
|
node_modules_dir_path: Option<PathBuf>,
|
||||||
npm_system_info: NpmSystemInfo,
|
npm_system_info: NpmSystemInfo,
|
||||||
|
@ -161,7 +162,7 @@ fn create_inner(
|
||||||
let fs_resolver = create_npm_fs_resolver(
|
let fs_resolver = create_npm_fs_resolver(
|
||||||
fs.clone(),
|
fs.clone(),
|
||||||
npm_cache.clone(),
|
npm_cache.clone(),
|
||||||
&package_json_deps_provider,
|
&npm_install_deps_provider,
|
||||||
&text_only_progress_bar,
|
&text_only_progress_bar,
|
||||||
resolution.clone(),
|
resolution.clone(),
|
||||||
tarball_cache.clone(),
|
tarball_cache.clone(),
|
||||||
|
@ -175,7 +176,7 @@ fn create_inner(
|
||||||
maybe_lockfile,
|
maybe_lockfile,
|
||||||
npm_api,
|
npm_api,
|
||||||
npm_cache,
|
npm_cache,
|
||||||
package_json_deps_provider,
|
npm_install_deps_provider,
|
||||||
resolution,
|
resolution,
|
||||||
tarball_cache,
|
tarball_cache,
|
||||||
text_only_progress_bar,
|
text_only_progress_bar,
|
||||||
|
@ -261,7 +262,7 @@ pub struct ManagedCliNpmResolver {
|
||||||
maybe_lockfile: Option<Arc<CliLockfile>>,
|
maybe_lockfile: Option<Arc<CliLockfile>>,
|
||||||
npm_api: Arc<CliNpmRegistryApi>,
|
npm_api: Arc<CliNpmRegistryApi>,
|
||||||
npm_cache: Arc<NpmCache>,
|
npm_cache: Arc<NpmCache>,
|
||||||
package_json_deps_provider: Arc<PackageJsonInstallDepsProvider>,
|
npm_install_deps_provider: Arc<NpmInstallDepsProvider>,
|
||||||
resolution: Arc<NpmResolution>,
|
resolution: Arc<NpmResolution>,
|
||||||
tarball_cache: Arc<TarballCache>,
|
tarball_cache: Arc<TarballCache>,
|
||||||
text_only_progress_bar: ProgressBar,
|
text_only_progress_bar: ProgressBar,
|
||||||
|
@ -286,7 +287,7 @@ impl ManagedCliNpmResolver {
|
||||||
maybe_lockfile: Option<Arc<CliLockfile>>,
|
maybe_lockfile: Option<Arc<CliLockfile>>,
|
||||||
npm_api: Arc<CliNpmRegistryApi>,
|
npm_api: Arc<CliNpmRegistryApi>,
|
||||||
npm_cache: Arc<NpmCache>,
|
npm_cache: Arc<NpmCache>,
|
||||||
package_json_deps_provider: Arc<PackageJsonInstallDepsProvider>,
|
npm_install_deps_provider: Arc<NpmInstallDepsProvider>,
|
||||||
resolution: Arc<NpmResolution>,
|
resolution: Arc<NpmResolution>,
|
||||||
tarball_cache: Arc<TarballCache>,
|
tarball_cache: Arc<TarballCache>,
|
||||||
text_only_progress_bar: ProgressBar,
|
text_only_progress_bar: ProgressBar,
|
||||||
|
@ -299,7 +300,7 @@ impl ManagedCliNpmResolver {
|
||||||
maybe_lockfile,
|
maybe_lockfile,
|
||||||
npm_api,
|
npm_api,
|
||||||
npm_cache,
|
npm_cache,
|
||||||
package_json_deps_provider,
|
npm_install_deps_provider,
|
||||||
text_only_progress_bar,
|
text_only_progress_bar,
|
||||||
resolution,
|
resolution,
|
||||||
tarball_cache,
|
tarball_cache,
|
||||||
|
@ -406,8 +407,7 @@ impl ManagedCliNpmResolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if result.dependencies_result.is_ok() {
|
if result.dependencies_result.is_ok() {
|
||||||
result.dependencies_result =
|
result.dependencies_result = self.cache_packages().await;
|
||||||
self.cache_packages().await.map_err(AnyError::from);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
|
@ -477,7 +477,7 @@ impl ManagedCliNpmResolver {
|
||||||
if !self.top_level_install_flag.raise() {
|
if !self.top_level_install_flag.raise() {
|
||||||
return Ok(false); // already did this
|
return Ok(false); // already did this
|
||||||
}
|
}
|
||||||
let pkg_json_remote_pkgs = self.package_json_deps_provider.remote_pkgs();
|
let pkg_json_remote_pkgs = self.npm_install_deps_provider.remote_pkgs();
|
||||||
if pkg_json_remote_pkgs.is_empty() {
|
if pkg_json_remote_pkgs.is_empty() {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
@ -606,7 +606,7 @@ impl CliNpmResolver for ManagedCliNpmResolver {
|
||||||
create_npm_fs_resolver(
|
create_npm_fs_resolver(
|
||||||
self.fs.clone(),
|
self.fs.clone(),
|
||||||
self.npm_cache.clone(),
|
self.npm_cache.clone(),
|
||||||
&self.package_json_deps_provider,
|
&self.npm_install_deps_provider,
|
||||||
&self.text_only_progress_bar,
|
&self.text_only_progress_bar,
|
||||||
npm_resolution.clone(),
|
npm_resolution.clone(),
|
||||||
self.tarball_cache.clone(),
|
self.tarball_cache.clone(),
|
||||||
|
@ -617,7 +617,7 @@ impl CliNpmResolver for ManagedCliNpmResolver {
|
||||||
self.maybe_lockfile.clone(),
|
self.maybe_lockfile.clone(),
|
||||||
self.npm_api.clone(),
|
self.npm_api.clone(),
|
||||||
self.npm_cache.clone(),
|
self.npm_cache.clone(),
|
||||||
self.package_json_deps_provider.clone(),
|
self.npm_install_deps_provider.clone(),
|
||||||
npm_resolution,
|
npm_resolution,
|
||||||
self.tarball_cache.clone(),
|
self.tarball_cache.clone(),
|
||||||
self.text_only_progress_bar.clone(),
|
self.text_only_progress_bar.clone(),
|
||||||
|
|
|
@ -22,6 +22,7 @@ use deno_npm::NpmPackageCacheFolderId;
|
||||||
use deno_npm::NpmPackageId;
|
use deno_npm::NpmPackageId;
|
||||||
use deno_npm::NpmResolutionPackage;
|
use deno_npm::NpmResolutionPackage;
|
||||||
use deno_npm::NpmSystemInfo;
|
use deno_npm::NpmSystemInfo;
|
||||||
|
use deno_semver::jsr::JsrDepPackageReq;
|
||||||
use deno_semver::package::PackageNv;
|
use deno_semver::package::PackageNv;
|
||||||
use deno_semver::package::PackageReq;
|
use deno_semver::package::PackageReq;
|
||||||
use deno_semver::VersionReq;
|
use deno_semver::VersionReq;
|
||||||
|
@ -329,16 +330,10 @@ fn populate_lockfile_from_snapshot(
|
||||||
) {
|
) {
|
||||||
let mut lockfile = lockfile.lock();
|
let mut lockfile = lockfile.lock();
|
||||||
for (package_req, nv) in snapshot.package_reqs() {
|
for (package_req, nv) in snapshot.package_reqs() {
|
||||||
|
let id = &snapshot.resolve_package_from_deno_module(nv).unwrap().id;
|
||||||
lockfile.insert_package_specifier(
|
lockfile.insert_package_specifier(
|
||||||
format!("npm:{}", package_req),
|
JsrDepPackageReq::npm(package_req.clone()),
|
||||||
format!(
|
format!("{}{}", id.nv.version, id.peer_deps_serialized()),
|
||||||
"npm:{}",
|
|
||||||
snapshot
|
|
||||||
.resolve_package_from_deno_module(nv)
|
|
||||||
.unwrap()
|
|
||||||
.id
|
|
||||||
.as_serialized()
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
for package in snapshot.all_packages_for_every_system() {
|
for package in snapshot.all_packages_for_every_system() {
|
||||||
|
|
|
@ -10,6 +10,7 @@ use std::cmp::Ordering;
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -41,7 +42,7 @@ use node_resolver::errors::ReferrerNotFoundError;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::args::PackageJsonInstallDepsProvider;
|
use crate::args::NpmInstallDepsProvider;
|
||||||
use crate::cache::CACHE_PERM;
|
use crate::cache::CACHE_PERM;
|
||||||
use crate::npm::cache_dir::mixed_case_package_name_decode;
|
use crate::npm::cache_dir::mixed_case_package_name_decode;
|
||||||
use crate::npm::cache_dir::mixed_case_package_name_encode;
|
use crate::npm::cache_dir::mixed_case_package_name_encode;
|
||||||
|
@ -65,7 +66,7 @@ use super::common::RegistryReadPermissionChecker;
|
||||||
pub struct LocalNpmPackageResolver {
|
pub struct LocalNpmPackageResolver {
|
||||||
cache: Arc<NpmCache>,
|
cache: Arc<NpmCache>,
|
||||||
fs: Arc<dyn deno_fs::FileSystem>,
|
fs: Arc<dyn deno_fs::FileSystem>,
|
||||||
pkg_json_deps_provider: Arc<PackageJsonInstallDepsProvider>,
|
npm_install_deps_provider: Arc<NpmInstallDepsProvider>,
|
||||||
progress_bar: ProgressBar,
|
progress_bar: ProgressBar,
|
||||||
resolution: Arc<NpmResolution>,
|
resolution: Arc<NpmResolution>,
|
||||||
tarball_cache: Arc<TarballCache>,
|
tarball_cache: Arc<TarballCache>,
|
||||||
|
@ -81,7 +82,7 @@ impl LocalNpmPackageResolver {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
cache: Arc<NpmCache>,
|
cache: Arc<NpmCache>,
|
||||||
fs: Arc<dyn deno_fs::FileSystem>,
|
fs: Arc<dyn deno_fs::FileSystem>,
|
||||||
pkg_json_deps_provider: Arc<PackageJsonInstallDepsProvider>,
|
npm_install_deps_provider: Arc<NpmInstallDepsProvider>,
|
||||||
progress_bar: ProgressBar,
|
progress_bar: ProgressBar,
|
||||||
resolution: Arc<NpmResolution>,
|
resolution: Arc<NpmResolution>,
|
||||||
tarball_cache: Arc<TarballCache>,
|
tarball_cache: Arc<TarballCache>,
|
||||||
|
@ -92,7 +93,7 @@ impl LocalNpmPackageResolver {
|
||||||
Self {
|
Self {
|
||||||
cache,
|
cache,
|
||||||
fs: fs.clone(),
|
fs: fs.clone(),
|
||||||
pkg_json_deps_provider,
|
npm_install_deps_provider,
|
||||||
progress_bar,
|
progress_bar,
|
||||||
resolution,
|
resolution,
|
||||||
tarball_cache,
|
tarball_cache,
|
||||||
|
@ -248,7 +249,7 @@ impl NpmPackageFsResolver for LocalNpmPackageResolver {
|
||||||
sync_resolution_with_fs(
|
sync_resolution_with_fs(
|
||||||
&self.resolution.snapshot(),
|
&self.resolution.snapshot(),
|
||||||
&self.cache,
|
&self.cache,
|
||||||
&self.pkg_json_deps_provider,
|
&self.npm_install_deps_provider,
|
||||||
&self.progress_bar,
|
&self.progress_bar,
|
||||||
&self.tarball_cache,
|
&self.tarball_cache,
|
||||||
&self.root_node_modules_path,
|
&self.root_node_modules_path,
|
||||||
|
@ -412,14 +413,16 @@ fn has_lifecycle_scripts(
|
||||||
async fn sync_resolution_with_fs(
|
async fn sync_resolution_with_fs(
|
||||||
snapshot: &NpmResolutionSnapshot,
|
snapshot: &NpmResolutionSnapshot,
|
||||||
cache: &Arc<NpmCache>,
|
cache: &Arc<NpmCache>,
|
||||||
pkg_json_deps_provider: &PackageJsonInstallDepsProvider,
|
npm_install_deps_provider: &NpmInstallDepsProvider,
|
||||||
progress_bar: &ProgressBar,
|
progress_bar: &ProgressBar,
|
||||||
tarball_cache: &Arc<TarballCache>,
|
tarball_cache: &Arc<TarballCache>,
|
||||||
root_node_modules_dir_path: &Path,
|
root_node_modules_dir_path: &Path,
|
||||||
system_info: &NpmSystemInfo,
|
system_info: &NpmSystemInfo,
|
||||||
lifecycle_scripts: &LifecycleScriptsConfig,
|
lifecycle_scripts: &LifecycleScriptsConfig,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
if snapshot.is_empty() && pkg_json_deps_provider.workspace_pkgs().is_empty() {
|
if snapshot.is_empty()
|
||||||
|
&& npm_install_deps_provider.workspace_pkgs().is_empty()
|
||||||
|
{
|
||||||
return Ok(()); // don't create the directory
|
return Ok(()); // don't create the directory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -618,9 +621,12 @@ async fn sync_resolution_with_fs(
|
||||||
|
|
||||||
let mut found_names: HashMap<&String, &PackageNv> = HashMap::new();
|
let mut found_names: HashMap<&String, &PackageNv> = HashMap::new();
|
||||||
|
|
||||||
|
// set of node_modules in workspace packages that we've already ensured exist
|
||||||
|
let mut existing_child_node_modules_dirs: HashSet<PathBuf> = HashSet::new();
|
||||||
|
|
||||||
// 4. Create symlinks for package json dependencies
|
// 4. Create symlinks for package json dependencies
|
||||||
{
|
{
|
||||||
for remote in pkg_json_deps_provider.remote_pkgs() {
|
for remote in npm_install_deps_provider.remote_pkgs() {
|
||||||
let remote_pkg = if let Ok(remote_pkg) =
|
let remote_pkg = if let Ok(remote_pkg) =
|
||||||
snapshot.resolve_pkg_from_pkg_req(&remote.req)
|
snapshot.resolve_pkg_from_pkg_req(&remote.req)
|
||||||
{
|
{
|
||||||
|
@ -665,8 +671,15 @@ async fn sync_resolution_with_fs(
|
||||||
);
|
);
|
||||||
if install_in_child {
|
if install_in_child {
|
||||||
// symlink the dep into the package's child node_modules folder
|
// symlink the dep into the package's child node_modules folder
|
||||||
let dest_path =
|
let dest_node_modules = remote.base_dir.join("node_modules");
|
||||||
remote.base_dir.join("node_modules").join(&remote.alias);
|
if !existing_child_node_modules_dirs.contains(&dest_node_modules) {
|
||||||
|
fs::create_dir_all(&dest_node_modules).with_context(|| {
|
||||||
|
format!("Creating '{}'", dest_node_modules.display())
|
||||||
|
})?;
|
||||||
|
existing_child_node_modules_dirs.insert(dest_node_modules.clone());
|
||||||
|
}
|
||||||
|
let mut dest_path = dest_node_modules;
|
||||||
|
dest_path.push(&remote.alias);
|
||||||
|
|
||||||
symlink_package_dir(&local_registry_package_path, &dest_path)?;
|
symlink_package_dir(&local_registry_package_path, &dest_path)?;
|
||||||
} else {
|
} else {
|
||||||
|
@ -684,7 +697,7 @@ async fn sync_resolution_with_fs(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Create symlinks for the remaining top level packages in the node_modules folder.
|
// 5. Create symlinks for the remaining top level packages in the node_modules folder.
|
||||||
// (These may be present if they are not in the package.json dependencies, such as )
|
// (These may be present if they are not in the package.json dependencies)
|
||||||
// Symlink node_modules/.deno/<package_id>/node_modules/<package_name> to
|
// Symlink node_modules/.deno/<package_id>/node_modules/<package_name> to
|
||||||
// node_modules/<package_name>
|
// node_modules/<package_name>
|
||||||
let mut ids = snapshot
|
let mut ids = snapshot
|
||||||
|
@ -757,10 +770,10 @@ async fn sync_resolution_with_fs(
|
||||||
|
|
||||||
// 8. Create symlinks for the workspace packages
|
// 8. Create symlinks for the workspace packages
|
||||||
{
|
{
|
||||||
// todo(#24419): this is not exactly correct because it should
|
// todo(dsherret): this is not exactly correct because it should
|
||||||
// install correctly for a workspace (potentially in sub directories),
|
// install correctly for a workspace (potentially in sub directories),
|
||||||
// but this is good enough for a first pass
|
// but this is good enough for a first pass
|
||||||
for workspace in pkg_json_deps_provider.workspace_pkgs() {
|
for workspace in npm_install_deps_provider.workspace_pkgs() {
|
||||||
symlink_package_dir(
|
symlink_package_dir(
|
||||||
&workspace.target_dir,
|
&workspace.target_dir,
|
||||||
&root_node_modules_dir_path.join(&workspace.alias),
|
&root_node_modules_dir_path.join(&workspace.alias),
|
||||||
|
@ -831,22 +844,14 @@ async fn sync_resolution_with_fs(
|
||||||
}
|
}
|
||||||
|
|
||||||
if !packages_with_scripts_not_run.is_empty() {
|
if !packages_with_scripts_not_run.is_empty() {
|
||||||
let (maybe_install, maybe_install_example) = if *crate::args::DENO_FUTURE {
|
|
||||||
(
|
|
||||||
" or `deno install`",
|
|
||||||
" or `deno install --allow-scripts=pkg1,pkg2`",
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
("", "")
|
|
||||||
};
|
|
||||||
let packages = packages_with_scripts_not_run
|
let packages = packages_with_scripts_not_run
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(_, p)| format!("npm:{p}"))
|
.map(|(_, p)| format!("npm:{p}"))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(", ");
|
.join(", ");
|
||||||
log::warn!("{}: Packages contained npm lifecycle scripts (preinstall/install/postinstall) that were not executed.
|
log::warn!("{} Packages contained npm lifecycle scripts (preinstall/install/postinstall) that were not executed.
|
||||||
This may cause the packages to not work correctly. To run them, use the `--allow-scripts` flag with `deno cache`{maybe_install}
|
This may cause the packages to not work correctly. To run them, use the `--allow-scripts` flag with `deno cache` or `deno install`
|
||||||
(e.g. `deno cache --allow-scripts=pkg1,pkg2 <entrypoint>`{maybe_install_example}):\n {packages}", crate::colors::yellow("warning"));
|
(e.g. `deno cache --allow-scripts=pkg1,pkg2 <entrypoint>` or `deno install --allow-scripts=pkg1,pkg2`):\n {packages}", crate::colors::yellow("Warning"));
|
||||||
for (scripts_warned_path, _) in packages_with_scripts_not_run {
|
for (scripts_warned_path, _) in packages_with_scripts_not_run {
|
||||||
let _ignore_err = fs::write(scripts_warned_path, "");
|
let _ignore_err = fs::write(scripts_warned_path, "");
|
||||||
}
|
}
|
||||||
|
@ -993,21 +998,31 @@ impl SetupCache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Normalizes a package name for use at `node_modules/.deno/<pkg-name>@<version>[_<copy_index>]`
|
||||||
|
pub fn normalize_pkg_name_for_node_modules_deno_folder(name: &str) -> Cow<str> {
|
||||||
|
let name = if name.to_lowercase() == name {
|
||||||
|
Cow::Borrowed(name)
|
||||||
|
} else {
|
||||||
|
Cow::Owned(format!("_{}", mixed_case_package_name_encode(name)))
|
||||||
|
};
|
||||||
|
if name.starts_with('@') {
|
||||||
|
name.replace('/', "+").into()
|
||||||
|
} else {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_package_folder_id_folder_name(
|
fn get_package_folder_id_folder_name(
|
||||||
folder_id: &NpmPackageCacheFolderId,
|
folder_id: &NpmPackageCacheFolderId,
|
||||||
) -> String {
|
) -> String {
|
||||||
let copy_str = if folder_id.copy_index == 0 {
|
let copy_str = if folder_id.copy_index == 0 {
|
||||||
"".to_string()
|
Cow::Borrowed("")
|
||||||
} else {
|
} else {
|
||||||
format!("_{}", folder_id.copy_index)
|
Cow::Owned(format!("_{}", folder_id.copy_index))
|
||||||
};
|
};
|
||||||
let nv = &folder_id.nv;
|
let nv = &folder_id.nv;
|
||||||
let name = if nv.name.to_lowercase() == nv.name {
|
let name = normalize_pkg_name_for_node_modules_deno_folder(&nv.name);
|
||||||
Cow::Borrowed(&nv.name)
|
format!("{}@{}{}", name, nv.version, copy_str)
|
||||||
} else {
|
|
||||||
Cow::Owned(format!("_{}", mixed_case_package_name_encode(&nv.name)))
|
|
||||||
};
|
|
||||||
format!("{}@{}{}", name, nv.version, copy_str).replace('/', "+")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_package_folder_id_from_folder_name(
|
fn get_package_folder_id_from_folder_name(
|
||||||
|
|
|
@ -11,10 +11,11 @@ use deno_npm::NpmSystemInfo;
|
||||||
use deno_runtime::deno_fs::FileSystem;
|
use deno_runtime::deno_fs::FileSystem;
|
||||||
|
|
||||||
use crate::args::LifecycleScriptsConfig;
|
use crate::args::LifecycleScriptsConfig;
|
||||||
use crate::args::PackageJsonInstallDepsProvider;
|
use crate::args::NpmInstallDepsProvider;
|
||||||
use crate::util::progress_bar::ProgressBar;
|
use crate::util::progress_bar::ProgressBar;
|
||||||
|
|
||||||
pub use self::common::NpmPackageFsResolver;
|
pub use self::common::NpmPackageFsResolver;
|
||||||
|
pub use self::local::normalize_pkg_name_for_node_modules_deno_folder;
|
||||||
|
|
||||||
use self::global::GlobalNpmPackageResolver;
|
use self::global::GlobalNpmPackageResolver;
|
||||||
use self::local::LocalNpmPackageResolver;
|
use self::local::LocalNpmPackageResolver;
|
||||||
|
@ -27,7 +28,7 @@ use super::resolution::NpmResolution;
|
||||||
pub fn create_npm_fs_resolver(
|
pub fn create_npm_fs_resolver(
|
||||||
fs: Arc<dyn FileSystem>,
|
fs: Arc<dyn FileSystem>,
|
||||||
npm_cache: Arc<NpmCache>,
|
npm_cache: Arc<NpmCache>,
|
||||||
pkg_json_deps_provider: &Arc<PackageJsonInstallDepsProvider>,
|
npm_install_deps_provider: &Arc<NpmInstallDepsProvider>,
|
||||||
progress_bar: &ProgressBar,
|
progress_bar: &ProgressBar,
|
||||||
resolution: Arc<NpmResolution>,
|
resolution: Arc<NpmResolution>,
|
||||||
tarball_cache: Arc<TarballCache>,
|
tarball_cache: Arc<TarballCache>,
|
||||||
|
@ -39,7 +40,7 @@ pub fn create_npm_fs_resolver(
|
||||||
Some(node_modules_folder) => Arc::new(LocalNpmPackageResolver::new(
|
Some(node_modules_folder) => Arc::new(LocalNpmPackageResolver::new(
|
||||||
npm_cache,
|
npm_cache,
|
||||||
fs,
|
fs,
|
||||||
pkg_json_deps_provider.clone(),
|
npm_install_deps_provider.clone(),
|
||||||
progress_bar.clone(),
|
progress_bar.clone(),
|
||||||
resolution,
|
resolution,
|
||||||
tarball_cache,
|
tarball_cache,
|
||||||
|
|
|
@ -146,7 +146,7 @@ impl CliNodeResolver {
|
||||||
concat!(
|
concat!(
|
||||||
"Could not resolve \"{}\", but found it in a package.json. ",
|
"Could not resolve \"{}\", but found it in a package.json. ",
|
||||||
"Deno expects the node_modules/ directory to be up to date. ",
|
"Deno expects the node_modules/ directory to be up to date. ",
|
||||||
"Did you forget to run `npm install`?"
|
"Did you forget to run `deno install`?"
|
||||||
),
|
),
|
||||||
specifier
|
specifier
|
||||||
));
|
));
|
||||||
|
@ -225,13 +225,8 @@ impl CliNodeResolver {
|
||||||
let package_json_path = package_folder.join("package.json");
|
let package_json_path = package_folder.join("package.json");
|
||||||
if !self.fs.exists_sync(&package_json_path) {
|
if !self.fs.exists_sync(&package_json_path) {
|
||||||
return Err(anyhow!(
|
return Err(anyhow!(
|
||||||
"Could not find '{}'. Deno expects the node_modules/ directory to be up to date. Did you forget to run `{}`?",
|
"Could not find '{}'. Deno expects the node_modules/ directory to be up to date. Did you forget to run `deno install`?",
|
||||||
package_json_path.display(),
|
package_json_path.display(),
|
||||||
if *crate::args::DENO_FUTURE {
|
|
||||||
"deno install"
|
|
||||||
} else {
|
|
||||||
"npm install"
|
|
||||||
},
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -332,7 +327,9 @@ impl NpmModuleLoader {
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
maybe_referrer: Option<&ModuleSpecifier>,
|
maybe_referrer: Option<&ModuleSpecifier>,
|
||||||
) -> Option<Result<ModuleCodeStringSource, AnyError>> {
|
) -> Option<Result<ModuleCodeStringSource, AnyError>> {
|
||||||
if self.node_resolver.in_npm_package(specifier) {
|
if self.node_resolver.in_npm_package(specifier)
|
||||||
|
|| (specifier.scheme() == "file" && specifier.path().ends_with(".cjs"))
|
||||||
|
{
|
||||||
Some(self.load(specifier, maybe_referrer).await)
|
Some(self.load(specifier, maybe_referrer).await)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -381,7 +378,9 @@ impl NpmModuleLoader {
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let code = if self.cjs_resolutions.contains(specifier) {
|
let code = if self.cjs_resolutions.contains(specifier)
|
||||||
|
|| (specifier.scheme() == "file" && specifier.path().ends_with(".cjs"))
|
||||||
|
{
|
||||||
// translate cjs to esm if it's cjs and inject node globals
|
// translate cjs to esm if it's cjs and inject node globals
|
||||||
let code = match String::from_utf8_lossy(&code) {
|
let code = match String::from_utf8_lossy(&code) {
|
||||||
Cow::Owned(code) => code,
|
Cow::Owned(code) => code,
|
||||||
|
@ -507,7 +506,7 @@ impl Resolver for CliGraphResolver {
|
||||||
|
|
||||||
fn resolve(
|
fn resolve(
|
||||||
&self,
|
&self,
|
||||||
specifier: &str,
|
raw_specifier: &str,
|
||||||
referrer_range: &deno_graph::Range,
|
referrer_range: &deno_graph::Range,
|
||||||
mode: ResolutionMode,
|
mode: ResolutionMode,
|
||||||
) -> Result<ModuleSpecifier, ResolveError> {
|
) -> Result<ModuleSpecifier, ResolveError> {
|
||||||
|
@ -524,7 +523,7 @@ impl Resolver for CliGraphResolver {
|
||||||
if let Some(node_resolver) = self.node_resolver.as_ref() {
|
if let Some(node_resolver) = self.node_resolver.as_ref() {
|
||||||
if referrer.scheme() == "file" && node_resolver.in_npm_package(referrer) {
|
if referrer.scheme() == "file" && node_resolver.in_npm_package(referrer) {
|
||||||
return node_resolver
|
return node_resolver
|
||||||
.resolve(specifier, referrer, to_node_mode(mode))
|
.resolve(raw_specifier, referrer, to_node_mode(mode))
|
||||||
.map(|res| res.into_url())
|
.map(|res| res.into_url())
|
||||||
.map_err(|e| ResolveError::Other(e.into()));
|
.map_err(|e| ResolveError::Other(e.into()));
|
||||||
}
|
}
|
||||||
|
@ -533,7 +532,7 @@ impl Resolver for CliGraphResolver {
|
||||||
// Attempt to resolve with the workspace resolver
|
// Attempt to resolve with the workspace resolver
|
||||||
let result: Result<_, ResolveError> = self
|
let result: Result<_, ResolveError> = self
|
||||||
.workspace_resolver
|
.workspace_resolver
|
||||||
.resolve(specifier, referrer)
|
.resolve(raw_specifier, referrer)
|
||||||
.map_err(|err| match err {
|
.map_err(|err| match err {
|
||||||
MappedResolutionError::Specifier(err) => ResolveError::Specifier(err),
|
MappedResolutionError::Specifier(err) => ResolveError::Specifier(err),
|
||||||
MappedResolutionError::ImportMap(err) => {
|
MappedResolutionError::ImportMap(err) => {
|
||||||
|
@ -705,7 +704,7 @@ impl Resolver for CliGraphResolver {
|
||||||
// If byonm, check if the bare specifier resolves to an npm package
|
// If byonm, check if the bare specifier resolves to an npm package
|
||||||
if is_byonm && referrer.scheme() == "file" {
|
if is_byonm && referrer.scheme() == "file" {
|
||||||
let maybe_resolution = node_resolver
|
let maybe_resolution = node_resolver
|
||||||
.resolve_if_for_npm_pkg(specifier, referrer, to_node_mode(mode))
|
.resolve_if_for_npm_pkg(raw_specifier, referrer, to_node_mode(mode))
|
||||||
.map_err(ResolveError::Other)?;
|
.map_err(ResolveError::Other)?;
|
||||||
if let Some(res) = maybe_resolution {
|
if let Some(res) = maybe_resolution {
|
||||||
return Ok(res.into_url());
|
return Ok(res.into_url());
|
||||||
|
@ -754,7 +753,7 @@ impl<'a> deno_graph::source::NpmResolver for WorkerCliNpmGraphResolver<'a> {
|
||||||
let line = start.line + 1;
|
let line = start.line + 1;
|
||||||
let column = start.character + 1;
|
let column = start.character + 1;
|
||||||
if !*DENO_DISABLE_PEDANTIC_NODE_WARNINGS {
|
if !*DENO_DISABLE_PEDANTIC_NODE_WARNINGS {
|
||||||
log::warn!("Warning: Resolving \"{module_name}\" as \"node:{module_name}\" at {specifier}:{line}:{column}. If you want to use a built-in Node module, add a \"node:\" prefix.")
|
log::warn!("{} Resolving \"{module_name}\" as \"node:{module_name}\" at {specifier}:{line}:{column}. If you want to use a built-in Node module, add a \"node:\" prefix.", colors::yellow("Warning"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -223,7 +223,7 @@
|
||||||
"useUnknownInCatchVariables": {
|
"useUnknownInCatchVariables": {
|
||||||
"description": "Default catch clause variables as `unknown` instead of `any`.",
|
"description": "Default catch clause variables as `unknown` instead of `any`.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": true,
|
||||||
"markdownDescription": "Default catch clause variables as `unknown` instead of `any`.\n\nSee more: https://www.typescriptlang.org/tsconfig#useUnknownInCatchVariables"
|
"markdownDescription": "Default catch clause variables as `unknown` instead of `any`.\n\nSee more: https://www.typescriptlang.org/tsconfig#useUnknownInCatchVariables"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -622,6 +622,11 @@
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "A map of package exports to files in this JSR package.",
|
"description": "A map of package exports to files in this JSR package.",
|
||||||
|
"propertyNames": {
|
||||||
|
"description": "Package export name",
|
||||||
|
"examples": [".", "./foo", "./bar"],
|
||||||
|
"pattern": "^\\.(/.*)?$"
|
||||||
|
},
|
||||||
"patternProperties": {
|
"patternProperties": {
|
||||||
"^\\.(/.*)?$": {
|
"^\\.(/.*)?$": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|
|
@ -83,14 +83,6 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The checksum of the local source file. This can be used to validate if the current on disk version matches the version described here."
|
"description": "The checksum of the local source file. This can be used to validate if the current on disk version matches the version described here."
|
||||||
},
|
},
|
||||||
"emit": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The path to an emitted version of the module, if the module requires transpilation to be loaded into the Deno runtime."
|
|
||||||
},
|
|
||||||
"map": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The path to an optionally emitted source map between the original and emitted version of the file."
|
|
||||||
},
|
|
||||||
"error": {
|
"error": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "If when resolving the module, Deno encountered an error and the module is unavailable, the text of that error will be indicated here."
|
"description": "If when resolving the module, Deno encountered an error and the module is unavailable, the text of that error will be indicated here."
|
||||||
|
|
|
@ -45,7 +45,7 @@ use serde::Serialize;
|
||||||
use crate::args::CaData;
|
use crate::args::CaData;
|
||||||
use crate::args::CliOptions;
|
use crate::args::CliOptions;
|
||||||
use crate::args::CompileFlags;
|
use crate::args::CompileFlags;
|
||||||
use crate::args::PackageJsonInstallDepsProvider;
|
use crate::args::NpmInstallDepsProvider;
|
||||||
use crate::args::PermissionFlags;
|
use crate::args::PermissionFlags;
|
||||||
use crate::args::UnstableConfig;
|
use crate::args::UnstableConfig;
|
||||||
use crate::cache::DenoDir;
|
use crate::cache::DenoDir;
|
||||||
|
@ -117,7 +117,6 @@ pub struct Metadata {
|
||||||
pub workspace_resolver: SerializedWorkspaceResolver,
|
pub workspace_resolver: SerializedWorkspaceResolver,
|
||||||
pub entrypoint_key: String,
|
pub entrypoint_key: String,
|
||||||
pub node_modules: Option<NodeModules>,
|
pub node_modules: Option<NodeModules>,
|
||||||
pub disable_deprecated_api_warning: bool,
|
|
||||||
pub unstable_config: UnstableConfig,
|
pub unstable_config: UnstableConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -624,12 +623,9 @@ impl<'a> DenoCompileBinaryWriter<'a> {
|
||||||
pkg_json_resolution: self.workspace_resolver.pkg_json_dep_resolution(),
|
pkg_json_resolution: self.workspace_resolver.pkg_json_dep_resolution(),
|
||||||
},
|
},
|
||||||
node_modules,
|
node_modules,
|
||||||
disable_deprecated_api_warning: cli_options
|
|
||||||
.disable_deprecated_api_warning,
|
|
||||||
unstable_config: UnstableConfig {
|
unstable_config: UnstableConfig {
|
||||||
legacy_flag_enabled: cli_options.legacy_unstable_flag(),
|
legacy_flag_enabled: cli_options.legacy_unstable_flag(),
|
||||||
bare_node_builtins: cli_options.unstable_bare_node_builtins(),
|
bare_node_builtins: cli_options.unstable_bare_node_builtins(),
|
||||||
byonm: cli_options.use_byonm(),
|
|
||||||
sloppy_imports: cli_options.unstable_sloppy_imports(),
|
sloppy_imports: cli_options.unstable_sloppy_imports(),
|
||||||
features: cli_options.unstable_features(),
|
features: cli_options.unstable_features(),
|
||||||
},
|
},
|
||||||
|
|
|
@ -48,7 +48,7 @@ use crate::args::get_root_cert_store;
|
||||||
use crate::args::npm_pkg_req_ref_to_binary_command;
|
use crate::args::npm_pkg_req_ref_to_binary_command;
|
||||||
use crate::args::CaData;
|
use crate::args::CaData;
|
||||||
use crate::args::CacheSetting;
|
use crate::args::CacheSetting;
|
||||||
use crate::args::PackageJsonInstallDepsProvider;
|
use crate::args::NpmInstallDepsProvider;
|
||||||
use crate::args::StorageKeyResolver;
|
use crate::args::StorageKeyResolver;
|
||||||
use crate::cache::Caches;
|
use crate::cache::Caches;
|
||||||
use crate::cache::DenoDirProvider;
|
use crate::cache::DenoDirProvider;
|
||||||
|
@ -138,7 +138,7 @@ pub const UNSUPPORTED_SCHEME: &str = "Unsupported scheme";
|
||||||
impl ModuleLoader for EmbeddedModuleLoader {
|
impl ModuleLoader for EmbeddedModuleLoader {
|
||||||
fn resolve(
|
fn resolve(
|
||||||
&self,
|
&self,
|
||||||
specifier: &str,
|
raw_specifier: &str,
|
||||||
referrer: &str,
|
referrer: &str,
|
||||||
kind: ResolutionKind,
|
kind: ResolutionKind,
|
||||||
) -> Result<ModuleSpecifier, AnyError> {
|
) -> Result<ModuleSpecifier, AnyError> {
|
||||||
|
@ -162,13 +162,15 @@ impl ModuleLoader for EmbeddedModuleLoader {
|
||||||
self
|
self
|
||||||
.shared
|
.shared
|
||||||
.node_resolver
|
.node_resolver
|
||||||
.resolve(specifier, &referrer, NodeResolutionMode::Execution)?
|
.resolve(raw_specifier, &referrer, NodeResolutionMode::Execution)?
|
||||||
.into_url(),
|
.into_url(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mapped_resolution =
|
let mapped_resolution = self
|
||||||
self.shared.workspace_resolver.resolve(specifier, &referrer);
|
.shared
|
||||||
|
.workspace_resolver
|
||||||
|
.resolve(raw_specifier, &referrer);
|
||||||
|
|
||||||
match mapped_resolution {
|
match mapped_resolution {
|
||||||
Ok(MappedResolution::WorkspaceJsrPackage { specifier, .. }) => {
|
Ok(MappedResolution::WorkspaceJsrPackage { specifier, .. }) => {
|
||||||
|
@ -262,7 +264,7 @@ impl ModuleLoader for EmbeddedModuleLoader {
|
||||||
if err.is_unmapped_bare_specifier() && referrer.scheme() == "file" =>
|
if err.is_unmapped_bare_specifier() && referrer.scheme() == "file" =>
|
||||||
{
|
{
|
||||||
let maybe_res = self.shared.node_resolver.resolve_if_for_npm_pkg(
|
let maybe_res = self.shared.node_resolver.resolve_if_for_npm_pkg(
|
||||||
specifier,
|
raw_specifier,
|
||||||
&referrer,
|
&referrer,
|
||||||
NodeResolutionMode::Execution,
|
NodeResolutionMode::Execution,
|
||||||
)?;
|
)?;
|
||||||
|
@ -502,9 +504,9 @@ pub async fn run(
|
||||||
text_only_progress_bar: progress_bar,
|
text_only_progress_bar: progress_bar,
|
||||||
maybe_node_modules_path,
|
maybe_node_modules_path,
|
||||||
npm_system_info: Default::default(),
|
npm_system_info: Default::default(),
|
||||||
package_json_deps_provider: Arc::new(
|
npm_install_deps_provider: Arc::new(
|
||||||
// this is only used for installing packages, which isn't necessary with deno compile
|
// this is only used for installing packages, which isn't necessary with deno compile
|
||||||
PackageJsonInstallDepsProvider::empty(),
|
NpmInstallDepsProvider::empty(),
|
||||||
),
|
),
|
||||||
// create an npmrc that uses the fake npm_registry_url to resolve packages
|
// create an npmrc that uses the fake npm_registry_url to resolve packages
|
||||||
npmrc: Arc::new(ResolvedNpmRc {
|
npmrc: Arc::new(ResolvedNpmRc {
|
||||||
|
@ -554,9 +556,9 @@ pub async fn run(
|
||||||
text_only_progress_bar: progress_bar,
|
text_only_progress_bar: progress_bar,
|
||||||
maybe_node_modules_path: None,
|
maybe_node_modules_path: None,
|
||||||
npm_system_info: Default::default(),
|
npm_system_info: Default::default(),
|
||||||
package_json_deps_provider: Arc::new(
|
npm_install_deps_provider: Arc::new(
|
||||||
// this is only used for installing packages, which isn't necessary with deno compile
|
// this is only used for installing packages, which isn't necessary with deno compile
|
||||||
PackageJsonInstallDepsProvider::empty(),
|
NpmInstallDepsProvider::empty(),
|
||||||
),
|
),
|
||||||
// Packages from different registries are already inlined in the ESZip,
|
// Packages from different registries are already inlined in the ESZip,
|
||||||
// so no need to create actual `.npmrc` configuration.
|
// so no need to create actual `.npmrc` configuration.
|
||||||
|
@ -706,6 +708,8 @@ pub async fn run(
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
feature_checker,
|
feature_checker,
|
||||||
|
// Code cache is not supported for standalone binary yet.
|
||||||
|
None,
|
||||||
CliMainWorkerOptions {
|
CliMainWorkerOptions {
|
||||||
argv: metadata.argv,
|
argv: metadata.argv,
|
||||||
log_level: WorkerLogLevel::Info,
|
log_level: WorkerLogLevel::Info,
|
||||||
|
@ -732,17 +736,10 @@ pub async fn run(
|
||||||
unstable: metadata.unstable_config.legacy_flag_enabled,
|
unstable: metadata.unstable_config.legacy_flag_enabled,
|
||||||
create_hmr_runner: None,
|
create_hmr_runner: None,
|
||||||
create_coverage_collector: None,
|
create_coverage_collector: None,
|
||||||
|
node_ipc: None,
|
||||||
|
serve_port: None,
|
||||||
|
serve_host: None,
|
||||||
},
|
},
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
false,
|
|
||||||
// TODO(bartlomieju): temporarily disabled
|
|
||||||
// metadata.disable_deprecated_api_warning,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
// Code cache is not supported for standalone binary yet.
|
|
||||||
None,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Initialize v8 once from the main thread.
|
// Initialize v8 once from the main thread.
|
||||||
|
|
|
@ -213,8 +213,8 @@ impl ShellCommand for NodeGypCommand {
|
||||||
) -> LocalBoxFuture<'static, ExecuteResult> {
|
) -> LocalBoxFuture<'static, ExecuteResult> {
|
||||||
// at the moment this shell command is just to give a warning if node-gyp is not found
|
// at the moment this shell command is just to give a warning if node-gyp is not found
|
||||||
// in the future, we could try to run/install node-gyp for the user with deno
|
// in the future, we could try to run/install node-gyp for the user with deno
|
||||||
if which::which("node-gyp").is_err() {
|
if context.state.resolve_command_path("node-gyp").is_err() {
|
||||||
log::warn!("{}: node-gyp was used in a script, but was not listed as a dependency. Either add it as a dependency or install it globally (e.g. `npm install -g node-gyp`)", crate::colors::yellow("warning"));
|
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(
|
ExecutableCommand::new(
|
||||||
"node-gyp".to_string(),
|
"node-gyp".to_string(),
|
||||||
|
|
|
@ -18,8 +18,11 @@ pub trait BenchReporter {
|
||||||
fn report_uncaught_error(&mut self, origin: &str, error: Box<JsError>);
|
fn report_uncaught_error(&mut self, origin: &str, error: Box<JsError>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const JSON_SCHEMA_VERSION: u8 = 1;
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
struct JsonReporterOutput {
|
struct JsonReporterOutput {
|
||||||
|
version: u8,
|
||||||
runtime: String,
|
runtime: String,
|
||||||
cpu: String,
|
cpu: String,
|
||||||
benches: Vec<JsonReporterBench>,
|
benches: Vec<JsonReporterBench>,
|
||||||
|
@ -28,6 +31,7 @@ struct JsonReporterOutput {
|
||||||
impl Default for JsonReporterOutput {
|
impl Default for JsonReporterOutput {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
version: JSON_SCHEMA_VERSION,
|
||||||
runtime: format!(
|
runtime: format!(
|
||||||
"{} {}",
|
"{} {}",
|
||||||
version::DENO_VERSION_INFO.user_agent,
|
version::DENO_VERSION_INFO.user_agent,
|
||||||
|
|
|
@ -1,164 +0,0 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
|
||||||
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_graph::Module;
|
|
||||||
use deno_terminal::colors;
|
|
||||||
|
|
||||||
use crate::args::BundleFlags;
|
|
||||||
use crate::args::CliOptions;
|
|
||||||
use crate::args::Flags;
|
|
||||||
use crate::args::TsConfigType;
|
|
||||||
use crate::factory::CliFactory;
|
|
||||||
use crate::graph_util::error_for_any_npm_specifier;
|
|
||||||
use crate::util;
|
|
||||||
use crate::util::display;
|
|
||||||
|
|
||||||
pub async fn bundle(
|
|
||||||
flags: Arc<Flags>,
|
|
||||||
bundle_flags: BundleFlags,
|
|
||||||
) -> Result<(), AnyError> {
|
|
||||||
log::info!(
|
|
||||||
"{}",
|
|
||||||
colors::yellow("⚠️ Warning: `deno bundle` is deprecated and will be removed in Deno 2.0.\nUse an alternative bundler like \"deno_emit\", \"esbuild\" or \"rollup\" instead."),
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(watch_flags) = &bundle_flags.watch {
|
|
||||||
util::file_watcher::watch_func(
|
|
||||||
flags,
|
|
||||||
util::file_watcher::PrintConfig::new(
|
|
||||||
"Bundle",
|
|
||||||
!watch_flags.no_clear_screen,
|
|
||||||
),
|
|
||||||
move |flags, watcher_communicator, _changed_paths| {
|
|
||||||
let bundle_flags = bundle_flags.clone();
|
|
||||||
Ok(async move {
|
|
||||||
let factory = CliFactory::from_flags_for_watcher(
|
|
||||||
flags,
|
|
||||||
watcher_communicator.clone(),
|
|
||||||
);
|
|
||||||
let cli_options = factory.cli_options()?;
|
|
||||||
let _ = watcher_communicator.watch_paths(cli_options.watch_paths());
|
|
||||||
bundle_action(factory, &bundle_flags).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
} else {
|
|
||||||
let factory = CliFactory::from_flags(flags);
|
|
||||||
bundle_action(factory, &bundle_flags).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn bundle_action(
|
|
||||||
factory: CliFactory,
|
|
||||||
bundle_flags: &BundleFlags,
|
|
||||||
) -> Result<(), AnyError> {
|
|
||||||
let cli_options = factory.cli_options()?;
|
|
||||||
let module_specifier = cli_options.resolve_main_module()?;
|
|
||||||
log::debug!(">>>>> bundle START");
|
|
||||||
let module_graph_creator = factory.module_graph_creator().await?;
|
|
||||||
let cli_options = factory.cli_options()?;
|
|
||||||
|
|
||||||
let graph = module_graph_creator
|
|
||||||
.create_graph_and_maybe_check(vec![module_specifier.clone()])
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let mut paths_to_watch: Vec<PathBuf> = graph
|
|
||||||
.specifiers()
|
|
||||||
.filter_map(|(_, r)| {
|
|
||||||
r.ok().and_then(|module| match module {
|
|
||||||
Module::Js(m) => m.specifier.to_file_path().ok(),
|
|
||||||
Module::Json(m) => m.specifier.to_file_path().ok(),
|
|
||||||
// nothing to watch
|
|
||||||
Module::Node(_) | Module::Npm(_) | Module::External(_) => None,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
if let Ok(Some(import_map_path)) = cli_options
|
|
||||||
.resolve_specified_import_map_specifier()
|
|
||||||
.map(|ms| ms.and_then(|ref s| s.to_file_path().ok()))
|
|
||||||
{
|
|
||||||
paths_to_watch.push(import_map_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
// at the moment, we don't support npm specifiers in deno bundle, so show an error
|
|
||||||
error_for_any_npm_specifier(&graph)?;
|
|
||||||
|
|
||||||
let bundle_output = bundle_module_graph(graph.as_ref(), cli_options)?;
|
|
||||||
log::debug!(">>>>> bundle END");
|
|
||||||
let out_file = &bundle_flags.out_file;
|
|
||||||
|
|
||||||
if let Some(out_file) = out_file {
|
|
||||||
let out_file = cli_options.initial_cwd().join(out_file);
|
|
||||||
let output_bytes = bundle_output.code.as_bytes();
|
|
||||||
let output_len = output_bytes.len();
|
|
||||||
util::fs::write_file(&out_file, output_bytes, 0o644)?;
|
|
||||||
log::info!(
|
|
||||||
"{} {:?} ({})",
|
|
||||||
colors::green("Emit"),
|
|
||||||
out_file,
|
|
||||||
colors::gray(display::human_size(output_len as f64))
|
|
||||||
);
|
|
||||||
if let Some(bundle_map) = bundle_output.maybe_map {
|
|
||||||
let map_bytes = bundle_map.as_bytes();
|
|
||||||
let map_len = map_bytes.len();
|
|
||||||
let ext = if let Some(curr_ext) = out_file.extension() {
|
|
||||||
format!("{}.map", curr_ext.to_string_lossy())
|
|
||||||
} else {
|
|
||||||
"map".to_string()
|
|
||||||
};
|
|
||||||
let map_out_file = out_file.with_extension(ext);
|
|
||||||
util::fs::write_file(&map_out_file, map_bytes, 0o644)?;
|
|
||||||
log::info!(
|
|
||||||
"{} {:?} ({})",
|
|
||||||
colors::green("Emit"),
|
|
||||||
map_out_file,
|
|
||||||
colors::gray(display::human_size(map_len as f64))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
#[allow(clippy::print_stdout)]
|
|
||||||
{
|
|
||||||
println!("{}", bundle_output.code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bundle_module_graph(
|
|
||||||
graph: &deno_graph::ModuleGraph,
|
|
||||||
cli_options: &CliOptions,
|
|
||||||
) -> Result<deno_emit::BundleEmit, AnyError> {
|
|
||||||
log::info!("{} {}", colors::green("Bundle"), graph.roots[0]);
|
|
||||||
|
|
||||||
let ts_config_result =
|
|
||||||
cli_options.resolve_ts_config_for_emit(TsConfigType::Bundle)?;
|
|
||||||
if !cli_options.type_check_mode().is_true() {
|
|
||||||
if let Some(ignored_options) = ts_config_result.maybe_ignored_options {
|
|
||||||
log::warn!("{}", ignored_options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let (transpile_options, emit_options) =
|
|
||||||
crate::args::ts_config_to_transpile_and_emit_options(
|
|
||||||
ts_config_result.ts_config,
|
|
||||||
)?;
|
|
||||||
deno_emit::bundle_graph(
|
|
||||||
graph,
|
|
||||||
deno_emit::BundleOptions {
|
|
||||||
minify: false,
|
|
||||||
bundle_type: deno_emit::BundleType::Module,
|
|
||||||
emit_options,
|
|
||||||
emit_ignore_directives: true,
|
|
||||||
transpile_options,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -14,6 +14,7 @@ use deno_terminal::colors;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
|
use crate::args::check_warn_tsconfig;
|
||||||
use crate::args::CliOptions;
|
use crate::args::CliOptions;
|
||||||
use crate::args::TsConfig;
|
use crate::args::TsConfig;
|
||||||
use crate::args::TsConfigType;
|
use crate::args::TsConfigType;
|
||||||
|
@ -118,9 +119,7 @@ impl TypeChecker {
|
||||||
.cli_options
|
.cli_options
|
||||||
.resolve_ts_config_for_emit(TsConfigType::Check { lib: options.lib })?;
|
.resolve_ts_config_for_emit(TsConfigType::Check { lib: options.lib })?;
|
||||||
if options.log_ignored_options {
|
if options.log_ignored_options {
|
||||||
if let Some(ignored_options) = ts_config_result.maybe_ignored_options {
|
check_warn_tsconfig(&ts_config_result);
|
||||||
log::warn!("{}", ignored_options);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let type_check_mode = options.type_check_mode;
|
let type_check_mode = options.type_check_mode;
|
||||||
|
@ -427,7 +426,7 @@ fn get_tsc_roots(
|
||||||
|
|
||||||
// now walk the graph that only includes the fast check dependencies
|
// now walk the graph that only includes the fast check dependencies
|
||||||
while let Some(specifier) = pending.pop_front() {
|
while let Some(specifier) = pending.pop_front() {
|
||||||
let Some(module) = graph.get(&specifier) else {
|
let Some(module) = graph.get(specifier) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if let Some(entry) = maybe_get_check_entry(module, check_js) {
|
if let Some(entry) = maybe_get_check_entry(module, check_js) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
use crate::args::check_warn_tsconfig;
|
||||||
use crate::args::CompileFlags;
|
use crate::args::CompileFlags;
|
||||||
use crate::args::Flags;
|
use crate::args::Flags;
|
||||||
use crate::factory::CliFactory;
|
use crate::factory::CliFactory;
|
||||||
|
@ -79,6 +80,7 @@ pub async fn compile(
|
||||||
|
|
||||||
let ts_config_for_emit = cli_options
|
let ts_config_for_emit = cli_options
|
||||||
.resolve_ts_config_for_emit(deno_config::deno_json::TsConfigType::Emit)?;
|
.resolve_ts_config_for_emit(deno_config::deno_json::TsConfigType::Emit)?;
|
||||||
|
check_warn_tsconfig(&ts_config_for_emit);
|
||||||
let (transpile_options, emit_options) =
|
let (transpile_options, emit_options) =
|
||||||
crate::args::ts_config_to_transpile_and_emit_options(
|
crate::args::ts_config_to_transpile_and_emit_options(
|
||||||
ts_config_for_emit.ts_config,
|
ts_config_for_emit.ts_config,
|
||||||
|
|
|
@ -5,8 +5,7 @@ use crate::args::DocHtmlFlag;
|
||||||
use crate::args::DocSourceFileFlag;
|
use crate::args::DocSourceFileFlag;
|
||||||
use crate::args::Flags;
|
use crate::args::Flags;
|
||||||
use crate::colors;
|
use crate::colors;
|
||||||
use crate::display::write_json_to_stdout;
|
use crate::display;
|
||||||
use crate::display::write_to_stdout_ignore_sigpipe;
|
|
||||||
use crate::factory::CliFactory;
|
use crate::factory::CliFactory;
|
||||||
use crate::graph_util::graph_exit_lock_errors;
|
use crate::graph_util::graph_exit_lock_errors;
|
||||||
use crate::tsc::get_types_declaration_file_text;
|
use crate::tsc::get_types_declaration_file_text;
|
||||||
|
@ -17,6 +16,7 @@ use deno_config::glob::PathOrPatternSet;
|
||||||
use deno_core::anyhow::bail;
|
use deno_core::anyhow::bail;
|
||||||
use deno_core::anyhow::Context;
|
use deno_core::anyhow::Context;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
|
use deno_core::serde_json;
|
||||||
use deno_doc as doc;
|
use deno_doc as doc;
|
||||||
use deno_doc::html::UrlResolveKind;
|
use deno_doc::html::UrlResolveKind;
|
||||||
use deno_graph::source::NullFileSystem;
|
use deno_graph::source::NullFileSystem;
|
||||||
|
@ -31,6 +31,8 @@ use std::collections::BTreeMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
const JSON_SCHEMA_VERSION: u8 = 1;
|
||||||
|
|
||||||
async fn generate_doc_nodes_for_builtin_types(
|
async fn generate_doc_nodes_for_builtin_types(
|
||||||
doc_flags: DocFlags,
|
doc_flags: DocFlags,
|
||||||
parser: &dyn ModuleParser,
|
parser: &dyn ModuleParser,
|
||||||
|
@ -228,7 +230,11 @@ pub async fn doc(
|
||||||
doc_nodes_by_url.into_values().flatten().collect::<Vec<_>>();
|
doc_nodes_by_url.into_values().flatten().collect::<Vec<_>>();
|
||||||
|
|
||||||
if doc_flags.json {
|
if doc_flags.json {
|
||||||
write_json_to_stdout(&doc_nodes)
|
let json_output = serde_json::json!({
|
||||||
|
"version": JSON_SCHEMA_VERSION,
|
||||||
|
"nodes": &doc_nodes
|
||||||
|
});
|
||||||
|
display::write_json_to_stdout(&json_output)
|
||||||
} else if doc_flags.lint {
|
} else if doc_flags.lint {
|
||||||
// don't output docs if running with only the --lint flag
|
// don't output docs if running with only the --lint flag
|
||||||
log::info!(
|
log::info!(
|
||||||
|
@ -553,7 +559,8 @@ fn print_docs_to_stdout(
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
write_to_stdout_ignore_sigpipe(details.as_bytes()).map_err(AnyError::from)
|
display::write_to_stdout_ignore_sigpipe(details.as_bytes())
|
||||||
|
.map_err(AnyError::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_diagnostics(diagnostics: &[DocDiagnostic]) -> Result<(), AnyError> {
|
fn check_diagnostics(diagnostics: &[DocDiagnostic]) -> Result<(), AnyError> {
|
||||||
|
|
|
@ -403,15 +403,6 @@ pub fn format_html(
|
||||||
let mut typescript_config =
|
let mut typescript_config =
|
||||||
get_resolved_typescript_config(fmt_options);
|
get_resolved_typescript_config(fmt_options);
|
||||||
typescript_config.line_width = hints.print_width as u32;
|
typescript_config.line_width = hints.print_width as u32;
|
||||||
if hints.attr {
|
|
||||||
typescript_config.quote_style = if let Some(true) =
|
|
||||||
fmt_options.single_quote
|
|
||||||
{
|
|
||||||
dprint_plugin_typescript::configuration::QuoteStyle::AlwaysDouble
|
|
||||||
} else {
|
|
||||||
dprint_plugin_typescript::configuration::QuoteStyle::AlwaysSingle
|
|
||||||
};
|
|
||||||
}
|
|
||||||
dprint_plugin_typescript::format_text(
|
dprint_plugin_typescript::format_text(
|
||||||
&path,
|
&path,
|
||||||
text.to_string(),
|
text.to_string(),
|
||||||
|
|
|
@ -11,7 +11,6 @@ use deno_core::anyhow::bail;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::resolve_url_or_path;
|
use deno_core::resolve_url_or_path;
|
||||||
use deno_core::serde_json;
|
use deno_core::serde_json;
|
||||||
use deno_core::serde_json::json;
|
|
||||||
use deno_graph::Dependency;
|
use deno_graph::Dependency;
|
||||||
use deno_graph::GraphKind;
|
use deno_graph::GraphKind;
|
||||||
use deno_graph::Module;
|
use deno_graph::Module;
|
||||||
|
@ -35,6 +34,8 @@ use crate::npm::CliNpmResolver;
|
||||||
use crate::npm::ManagedCliNpmResolver;
|
use crate::npm::ManagedCliNpmResolver;
|
||||||
use crate::util::checksum;
|
use crate::util::checksum;
|
||||||
|
|
||||||
|
const JSON_SCHEMA_VERSION: u8 = 1;
|
||||||
|
|
||||||
pub async fn info(
|
pub async fn info(
|
||||||
flags: Arc<Flags>,
|
flags: Arc<Flags>,
|
||||||
info_flags: InfoFlags,
|
info_flags: InfoFlags,
|
||||||
|
@ -79,7 +80,10 @@ pub async fn info(
|
||||||
}
|
}
|
||||||
|
|
||||||
if info_flags.json {
|
if info_flags.json {
|
||||||
let mut json_graph = json!(graph);
|
let mut json_graph = serde_json::json!(graph);
|
||||||
|
if let Some(output) = json_graph.as_object_mut() {
|
||||||
|
output.insert("version".to_string(), JSON_SCHEMA_VERSION.into());
|
||||||
|
}
|
||||||
add_npm_packages_to_json(&mut json_graph, npm_resolver.as_ref());
|
add_npm_packages_to_json(&mut json_graph, npm_resolver.as_ref());
|
||||||
display::write_json_to_stdout(&json_graph)?;
|
display::write_json_to_stdout(&json_graph)?;
|
||||||
} else {
|
} else {
|
||||||
|
@ -121,7 +125,8 @@ fn print_cache_info(
|
||||||
let local_storage_dir = origin_dir.join("local_storage");
|
let local_storage_dir = origin_dir.join("local_storage");
|
||||||
|
|
||||||
if json {
|
if json {
|
||||||
let mut output = json!({
|
let mut json_output = serde_json::json!({
|
||||||
|
"version": JSON_SCHEMA_VERSION,
|
||||||
"denoDir": deno_dir,
|
"denoDir": deno_dir,
|
||||||
"modulesCache": modules_cache,
|
"modulesCache": modules_cache,
|
||||||
"npmCache": npm_cache,
|
"npmCache": npm_cache,
|
||||||
|
@ -131,10 +136,10 @@ fn print_cache_info(
|
||||||
});
|
});
|
||||||
|
|
||||||
if location.is_some() {
|
if location.is_some() {
|
||||||
output["localStorage"] = serde_json::to_value(local_storage_dir)?;
|
json_output["localStorage"] = serde_json::to_value(local_storage_dir)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
display::write_json_to_stdout(&output)
|
display::write_json_to_stdout(&json_output)
|
||||||
} else {
|
} else {
|
||||||
println!("{} {}", colors::bold("DENO_DIR location:"), deno_dir);
|
println!("{} {}", colors::bold("DENO_DIR location:"), deno_dir);
|
||||||
println!(
|
println!(
|
||||||
|
@ -440,7 +445,7 @@ impl<'a> GraphDisplayContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let root_specifier = self.graph.resolve(&self.graph.roots[0]);
|
let root_specifier = self.graph.resolve(&self.graph.roots[0]);
|
||||||
match self.graph.try_get(&root_specifier) {
|
match self.graph.try_get(root_specifier) {
|
||||||
Ok(Some(root)) => {
|
Ok(Some(root)) => {
|
||||||
let maybe_cache_info = match root {
|
let maybe_cache_info = match root {
|
||||||
Module::Js(module) => module.maybe_cache_info.as_ref(),
|
Module::Js(module) => module.maybe_cache_info.as_ref(),
|
||||||
|
@ -456,22 +461,6 @@ impl<'a> GraphDisplayContext<'a> {
|
||||||
local.to_string_lossy()
|
local.to_string_lossy()
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
if let Some(emit) = &cache_info.emit {
|
|
||||||
writeln!(
|
|
||||||
writer,
|
|
||||||
"{} {}",
|
|
||||||
colors::bold("emit:"),
|
|
||||||
emit.to_string_lossy()
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
if let Some(map) = &cache_info.map {
|
|
||||||
writeln!(
|
|
||||||
writer,
|
|
||||||
"{} {}",
|
|
||||||
colors::bold("map:"),
|
|
||||||
map.to_string_lossy()
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if let Some(module) = root.js() {
|
if let Some(module) = root.js() {
|
||||||
writeln!(writer, "{} {}", colors::bold("type:"), module.media_type)?;
|
writeln!(writer, "{} {}", colors::bold("type:"), module.media_type)?;
|
||||||
|
@ -694,9 +683,9 @@ impl<'a> GraphDisplayContext<'a> {
|
||||||
Resolution::Ok(resolved) => {
|
Resolution::Ok(resolved) => {
|
||||||
let specifier = &resolved.specifier;
|
let specifier = &resolved.specifier;
|
||||||
let resolved_specifier = self.graph.resolve(specifier);
|
let resolved_specifier = self.graph.resolve(specifier);
|
||||||
Some(match self.graph.try_get(&resolved_specifier) {
|
Some(match self.graph.try_get(resolved_specifier) {
|
||||||
Ok(Some(module)) => self.build_module_info(module, type_dep),
|
Ok(Some(module)) => self.build_module_info(module, type_dep),
|
||||||
Err(err) => self.build_error_info(err, &resolved_specifier),
|
Err(err) => self.build_error_info(err, resolved_specifier),
|
||||||
Ok(None) => TreeNode::from_text(format!(
|
Ok(None) => TreeNode::from_text(format!(
|
||||||
"{} {}",
|
"{} {}",
|
||||||
colors::red(specifier),
|
colors::red(specifier),
|
||||||
|
|
|
@ -37,7 +37,7 @@ const routes: Route[] = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pattern: new URLPattern({ pathname: "/static/*" }),
|
pattern: new URLPattern({ pathname: "/static/*" }),
|
||||||
handler: (req) => serveDir(req, { urlRoot: "./" }),
|
handler: (req) => serveDir(req),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -52,7 +52,6 @@ export default {
|
||||||
return handler(req);
|
return handler(req);
|
||||||
},
|
},
|
||||||
} satisfies Deno.ServeDefaultExport;
|
} satisfies Deno.ServeDefaultExport;
|
||||||
|
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
create_file(
|
create_file(
|
||||||
|
@ -80,13 +79,23 @@ Deno.test(async function serverFetchUsers() {
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test(async function serverFetchStatic() {
|
Deno.test(async function serverFetchStatic() {
|
||||||
const req = new Request("https://deno.land/static/main.ts");
|
const req = new Request("https://deno.land/static/hello.js");
|
||||||
const res = await server.fetch(req);
|
const res = await server.fetch(req);
|
||||||
assertEquals(res.headers.get("content-type"), "text/plain;charset=UTF-8");
|
assertEquals(await res.text(), 'console.log("Hello, world!");\n');
|
||||||
|
assertEquals(res.headers.get("content-type"), "text/javascript; charset=UTF-8");
|
||||||
});
|
});
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
let static_dir = dir.join("static");
|
||||||
|
std::fs::create_dir_all(&static_dir)?;
|
||||||
|
create_file(
|
||||||
|
&static_dir,
|
||||||
|
"hello.js",
|
||||||
|
r#"console.log("Hello, world!");
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
create_json_file(
|
create_json_file(
|
||||||
&dir,
|
&dir,
|
||||||
"deno.json",
|
"deno.json",
|
||||||
|
@ -203,7 +212,7 @@ Deno.test(function addTest() {
|
||||||
info!(" deno task dev");
|
info!(" deno task dev");
|
||||||
info!("");
|
info!("");
|
||||||
info!(" {}", colors::gray("# Run the tests"));
|
info!(" {}", colors::gray("# Run the tests"));
|
||||||
info!(" deno -R test");
|
info!(" deno test -R");
|
||||||
} else if init_flags.lib {
|
} else if init_flags.lib {
|
||||||
info!(" {}", colors::gray("# Run the tests"));
|
info!(" {}", colors::gray("# Run the tests"));
|
||||||
info!(" deno test");
|
info!(" deno test");
|
||||||
|
|
|
@ -7,14 +7,17 @@ use crate::args::ConfigFlag;
|
||||||
use crate::args::Flags;
|
use crate::args::Flags;
|
||||||
use crate::args::InstallFlags;
|
use crate::args::InstallFlags;
|
||||||
use crate::args::InstallFlagsGlobal;
|
use crate::args::InstallFlagsGlobal;
|
||||||
|
use crate::args::InstallFlagsLocal;
|
||||||
use crate::args::InstallKind;
|
use crate::args::InstallKind;
|
||||||
use crate::args::TypeCheckMode;
|
use crate::args::TypeCheckMode;
|
||||||
use crate::args::UninstallFlags;
|
use crate::args::UninstallFlags;
|
||||||
use crate::args::UninstallKind;
|
use crate::args::UninstallKind;
|
||||||
use crate::factory::CliFactory;
|
use crate::factory::CliFactory;
|
||||||
|
use crate::graph_container::ModuleGraphContainer;
|
||||||
use crate::http_util::HttpClientProvider;
|
use crate::http_util::HttpClientProvider;
|
||||||
use crate::util::fs::canonicalize_path_maybe_not_exists;
|
use crate::util::fs::canonicalize_path_maybe_not_exists;
|
||||||
|
|
||||||
|
use deno_core::anyhow::bail;
|
||||||
use deno_core::anyhow::Context;
|
use deno_core::anyhow::Context;
|
||||||
use deno_core::error::generic_error;
|
use deno_core::error::generic_error;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
|
@ -195,14 +198,15 @@ pub async fn infer_name_from_url(
|
||||||
Some(stem.to_string())
|
Some(stem.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uninstall(uninstall_flags: UninstallFlags) -> Result<(), AnyError> {
|
pub async fn uninstall(
|
||||||
if !uninstall_flags.global {
|
flags: Arc<Flags>,
|
||||||
log::warn!("⚠️ `deno install` behavior will change in Deno 2. To preserve the current behavior use the `-g` or `--global` flag.");
|
uninstall_flags: UninstallFlags,
|
||||||
}
|
) -> Result<(), AnyError> {
|
||||||
|
|
||||||
let uninstall_flags = match uninstall_flags.kind {
|
let uninstall_flags = match uninstall_flags.kind {
|
||||||
UninstallKind::Global(flags) => flags,
|
UninstallKind::Global(flags) => flags,
|
||||||
UninstallKind::Local => unreachable!(),
|
UninstallKind::Local(remove_flags) => {
|
||||||
|
return super::registry::remove(flags, remove_flags).await;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let cwd = std::env::current_dir().context("Unable to get CWD")?;
|
let cwd = std::env::current_dir().context("Unable to get CWD")?;
|
||||||
|
@ -261,19 +265,38 @@ pub fn uninstall(uninstall_flags: UninstallFlags) -> Result<(), AnyError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn install_from_entrypoints(
|
||||||
|
flags: Arc<Flags>,
|
||||||
|
entrypoints: &[String],
|
||||||
|
) -> Result<(), AnyError> {
|
||||||
|
let factory = CliFactory::from_flags(flags.clone());
|
||||||
|
let emitter = factory.emitter()?;
|
||||||
|
let main_graph_container = factory.main_module_graph_container().await?;
|
||||||
|
main_graph_container
|
||||||
|
.load_and_type_check_files(entrypoints)
|
||||||
|
.await?;
|
||||||
|
emitter
|
||||||
|
.cache_module_emits(&main_graph_container.graph())
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
async fn install_local(
|
async fn install_local(
|
||||||
flags: Arc<Flags>,
|
flags: Arc<Flags>,
|
||||||
maybe_add_flags: Option<AddFlags>,
|
install_flags: InstallFlagsLocal,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
if let Some(add_flags) = maybe_add_flags {
|
match install_flags {
|
||||||
return super::registry::add(
|
InstallFlagsLocal::Add(add_flags) => {
|
||||||
|
super::registry::add(
|
||||||
flags,
|
flags,
|
||||||
add_flags,
|
add_flags,
|
||||||
super::registry::AddCommandName::Install,
|
super::registry::AddCommandName::Install,
|
||||||
)
|
)
|
||||||
.await;
|
.await
|
||||||
}
|
}
|
||||||
|
InstallFlagsLocal::Entrypoints(entrypoints) => {
|
||||||
|
install_from_entrypoints(flags, &entrypoints).await
|
||||||
|
}
|
||||||
|
InstallFlagsLocal::TopLevel => {
|
||||||
let factory = CliFactory::from_flags(flags);
|
let factory = CliFactory::from_flags(flags);
|
||||||
crate::tools::registry::cache_top_level_deps(&factory, None).await?;
|
crate::tools::registry::cache_top_level_deps(&factory, None).await?;
|
||||||
|
|
||||||
|
@ -281,6 +304,26 @@ async fn install_local(
|
||||||
lockfile.write_if_changed()?;
|
lockfile.write_if_changed()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_if_installs_a_single_package_globally(
|
||||||
|
maybe_add_flags: Option<&AddFlags>,
|
||||||
|
) -> Result<(), AnyError> {
|
||||||
|
let Some(add_flags) = maybe_add_flags else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
if add_flags.packages.len() != 1 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let Ok(url) = Url::parse(&add_flags.packages[0]) else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
if matches!(url.scheme(), "http" | "https") {
|
||||||
|
bail!("Failed to install \"{}\" specifier. If you are trying to install {} globally, run again with `-g` flag:\n deno install -g {}", url.scheme(), url.as_str(), url.as_str());
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,14 +333,13 @@ pub async fn install_command(
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
match install_flags.kind {
|
match install_flags.kind {
|
||||||
InstallKind::Global(global_flags) => {
|
InstallKind::Global(global_flags) => {
|
||||||
if !install_flags.global {
|
|
||||||
log::warn!("⚠️ `deno install` behavior will change in Deno 2. To preserve the current behavior use the `-g` or `--global` flag.");
|
|
||||||
}
|
|
||||||
|
|
||||||
install_global(flags, global_flags).await
|
install_global(flags, global_flags).await
|
||||||
}
|
}
|
||||||
InstallKind::Local(maybe_add_flags) => {
|
InstallKind::Local(local_flags) => {
|
||||||
install_local(flags, maybe_add_flags).await
|
if let InstallFlagsLocal::Add(add_flags) = &local_flags {
|
||||||
|
check_if_installs_a_single_package_globally(Some(add_flags))?;
|
||||||
|
}
|
||||||
|
install_local(flags, local_flags).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -464,10 +506,6 @@ async fn resolve_shim_data(
|
||||||
executable_args.push("--no-npm".to_string());
|
executable_args.push("--no-npm".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
if flags.lock_write {
|
|
||||||
executable_args.push("--lock-write".to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.cached_only {
|
if flags.cached_only {
|
||||||
executable_args.push("--cached-only".to_string());
|
executable_args.push("--cached-only".to_string());
|
||||||
}
|
}
|
||||||
|
@ -1471,8 +1509,8 @@ mod tests {
|
||||||
assert!(content.contains(&expected_string));
|
assert!(content.contains(&expected_string));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn uninstall_basic() {
|
async fn uninstall_basic() {
|
||||||
let temp_dir = TempDir::new();
|
let temp_dir = TempDir::new();
|
||||||
let bin_dir = temp_dir.path().join("bin");
|
let bin_dir = temp_dir.path().join("bin");
|
||||||
std::fs::create_dir(&bin_dir).unwrap();
|
std::fs::create_dir(&bin_dir).unwrap();
|
||||||
|
@ -1499,13 +1537,16 @@ mod tests {
|
||||||
File::create(file_path).unwrap();
|
File::create(file_path).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
uninstall(UninstallFlags {
|
uninstall(
|
||||||
|
Default::default(),
|
||||||
|
UninstallFlags {
|
||||||
kind: UninstallKind::Global(UninstallFlagsGlobal {
|
kind: UninstallKind::Global(UninstallFlagsGlobal {
|
||||||
name: "echo_test".to_string(),
|
name: "echo_test".to_string(),
|
||||||
root: Some(temp_dir.path().to_string()),
|
root: Some(temp_dir.path().to_string()),
|
||||||
}),
|
}),
|
||||||
global: false,
|
},
|
||||||
})
|
)
|
||||||
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert!(!file_path.exists());
|
assert!(!file_path.exists());
|
||||||
|
|
|
@ -45,6 +45,7 @@ use crate::colors;
|
||||||
use crate::factory::CliFactory;
|
use crate::factory::CliFactory;
|
||||||
use crate::graph_util::ModuleGraphCreator;
|
use crate::graph_util::ModuleGraphCreator;
|
||||||
use crate::tools::fmt::run_parallelized;
|
use crate::tools::fmt::run_parallelized;
|
||||||
|
use crate::util::display;
|
||||||
use crate::util::file_watcher;
|
use crate::util::file_watcher;
|
||||||
use crate::util::fs::canonicalize_path;
|
use crate::util::fs::canonicalize_path;
|
||||||
use crate::util::path::is_script_ext;
|
use crate::util::path::is_script_ext;
|
||||||
|
@ -60,6 +61,8 @@ pub use rules::collect_no_slow_type_diagnostics;
|
||||||
pub use rules::ConfiguredRules;
|
pub use rules::ConfiguredRules;
|
||||||
pub use rules::LintRuleProvider;
|
pub use rules::LintRuleProvider;
|
||||||
|
|
||||||
|
const JSON_SCHEMA_VERSION: u8 = 1;
|
||||||
|
|
||||||
static STDIN_FILE_NAME: &str = "$deno$stdin.ts";
|
static STDIN_FILE_NAME: &str = "$deno$stdin.ts";
|
||||||
|
|
||||||
pub async fn lint(
|
pub async fn lint(
|
||||||
|
@ -440,7 +443,9 @@ pub fn print_rules_list(json: bool, maybe_rules_tags: Option<Vec<String>>) {
|
||||||
.rules;
|
.rules;
|
||||||
|
|
||||||
if json {
|
if json {
|
||||||
let json_rules: Vec<serde_json::Value> = lint_rules
|
let json_output = serde_json::json!({
|
||||||
|
"version": JSON_SCHEMA_VERSION,
|
||||||
|
"rules": lint_rules
|
||||||
.iter()
|
.iter()
|
||||||
.map(|rule| {
|
.map(|rule| {
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
|
@ -449,9 +454,9 @@ pub fn print_rules_list(json: bool, maybe_rules_tags: Option<Vec<String>>) {
|
||||||
"docs": rule.docs(),
|
"docs": rule.docs(),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect();
|
.collect::<Vec<serde_json::Value>>(),
|
||||||
let json_str = serde_json::to_string_pretty(&json_rules).unwrap();
|
});
|
||||||
println!("{json_str}");
|
display::write_json_to_stdout(&json_output).unwrap();
|
||||||
} else {
|
} else {
|
||||||
// The rules should still be printed even if `--quiet` option is enabled,
|
// The rules should still be printed even if `--quiet` option is enabled,
|
||||||
// so use `println!` here instead of `info!`.
|
// so use `println!` here instead of `info!`.
|
||||||
|
|
|
@ -12,6 +12,8 @@ use crate::args::LintReporterKind;
|
||||||
|
|
||||||
use super::LintError;
|
use super::LintError;
|
||||||
|
|
||||||
|
const JSON_SCHEMA_VERSION: u8 = 1;
|
||||||
|
|
||||||
pub fn create_reporter(kind: LintReporterKind) -> Box<dyn LintReporter + Send> {
|
pub fn create_reporter(kind: LintReporterKind) -> Box<dyn LintReporter + Send> {
|
||||||
match kind {
|
match kind {
|
||||||
LintReporterKind::Pretty => Box::new(PrettyLintReporter::new()),
|
LintReporterKind::Pretty => Box::new(PrettyLintReporter::new()),
|
||||||
|
@ -170,6 +172,7 @@ struct JsonLintDiagnostic {
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct JsonLintReporter {
|
struct JsonLintReporter {
|
||||||
|
version: u8,
|
||||||
diagnostics: Vec<JsonLintDiagnostic>,
|
diagnostics: Vec<JsonLintDiagnostic>,
|
||||||
errors: Vec<LintError>,
|
errors: Vec<LintError>,
|
||||||
}
|
}
|
||||||
|
@ -177,6 +180,7 @@ struct JsonLintReporter {
|
||||||
impl JsonLintReporter {
|
impl JsonLintReporter {
|
||||||
fn new() -> JsonLintReporter {
|
fn new() -> JsonLintReporter {
|
||||||
JsonLintReporter {
|
JsonLintReporter {
|
||||||
|
version: JSON_SCHEMA_VERSION,
|
||||||
diagnostics: Vec::new(),
|
diagnostics: Vec::new(),
|
||||||
errors: Vec::new(),
|
errors: Vec::new(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
pub mod bench;
|
pub mod bench;
|
||||||
pub mod bundle;
|
|
||||||
pub mod check;
|
pub mod check;
|
||||||
pub mod clean;
|
pub mod clean;
|
||||||
pub mod compile;
|
pub mod compile;
|
||||||
|
@ -20,4 +19,3 @@ pub mod serve;
|
||||||
pub mod task;
|
pub mod task;
|
||||||
pub mod test;
|
pub mod test;
|
||||||
pub mod upgrade;
|
pub mod upgrade;
|
||||||
pub mod vendor;
|
|
||||||
|
|
|
@ -1049,7 +1049,8 @@ async fn publish_package(
|
||||||
sha256: faster_hex::hex_string(&sha2::Sha256::digest(&meta_bytes)),
|
sha256: faster_hex::hex_string(&sha2::Sha256::digest(&meta_bytes)),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let bundle = provenance::generate_provenance(http_client, subject).await?;
|
let bundle =
|
||||||
|
provenance::generate_provenance(http_client, vec![subject]).await?;
|
||||||
|
|
||||||
let tlog_entry = &bundle.verification_material.tlog_entries[0];
|
let tlog_entry = &bundle.verification_material.tlog_entries[0];
|
||||||
log::info!("{}",
|
log::info!("{}",
|
||||||
|
|
|
@ -3,9 +3,10 @@
|
||||||
mod cache_deps;
|
mod cache_deps;
|
||||||
|
|
||||||
pub use cache_deps::cache_top_level_deps;
|
pub use cache_deps::cache_top_level_deps;
|
||||||
|
use deno_semver::jsr::JsrPackageReqReference;
|
||||||
|
use deno_semver::npm::NpmPackageReqReference;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::path::Path;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -24,9 +25,11 @@ use deno_semver::package::PackageReq;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use jsonc_parser::ast::ObjectProp;
|
use jsonc_parser::ast::ObjectProp;
|
||||||
use jsonc_parser::ast::Value;
|
use jsonc_parser::ast::Value;
|
||||||
|
use yoke::Yoke;
|
||||||
|
|
||||||
use crate::args::AddFlags;
|
use crate::args::AddFlags;
|
||||||
use crate::args::CacheSetting;
|
use crate::args::CacheSetting;
|
||||||
|
use crate::args::CliOptions;
|
||||||
use crate::args::Flags;
|
use crate::args::Flags;
|
||||||
use crate::args::RemoveFlags;
|
use crate::args::RemoveFlags;
|
||||||
use crate::factory::CliFactory;
|
use crate::factory::CliFactory;
|
||||||
|
@ -54,115 +57,303 @@ impl DenoConfigFormat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DenoConfig {
|
||||||
|
config: Arc<deno_config::deno_json::ConfigFile>,
|
||||||
|
format: DenoConfigFormat,
|
||||||
|
imports: IndexMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deno_json_imports(
|
||||||
|
config: &deno_config::deno_json::ConfigFile,
|
||||||
|
) -> Result<IndexMap<String, String>, AnyError> {
|
||||||
|
Ok(
|
||||||
|
config
|
||||||
|
.json
|
||||||
|
.imports
|
||||||
|
.clone()
|
||||||
|
.map(|imports| {
|
||||||
|
serde_json::from_value(imports)
|
||||||
|
.map_err(|err| anyhow!("Malformed \"imports\" configuration: {err}"))
|
||||||
|
})
|
||||||
|
.transpose()?
|
||||||
|
.unwrap_or_default(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
impl DenoConfig {
|
||||||
|
fn from_options(options: &CliOptions) -> Result<Option<Self>, AnyError> {
|
||||||
|
let start_dir = &options.start_dir;
|
||||||
|
if let Some(config) = start_dir.maybe_deno_json() {
|
||||||
|
Ok(Some(Self {
|
||||||
|
imports: deno_json_imports(config)?,
|
||||||
|
config: config.clone(),
|
||||||
|
format: DenoConfigFormat::from_specifier(&config.specifier)?,
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add(&mut self, selected: SelectedPackage) {
|
||||||
|
self.imports.insert(
|
||||||
|
selected.import_name,
|
||||||
|
format!("{}@{}", selected.package_name, selected.version_req),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove(&mut self, package: &str) -> bool {
|
||||||
|
self.imports.shift_remove(package).is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_import_fields(
|
||||||
|
&mut self,
|
||||||
|
) -> Vec<(&'static str, IndexMap<String, String>)> {
|
||||||
|
vec![("imports", std::mem::take(&mut self.imports))]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NpmConfig {
|
||||||
|
fn from_options(options: &CliOptions) -> Result<Option<Self>, AnyError> {
|
||||||
|
let start_dir = &options.start_dir;
|
||||||
|
if let Some(pkg_json) = start_dir.maybe_pkg_json() {
|
||||||
|
Ok(Some(Self {
|
||||||
|
dependencies: pkg_json.dependencies.clone().unwrap_or_default(),
|
||||||
|
dev_dependencies: pkg_json.dev_dependencies.clone().unwrap_or_default(),
|
||||||
|
config: pkg_json.clone(),
|
||||||
|
fmt_options: None,
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add(&mut self, selected: SelectedPackage, dev: bool) {
|
||||||
|
let (name, version) = package_json_dependency_entry(selected);
|
||||||
|
if dev {
|
||||||
|
self.dev_dependencies.insert(name, version);
|
||||||
|
} else {
|
||||||
|
self.dependencies.insert(name, version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove(&mut self, package: &str) -> bool {
|
||||||
|
let in_deps = self.dependencies.shift_remove(package).is_some();
|
||||||
|
let in_dev_deps = self.dev_dependencies.shift_remove(package).is_some();
|
||||||
|
in_deps || in_dev_deps
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_import_fields(
|
||||||
|
&mut self,
|
||||||
|
) -> Vec<(&'static str, IndexMap<String, String>)> {
|
||||||
|
vec![
|
||||||
|
("dependencies", std::mem::take(&mut self.dependencies)),
|
||||||
|
(
|
||||||
|
"devDependencies",
|
||||||
|
std::mem::take(&mut self.dev_dependencies),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NpmConfig {
|
||||||
|
config: Arc<deno_node::PackageJson>,
|
||||||
|
fmt_options: Option<FmtOptionsConfig>,
|
||||||
|
dependencies: IndexMap<String, String>,
|
||||||
|
dev_dependencies: IndexMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
enum DenoOrPackageJson {
|
enum DenoOrPackageJson {
|
||||||
Deno(Arc<deno_config::deno_json::ConfigFile>, DenoConfigFormat),
|
Deno(DenoConfig),
|
||||||
Npm(Arc<deno_node::PackageJson>, Option<FmtOptionsConfig>),
|
Npm(NpmConfig),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<DenoConfig> for DenoOrPackageJson {
|
||||||
|
fn from(config: DenoConfig) -> Self {
|
||||||
|
Self::Deno(config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<NpmConfig> for DenoOrPackageJson {
|
||||||
|
fn from(config: NpmConfig) -> Self {
|
||||||
|
Self::Npm(config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapper around `jsonc_parser::ast::Object` that can be stored in a `Yoke`
|
||||||
|
#[derive(yoke::Yokeable)]
|
||||||
|
struct JsoncObjectView<'a>(jsonc_parser::ast::Object<'a>);
|
||||||
|
|
||||||
|
struct ConfigUpdater {
|
||||||
|
config: DenoOrPackageJson,
|
||||||
|
// the `Yoke` is so we can carry the parsed object (which borrows from
|
||||||
|
// the source) along with the source itself
|
||||||
|
ast: Yoke<JsoncObjectView<'static>, String>,
|
||||||
|
path: PathBuf,
|
||||||
|
modified: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConfigUpdater {
|
||||||
|
fn obj(&self) -> &jsonc_parser::ast::Object<'_> {
|
||||||
|
&self.ast.get().0
|
||||||
|
}
|
||||||
|
fn contents(&self) -> &str {
|
||||||
|
self.ast.backing_cart()
|
||||||
|
}
|
||||||
|
async fn maybe_new(
|
||||||
|
config: Option<impl Into<DenoOrPackageJson>>,
|
||||||
|
) -> Result<Option<Self>, AnyError> {
|
||||||
|
if let Some(config) = config {
|
||||||
|
Ok(Some(Self::new(config.into()).await?))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async fn new(config: DenoOrPackageJson) -> Result<Self, AnyError> {
|
||||||
|
let specifier = config.specifier();
|
||||||
|
if specifier.scheme() != "file" {
|
||||||
|
bail!("Can't update a remote configuration file");
|
||||||
|
}
|
||||||
|
let config_file_path = specifier.to_file_path().map_err(|_| {
|
||||||
|
anyhow!("Specifier {specifier:?} is an invalid file path")
|
||||||
|
})?;
|
||||||
|
let config_file_contents = {
|
||||||
|
let contents = tokio::fs::read_to_string(&config_file_path)
|
||||||
|
.await
|
||||||
|
.with_context(|| {
|
||||||
|
format!("Reading config file at: {}", config_file_path.display())
|
||||||
|
})?;
|
||||||
|
if contents.trim().is_empty() {
|
||||||
|
"{}\n".into()
|
||||||
|
} else {
|
||||||
|
contents
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let ast = Yoke::try_attach_to_cart(config_file_contents, |contents| {
|
||||||
|
let ast = jsonc_parser::parse_to_ast(
|
||||||
|
contents,
|
||||||
|
&Default::default(),
|
||||||
|
&Default::default(),
|
||||||
|
)
|
||||||
|
.with_context(|| {
|
||||||
|
format!("Failed to parse config file at {}", specifier)
|
||||||
|
})?;
|
||||||
|
let obj = match ast.value {
|
||||||
|
Some(Value::Object(obj)) => obj,
|
||||||
|
_ => bail!(
|
||||||
|
"Failed to update config file at {}, expected an object",
|
||||||
|
specifier
|
||||||
|
),
|
||||||
|
};
|
||||||
|
Ok(JsoncObjectView(obj))
|
||||||
|
})?;
|
||||||
|
Ok(Self {
|
||||||
|
config,
|
||||||
|
ast,
|
||||||
|
path: config_file_path,
|
||||||
|
modified: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add(&mut self, selected: SelectedPackage, dev: bool) {
|
||||||
|
match &mut self.config {
|
||||||
|
DenoOrPackageJson::Deno(deno) => deno.add(selected),
|
||||||
|
DenoOrPackageJson::Npm(npm) => npm.add(selected, dev),
|
||||||
|
}
|
||||||
|
self.modified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove(&mut self, package: &str) -> bool {
|
||||||
|
let removed = match &mut self.config {
|
||||||
|
DenoOrPackageJson::Deno(deno) => deno.remove(package),
|
||||||
|
DenoOrPackageJson::Npm(npm) => npm.remove(package),
|
||||||
|
};
|
||||||
|
if removed {
|
||||||
|
self.modified = true;
|
||||||
|
}
|
||||||
|
removed
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn commit(mut self) -> Result<(), AnyError> {
|
||||||
|
if !self.modified {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let import_fields = self.config.take_import_fields();
|
||||||
|
|
||||||
|
let fmt_config_options = self.config.fmt_options();
|
||||||
|
|
||||||
|
let new_text = update_config_file_content(
|
||||||
|
self.obj(),
|
||||||
|
self.contents(),
|
||||||
|
fmt_config_options,
|
||||||
|
import_fields.into_iter().map(|(k, v)| {
|
||||||
|
(
|
||||||
|
k,
|
||||||
|
if v.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(generate_imports(v.into_iter().collect()))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
self.config.file_name(),
|
||||||
|
);
|
||||||
|
|
||||||
|
tokio::fs::write(&self.path, new_text).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DenoOrPackageJson {
|
impl DenoOrPackageJson {
|
||||||
fn specifier(&self) -> Cow<ModuleSpecifier> {
|
fn specifier(&self) -> Cow<ModuleSpecifier> {
|
||||||
match self {
|
match self {
|
||||||
Self::Deno(d, ..) => Cow::Borrowed(&d.specifier),
|
Self::Deno(d, ..) => Cow::Borrowed(&d.config.specifier),
|
||||||
Self::Npm(n, ..) => Cow::Owned(n.specifier()),
|
Self::Npm(n, ..) => Cow::Owned(n.config.specifier()),
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the existing imports/dependencies from the config.
|
|
||||||
fn existing_imports(&self) -> Result<IndexMap<String, String>, AnyError> {
|
|
||||||
match self {
|
|
||||||
DenoOrPackageJson::Deno(deno, ..) => {
|
|
||||||
if let Some(imports) = deno.json.imports.clone() {
|
|
||||||
match serde_json::from_value(imports) {
|
|
||||||
Ok(map) => Ok(map),
|
|
||||||
Err(err) => {
|
|
||||||
bail!("Malformed \"imports\" configuration: {err}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(Default::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DenoOrPackageJson::Npm(npm, ..) => {
|
|
||||||
Ok(npm.dependencies.clone().unwrap_or_default())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmt_options(&self) -> FmtOptionsConfig {
|
fn fmt_options(&self) -> FmtOptionsConfig {
|
||||||
match self {
|
match self {
|
||||||
DenoOrPackageJson::Deno(deno, ..) => deno
|
DenoOrPackageJson::Deno(deno, ..) => deno
|
||||||
|
.config
|
||||||
.to_fmt_config()
|
.to_fmt_config()
|
||||||
.ok()
|
.ok()
|
||||||
.map(|f| f.options)
|
.map(|f| f.options)
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
DenoOrPackageJson::Npm(_, config) => config.clone().unwrap_or_default(),
|
DenoOrPackageJson::Npm(config) => {
|
||||||
|
config.fmt_options.clone().unwrap_or_default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn imports_key(&self) -> &'static str {
|
fn take_import_fields(
|
||||||
|
&mut self,
|
||||||
|
) -> Vec<(&'static str, IndexMap<String, String>)> {
|
||||||
match self {
|
match self {
|
||||||
DenoOrPackageJson::Deno(..) => "imports",
|
Self::Deno(d) => d.take_import_fields(),
|
||||||
DenoOrPackageJson::Npm(..) => "dependencies",
|
Self::Npm(n) => n.take_import_fields(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file_name(&self) -> &'static str {
|
fn file_name(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
DenoOrPackageJson::Deno(_, format) => match format {
|
DenoOrPackageJson::Deno(config) => match config.format {
|
||||||
DenoConfigFormat::Json => "deno.json",
|
DenoConfigFormat::Json => "deno.json",
|
||||||
DenoConfigFormat::Jsonc => "deno.jsonc",
|
DenoConfigFormat::Jsonc => "deno.jsonc",
|
||||||
},
|
},
|
||||||
DenoOrPackageJson::Npm(..) => "package.json",
|
DenoOrPackageJson::Npm(..) => "package.json",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn is_npm(&self) -> bool {
|
fn create_deno_json(
|
||||||
matches!(self, Self::Npm(..))
|
flags: &Arc<Flags>,
|
||||||
}
|
options: &CliOptions,
|
||||||
|
) -> Result<CliFactory, AnyError> {
|
||||||
/// Get the preferred config file to operate on
|
|
||||||
/// given the flags. If no config file is present,
|
|
||||||
/// creates a `deno.json` file - in this case
|
|
||||||
/// we also return a new `CliFactory` that knows about
|
|
||||||
/// the new config
|
|
||||||
fn from_flags(flags: Arc<Flags>) -> Result<(Self, CliFactory), AnyError> {
|
|
||||||
let factory = CliFactory::from_flags(flags.clone());
|
|
||||||
let options = factory.cli_options()?;
|
|
||||||
let start_dir = &options.start_dir;
|
|
||||||
|
|
||||||
match (start_dir.maybe_deno_json(), start_dir.maybe_pkg_json()) {
|
|
||||||
// when both are present, for now,
|
|
||||||
// default to deno.json
|
|
||||||
(Some(deno), Some(_) | None) => Ok((
|
|
||||||
DenoOrPackageJson::Deno(
|
|
||||||
deno.clone(),
|
|
||||||
DenoConfigFormat::from_specifier(&deno.specifier)?,
|
|
||||||
),
|
|
||||||
factory,
|
|
||||||
)),
|
|
||||||
(None, Some(package_json)) if options.enable_future_features() => {
|
|
||||||
Ok((DenoOrPackageJson::Npm(package_json.clone(), None), factory))
|
|
||||||
}
|
|
||||||
(None, Some(_) | None) => {
|
|
||||||
std::fs::write(options.initial_cwd().join("deno.json"), "{}\n")
|
std::fs::write(options.initial_cwd().join("deno.json"), "{}\n")
|
||||||
.context("Failed to create deno.json file")?;
|
.context("Failed to create deno.json file")?;
|
||||||
drop(factory); // drop to prevent use
|
|
||||||
log::info!("Created deno.json configuration file.");
|
log::info!("Created deno.json configuration file.");
|
||||||
let factory = CliFactory::from_flags(flags.clone());
|
let factory = CliFactory::from_flags(flags.clone());
|
||||||
let options = factory.cli_options()?.clone();
|
Ok(factory)
|
||||||
let start_dir = &options.start_dir;
|
|
||||||
Ok((
|
|
||||||
DenoOrPackageJson::Deno(
|
|
||||||
start_dir.maybe_deno_json().cloned().ok_or_else(|| {
|
|
||||||
anyhow!("config not found, but it was just created")
|
|
||||||
})?,
|
|
||||||
DenoConfigFormat::Json,
|
|
||||||
),
|
|
||||||
factory,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn package_json_dependency_entry(
|
fn package_json_dependency_entry(
|
||||||
|
@ -197,19 +388,53 @@ impl std::fmt::Display for AddCommandName {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_configs(
|
||||||
|
flags: &Arc<Flags>,
|
||||||
|
) -> Result<(CliFactory, Option<NpmConfig>, Option<DenoConfig>), AnyError> {
|
||||||
|
let cli_factory = CliFactory::from_flags(flags.clone());
|
||||||
|
let options = cli_factory.cli_options()?;
|
||||||
|
let npm_config = NpmConfig::from_options(options)?;
|
||||||
|
let (cli_factory, deno_config) = match DenoConfig::from_options(options)? {
|
||||||
|
Some(config) => (cli_factory, Some(config)),
|
||||||
|
None if npm_config.is_some() => (cli_factory, None),
|
||||||
|
None => {
|
||||||
|
let factory = create_deno_json(flags, options)?;
|
||||||
|
let options = factory.cli_options()?.clone();
|
||||||
|
(
|
||||||
|
factory,
|
||||||
|
Some(
|
||||||
|
DenoConfig::from_options(&options)?.expect("Just created deno.json"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
assert!(deno_config.is_some() || npm_config.is_some());
|
||||||
|
Ok((cli_factory, npm_config, deno_config))
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn add(
|
pub async fn add(
|
||||||
flags: Arc<Flags>,
|
flags: Arc<Flags>,
|
||||||
add_flags: AddFlags,
|
add_flags: AddFlags,
|
||||||
cmd_name: AddCommandName,
|
cmd_name: AddCommandName,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let (config_file, cli_factory) =
|
let (cli_factory, npm_config, deno_config) = load_configs(&flags)?;
|
||||||
DenoOrPackageJson::from_flags(flags.clone())?;
|
let mut npm_config = ConfigUpdater::maybe_new(npm_config).await?;
|
||||||
|
let mut deno_config = ConfigUpdater::maybe_new(deno_config).await?;
|
||||||
|
|
||||||
let config_specifier = config_file.specifier();
|
if let Some(deno) = &deno_config {
|
||||||
if config_specifier.scheme() != "file" {
|
let specifier = deno.config.specifier();
|
||||||
bail!("Can't add dependencies to a remote configuration file");
|
if deno.obj().get_string("importMap").is_some() {
|
||||||
|
bail!(
|
||||||
|
concat!(
|
||||||
|
"`deno {}` is not supported when configuration file contains an \"importMap\" field. ",
|
||||||
|
"Inline the import map into the Deno configuration file.\n",
|
||||||
|
" at {}",
|
||||||
|
),
|
||||||
|
cmd_name,
|
||||||
|
specifier
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let config_file_path = config_specifier.to_file_path().unwrap();
|
|
||||||
|
|
||||||
let http_client = cli_factory.http_client_provider();
|
let http_client = cli_factory.http_client_provider();
|
||||||
|
|
||||||
|
@ -277,39 +502,7 @@ pub async fn add(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let config_file_contents = {
|
let dev = add_flags.dev;
|
||||||
let contents = tokio::fs::read_to_string(&config_file_path).await.unwrap();
|
|
||||||
if contents.trim().is_empty() {
|
|
||||||
"{}\n".into()
|
|
||||||
} else {
|
|
||||||
contents
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let ast = jsonc_parser::parse_to_ast(
|
|
||||||
&config_file_contents,
|
|
||||||
&Default::default(),
|
|
||||||
&Default::default(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let obj = match ast.value {
|
|
||||||
Some(Value::Object(obj)) => obj,
|
|
||||||
_ => bail!("Failed updating config file due to no object."),
|
|
||||||
};
|
|
||||||
|
|
||||||
if obj.get_string("importMap").is_some() {
|
|
||||||
bail!(
|
|
||||||
concat!(
|
|
||||||
"`deno add` is not supported when configuration file contains an \"importMap\" field. ",
|
|
||||||
"Inline the import map into the Deno configuration file.\n",
|
|
||||||
" at {}",
|
|
||||||
),
|
|
||||||
config_specifier
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut existing_imports = config_file.existing_imports()?;
|
|
||||||
|
|
||||||
let is_npm = config_file.is_npm();
|
|
||||||
for selected_package in selected_packages {
|
for selected_package in selected_packages {
|
||||||
log::info!(
|
log::info!(
|
||||||
"Add {}{}{}",
|
"Add {}{}{}",
|
||||||
|
@ -318,39 +511,32 @@ pub async fn add(
|
||||||
selected_package.selected_version
|
selected_package.selected_version
|
||||||
);
|
);
|
||||||
|
|
||||||
if is_npm {
|
if selected_package.package_name.starts_with("npm:") {
|
||||||
let (name, version) = package_json_dependency_entry(selected_package);
|
if let Some(npm) = &mut npm_config {
|
||||||
existing_imports.insert(name, version)
|
npm.add(selected_package, dev);
|
||||||
} else {
|
} else {
|
||||||
existing_imports.insert(
|
deno_config.as_mut().unwrap().add(selected_package, dev);
|
||||||
selected_package.import_name,
|
}
|
||||||
format!(
|
} else if let Some(deno) = &mut deno_config {
|
||||||
"{}@{}",
|
deno.add(selected_package, dev);
|
||||||
selected_package.package_name, selected_package.version_req
|
} else {
|
||||||
),
|
npm_config.as_mut().unwrap().add(selected_package, dev);
|
||||||
)
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
let mut import_list: Vec<(String, String)> =
|
|
||||||
existing_imports.into_iter().collect();
|
|
||||||
|
|
||||||
import_list.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
|
let mut commit_futures = vec![];
|
||||||
let generated_imports = generate_imports(import_list);
|
if let Some(npm) = npm_config {
|
||||||
|
commit_futures.push(npm.commit());
|
||||||
|
}
|
||||||
|
if let Some(deno) = deno_config {
|
||||||
|
commit_futures.push(deno.commit());
|
||||||
|
}
|
||||||
|
let commit_futures =
|
||||||
|
deno_core::futures::future::join_all(commit_futures).await;
|
||||||
|
|
||||||
let fmt_config_options = config_file.fmt_options();
|
for result in commit_futures {
|
||||||
|
result.context("Failed to update configuration file")?;
|
||||||
let new_text = update_config_file_content(
|
}
|
||||||
obj,
|
|
||||||
&config_file_contents,
|
|
||||||
generated_imports,
|
|
||||||
fmt_config_options,
|
|
||||||
config_file.imports_key(),
|
|
||||||
config_file.file_name(),
|
|
||||||
);
|
|
||||||
|
|
||||||
tokio::fs::write(&config_file_path, new_text)
|
|
||||||
.await
|
|
||||||
.context("Failed to update configuration file")?;
|
|
||||||
|
|
||||||
// clear the previously cached package.json from memory before reloading it
|
// clear the previously cached package.json from memory before reloading it
|
||||||
node_resolver::PackageJsonThreadLocalCache::clear();
|
node_resolver::PackageJsonThreadLocalCache::clear();
|
||||||
|
@ -501,14 +687,18 @@ impl AddPackageReq {
|
||||||
|
|
||||||
match prefix {
|
match prefix {
|
||||||
Prefix::Jsr => {
|
Prefix::Jsr => {
|
||||||
let package_req = PackageReq::from_str(entry_text)?;
|
let req_ref =
|
||||||
|
JsrPackageReqReference::from_str(&format!("jsr:{}", entry_text))?;
|
||||||
|
let package_req = req_ref.into_inner().req;
|
||||||
Ok(AddPackageReq {
|
Ok(AddPackageReq {
|
||||||
alias: maybe_alias.unwrap_or_else(|| package_req.name.to_string()),
|
alias: maybe_alias.unwrap_or_else(|| package_req.name.to_string()),
|
||||||
value: AddPackageReqValue::Jsr(package_req),
|
value: AddPackageReqValue::Jsr(package_req),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Prefix::Npm => {
|
Prefix::Npm => {
|
||||||
let package_req = PackageReq::from_str(entry_text)?;
|
let req_ref =
|
||||||
|
NpmPackageReqReference::from_str(&format!("npm:{}", entry_text))?;
|
||||||
|
let package_req = req_ref.into_inner().req;
|
||||||
Ok(AddPackageReq {
|
Ok(AddPackageReq {
|
||||||
alias: maybe_alias.unwrap_or_else(|| package_req.name.to_string()),
|
alias: maybe_alias.unwrap_or_else(|| package_req.name.to_string()),
|
||||||
value: AddPackageReqValue::Npm(package_req),
|
value: AddPackageReqValue::Npm(package_req),
|
||||||
|
@ -518,7 +708,8 @@ impl AddPackageReq {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_imports(packages_to_version: Vec<(String, String)>) -> String {
|
fn generate_imports(mut packages_to_version: Vec<(String, String)>) -> String {
|
||||||
|
packages_to_version.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
|
||||||
let mut contents = vec![];
|
let mut contents = vec![];
|
||||||
let len = packages_to_version.len();
|
let len = packages_to_version.len();
|
||||||
for (index, (package, version)) in packages_to_version.iter().enumerate() {
|
for (index, (package, version)) in packages_to_version.iter().enumerate() {
|
||||||
|
@ -531,68 +722,27 @@ fn generate_imports(packages_to_version: Vec<(String, String)>) -> String {
|
||||||
contents.join("\n")
|
contents.join("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_from_config(
|
|
||||||
config_path: &Path,
|
|
||||||
keys: &[&'static str],
|
|
||||||
packages_to_remove: &[String],
|
|
||||||
removed_packages: &mut Vec<String>,
|
|
||||||
fmt_options: &FmtOptionsConfig,
|
|
||||||
) -> Result<(), AnyError> {
|
|
||||||
let mut json: serde_json::Value =
|
|
||||||
serde_json::from_slice(&std::fs::read(config_path)?)?;
|
|
||||||
for key in keys {
|
|
||||||
let Some(obj) = json.get_mut(*key).and_then(|v| v.as_object_mut()) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
for package in packages_to_remove {
|
|
||||||
if obj.shift_remove(package).is_some() {
|
|
||||||
removed_packages.push(package.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let config = serde_json::to_string_pretty(&json)?;
|
|
||||||
let config =
|
|
||||||
crate::tools::fmt::format_json(config_path, &config, fmt_options)
|
|
||||||
.ok()
|
|
||||||
.flatten()
|
|
||||||
.unwrap_or(config);
|
|
||||||
|
|
||||||
std::fs::write(config_path, config)
|
|
||||||
.context("Failed to update configuration file")?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn remove(
|
pub async fn remove(
|
||||||
flags: Arc<Flags>,
|
flags: Arc<Flags>,
|
||||||
remove_flags: RemoveFlags,
|
remove_flags: RemoveFlags,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let (config_file, factory) = DenoOrPackageJson::from_flags(flags.clone())?;
|
let (_, npm_config, deno_config) = load_configs(&flags)?;
|
||||||
let options = factory.cli_options()?;
|
|
||||||
let start_dir = &options.start_dir;
|
|
||||||
let fmt_config_options = config_file.fmt_options();
|
|
||||||
|
|
||||||
let mut removed_packages = Vec::new();
|
let mut configs = [
|
||||||
|
ConfigUpdater::maybe_new(npm_config).await?,
|
||||||
|
ConfigUpdater::maybe_new(deno_config).await?,
|
||||||
|
];
|
||||||
|
|
||||||
if let Some(deno_json) = start_dir.maybe_deno_json() {
|
let mut removed_packages = vec![];
|
||||||
remove_from_config(
|
|
||||||
&deno_json.specifier.to_file_path().unwrap(),
|
for package in &remove_flags.packages {
|
||||||
&["imports"],
|
let mut removed = false;
|
||||||
&remove_flags.packages,
|
for config in configs.iter_mut().flatten() {
|
||||||
&mut removed_packages,
|
removed |= config.remove(package);
|
||||||
&fmt_config_options,
|
}
|
||||||
)?;
|
if removed {
|
||||||
|
removed_packages.push(package.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(pkg_json) = start_dir.maybe_pkg_json() {
|
|
||||||
remove_from_config(
|
|
||||||
&pkg_json.path,
|
|
||||||
&["dependencies", "devDependencies"],
|
|
||||||
&remove_flags.packages,
|
|
||||||
&mut removed_packages,
|
|
||||||
&fmt_config_options,
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if removed_packages.is_empty() {
|
if removed_packages.is_empty() {
|
||||||
|
@ -601,6 +751,10 @@ pub async fn remove(
|
||||||
for package in &removed_packages {
|
for package in &removed_packages {
|
||||||
log::info!("Removed {}", crate::colors::green(package));
|
log::info!("Removed {}", crate::colors::green(package));
|
||||||
}
|
}
|
||||||
|
for config in configs.into_iter().flatten() {
|
||||||
|
config.commit().await?;
|
||||||
|
}
|
||||||
|
|
||||||
// Update deno.lock
|
// Update deno.lock
|
||||||
node_resolver::PackageJsonThreadLocalCache::clear();
|
node_resolver::PackageJsonThreadLocalCache::clear();
|
||||||
let cli_factory = CliFactory::from_flags(flags);
|
let cli_factory = CliFactory::from_flags(flags);
|
||||||
|
@ -610,25 +764,54 @@ pub async fn remove(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_config_file_content(
|
fn update_config_file_content<
|
||||||
obj: jsonc_parser::ast::Object,
|
I: IntoIterator<Item = (&'static str, Option<String>)>,
|
||||||
|
>(
|
||||||
|
obj: &jsonc_parser::ast::Object,
|
||||||
config_file_contents: &str,
|
config_file_contents: &str,
|
||||||
generated_imports: String,
|
|
||||||
fmt_options: FmtOptionsConfig,
|
fmt_options: FmtOptionsConfig,
|
||||||
imports_key: &str,
|
entries: I,
|
||||||
file_name: &str,
|
file_name: &str,
|
||||||
) -> String {
|
) -> String {
|
||||||
let mut text_changes = vec![];
|
let mut text_changes = vec![];
|
||||||
|
for (key, value) in entries {
|
||||||
match obj.get(imports_key) {
|
match obj.properties.iter().enumerate().find_map(|(idx, k)| {
|
||||||
Some(ObjectProp {
|
if k.name.as_str() == key {
|
||||||
|
Some((idx, k))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Some((
|
||||||
|
idx,
|
||||||
|
ObjectProp {
|
||||||
value: Value::Object(lit),
|
value: Value::Object(lit),
|
||||||
|
range,
|
||||||
..
|
..
|
||||||
}) => text_changes.push(TextChange {
|
},
|
||||||
|
)) => {
|
||||||
|
if let Some(value) = value {
|
||||||
|
text_changes.push(TextChange {
|
||||||
range: (lit.range.start + 1)..(lit.range.end - 1),
|
range: (lit.range.start + 1)..(lit.range.end - 1),
|
||||||
new_text: generated_imports,
|
new_text: value,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
text_changes.push(TextChange {
|
||||||
|
// remove field entirely, making sure to
|
||||||
|
// remove the comma if it's not the last field
|
||||||
|
range: range.start..(if idx == obj.properties.len() - 1 {
|
||||||
|
range.end
|
||||||
|
} else {
|
||||||
|
obj.properties[idx + 1].range.start
|
||||||
}),
|
}),
|
||||||
|
new_text: "".to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// need to add field
|
||||||
None => {
|
None => {
|
||||||
|
if let Some(value) = value {
|
||||||
let insert_position = obj.range.end - 1;
|
let insert_position = obj.range.end - 1;
|
||||||
text_changes.push(TextChange {
|
text_changes.push(TextChange {
|
||||||
range: insert_position..insert_position,
|
range: insert_position..insert_position,
|
||||||
|
@ -640,12 +823,14 @@ fn update_config_file_content(
|
||||||
// "<package_name>": "<registry>:<package_name>@<semver>"
|
// "<package_name>": "<registry>:<package_name>@<semver>"
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
new_text: format!("\"{imports_key}\": {{\n {generated_imports} }}"),
|
new_text: format!("\"{key}\": {{\n {value} }}"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// we verified the shape of `imports`/`dependencies` above
|
// we verified the shape of `imports`/`dependencies` above
|
||||||
Some(_) => unreachable!(),
|
Some(_) => unreachable!(),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let new_text =
|
let new_text =
|
||||||
deno_ast::apply_text_changes(config_file_contents, text_changes);
|
deno_ast::apply_text_changes(config_file_contents, text_changes);
|
||||||
|
|
|
@ -229,16 +229,16 @@ impl Predicate {
|
||||||
struct ProvenanceAttestation {
|
struct ProvenanceAttestation {
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
_type: &'static str,
|
_type: &'static str,
|
||||||
subject: Subject,
|
subject: Vec<Subject>,
|
||||||
predicate_type: &'static str,
|
predicate_type: &'static str,
|
||||||
predicate: Predicate,
|
predicate: Predicate,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProvenanceAttestation {
|
impl ProvenanceAttestation {
|
||||||
pub fn new_github_actions(subject: Subject) -> Self {
|
pub fn new_github_actions(subjects: Vec<Subject>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
_type: INTOTO_STATEMENT_TYPE,
|
_type: INTOTO_STATEMENT_TYPE,
|
||||||
subject,
|
subject: subjects,
|
||||||
predicate_type: SLSA_PREDICATE_TYPE,
|
predicate_type: SLSA_PREDICATE_TYPE,
|
||||||
predicate: Predicate::new_github_actions(),
|
predicate: Predicate::new_github_actions(),
|
||||||
}
|
}
|
||||||
|
@ -296,7 +296,7 @@ pub struct ProvenanceBundle {
|
||||||
|
|
||||||
pub async fn generate_provenance(
|
pub async fn generate_provenance(
|
||||||
http_client: &HttpClient,
|
http_client: &HttpClient,
|
||||||
subject: Subject,
|
subjects: Vec<Subject>,
|
||||||
) -> Result<ProvenanceBundle, AnyError> {
|
) -> Result<ProvenanceBundle, AnyError> {
|
||||||
if !is_gha() {
|
if !is_gha() {
|
||||||
bail!("Automatic provenance is only available in GitHub Actions");
|
bail!("Automatic provenance is only available in GitHub Actions");
|
||||||
|
@ -308,7 +308,7 @@ pub async fn generate_provenance(
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
let slsa = ProvenanceAttestation::new_github_actions(subject);
|
let slsa = ProvenanceAttestation::new_github_actions(subjects);
|
||||||
|
|
||||||
let attestation = serde_json::to_string(&slsa)?;
|
let attestation = serde_json::to_string(&slsa)?;
|
||||||
let bundle = attest(http_client, &attestation, INTOTO_PAYLOAD_TYPE).await?;
|
let bundle = attest(http_client, &attestation, INTOTO_PAYLOAD_TYPE).await?;
|
||||||
|
@ -738,8 +738,13 @@ mod tests {
|
||||||
sha256: "yourmom".to_string(),
|
sha256: "yourmom".to_string(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let slsa = ProvenanceAttestation::new_github_actions(subject);
|
let slsa = ProvenanceAttestation::new_github_actions(vec![subject]);
|
||||||
assert_eq!(slsa.subject.name, "jsr:@divy/sdl2@0.0.1");
|
assert_eq!(
|
||||||
assert_eq!(slsa.subject.digest.sha256, "yourmom");
|
slsa.subject.len(),
|
||||||
|
1,
|
||||||
|
"Subject should be an array per the in-toto specification"
|
||||||
|
);
|
||||||
|
assert_eq!(slsa.subject[0].name, "jsr:@divy/sdl2@0.0.1");
|
||||||
|
assert_eq!(slsa.subject[0].digest.sha256, "yourmom");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use deno_config::deno_json::NodeModulesDirMode;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_runtime::deno_permissions::Permissions;
|
use deno_runtime::deno_permissions::Permissions;
|
||||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||||
|
@ -194,7 +195,9 @@ pub async fn eval_command(
|
||||||
pub async fn maybe_npm_install(factory: &CliFactory) -> Result<(), AnyError> {
|
pub async fn maybe_npm_install(factory: &CliFactory) -> Result<(), AnyError> {
|
||||||
// ensure an "npm install" is done if the user has explicitly
|
// ensure an "npm install" is done if the user has explicitly
|
||||||
// opted into using a managed node_modules directory
|
// opted into using a managed node_modules directory
|
||||||
if factory.cli_options()?.node_modules_dir_enablement() == Some(true) {
|
if factory.cli_options()?.node_modules_dir()?
|
||||||
|
== Some(NodeModulesDirMode::Auto)
|
||||||
|
{
|
||||||
if let Some(npm_resolver) = factory.npm_resolver().await?.as_managed() {
|
if let Some(npm_resolver) = factory.npm_resolver().await?.as_managed() {
|
||||||
npm_resolver.ensure_top_level_package_json_install().await?;
|
npm_resolver.ensure_top_level_package_json_install().await?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use crate::args::CliOptions;
|
use std::borrow::Cow;
|
||||||
use crate::args::Flags;
|
use std::collections::HashMap;
|
||||||
use crate::args::TaskFlags;
|
use std::collections::HashSet;
|
||||||
use crate::colors;
|
use std::path::Path;
|
||||||
use crate::factory::CliFactory;
|
use std::path::PathBuf;
|
||||||
use crate::npm::CliNpmResolver;
|
use std::rc::Rc;
|
||||||
use crate::task_runner;
|
use std::sync::Arc;
|
||||||
use crate::util::fs::canonicalize_path;
|
|
||||||
use deno_config::deno_json::Task;
|
use deno_config::deno_json::Task;
|
||||||
use deno_config::workspace::TaskOrScript;
|
use deno_config::workspace::TaskOrScript;
|
||||||
use deno_config::workspace::WorkspaceDirectory;
|
use deno_config::workspace::WorkspaceDirectory;
|
||||||
|
@ -18,13 +18,15 @@ use deno_core::anyhow::Context;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::normalize_path;
|
use deno_core::normalize_path;
|
||||||
use deno_task_shell::ShellCommand;
|
use deno_task_shell::ShellCommand;
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::collections::HashMap;
|
use crate::args::CliOptions;
|
||||||
use std::collections::HashSet;
|
use crate::args::Flags;
|
||||||
use std::path::Path;
|
use crate::args::TaskFlags;
|
||||||
use std::path::PathBuf;
|
use crate::colors;
|
||||||
use std::rc::Rc;
|
use crate::factory::CliFactory;
|
||||||
use std::sync::Arc;
|
use crate::npm::CliNpmResolver;
|
||||||
|
use crate::task_runner;
|
||||||
|
use crate::util::fs::canonicalize_path;
|
||||||
|
|
||||||
pub async fn execute_script(
|
pub async fn execute_script(
|
||||||
flags: Arc<Flags>,
|
flags: Arc<Flags>,
|
||||||
|
@ -106,13 +108,10 @@ See https://docs.deno.com/go/config"#
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
TaskOrScript::Script(scripts, _script) => {
|
TaskOrScript::Script(scripts, _script) => {
|
||||||
// ensure the npm packages are installed if using a node_modules
|
// ensure the npm packages are installed if using a managed resolver
|
||||||
// directory and managed resolver
|
|
||||||
if cli_options.has_node_modules_dir() {
|
|
||||||
if let Some(npm_resolver) = npm_resolver.as_managed() {
|
if let Some(npm_resolver) = npm_resolver.as_managed() {
|
||||||
npm_resolver.ensure_top_level_package_json_install().await?;
|
npm_resolver.ensure_top_level_package_json_install().await?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let cwd = match task_flags.cwd {
|
let cwd = match task_flags.cwd {
|
||||||
Some(path) => canonicalize_path(&PathBuf::from(path))?,
|
Some(path) => canonicalize_path(&PathBuf::from(path))?,
|
||||||
|
|
|
@ -319,14 +319,11 @@ pub const OP_DETAILS: phf::Map<&'static str, [&'static str; 2]> = phf_map! {
|
||||||
"op_fs_copy_file_async" => ["copy a file", "awaiting the result of a `Deno.copyFile` call"],
|
"op_fs_copy_file_async" => ["copy a file", "awaiting the result of a `Deno.copyFile` call"],
|
||||||
"op_fs_events_poll" => ["get the next file system event", "breaking out of a for await loop looping over `Deno.FsEvents`"],
|
"op_fs_events_poll" => ["get the next file system event", "breaking out of a for await loop looping over `Deno.FsEvents`"],
|
||||||
"op_fs_fdatasync_async" => ["flush pending data operations for a file to disk", "awaiting the result of a `Deno.fdatasync` or `Deno.FsFile.syncData` call"],
|
"op_fs_fdatasync_async" => ["flush pending data operations for a file to disk", "awaiting the result of a `Deno.fdatasync` or `Deno.FsFile.syncData` call"],
|
||||||
"op_fs_file_stat_async" => ["get file metadata", "awaiting the result of a `Deno.fstat` or `Deno.FsFile.stat` call"],
|
"op_fs_file_stat_async" => ["get file metadata", "awaiting the result of a `Deno.FsFile.prototype.stat` call"],
|
||||||
"op_fs_flock_async_unstable" => ["lock a file", "awaiting the result of a `Deno.flock` call"],
|
|
||||||
"op_fs_flock_async" => ["lock a file", "awaiting the result of a `Deno.FsFile.lock` call"],
|
"op_fs_flock_async" => ["lock a file", "awaiting the result of a `Deno.FsFile.lock` call"],
|
||||||
"op_fs_fsync_async" => ["flush pending data operations for a file to disk", "awaiting the result of a `Deno.fsync` or `Deno.FsFile.sync` call"],
|
"op_fs_fsync_async" => ["flush pending data operations for a file to disk", "awaiting the result of a `Deno.fsync` or `Deno.FsFile.sync` call"],
|
||||||
"op_fs_ftruncate_async" => ["truncate a file", "awaiting the result of a `Deno.ftruncate` or `Deno.FsFile.truncate` call"],
|
"op_fs_file_truncate_async" => ["truncate a file", "awaiting the result of a `Deno.FsFile.prototype.truncate` call"],
|
||||||
"op_fs_funlock_async_unstable" => ["unlock a file", "awaiting the result of a `Deno.funlock` call"],
|
|
||||||
"op_fs_funlock_async" => ["unlock a file", "awaiting the result of a `Deno.FsFile.unlock` call"],
|
"op_fs_funlock_async" => ["unlock a file", "awaiting the result of a `Deno.FsFile.unlock` call"],
|
||||||
"op_fs_futime_async" => ["change file timestamps", "awaiting the result of a `Deno.futime` or `Deno.FsFile.utime` call"],
|
|
||||||
"op_fs_link_async" => ["create a hard link", "awaiting the result of a `Deno.link` call"],
|
"op_fs_link_async" => ["create a hard link", "awaiting the result of a `Deno.link` call"],
|
||||||
"op_fs_lstat_async" => ["get file metadata", "awaiting the result of a `Deno.lstat` call"],
|
"op_fs_lstat_async" => ["get file metadata", "awaiting the result of a `Deno.lstat` call"],
|
||||||
"op_fs_make_temp_dir_async" => ["create a temporary directory", "awaiting the result of a `Deno.makeTempDir` call"],
|
"op_fs_make_temp_dir_async" => ["create a temporary directory", "awaiting the result of a `Deno.makeTempDir` call"],
|
||||||
|
@ -340,7 +337,7 @@ pub const OP_DETAILS: phf::Map<&'static str, [&'static str; 2]> = phf_map! {
|
||||||
"op_fs_realpath_async" => ["resolve a path", "awaiting the result of a `Deno.realpath` call"],
|
"op_fs_realpath_async" => ["resolve a path", "awaiting the result of a `Deno.realpath` call"],
|
||||||
"op_fs_remove_async" => ["remove a file or directory", "awaiting the result of a `Deno.remove` call"],
|
"op_fs_remove_async" => ["remove a file or directory", "awaiting the result of a `Deno.remove` call"],
|
||||||
"op_fs_rename_async" => ["rename a file or directory", "awaiting the result of a `Deno.rename` call"],
|
"op_fs_rename_async" => ["rename a file or directory", "awaiting the result of a `Deno.rename` call"],
|
||||||
"op_fs_seek_async" => ["seek in a file", "awaiting the result of a `Deno.seek` or `Deno.FsFile.seek` call"],
|
"op_fs_seek_async" => ["seek in a file", "awaiting the result of a `Deno.FsFile.prototype.seek` call"],
|
||||||
"op_fs_stat_async" => ["get file metadata", "awaiting the result of a `Deno.stat` call"],
|
"op_fs_stat_async" => ["get file metadata", "awaiting the result of a `Deno.stat` call"],
|
||||||
"op_fs_symlink_async" => ["create a symlink", "awaiting the result of a `Deno.symlink` call"],
|
"op_fs_symlink_async" => ["create a symlink", "awaiting the result of a `Deno.symlink` call"],
|
||||||
"op_fs_truncate_async" => ["truncate a file", "awaiting the result of a `Deno.truncate` call"],
|
"op_fs_truncate_async" => ["truncate a file", "awaiting the result of a `Deno.truncate` call"],
|
||||||
|
|
|
@ -1778,7 +1778,8 @@ pub async fn run_tests(
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if !workspace_test_options.allow_none && specifiers_with_mode.is_empty() {
|
if !workspace_test_options.permit_no_files && specifiers_with_mode.is_empty()
|
||||||
|
{
|
||||||
return Err(generic_error("No test modules found"));
|
return Err(generic_error("No test modules found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ use crate::util::progress_bar::ProgressBarStyle;
|
||||||
use crate::version;
|
use crate::version;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use color_print::cstr;
|
||||||
use deno_core::anyhow::bail;
|
use deno_core::anyhow::bail;
|
||||||
use deno_core::anyhow::Context;
|
use deno_core::anyhow::Context;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
|
@ -37,6 +38,8 @@ const RELEASE_URL: &str = "https://github.com/denoland/deno/releases";
|
||||||
const CANARY_URL: &str = "https://dl.deno.land/canary";
|
const CANARY_URL: &str = "https://dl.deno.land/canary";
|
||||||
const RC_URL: &str = "https://dl.deno.land/release";
|
const RC_URL: &str = "https://dl.deno.land/release";
|
||||||
|
|
||||||
|
static EXAMPLE_USAGE: &str = cstr!("Example usage:\n <p(245)>deno upgrade | deno upgrade 1.46 | deno upgrade canary</>");
|
||||||
|
|
||||||
pub static ARCHIVE_NAME: Lazy<String> =
|
pub static ARCHIVE_NAME: Lazy<String> =
|
||||||
Lazy::new(|| format!("deno-{}.zip", env!("TARGET")));
|
Lazy::new(|| format!("deno-{}.zip", env!("TARGET")));
|
||||||
|
|
||||||
|
@ -226,15 +229,70 @@ impl<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_minor_version(version: &str) -> &str {
|
fn get_minor_version_blog_post_url(semver: &Version) -> String {
|
||||||
version.rsplitn(2, '.').collect::<Vec<&str>>()[1]
|
format!("https://deno.com/blog/v{}.{}", semver.major, semver.minor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_release_notes(current_version: &str, new_version: &str) {
|
fn get_rc_version_blog_post_url(semver: &Version) -> String {
|
||||||
// TODO(bartlomieju): we might want to reconsider this one for RC releases.
|
format!(
|
||||||
// TODO(bartlomieju): also maybe just parse using `Version::standard` instead
|
"https://deno.com/blog/v{}.{}-rc-{}",
|
||||||
// of using `get_minor_version`?
|
semver.major, semver.minor, semver.pre[1]
|
||||||
if get_minor_version(current_version) == get_minor_version(new_version) {
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn print_release_notes(
|
||||||
|
current_version: &str,
|
||||||
|
new_version: &str,
|
||||||
|
client: &HttpClient,
|
||||||
|
) {
|
||||||
|
let Ok(current_semver) = Version::parse_standard(current_version) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Ok(new_semver) = Version::parse_standard(new_version) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let is_switching_from_deno1_to_deno2 =
|
||||||
|
new_semver.major == 2 && current_semver.major == 1;
|
||||||
|
let is_deno_2_rc = new_semver.major == 2
|
||||||
|
&& new_semver.minor == 0
|
||||||
|
&& new_semver.patch == 0
|
||||||
|
&& new_semver.pre.first() == Some(&"rc".to_string());
|
||||||
|
|
||||||
|
if is_deno_2_rc || is_switching_from_deno1_to_deno2 {
|
||||||
|
log::info!(
|
||||||
|
"{}\n\n {}\n",
|
||||||
|
colors::gray("Migration guide:"),
|
||||||
|
colors::bold(
|
||||||
|
"https://docs.deno.com/runtime/manual/advanced/migrate_deprecations"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_deno_2_rc {
|
||||||
|
log::info!(
|
||||||
|
"{}\n\n {}\n",
|
||||||
|
colors::gray("If you find a bug, please report to:"),
|
||||||
|
colors::bold("https://github.com/denoland/deno/issues/new")
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if there's blog post entry for this release
|
||||||
|
let blog_url_str = get_rc_version_blog_post_url(&new_semver);
|
||||||
|
let blog_url = Url::parse(&blog_url_str).unwrap();
|
||||||
|
if client.download(blog_url).await.is_ok() {
|
||||||
|
log::info!(
|
||||||
|
"{}\n\n {}\n",
|
||||||
|
colors::gray("Blog post:"),
|
||||||
|
colors::bold(blog_url_str)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let should_print = current_semver.major != new_semver.major
|
||||||
|
|| current_semver.minor != new_semver.minor;
|
||||||
|
|
||||||
|
if !should_print {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,10 +307,7 @@ fn print_release_notes(current_version: &str, new_version: &str) {
|
||||||
log::info!(
|
log::info!(
|
||||||
"{}\n\n {}\n",
|
"{}\n\n {}\n",
|
||||||
colors::gray("Blog post:"),
|
colors::gray("Blog post:"),
|
||||||
colors::bold(format!(
|
colors::bold(get_minor_version_blog_post_url(&new_semver))
|
||||||
"https://deno.com/blog/v{}",
|
|
||||||
get_minor_version(new_version)
|
|
||||||
))
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,14 +375,14 @@ pub fn check_for_upgrades(
|
||||||
log::info!(
|
log::info!(
|
||||||
"{} {}",
|
"{} {}",
|
||||||
colors::green("A new canary release of Deno is available."),
|
colors::green("A new canary release of Deno is available."),
|
||||||
colors::italic_gray("Run `deno upgrade --canary` to install it.")
|
colors::italic_gray("Run `deno upgrade canary` to install it.")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ReleaseChannel::Rc => {
|
ReleaseChannel::Rc => {
|
||||||
log::info!(
|
log::info!(
|
||||||
"{} {}",
|
"{} {}",
|
||||||
colors::green("A new release candidate of Deno is available."),
|
colors::green("A new release candidate of Deno is available."),
|
||||||
colors::italic_gray("Run `deno upgrade --rc` to install it.")
|
colors::italic_gray("Run `deno upgrade rc` to install it.")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// TODO(bartlomieju)
|
// TODO(bartlomieju)
|
||||||
|
@ -512,7 +567,9 @@ pub async fn upgrade(
|
||||||
print_release_notes(
|
print_release_notes(
|
||||||
version::DENO_VERSION_INFO.deno,
|
version::DENO_VERSION_INFO.deno,
|
||||||
&selected_version_to_upgrade.version_or_hash,
|
&selected_version_to_upgrade.version_or_hash,
|
||||||
);
|
&client,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
drop(temp_dir);
|
drop(temp_dir);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -540,7 +597,9 @@ pub async fn upgrade(
|
||||||
print_release_notes(
|
print_release_notes(
|
||||||
version::DENO_VERSION_INFO.deno,
|
version::DENO_VERSION_INFO.deno,
|
||||||
&selected_version_to_upgrade.version_or_hash,
|
&selected_version_to_upgrade.version_or_hash,
|
||||||
);
|
&client,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(temp_dir); // delete the temp dir
|
drop(temp_dir); // delete the temp dir
|
||||||
|
@ -591,12 +650,20 @@ impl RequestedVersion {
|
||||||
|
|
||||||
let (channel, passed_version) = if is_canary {
|
let (channel, passed_version) = if is_canary {
|
||||||
if !re_hash.is_match(&passed_version) {
|
if !re_hash.is_match(&passed_version) {
|
||||||
bail!("Invalid commit hash passed");
|
bail!(
|
||||||
|
"Invalid commit hash passed ({})\n\n{}",
|
||||||
|
colors::gray(passed_version),
|
||||||
|
EXAMPLE_USAGE
|
||||||
|
);
|
||||||
}
|
}
|
||||||
(ReleaseChannel::Canary, passed_version)
|
(ReleaseChannel::Canary, passed_version)
|
||||||
} else {
|
} else {
|
||||||
let Ok(semver) = Version::parse_standard(&passed_version) else {
|
let Ok(semver) = Version::parse_standard(&passed_version) else {
|
||||||
bail!("Invalid version passed");
|
bail!(
|
||||||
|
"Invalid version passed ({})\n\n{}",
|
||||||
|
colors::gray(passed_version),
|
||||||
|
EXAMPLE_USAGE
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
if semver.pre.contains(&"rc".to_string()) {
|
if semver.pre.contains(&"rc".to_string()) {
|
||||||
|
@ -1692,4 +1759,31 @@ mod test {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn blog_post_links() {
|
||||||
|
let version = Version::parse_standard("1.46.0").unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
get_minor_version_blog_post_url(&version),
|
||||||
|
"https://deno.com/blog/v1.46"
|
||||||
|
);
|
||||||
|
|
||||||
|
let version = Version::parse_standard("2.1.1").unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
get_minor_version_blog_post_url(&version),
|
||||||
|
"https://deno.com/blog/v2.1"
|
||||||
|
);
|
||||||
|
|
||||||
|
let version = Version::parse_standard("2.0.0-rc.0").unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
get_rc_version_blog_post_url(&version),
|
||||||
|
"https://deno.com/blog/v2.0-rc-0"
|
||||||
|
);
|
||||||
|
|
||||||
|
let version = Version::parse_standard("2.0.0-rc.2").unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
get_rc_version_blog_post_url(&version),
|
||||||
|
"https://deno.com/blog/v2.0-rc-2"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
113
cli/tools/vendor/analyze.rs
vendored
113
cli/tools/vendor/analyze.rs
vendored
|
@ -1,113 +0,0 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
|
||||||
|
|
||||||
use deno_ast::swc::ast::ExportDefaultDecl;
|
|
||||||
use deno_ast::swc::ast::ExportSpecifier;
|
|
||||||
use deno_ast::swc::ast::ModuleExportName;
|
|
||||||
use deno_ast::swc::ast::NamedExport;
|
|
||||||
use deno_ast::swc::ast::Program;
|
|
||||||
use deno_ast::swc::visit::noop_visit_type;
|
|
||||||
use deno_ast::swc::visit::Visit;
|
|
||||||
use deno_ast::swc::visit::VisitWith;
|
|
||||||
use deno_ast::ParsedSource;
|
|
||||||
|
|
||||||
/// Gets if the parsed source has a default export.
|
|
||||||
pub fn has_default_export(source: &ParsedSource) -> bool {
|
|
||||||
let mut visitor = DefaultExportFinder {
|
|
||||||
has_default_export: false,
|
|
||||||
};
|
|
||||||
let program = source.program();
|
|
||||||
let program: &Program = &program;
|
|
||||||
program.visit_with(&mut visitor);
|
|
||||||
visitor.has_default_export
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DefaultExportFinder {
|
|
||||||
has_default_export: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Visit for DefaultExportFinder {
|
|
||||||
noop_visit_type!();
|
|
||||||
|
|
||||||
fn visit_export_default_decl(&mut self, _: &ExportDefaultDecl) {
|
|
||||||
self.has_default_export = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_named_export(&mut self, named_export: &NamedExport) {
|
|
||||||
if named_export
|
|
||||||
.specifiers
|
|
||||||
.iter()
|
|
||||||
.any(export_specifier_has_default)
|
|
||||||
{
|
|
||||||
self.has_default_export = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn export_specifier_has_default(s: &ExportSpecifier) -> bool {
|
|
||||||
match s {
|
|
||||||
ExportSpecifier::Default(_) => true,
|
|
||||||
ExportSpecifier::Namespace(_) => false,
|
|
||||||
ExportSpecifier::Named(named) => {
|
|
||||||
let export_name = named.exported.as_ref().unwrap_or(&named.orig);
|
|
||||||
|
|
||||||
match export_name {
|
|
||||||
ModuleExportName::Str(_) => false,
|
|
||||||
ModuleExportName::Ident(ident) => &*ident.sym == "default",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use deno_ast::MediaType;
|
|
||||||
use deno_ast::ModuleSpecifier;
|
|
||||||
use deno_ast::ParseParams;
|
|
||||||
use deno_ast::ParsedSource;
|
|
||||||
|
|
||||||
use super::has_default_export;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn has_default_when_export_default_decl() {
|
|
||||||
let parsed_source = parse_module("export default class Class {}");
|
|
||||||
assert!(has_default_export(&parsed_source));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn has_default_when_named_export() {
|
|
||||||
let parsed_source = parse_module("export {default} from './test.ts';");
|
|
||||||
assert!(has_default_export(&parsed_source));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn has_default_when_named_export_alias() {
|
|
||||||
let parsed_source =
|
|
||||||
parse_module("export {test as default} from './test.ts';");
|
|
||||||
assert!(has_default_export(&parsed_source));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn not_has_default_when_named_export_not_exported() {
|
|
||||||
let parsed_source =
|
|
||||||
parse_module("export {default as test} from './test.ts';");
|
|
||||||
assert!(!has_default_export(&parsed_source));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn not_has_default_when_not() {
|
|
||||||
let parsed_source = parse_module("export {test} from './test.ts'; export class Test{} export * from './test';");
|
|
||||||
assert!(!has_default_export(&parsed_source));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_module(text: &str) -> ParsedSource {
|
|
||||||
deno_ast::parse_module(ParseParams {
|
|
||||||
specifier: ModuleSpecifier::parse("file:///mod.ts").unwrap(),
|
|
||||||
capture_tokens: false,
|
|
||||||
maybe_syntax: None,
|
|
||||||
media_type: MediaType::TypeScript,
|
|
||||||
scope_analysis: false,
|
|
||||||
text: text.into(),
|
|
||||||
})
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
1330
cli/tools/vendor/build.rs
vendored
1330
cli/tools/vendor/build.rs
vendored
File diff suppressed because it is too large
Load diff
508
cli/tools/vendor/import_map.rs
vendored
508
cli/tools/vendor/import_map.rs
vendored
|
@ -1,508 +0,0 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
|
||||||
|
|
||||||
use deno_ast::LineAndColumnIndex;
|
|
||||||
use deno_ast::ModuleSpecifier;
|
|
||||||
use deno_ast::SourceTextInfo;
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_graph::source::ResolutionMode;
|
|
||||||
use deno_graph::Module;
|
|
||||||
use deno_graph::ModuleGraph;
|
|
||||||
use deno_graph::Position;
|
|
||||||
use deno_graph::Range;
|
|
||||||
use deno_graph::Resolution;
|
|
||||||
use import_map::ImportMap;
|
|
||||||
use import_map::SpecifierMap;
|
|
||||||
use indexmap::IndexMap;
|
|
||||||
use log::warn;
|
|
||||||
|
|
||||||
use crate::args::JsxImportSourceConfig;
|
|
||||||
use crate::cache::ParsedSourceCache;
|
|
||||||
|
|
||||||
use super::mappings::Mappings;
|
|
||||||
use super::specifiers::is_remote_specifier;
|
|
||||||
use super::specifiers::is_remote_specifier_text;
|
|
||||||
|
|
||||||
struct ImportMapBuilder<'a> {
|
|
||||||
base_dir: &'a ModuleSpecifier,
|
|
||||||
mappings: &'a Mappings,
|
|
||||||
imports: ImportsBuilder<'a>,
|
|
||||||
scopes: IndexMap<String, ImportsBuilder<'a>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ImportMapBuilder<'a> {
|
|
||||||
pub fn new(base_dir: &'a ModuleSpecifier, mappings: &'a Mappings) -> Self {
|
|
||||||
ImportMapBuilder {
|
|
||||||
base_dir,
|
|
||||||
mappings,
|
|
||||||
imports: ImportsBuilder::new(base_dir, mappings),
|
|
||||||
scopes: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn base_dir(&self) -> &ModuleSpecifier {
|
|
||||||
self.base_dir
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn scope(
|
|
||||||
&mut self,
|
|
||||||
base_specifier: &ModuleSpecifier,
|
|
||||||
) -> &mut ImportsBuilder<'a> {
|
|
||||||
self
|
|
||||||
.scopes
|
|
||||||
.entry(
|
|
||||||
self
|
|
||||||
.mappings
|
|
||||||
.relative_specifier_text(self.base_dir, base_specifier),
|
|
||||||
)
|
|
||||||
.or_insert_with(|| ImportsBuilder::new(self.base_dir, self.mappings))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_import_map(
|
|
||||||
self,
|
|
||||||
maybe_original_import_map: Option<&ImportMap>,
|
|
||||||
) -> ImportMap {
|
|
||||||
fn get_local_imports(
|
|
||||||
new_relative_path: &str,
|
|
||||||
original_imports: &SpecifierMap,
|
|
||||||
) -> Vec<(String, String)> {
|
|
||||||
let mut result = Vec::new();
|
|
||||||
for entry in original_imports.entries() {
|
|
||||||
if let Some(raw_value) = entry.raw_value {
|
|
||||||
if raw_value.starts_with("./") || raw_value.starts_with("../") {
|
|
||||||
let sub_index = raw_value.find('/').unwrap() + 1;
|
|
||||||
result.push((
|
|
||||||
entry.raw_key.to_string(),
|
|
||||||
format!("{}{}", new_relative_path, &raw_value[sub_index..]),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_local_imports<'a>(
|
|
||||||
new_relative_path: &str,
|
|
||||||
original_imports: &SpecifierMap,
|
|
||||||
get_new_imports: impl FnOnce() -> &'a mut SpecifierMap,
|
|
||||||
) {
|
|
||||||
let local_imports =
|
|
||||||
get_local_imports(new_relative_path, original_imports);
|
|
||||||
if !local_imports.is_empty() {
|
|
||||||
let new_imports = get_new_imports();
|
|
||||||
for (key, value) in local_imports {
|
|
||||||
if let Err(warning) = new_imports.append(key, value) {
|
|
||||||
warn!("{}", warning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut import_map = ImportMap::new(self.base_dir.clone());
|
|
||||||
|
|
||||||
if let Some(original_im) = maybe_original_import_map {
|
|
||||||
let original_base_dir = ModuleSpecifier::from_directory_path(
|
|
||||||
original_im
|
|
||||||
.base_url()
|
|
||||||
.to_file_path()
|
|
||||||
.unwrap()
|
|
||||||
.parent()
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let new_relative_path = self
|
|
||||||
.mappings
|
|
||||||
.relative_specifier_text(self.base_dir, &original_base_dir);
|
|
||||||
// add the imports
|
|
||||||
add_local_imports(&new_relative_path, original_im.imports(), || {
|
|
||||||
import_map.imports_mut()
|
|
||||||
});
|
|
||||||
|
|
||||||
for scope in original_im.scopes() {
|
|
||||||
if scope.raw_key.starts_with("./") || scope.raw_key.starts_with("../") {
|
|
||||||
let sub_index = scope.raw_key.find('/').unwrap() + 1;
|
|
||||||
let new_key =
|
|
||||||
format!("{}{}", new_relative_path, &scope.raw_key[sub_index..]);
|
|
||||||
add_local_imports(&new_relative_path, scope.imports, || {
|
|
||||||
import_map.get_or_append_scope_mut(&new_key).unwrap()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let imports = import_map.imports_mut();
|
|
||||||
for (key, value) in self.imports.imports {
|
|
||||||
if !imports.contains(&key) {
|
|
||||||
imports.append(key, value).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (scope_key, scope_value) in self.scopes {
|
|
||||||
if !scope_value.imports.is_empty() {
|
|
||||||
let imports = import_map.get_or_append_scope_mut(&scope_key).unwrap();
|
|
||||||
for (key, value) in scope_value.imports {
|
|
||||||
if !imports.contains(&key) {
|
|
||||||
imports.append(key, value).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
import_map
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ImportsBuilder<'a> {
|
|
||||||
base_dir: &'a ModuleSpecifier,
|
|
||||||
mappings: &'a Mappings,
|
|
||||||
imports: IndexMap<String, String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ImportsBuilder<'a> {
|
|
||||||
pub fn new(base_dir: &'a ModuleSpecifier, mappings: &'a Mappings) -> Self {
|
|
||||||
Self {
|
|
||||||
base_dir,
|
|
||||||
mappings,
|
|
||||||
imports: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add(&mut self, key: String, specifier: &ModuleSpecifier) {
|
|
||||||
let value = self
|
|
||||||
.mappings
|
|
||||||
.relative_specifier_text(self.base_dir, specifier);
|
|
||||||
|
|
||||||
// skip creating identity entries
|
|
||||||
if key != value {
|
|
||||||
self.imports.insert(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct BuildImportMapInput<'a> {
|
|
||||||
pub base_dir: &'a ModuleSpecifier,
|
|
||||||
pub modules: &'a [&'a Module],
|
|
||||||
pub graph: &'a ModuleGraph,
|
|
||||||
pub mappings: &'a Mappings,
|
|
||||||
pub maybe_original_import_map: Option<&'a ImportMap>,
|
|
||||||
pub maybe_jsx_import_source: Option<&'a JsxImportSourceConfig>,
|
|
||||||
pub resolver: &'a dyn deno_graph::source::Resolver,
|
|
||||||
pub parsed_source_cache: &'a ParsedSourceCache,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build_import_map(
|
|
||||||
input: BuildImportMapInput<'_>,
|
|
||||||
) -> Result<String, AnyError> {
|
|
||||||
let BuildImportMapInput {
|
|
||||||
base_dir,
|
|
||||||
modules,
|
|
||||||
graph,
|
|
||||||
mappings,
|
|
||||||
maybe_original_import_map,
|
|
||||||
maybe_jsx_import_source,
|
|
||||||
resolver,
|
|
||||||
parsed_source_cache,
|
|
||||||
} = input;
|
|
||||||
let mut builder = ImportMapBuilder::new(base_dir, mappings);
|
|
||||||
visit_modules(graph, modules, mappings, &mut builder, parsed_source_cache)?;
|
|
||||||
|
|
||||||
for base_specifier in mappings.base_specifiers() {
|
|
||||||
builder
|
|
||||||
.imports
|
|
||||||
.add(base_specifier.to_string(), base_specifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the jsx import source to the destination import map, if mapped in the original import map
|
|
||||||
if let Some(jsx_import_source) = maybe_jsx_import_source {
|
|
||||||
if let Some(specifier_text) = jsx_import_source.maybe_specifier_text() {
|
|
||||||
if let Ok(resolved_url) = resolver.resolve(
|
|
||||||
&specifier_text,
|
|
||||||
&deno_graph::Range {
|
|
||||||
specifier: jsx_import_source.base_url.clone(),
|
|
||||||
start: deno_graph::Position::zeroed(),
|
|
||||||
end: deno_graph::Position::zeroed(),
|
|
||||||
},
|
|
||||||
ResolutionMode::Execution,
|
|
||||||
) {
|
|
||||||
builder.imports.add(specifier_text, &resolved_url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(builder.into_import_map(maybe_original_import_map).to_json())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_modules(
|
|
||||||
graph: &ModuleGraph,
|
|
||||||
modules: &[&Module],
|
|
||||||
mappings: &Mappings,
|
|
||||||
import_map: &mut ImportMapBuilder,
|
|
||||||
parsed_source_cache: &ParsedSourceCache,
|
|
||||||
) -> Result<(), AnyError> {
|
|
||||||
for module in modules {
|
|
||||||
let module = match module {
|
|
||||||
Module::Js(module) => module,
|
|
||||||
// skip visiting Json modules as they are leaves
|
|
||||||
Module::Json(_)
|
|
||||||
| Module::Npm(_)
|
|
||||||
| Module::Node(_)
|
|
||||||
| Module::External(_) => continue,
|
|
||||||
};
|
|
||||||
|
|
||||||
let parsed_source =
|
|
||||||
parsed_source_cache.get_parsed_source_from_js_module(module)?;
|
|
||||||
let text_info = parsed_source.text_info_lazy().clone();
|
|
||||||
|
|
||||||
for dep in module.dependencies.values() {
|
|
||||||
visit_resolution(
|
|
||||||
&dep.maybe_code,
|
|
||||||
graph,
|
|
||||||
import_map,
|
|
||||||
&module.specifier,
|
|
||||||
mappings,
|
|
||||||
&text_info,
|
|
||||||
&module.source,
|
|
||||||
);
|
|
||||||
visit_resolution(
|
|
||||||
&dep.maybe_type,
|
|
||||||
graph,
|
|
||||||
import_map,
|
|
||||||
&module.specifier,
|
|
||||||
mappings,
|
|
||||||
&text_info,
|
|
||||||
&module.source,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(types_dep) = &module.maybe_types_dependency {
|
|
||||||
visit_resolution(
|
|
||||||
&types_dep.dependency,
|
|
||||||
graph,
|
|
||||||
import_map,
|
|
||||||
&module.specifier,
|
|
||||||
mappings,
|
|
||||||
&text_info,
|
|
||||||
&module.source,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_resolution(
|
|
||||||
resolution: &Resolution,
|
|
||||||
graph: &ModuleGraph,
|
|
||||||
import_map: &mut ImportMapBuilder,
|
|
||||||
referrer: &ModuleSpecifier,
|
|
||||||
mappings: &Mappings,
|
|
||||||
text_info: &SourceTextInfo,
|
|
||||||
source_text: &str,
|
|
||||||
) {
|
|
||||||
if let Some(resolved) = resolution.ok() {
|
|
||||||
let text = text_from_range(text_info, source_text, &resolved.range);
|
|
||||||
// if the text is empty then it's probably an x-TypeScript-types
|
|
||||||
if !text.is_empty() {
|
|
||||||
handle_dep_specifier(
|
|
||||||
text,
|
|
||||||
&resolved.specifier,
|
|
||||||
graph,
|
|
||||||
import_map,
|
|
||||||
referrer,
|
|
||||||
mappings,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_dep_specifier(
|
|
||||||
text: &str,
|
|
||||||
unresolved_specifier: &ModuleSpecifier,
|
|
||||||
graph: &ModuleGraph,
|
|
||||||
import_map: &mut ImportMapBuilder,
|
|
||||||
referrer: &ModuleSpecifier,
|
|
||||||
mappings: &Mappings,
|
|
||||||
) {
|
|
||||||
let specifier = match graph.get(unresolved_specifier) {
|
|
||||||
Some(module) => module.specifier().clone(),
|
|
||||||
// Ignore when None. The graph was previous validated so this is a
|
|
||||||
// dynamic import that was missing and is ignored for vendoring
|
|
||||||
None => return,
|
|
||||||
};
|
|
||||||
// check if it's referencing a remote module
|
|
||||||
if is_remote_specifier(&specifier) {
|
|
||||||
handle_remote_dep_specifier(
|
|
||||||
text,
|
|
||||||
unresolved_specifier,
|
|
||||||
&specifier,
|
|
||||||
import_map,
|
|
||||||
referrer,
|
|
||||||
mappings,
|
|
||||||
)
|
|
||||||
} else if specifier.scheme() == "file" {
|
|
||||||
handle_local_dep_specifier(
|
|
||||||
text,
|
|
||||||
unresolved_specifier,
|
|
||||||
&specifier,
|
|
||||||
import_map,
|
|
||||||
referrer,
|
|
||||||
mappings,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_remote_dep_specifier(
|
|
||||||
text: &str,
|
|
||||||
unresolved_specifier: &ModuleSpecifier,
|
|
||||||
specifier: &ModuleSpecifier,
|
|
||||||
import_map: &mut ImportMapBuilder,
|
|
||||||
referrer: &ModuleSpecifier,
|
|
||||||
mappings: &Mappings,
|
|
||||||
) {
|
|
||||||
if is_remote_specifier_text(text) {
|
|
||||||
let base_specifier = mappings.base_specifier(specifier);
|
|
||||||
if text.starts_with(base_specifier.as_str()) {
|
|
||||||
let sub_path = &text[base_specifier.as_str().len()..];
|
|
||||||
let relative_text =
|
|
||||||
mappings.relative_specifier_text(base_specifier, specifier);
|
|
||||||
let expected_sub_path = relative_text.trim_start_matches("./");
|
|
||||||
if expected_sub_path != sub_path {
|
|
||||||
import_map.imports.add(text.to_string(), specifier);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// it's probably a redirect. Add it explicitly to the import map
|
|
||||||
import_map.imports.add(text.to_string(), specifier);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let expected_relative_specifier_text =
|
|
||||||
mappings.relative_specifier_text(referrer, specifier);
|
|
||||||
if expected_relative_specifier_text == text {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !is_remote_specifier(referrer) {
|
|
||||||
// local module referencing a remote module using
|
|
||||||
// non-remote specifier text means it was something in
|
|
||||||
// the original import map, so add a mapping to it
|
|
||||||
import_map.imports.add(text.to_string(), specifier);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let base_referrer = mappings.base_specifier(referrer);
|
|
||||||
let base_dir = import_map.base_dir().clone();
|
|
||||||
let imports = import_map.scope(base_referrer);
|
|
||||||
if text.starts_with("./") || text.starts_with("../") {
|
|
||||||
// resolve relative specifier key
|
|
||||||
let mut local_base_specifier = mappings.local_uri(base_referrer);
|
|
||||||
local_base_specifier = local_base_specifier
|
|
||||||
// path includes "/" so make it relative
|
|
||||||
.join(&format!(".{}", unresolved_specifier.path()))
|
|
||||||
.unwrap_or_else(|_| {
|
|
||||||
panic!(
|
|
||||||
"Error joining {} to {}",
|
|
||||||
unresolved_specifier.path(),
|
|
||||||
local_base_specifier
|
|
||||||
)
|
|
||||||
});
|
|
||||||
local_base_specifier.set_query(unresolved_specifier.query());
|
|
||||||
|
|
||||||
imports.add(
|
|
||||||
mappings.relative_specifier_text(&base_dir, &local_base_specifier),
|
|
||||||
specifier,
|
|
||||||
);
|
|
||||||
|
|
||||||
// add a mapping that uses the local directory name and the remote
|
|
||||||
// filename in order to support files importing this relatively
|
|
||||||
imports.add(
|
|
||||||
{
|
|
||||||
let local_path = mappings.local_path(specifier);
|
|
||||||
let mut value =
|
|
||||||
ModuleSpecifier::from_directory_path(local_path.parent().unwrap())
|
|
||||||
.unwrap();
|
|
||||||
value.set_query(specifier.query());
|
|
||||||
value.set_path(&format!(
|
|
||||||
"{}{}",
|
|
||||||
value.path(),
|
|
||||||
specifier.path_segments().unwrap().last().unwrap(),
|
|
||||||
));
|
|
||||||
mappings.relative_specifier_text(&base_dir, &value)
|
|
||||||
},
|
|
||||||
specifier,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// absolute (`/`) or bare specifier should be left as-is
|
|
||||||
imports.add(text.to_string(), specifier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_local_dep_specifier(
|
|
||||||
text: &str,
|
|
||||||
unresolved_specifier: &ModuleSpecifier,
|
|
||||||
specifier: &ModuleSpecifier,
|
|
||||||
import_map: &mut ImportMapBuilder,
|
|
||||||
referrer: &ModuleSpecifier,
|
|
||||||
mappings: &Mappings,
|
|
||||||
) {
|
|
||||||
if !is_remote_specifier(referrer) {
|
|
||||||
// do not handle local modules referencing local modules
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The remote module is referencing a local file. This could occur via an
|
|
||||||
// existing import map. In this case, we'll have to add an import map
|
|
||||||
// entry in order to map the path back to the local path once vendored.
|
|
||||||
let base_dir = import_map.base_dir().clone();
|
|
||||||
let base_specifier = mappings.base_specifier(referrer);
|
|
||||||
let imports = import_map.scope(base_specifier);
|
|
||||||
|
|
||||||
if text.starts_with("./") || text.starts_with("../") {
|
|
||||||
let referrer_local_uri = mappings.local_uri(referrer);
|
|
||||||
let mut specifier_local_uri =
|
|
||||||
referrer_local_uri.join(text).unwrap_or_else(|_| {
|
|
||||||
panic!(
|
|
||||||
"Error joining {} to {}",
|
|
||||||
unresolved_specifier.path(),
|
|
||||||
referrer_local_uri
|
|
||||||
)
|
|
||||||
});
|
|
||||||
specifier_local_uri.set_query(unresolved_specifier.query());
|
|
||||||
|
|
||||||
imports.add(
|
|
||||||
mappings.relative_specifier_text(&base_dir, &specifier_local_uri),
|
|
||||||
specifier,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
imports.add(text.to_string(), specifier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn text_from_range<'a>(
|
|
||||||
text_info: &SourceTextInfo,
|
|
||||||
text: &'a str,
|
|
||||||
range: &Range,
|
|
||||||
) -> &'a str {
|
|
||||||
let result = &text[byte_range(text_info, range)];
|
|
||||||
if result.starts_with('"') || result.starts_with('\'') {
|
|
||||||
// remove the quotes
|
|
||||||
&result[1..result.len() - 1]
|
|
||||||
} else {
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn byte_range(
|
|
||||||
text_info: &SourceTextInfo,
|
|
||||||
range: &Range,
|
|
||||||
) -> std::ops::Range<usize> {
|
|
||||||
let start = byte_index(text_info, &range.start);
|
|
||||||
let end = byte_index(text_info, &range.end);
|
|
||||||
start..end
|
|
||||||
}
|
|
||||||
|
|
||||||
fn byte_index(text_info: &SourceTextInfo, pos: &Position) -> usize {
|
|
||||||
// todo(https://github.com/denoland/deno_graph/issues/79): use byte indexes all the way down
|
|
||||||
text_info.loc_to_source_pos(LineAndColumnIndex {
|
|
||||||
line_index: pos.line,
|
|
||||||
column_index: pos.character,
|
|
||||||
}) - text_info.range().start
|
|
||||||
}
|
|
255
cli/tools/vendor/mappings.rs
vendored
255
cli/tools/vendor/mappings.rs
vendored
|
@ -1,255 +0,0 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::collections::HashSet;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use deno_ast::MediaType;
|
|
||||||
use deno_ast::ModuleSpecifier;
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_graph::Module;
|
|
||||||
use deno_graph::ModuleGraph;
|
|
||||||
use deno_graph::Position;
|
|
||||||
|
|
||||||
use crate::util::path::path_with_stem_suffix;
|
|
||||||
use crate::util::path::relative_specifier;
|
|
||||||
|
|
||||||
use super::specifiers::dir_name_for_root;
|
|
||||||
use super::specifiers::get_unique_path;
|
|
||||||
use super::specifiers::make_url_relative;
|
|
||||||
use super::specifiers::partition_by_root_specifiers;
|
|
||||||
use super::specifiers::sanitize_filepath;
|
|
||||||
|
|
||||||
pub struct ProxiedModule {
|
|
||||||
pub output_path: PathBuf,
|
|
||||||
pub declaration_specifier: ModuleSpecifier,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs and holds the remote specifier to local path mappings.
|
|
||||||
pub struct Mappings {
|
|
||||||
mappings: HashMap<ModuleSpecifier, PathBuf>,
|
|
||||||
base_specifiers: Vec<ModuleSpecifier>,
|
|
||||||
proxies: HashMap<ModuleSpecifier, ProxiedModule>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Mappings {
|
|
||||||
pub fn from_remote_modules(
|
|
||||||
graph: &ModuleGraph,
|
|
||||||
remote_modules: &[&Module],
|
|
||||||
output_dir: &Path,
|
|
||||||
) -> Result<Self, AnyError> {
|
|
||||||
let partitioned_specifiers = partition_by_root_specifiers(
|
|
||||||
remote_modules.iter().map(|m| m.specifier()),
|
|
||||||
);
|
|
||||||
let mut mapped_paths = HashSet::new();
|
|
||||||
let mut mappings = HashMap::new();
|
|
||||||
let mut proxies = HashMap::new();
|
|
||||||
let mut base_specifiers = Vec::new();
|
|
||||||
|
|
||||||
for (root, specifiers) in partitioned_specifiers.into_iter() {
|
|
||||||
let base_dir = get_unique_path(
|
|
||||||
output_dir.join(dir_name_for_root(&root)),
|
|
||||||
&mut mapped_paths,
|
|
||||||
);
|
|
||||||
for specifier in specifiers {
|
|
||||||
let module = graph.get(&specifier).unwrap();
|
|
||||||
let media_type = match module {
|
|
||||||
Module::Js(module) => module.media_type,
|
|
||||||
Module::Json(_) => MediaType::Json,
|
|
||||||
Module::Node(_) | Module::Npm(_) | Module::External(_) => continue,
|
|
||||||
};
|
|
||||||
let sub_path = sanitize_filepath(&make_url_relative(&root, &{
|
|
||||||
let mut specifier = specifier.clone();
|
|
||||||
specifier.set_query(None);
|
|
||||||
specifier
|
|
||||||
})?);
|
|
||||||
let new_path = path_with_extension(
|
|
||||||
&base_dir.join(if cfg!(windows) {
|
|
||||||
sub_path.replace('/', "\\")
|
|
||||||
} else {
|
|
||||||
sub_path
|
|
||||||
}),
|
|
||||||
&media_type.as_ts_extension()[1..],
|
|
||||||
);
|
|
||||||
mappings
|
|
||||||
.insert(specifier, get_unique_path(new_path, &mut mapped_paths));
|
|
||||||
}
|
|
||||||
base_specifiers.push(root.clone());
|
|
||||||
mappings.insert(root, base_dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
// resolve all the "proxy" paths to use for when an x-typescript-types header is specified
|
|
||||||
for module in remote_modules {
|
|
||||||
if let Some(module) = module.js() {
|
|
||||||
if let Some(resolved) = &module
|
|
||||||
.maybe_types_dependency
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|d| d.dependency.ok())
|
|
||||||
{
|
|
||||||
let range = &resolved.range;
|
|
||||||
// hack to tell if it's an x-typescript-types header
|
|
||||||
let is_ts_types_header = range.start == Position::zeroed()
|
|
||||||
&& range.end == Position::zeroed();
|
|
||||||
if is_ts_types_header {
|
|
||||||
let module_path = mappings.get(&module.specifier).unwrap();
|
|
||||||
let proxied_path = get_unique_path(
|
|
||||||
path_with_stem_suffix(module_path, ".proxied"),
|
|
||||||
&mut mapped_paths,
|
|
||||||
);
|
|
||||||
proxies.insert(
|
|
||||||
module.specifier.clone(),
|
|
||||||
ProxiedModule {
|
|
||||||
output_path: proxied_path,
|
|
||||||
declaration_specifier: resolved.specifier.clone(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
mappings,
|
|
||||||
base_specifiers,
|
|
||||||
proxies,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn local_uri(&self, specifier: &ModuleSpecifier) -> ModuleSpecifier {
|
|
||||||
if specifier.scheme() == "file" {
|
|
||||||
specifier.clone()
|
|
||||||
} else {
|
|
||||||
let local_path = self.local_path(specifier);
|
|
||||||
if specifier.path().ends_with('/') {
|
|
||||||
ModuleSpecifier::from_directory_path(&local_path)
|
|
||||||
} else {
|
|
||||||
ModuleSpecifier::from_file_path(&local_path)
|
|
||||||
}
|
|
||||||
.unwrap_or_else(|_| {
|
|
||||||
panic!("Could not convert {} to uri.", local_path.display())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn local_path(&self, specifier: &ModuleSpecifier) -> PathBuf {
|
|
||||||
if specifier.scheme() == "file" {
|
|
||||||
specifier.to_file_path().unwrap()
|
|
||||||
} else {
|
|
||||||
self
|
|
||||||
.mappings
|
|
||||||
.get(specifier)
|
|
||||||
.unwrap_or_else(|| panic!("Could not find local path for {specifier}"))
|
|
||||||
.to_path_buf()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn relative_specifier_text(
|
|
||||||
&self,
|
|
||||||
from: &ModuleSpecifier,
|
|
||||||
to: &ModuleSpecifier,
|
|
||||||
) -> String {
|
|
||||||
let from = self.local_uri(from);
|
|
||||||
let to = self.local_uri(to);
|
|
||||||
relative_specifier(&from, &to).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn base_specifiers(&self) -> &Vec<ModuleSpecifier> {
|
|
||||||
&self.base_specifiers
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn base_specifier(
|
|
||||||
&self,
|
|
||||||
child_specifier: &ModuleSpecifier,
|
|
||||||
) -> &ModuleSpecifier {
|
|
||||||
self
|
|
||||||
.base_specifiers
|
|
||||||
.iter()
|
|
||||||
.find(|s| child_specifier.as_str().starts_with(s.as_str()))
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
panic!("Could not find base specifier for {child_specifier}")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn proxied_path(&self, specifier: &ModuleSpecifier) -> Option<PathBuf> {
|
|
||||||
self.proxies.get(specifier).map(|s| s.output_path.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn proxied_modules(
|
|
||||||
&self,
|
|
||||||
) -> std::collections::hash_map::Iter<'_, ModuleSpecifier, ProxiedModule> {
|
|
||||||
self.proxies.iter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn path_with_extension(path: &Path, new_ext: &str) -> PathBuf {
|
|
||||||
if let Some(file_stem) = path.file_stem().map(|f| f.to_string_lossy()) {
|
|
||||||
if let Some(old_ext) = path.extension().map(|f| f.to_string_lossy()) {
|
|
||||||
if file_stem.to_lowercase().ends_with(".d") {
|
|
||||||
if new_ext.to_lowercase() == format!("d.{}", old_ext.to_lowercase()) {
|
|
||||||
// maintain casing
|
|
||||||
return path.to_path_buf();
|
|
||||||
}
|
|
||||||
return path.with_file_name(format!(
|
|
||||||
"{}.{}",
|
|
||||||
&file_stem[..file_stem.len() - ".d".len()],
|
|
||||||
new_ext
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if new_ext.to_lowercase() == old_ext.to_lowercase() {
|
|
||||||
// maintain casing
|
|
||||||
return path.to_path_buf();
|
|
||||||
}
|
|
||||||
let media_type = MediaType::from_path(path);
|
|
||||||
if media_type == MediaType::Unknown {
|
|
||||||
return path.with_file_name(format!(
|
|
||||||
"{}.{}",
|
|
||||||
path.file_name().unwrap().to_string_lossy(),
|
|
||||||
new_ext
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
path.with_extension(new_ext)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use pretty_assertions::assert_eq;
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_path_with_extension() {
|
|
||||||
assert_eq!(
|
|
||||||
path_with_extension(&PathBuf::from("/test.D.TS"), "ts"),
|
|
||||||
PathBuf::from("/test.ts")
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
path_with_extension(&PathBuf::from("/test.D.MTS"), "js"),
|
|
||||||
PathBuf::from("/test.js")
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
path_with_extension(&PathBuf::from("/test.D.TS"), "d.ts"),
|
|
||||||
// maintains casing
|
|
||||||
PathBuf::from("/test.D.TS"),
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
path_with_extension(&PathBuf::from("/test.TS"), "ts"),
|
|
||||||
// maintains casing
|
|
||||||
PathBuf::from("/test.TS"),
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
path_with_extension(&PathBuf::from("/test.ts"), "js"),
|
|
||||||
PathBuf::from("/test.js")
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
path_with_extension(&PathBuf::from("/test.js"), "js"),
|
|
||||||
PathBuf::from("/test.js")
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
path_with_extension(&PathBuf::from("/chai@1.2.3"), "js"),
|
|
||||||
PathBuf::from("/chai@1.2.3.js")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
575
cli/tools/vendor/mod.rs
vendored
575
cli/tools/vendor/mod.rs
vendored
|
@ -1,575 +0,0 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
|
||||||
|
|
||||||
use std::path::Path;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use deno_ast::ModuleSpecifier;
|
|
||||||
use deno_ast::TextChange;
|
|
||||||
use deno_core::anyhow::bail;
|
|
||||||
use deno_core::anyhow::Context;
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::futures::FutureExt;
|
|
||||||
use deno_core::resolve_url_or_path;
|
|
||||||
use deno_graph::GraphKind;
|
|
||||||
use deno_runtime::colors;
|
|
||||||
use log::warn;
|
|
||||||
|
|
||||||
use crate::args::CliOptions;
|
|
||||||
use crate::args::ConfigFile;
|
|
||||||
use crate::args::Flags;
|
|
||||||
use crate::args::FmtOptionsConfig;
|
|
||||||
use crate::args::VendorFlags;
|
|
||||||
use crate::factory::CliFactory;
|
|
||||||
use crate::tools::fmt::format_json;
|
|
||||||
use crate::util::fs::canonicalize_path;
|
|
||||||
use crate::util::fs::resolve_from_cwd;
|
|
||||||
use crate::util::path::relative_specifier;
|
|
||||||
use deno_runtime::fs_util::specifier_to_file_path;
|
|
||||||
|
|
||||||
mod analyze;
|
|
||||||
mod build;
|
|
||||||
mod import_map;
|
|
||||||
mod mappings;
|
|
||||||
mod specifiers;
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test;
|
|
||||||
|
|
||||||
pub async fn vendor(
|
|
||||||
flags: Arc<Flags>,
|
|
||||||
vendor_flags: VendorFlags,
|
|
||||||
) -> Result<(), AnyError> {
|
|
||||||
log::info!(
|
|
||||||
"{}",
|
|
||||||
colors::yellow("⚠️ Warning: `deno vendor` is deprecated and will be removed in Deno 2.0.\nAdd `\"vendor\": true` to your `deno.json` or use the `--vendor` flag instead."),
|
|
||||||
);
|
|
||||||
let mut cli_options = CliOptions::from_flags(flags)?;
|
|
||||||
let raw_output_dir = match &vendor_flags.output_path {
|
|
||||||
Some(output_path) => PathBuf::from(output_path).to_owned(),
|
|
||||||
None => PathBuf::from("vendor/"),
|
|
||||||
};
|
|
||||||
let output_dir = resolve_from_cwd(&raw_output_dir)?;
|
|
||||||
validate_output_dir(&output_dir, &vendor_flags)?;
|
|
||||||
validate_options(&mut cli_options, &output_dir)?;
|
|
||||||
let factory = CliFactory::from_cli_options(Arc::new(cli_options));
|
|
||||||
let cli_options = factory.cli_options()?;
|
|
||||||
if cli_options.workspace().config_folders().len() > 1 {
|
|
||||||
bail!("deno vendor is not supported in a workspace. Set `\"vendor\": true` in the workspace deno.json file instead");
|
|
||||||
}
|
|
||||||
let entry_points =
|
|
||||||
resolve_entry_points(&vendor_flags, cli_options.initial_cwd())?;
|
|
||||||
let jsx_import_source = cli_options
|
|
||||||
.workspace()
|
|
||||||
.to_maybe_jsx_import_source_config()?;
|
|
||||||
let module_graph_creator = factory.module_graph_creator().await?.clone();
|
|
||||||
let workspace_resolver = factory.workspace_resolver().await?;
|
|
||||||
let root_folder = cli_options.workspace().root_folder_configs();
|
|
||||||
let maybe_config_file = root_folder.deno_json.as_ref();
|
|
||||||
let output = build::build(build::BuildInput {
|
|
||||||
entry_points,
|
|
||||||
build_graph: move |entry_points| {
|
|
||||||
async move {
|
|
||||||
module_graph_creator
|
|
||||||
.create_graph(GraphKind::All, entry_points)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
.boxed_local()
|
|
||||||
},
|
|
||||||
parsed_source_cache: factory.parsed_source_cache(),
|
|
||||||
output_dir: &output_dir,
|
|
||||||
maybe_original_import_map: workspace_resolver.maybe_import_map(),
|
|
||||||
maybe_jsx_import_source: jsx_import_source.as_ref(),
|
|
||||||
resolver: factory.resolver().await?.as_graph_resolver(),
|
|
||||||
environment: &build::RealVendorEnvironment,
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let vendored_count = output.vendored_count;
|
|
||||||
let graph = output.graph;
|
|
||||||
let npm_package_count = graph.npm_packages.len();
|
|
||||||
let try_add_node_modules_dir = npm_package_count > 0
|
|
||||||
&& cli_options.node_modules_dir_enablement().unwrap_or(true);
|
|
||||||
|
|
||||||
log::info!(
|
|
||||||
concat!("Vendored {} {} into {} directory.",),
|
|
||||||
vendored_count,
|
|
||||||
if vendored_count == 1 {
|
|
||||||
"module"
|
|
||||||
} else {
|
|
||||||
"modules"
|
|
||||||
},
|
|
||||||
raw_output_dir.display(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let try_add_import_map = vendored_count > 0;
|
|
||||||
let modified_result = maybe_update_config_file(
|
|
||||||
&output_dir,
|
|
||||||
maybe_config_file,
|
|
||||||
try_add_import_map,
|
|
||||||
try_add_node_modules_dir,
|
|
||||||
);
|
|
||||||
|
|
||||||
// cache the node_modules folder when it's been added to the config file
|
|
||||||
if modified_result.added_node_modules_dir {
|
|
||||||
let node_modules_path =
|
|
||||||
cli_options.node_modules_dir_path().cloned().or_else(|| {
|
|
||||||
maybe_config_file
|
|
||||||
.as_ref()
|
|
||||||
.map(|d| &d.specifier)
|
|
||||||
.filter(|c| c.scheme() == "file")
|
|
||||||
.and_then(|c| c.to_file_path().ok())
|
|
||||||
.map(|config_path| config_path.parent().unwrap().join("node_modules"))
|
|
||||||
});
|
|
||||||
if let Some(node_modules_path) = node_modules_path {
|
|
||||||
let cli_options =
|
|
||||||
cli_options.with_node_modules_dir_path(node_modules_path);
|
|
||||||
let factory = CliFactory::from_cli_options(Arc::new(cli_options));
|
|
||||||
if let Some(managed) = factory.npm_resolver().await?.as_managed() {
|
|
||||||
managed.cache_packages().await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log::info!(
|
|
||||||
concat!(
|
|
||||||
"Vendored {} npm {} into node_modules directory. Set `nodeModulesDir: false` ",
|
|
||||||
"in the Deno configuration file to disable vendoring npm packages in the future.",
|
|
||||||
),
|
|
||||||
npm_package_count,
|
|
||||||
if npm_package_count == 1 {
|
|
||||||
"package"
|
|
||||||
} else {
|
|
||||||
"packages"
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if vendored_count > 0 {
|
|
||||||
let import_map_path = raw_output_dir.join("import_map.json");
|
|
||||||
if modified_result.updated_import_map {
|
|
||||||
log::info!(
|
|
||||||
concat!(
|
|
||||||
"\nUpdated your local Deno configuration file with a reference to the ",
|
|
||||||
"new vendored import map at {}. Invoking Deno subcommands will now ",
|
|
||||||
"automatically resolve using the vendored modules. You may override ",
|
|
||||||
"this by providing the `--import-map <other-import-map>` flag or by ",
|
|
||||||
"manually editing your Deno configuration file.",
|
|
||||||
),
|
|
||||||
import_map_path.display(),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
log::info!(
|
|
||||||
concat!(
|
|
||||||
"\nTo use vendored modules, specify the `--import-map {}` flag when ",
|
|
||||||
r#"invoking Deno subcommands or add an `"importMap": "<path_to_vendored_import_map>"` "#,
|
|
||||||
"entry to a deno.json file.",
|
|
||||||
),
|
|
||||||
import_map_path.display(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate_output_dir(
|
|
||||||
output_dir: &Path,
|
|
||||||
flags: &VendorFlags,
|
|
||||||
) -> Result<(), AnyError> {
|
|
||||||
if !flags.force && !is_dir_empty(output_dir)? {
|
|
||||||
bail!(concat!(
|
|
||||||
"Output directory was not empty. Please specify an empty directory or use ",
|
|
||||||
"--force to ignore this error and potentially overwrite its contents.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate_options(
|
|
||||||
options: &mut CliOptions,
|
|
||||||
output_dir: &Path,
|
|
||||||
) -> Result<(), AnyError> {
|
|
||||||
let import_map_specifier = options
|
|
||||||
.resolve_specified_import_map_specifier()?
|
|
||||||
.or_else(|| {
|
|
||||||
let config_file = options.workspace().root_deno_json()?;
|
|
||||||
config_file
|
|
||||||
.to_import_map_specifier()
|
|
||||||
.ok()
|
|
||||||
.flatten()
|
|
||||||
.or_else(|| {
|
|
||||||
if config_file.is_an_import_map() {
|
|
||||||
Some(config_file.specifier.clone())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
// check the import map
|
|
||||||
if let Some(import_map_path) = import_map_specifier
|
|
||||||
.and_then(|p| specifier_to_file_path(&p).ok())
|
|
||||||
.and_then(|p| canonicalize_path(&p).ok())
|
|
||||||
{
|
|
||||||
// make the output directory in order to canonicalize it for the check below
|
|
||||||
std::fs::create_dir_all(output_dir)?;
|
|
||||||
let output_dir = canonicalize_path(output_dir).with_context(|| {
|
|
||||||
format!("Failed to canonicalize: {}", output_dir.display())
|
|
||||||
})?;
|
|
||||||
|
|
||||||
if import_map_path.starts_with(output_dir) {
|
|
||||||
// canonicalize to make the test for this pass on the CI
|
|
||||||
let cwd = canonicalize_path(&std::env::current_dir()?)?;
|
|
||||||
// We don't allow using the output directory to help generate the
|
|
||||||
// new state because this may lead to cryptic error messages.
|
|
||||||
log::warn!(
|
|
||||||
concat!(
|
|
||||||
"Ignoring import map. Specifying an import map file ({}) in the ",
|
|
||||||
"deno vendor output directory is not supported. If you wish to use ",
|
|
||||||
"an import map while vendoring, please specify one located outside ",
|
|
||||||
"this directory."
|
|
||||||
),
|
|
||||||
import_map_path
|
|
||||||
.strip_prefix(&cwd)
|
|
||||||
.unwrap_or(&import_map_path)
|
|
||||||
.display()
|
|
||||||
.to_string(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// don't use an import map in the config
|
|
||||||
options.set_import_map_specifier(None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn maybe_update_config_file(
|
|
||||||
output_dir: &Path,
|
|
||||||
maybe_config_file: Option<&Arc<ConfigFile>>,
|
|
||||||
try_add_import_map: bool,
|
|
||||||
try_add_node_modules_dir: bool,
|
|
||||||
) -> ModifiedResult {
|
|
||||||
assert!(output_dir.is_absolute());
|
|
||||||
let config_file = match maybe_config_file {
|
|
||||||
Some(config_file) => config_file,
|
|
||||||
None => return ModifiedResult::default(),
|
|
||||||
};
|
|
||||||
if config_file.specifier.scheme() != "file" {
|
|
||||||
return ModifiedResult::default();
|
|
||||||
}
|
|
||||||
|
|
||||||
let fmt_config_options = config_file
|
|
||||||
.to_fmt_config()
|
|
||||||
.ok()
|
|
||||||
.map(|config| config.options)
|
|
||||||
.unwrap_or_default();
|
|
||||||
let result = update_config_file(
|
|
||||||
config_file,
|
|
||||||
&fmt_config_options,
|
|
||||||
if try_add_import_map {
|
|
||||||
Some(
|
|
||||||
ModuleSpecifier::from_file_path(output_dir.join("import_map.json"))
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
},
|
|
||||||
try_add_node_modules_dir,
|
|
||||||
);
|
|
||||||
match result {
|
|
||||||
Ok(modified_result) => modified_result,
|
|
||||||
Err(err) => {
|
|
||||||
warn!("Error updating config file. {:#}", err);
|
|
||||||
ModifiedResult::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_config_file(
|
|
||||||
config_file: &ConfigFile,
|
|
||||||
fmt_options: &FmtOptionsConfig,
|
|
||||||
import_map_specifier: Option<ModuleSpecifier>,
|
|
||||||
try_add_node_modules_dir: bool,
|
|
||||||
) -> Result<ModifiedResult, AnyError> {
|
|
||||||
let config_path = specifier_to_file_path(&config_file.specifier)?;
|
|
||||||
let config_text = std::fs::read_to_string(&config_path)?;
|
|
||||||
let import_map_specifier =
|
|
||||||
import_map_specifier.and_then(|import_map_specifier| {
|
|
||||||
relative_specifier(&config_file.specifier, &import_map_specifier)
|
|
||||||
});
|
|
||||||
let modified_result = update_config_text(
|
|
||||||
&config_text,
|
|
||||||
fmt_options,
|
|
||||||
import_map_specifier.as_deref(),
|
|
||||||
try_add_node_modules_dir,
|
|
||||||
)?;
|
|
||||||
if let Some(new_text) = &modified_result.new_text {
|
|
||||||
std::fs::write(config_path, new_text)?;
|
|
||||||
}
|
|
||||||
Ok(modified_result)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct ModifiedResult {
|
|
||||||
updated_import_map: bool,
|
|
||||||
added_node_modules_dir: bool,
|
|
||||||
new_text: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_config_text(
|
|
||||||
text: &str,
|
|
||||||
fmt_options: &FmtOptionsConfig,
|
|
||||||
import_map_specifier: Option<&str>,
|
|
||||||
try_add_node_modules_dir: bool,
|
|
||||||
) -> Result<ModifiedResult, AnyError> {
|
|
||||||
use jsonc_parser::ast::ObjectProp;
|
|
||||||
use jsonc_parser::ast::Value;
|
|
||||||
let text = if text.trim().is_empty() { "{}\n" } else { text };
|
|
||||||
let ast =
|
|
||||||
jsonc_parser::parse_to_ast(text, &Default::default(), &Default::default())?;
|
|
||||||
let obj = match ast.value {
|
|
||||||
Some(Value::Object(obj)) => obj,
|
|
||||||
_ => bail!("Failed updating config file due to no object."),
|
|
||||||
};
|
|
||||||
let mut modified_result = ModifiedResult::default();
|
|
||||||
let mut text_changes = Vec::new();
|
|
||||||
let mut should_format = false;
|
|
||||||
|
|
||||||
if try_add_node_modules_dir {
|
|
||||||
// Only modify the nodeModulesDir property if it's not set
|
|
||||||
// as this allows people to opt-out of this when vendoring
|
|
||||||
// by specifying `nodeModulesDir: false`
|
|
||||||
if obj.get("nodeModulesDir").is_none() {
|
|
||||||
let insert_position = obj.range.end - 1;
|
|
||||||
text_changes.push(TextChange {
|
|
||||||
range: insert_position..insert_position,
|
|
||||||
new_text: r#""nodeModulesDir": true"#.to_string(),
|
|
||||||
});
|
|
||||||
should_format = true;
|
|
||||||
modified_result.added_node_modules_dir = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(import_map_specifier) = import_map_specifier {
|
|
||||||
let import_map_specifier = import_map_specifier.replace('\"', "\\\"");
|
|
||||||
match obj.get("importMap") {
|
|
||||||
Some(ObjectProp {
|
|
||||||
value: Value::StringLit(lit),
|
|
||||||
..
|
|
||||||
}) => {
|
|
||||||
text_changes.push(TextChange {
|
|
||||||
range: lit.range.start..lit.range.end,
|
|
||||||
new_text: format!("\"{}\"", import_map_specifier),
|
|
||||||
});
|
|
||||||
modified_result.updated_import_map = true;
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
// insert it crudely at a position that won't cause any issues
|
|
||||||
// with comments and format after to make it look nice
|
|
||||||
let insert_position = obj.range.end - 1;
|
|
||||||
text_changes.push(TextChange {
|
|
||||||
range: insert_position..insert_position,
|
|
||||||
new_text: format!(r#""importMap": "{}""#, import_map_specifier),
|
|
||||||
});
|
|
||||||
should_format = true;
|
|
||||||
modified_result.updated_import_map = true;
|
|
||||||
}
|
|
||||||
// shouldn't happen
|
|
||||||
Some(_) => {
|
|
||||||
bail!("Failed updating importMap in config file due to invalid type.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if text_changes.is_empty() {
|
|
||||||
return Ok(modified_result);
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_text = deno_ast::apply_text_changes(text, text_changes);
|
|
||||||
modified_result.new_text = if should_format {
|
|
||||||
format_json(&PathBuf::from("deno.json"), &new_text, fmt_options)
|
|
||||||
.ok()
|
|
||||||
.map(|formatted_text| formatted_text.unwrap_or(new_text))
|
|
||||||
} else {
|
|
||||||
Some(new_text)
|
|
||||||
};
|
|
||||||
Ok(modified_result)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_dir_empty(dir_path: &Path) -> Result<bool, AnyError> {
|
|
||||||
match std::fs::read_dir(dir_path) {
|
|
||||||
Ok(mut dir) => Ok(dir.next().is_none()),
|
|
||||||
Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(true),
|
|
||||||
Err(err) => {
|
|
||||||
bail!("Error reading directory {}: {}", dir_path.display(), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_entry_points(
|
|
||||||
flags: &VendorFlags,
|
|
||||||
initial_cwd: &Path,
|
|
||||||
) -> Result<Vec<ModuleSpecifier>, AnyError> {
|
|
||||||
flags
|
|
||||||
.specifiers
|
|
||||||
.iter()
|
|
||||||
.map(|p| resolve_url_or_path(p, initial_cwd).map_err(|e| e.into()))
|
|
||||||
.collect::<Result<Vec<_>, _>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod internal_test {
|
|
||||||
use super::*;
|
|
||||||
use pretty_assertions::assert_eq;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn update_config_text_no_existing_props_add_prop() {
|
|
||||||
let result = update_config_text(
|
|
||||||
"{\n}",
|
|
||||||
&Default::default(),
|
|
||||||
Some("./vendor/import_map.json"),
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert!(result.updated_import_map);
|
|
||||||
assert!(!result.added_node_modules_dir);
|
|
||||||
assert_eq!(
|
|
||||||
result.new_text.unwrap(),
|
|
||||||
r#"{
|
|
||||||
"importMap": "./vendor/import_map.json"
|
|
||||||
}
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
let result = update_config_text(
|
|
||||||
"{\n}",
|
|
||||||
&Default::default(),
|
|
||||||
Some("./vendor/import_map.json"),
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert!(result.updated_import_map);
|
|
||||||
assert!(result.added_node_modules_dir);
|
|
||||||
assert_eq!(
|
|
||||||
result.new_text.unwrap(),
|
|
||||||
r#"{
|
|
||||||
"nodeModulesDir": true,
|
|
||||||
"importMap": "./vendor/import_map.json"
|
|
||||||
}
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
let result =
|
|
||||||
update_config_text("{\n}", &Default::default(), None, true).unwrap();
|
|
||||||
assert!(!result.updated_import_map);
|
|
||||||
assert!(result.added_node_modules_dir);
|
|
||||||
assert_eq!(
|
|
||||||
result.new_text.unwrap(),
|
|
||||||
r#"{
|
|
||||||
"nodeModulesDir": true
|
|
||||||
}
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn update_config_text_existing_props_add_prop() {
|
|
||||||
let result = update_config_text(
|
|
||||||
r#"{
|
|
||||||
"tasks": {
|
|
||||||
"task1": "other"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"#,
|
|
||||||
&Default::default(),
|
|
||||||
Some("./vendor/import_map.json"),
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
result.new_text.unwrap(),
|
|
||||||
r#"{
|
|
||||||
"tasks": {
|
|
||||||
"task1": "other"
|
|
||||||
},
|
|
||||||
"importMap": "./vendor/import_map.json"
|
|
||||||
}
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
// trailing comma
|
|
||||||
let result = update_config_text(
|
|
||||||
r#"{
|
|
||||||
"tasks": {
|
|
||||||
"task1": "other"
|
|
||||||
},
|
|
||||||
}
|
|
||||||
"#,
|
|
||||||
&Default::default(),
|
|
||||||
Some("./vendor/import_map.json"),
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
result.new_text.unwrap(),
|
|
||||||
r#"{
|
|
||||||
"tasks": {
|
|
||||||
"task1": "other"
|
|
||||||
},
|
|
||||||
"importMap": "./vendor/import_map.json"
|
|
||||||
}
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn update_config_text_update_prop() {
|
|
||||||
let result = update_config_text(
|
|
||||||
r#"{
|
|
||||||
"importMap": "./local.json"
|
|
||||||
}
|
|
||||||
"#,
|
|
||||||
&Default::default(),
|
|
||||||
Some("./vendor/import_map.json"),
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
result.new_text.unwrap(),
|
|
||||||
r#"{
|
|
||||||
"importMap": "./vendor/import_map.json"
|
|
||||||
}
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn no_update_node_modules_dir() {
|
|
||||||
// will not update if this is already set (even if it's false)
|
|
||||||
let result = update_config_text(
|
|
||||||
r#"{
|
|
||||||
"nodeModulesDir": false
|
|
||||||
}
|
|
||||||
"#,
|
|
||||||
&Default::default(),
|
|
||||||
None,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert!(!result.added_node_modules_dir);
|
|
||||||
assert!(!result.updated_import_map);
|
|
||||||
assert_eq!(result.new_text, None);
|
|
||||||
|
|
||||||
let result = update_config_text(
|
|
||||||
r#"{
|
|
||||||
"nodeModulesDir": true
|
|
||||||
}
|
|
||||||
"#,
|
|
||||||
&Default::default(),
|
|
||||||
None,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert!(!result.added_node_modules_dir);
|
|
||||||
assert!(!result.updated_import_map);
|
|
||||||
assert_eq!(result.new_text, None);
|
|
||||||
}
|
|
||||||
}
|
|
208
cli/tools/vendor/specifiers.rs
vendored
208
cli/tools/vendor/specifiers.rs
vendored
|
@ -1,208 +0,0 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use std::collections::HashSet;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use deno_ast::ModuleSpecifier;
|
|
||||||
use deno_core::anyhow::anyhow;
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
|
|
||||||
use crate::util::path::is_banned_path_char;
|
|
||||||
use crate::util::path::path_with_stem_suffix;
|
|
||||||
use crate::util::path::root_url_to_safe_local_dirname;
|
|
||||||
|
|
||||||
/// Partitions the provided specifiers by the non-path and non-query parts of a specifier.
|
|
||||||
pub fn partition_by_root_specifiers<'a>(
|
|
||||||
specifiers: impl Iterator<Item = &'a ModuleSpecifier>,
|
|
||||||
) -> BTreeMap<ModuleSpecifier, Vec<ModuleSpecifier>> {
|
|
||||||
let mut root_specifiers: BTreeMap<ModuleSpecifier, Vec<ModuleSpecifier>> =
|
|
||||||
Default::default();
|
|
||||||
for remote_specifier in specifiers {
|
|
||||||
let mut root_specifier = remote_specifier.clone();
|
|
||||||
root_specifier.set_query(None);
|
|
||||||
root_specifier.set_path("/");
|
|
||||||
|
|
||||||
let specifiers = root_specifiers.entry(root_specifier).or_default();
|
|
||||||
specifiers.push(remote_specifier.clone());
|
|
||||||
}
|
|
||||||
root_specifiers
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the directory name to use for the provided root.
|
|
||||||
pub fn dir_name_for_root(root: &ModuleSpecifier) -> PathBuf {
|
|
||||||
root_url_to_safe_local_dirname(root)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets a unique file path given the provided file path
|
|
||||||
/// and the set of existing file paths. Inserts to the
|
|
||||||
/// set when finding a unique path.
|
|
||||||
pub fn get_unique_path(
|
|
||||||
mut path: PathBuf,
|
|
||||||
unique_set: &mut HashSet<String>,
|
|
||||||
) -> PathBuf {
|
|
||||||
let original_path = path.clone();
|
|
||||||
let mut count = 2;
|
|
||||||
// case insensitive comparison so the output works on case insensitive file systems
|
|
||||||
while !unique_set.insert(path.to_string_lossy().to_lowercase()) {
|
|
||||||
path = path_with_stem_suffix(&original_path, &format!("_{count}"));
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn make_url_relative(
|
|
||||||
root: &ModuleSpecifier,
|
|
||||||
url: &ModuleSpecifier,
|
|
||||||
) -> Result<String, AnyError> {
|
|
||||||
root.make_relative(url).ok_or_else(|| {
|
|
||||||
anyhow!(
|
|
||||||
"Error making url ({}) relative to root: {}",
|
|
||||||
url.to_string(),
|
|
||||||
root.to_string()
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_remote_specifier(specifier: &ModuleSpecifier) -> bool {
|
|
||||||
matches!(specifier.scheme().to_lowercase().as_str(), "http" | "https")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_remote_specifier_text(text: &str) -> bool {
|
|
||||||
let text = text.trim_start().to_lowercase();
|
|
||||||
text.starts_with("http:") || text.starts_with("https:")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sanitize_filepath(text: &str) -> String {
|
|
||||||
text
|
|
||||||
.chars()
|
|
||||||
.map(|c| if is_banned_path_char(c) { '_' } else { c })
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
use pretty_assertions::assert_eq;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn partition_by_root_specifiers_same_sub_folder() {
|
|
||||||
run_partition_by_root_specifiers_test(
|
|
||||||
vec![
|
|
||||||
"https://deno.land/x/mod/A.ts",
|
|
||||||
"https://deno.land/x/mod/other/A.ts",
|
|
||||||
],
|
|
||||||
vec![(
|
|
||||||
"https://deno.land/",
|
|
||||||
vec![
|
|
||||||
"https://deno.land/x/mod/A.ts",
|
|
||||||
"https://deno.land/x/mod/other/A.ts",
|
|
||||||
],
|
|
||||||
)],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn partition_by_root_specifiers_different_sub_folder() {
|
|
||||||
run_partition_by_root_specifiers_test(
|
|
||||||
vec![
|
|
||||||
"https://deno.land/x/mod/A.ts",
|
|
||||||
"https://deno.land/x/other/A.ts",
|
|
||||||
],
|
|
||||||
vec![(
|
|
||||||
"https://deno.land/",
|
|
||||||
vec![
|
|
||||||
"https://deno.land/x/mod/A.ts",
|
|
||||||
"https://deno.land/x/other/A.ts",
|
|
||||||
],
|
|
||||||
)],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn partition_by_root_specifiers_different_hosts() {
|
|
||||||
run_partition_by_root_specifiers_test(
|
|
||||||
vec![
|
|
||||||
"https://deno.land/mod/A.ts",
|
|
||||||
"http://deno.land/B.ts",
|
|
||||||
"https://deno.land:8080/C.ts",
|
|
||||||
"https://localhost/mod/A.ts",
|
|
||||||
"https://other/A.ts",
|
|
||||||
],
|
|
||||||
vec![
|
|
||||||
("http://deno.land/", vec!["http://deno.land/B.ts"]),
|
|
||||||
("https://deno.land/", vec!["https://deno.land/mod/A.ts"]),
|
|
||||||
(
|
|
||||||
"https://deno.land:8080/",
|
|
||||||
vec!["https://deno.land:8080/C.ts"],
|
|
||||||
),
|
|
||||||
("https://localhost/", vec!["https://localhost/mod/A.ts"]),
|
|
||||||
("https://other/", vec!["https://other/A.ts"]),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_partition_by_root_specifiers_test(
|
|
||||||
input: Vec<&str>,
|
|
||||||
expected: Vec<(&str, Vec<&str>)>,
|
|
||||||
) {
|
|
||||||
let input = input
|
|
||||||
.iter()
|
|
||||||
.map(|s| ModuleSpecifier::parse(s).unwrap())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let output = partition_by_root_specifiers(input.iter());
|
|
||||||
// the assertion is much easier to compare when everything is strings
|
|
||||||
let output = output
|
|
||||||
.into_iter()
|
|
||||||
.map(|(s, vec)| {
|
|
||||||
(
|
|
||||||
s.to_string(),
|
|
||||||
vec.into_iter().map(|s| s.to_string()).collect::<Vec<_>>(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let expected = expected
|
|
||||||
.into_iter()
|
|
||||||
.map(|(s, vec)| {
|
|
||||||
(
|
|
||||||
s.to_string(),
|
|
||||||
vec.into_iter().map(|s| s.to_string()).collect::<Vec<_>>(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
assert_eq!(output, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_unique_path() {
|
|
||||||
let mut paths = HashSet::new();
|
|
||||||
assert_eq!(
|
|
||||||
get_unique_path(PathBuf::from("/test"), &mut paths),
|
|
||||||
PathBuf::from("/test")
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
get_unique_path(PathBuf::from("/test"), &mut paths),
|
|
||||||
PathBuf::from("/test_2")
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
get_unique_path(PathBuf::from("/test"), &mut paths),
|
|
||||||
PathBuf::from("/test_3")
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
get_unique_path(PathBuf::from("/TEST"), &mut paths),
|
|
||||||
PathBuf::from("/TEST_4")
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
get_unique_path(PathBuf::from("/test.txt"), &mut paths),
|
|
||||||
PathBuf::from("/test.txt")
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
get_unique_path(PathBuf::from("/test.txt"), &mut paths),
|
|
||||||
PathBuf::from("/test_2.txt")
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
get_unique_path(PathBuf::from("/TEST.TXT"), &mut paths),
|
|
||||||
PathBuf::from("/TEST_3.TXT")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
357
cli/tools/vendor/test.rs
vendored
357
cli/tools/vendor/test.rs
vendored
|
@ -1,357 +0,0 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
|
||||||
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::collections::HashSet;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use deno_ast::ModuleSpecifier;
|
|
||||||
use deno_config::workspace::WorkspaceResolver;
|
|
||||||
use deno_core::anyhow::anyhow;
|
|
||||||
use deno_core::anyhow::bail;
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::futures;
|
|
||||||
use deno_core::futures::FutureExt;
|
|
||||||
use deno_core::serde_json;
|
|
||||||
use deno_graph::source::LoadFuture;
|
|
||||||
use deno_graph::source::LoadResponse;
|
|
||||||
use deno_graph::source::Loader;
|
|
||||||
use deno_graph::DefaultModuleAnalyzer;
|
|
||||||
use deno_graph::GraphKind;
|
|
||||||
use deno_graph::ModuleGraph;
|
|
||||||
use import_map::ImportMap;
|
|
||||||
|
|
||||||
use crate::args::JsxImportSourceConfig;
|
|
||||||
use crate::cache::ParsedSourceCache;
|
|
||||||
use crate::resolver::CliGraphResolver;
|
|
||||||
use crate::resolver::CliGraphResolverOptions;
|
|
||||||
|
|
||||||
use super::build::VendorEnvironment;
|
|
||||||
|
|
||||||
// Utilities that help `deno vendor` get tested in memory.
|
|
||||||
|
|
||||||
type RemoteFileText = String;
|
|
||||||
type RemoteFileHeaders = Option<HashMap<String, String>>;
|
|
||||||
type RemoteFileResult = Result<(RemoteFileText, RemoteFileHeaders), String>;
|
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
|
||||||
pub struct TestLoader {
|
|
||||||
files: HashMap<ModuleSpecifier, RemoteFileResult>,
|
|
||||||
redirects: HashMap<ModuleSpecifier, ModuleSpecifier>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TestLoader {
|
|
||||||
pub fn add(
|
|
||||||
&mut self,
|
|
||||||
path_or_specifier: impl AsRef<str>,
|
|
||||||
text: impl AsRef<str>,
|
|
||||||
) -> &mut Self {
|
|
||||||
self.add_result(path_or_specifier, Ok((text.as_ref().to_string(), None)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_failure(
|
|
||||||
&mut self,
|
|
||||||
path_or_specifier: impl AsRef<str>,
|
|
||||||
message: impl AsRef<str>,
|
|
||||||
) -> &mut Self {
|
|
||||||
self.add_result(path_or_specifier, Err(message.as_ref().to_string()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_result(
|
|
||||||
&mut self,
|
|
||||||
path_or_specifier: impl AsRef<str>,
|
|
||||||
result: RemoteFileResult,
|
|
||||||
) -> &mut Self {
|
|
||||||
if path_or_specifier
|
|
||||||
.as_ref()
|
|
||||||
.to_lowercase()
|
|
||||||
.starts_with("http")
|
|
||||||
{
|
|
||||||
self.files.insert(
|
|
||||||
ModuleSpecifier::parse(path_or_specifier.as_ref()).unwrap(),
|
|
||||||
result,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
let path = make_path(path_or_specifier.as_ref());
|
|
||||||
let specifier = ModuleSpecifier::from_file_path(path).unwrap();
|
|
||||||
self.files.insert(specifier, result);
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_with_headers(
|
|
||||||
&mut self,
|
|
||||||
specifier: impl AsRef<str>,
|
|
||||||
text: impl AsRef<str>,
|
|
||||||
headers: &[(&str, &str)],
|
|
||||||
) -> &mut Self {
|
|
||||||
let headers = headers
|
|
||||||
.iter()
|
|
||||||
.map(|(key, value)| (key.to_string(), value.to_string()))
|
|
||||||
.collect();
|
|
||||||
self.files.insert(
|
|
||||||
ModuleSpecifier::parse(specifier.as_ref()).unwrap(),
|
|
||||||
Ok((text.as_ref().to_string(), Some(headers))),
|
|
||||||
);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_redirect(
|
|
||||||
&mut self,
|
|
||||||
from: impl AsRef<str>,
|
|
||||||
to: impl AsRef<str>,
|
|
||||||
) -> &mut Self {
|
|
||||||
self.redirects.insert(
|
|
||||||
ModuleSpecifier::parse(from.as_ref()).unwrap(),
|
|
||||||
ModuleSpecifier::parse(to.as_ref()).unwrap(),
|
|
||||||
);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Loader for TestLoader {
|
|
||||||
fn load(
|
|
||||||
&self,
|
|
||||||
specifier: &ModuleSpecifier,
|
|
||||||
_options: deno_graph::source::LoadOptions,
|
|
||||||
) -> LoadFuture {
|
|
||||||
if let Some(redirect) = self.redirects.get(specifier) {
|
|
||||||
return Box::pin(futures::future::ready(Ok(Some(
|
|
||||||
LoadResponse::Redirect {
|
|
||||||
specifier: redirect.clone(),
|
|
||||||
},
|
|
||||||
))));
|
|
||||||
}
|
|
||||||
let result = self.files.get(specifier).map(|result| match result {
|
|
||||||
Ok(result) => Ok(LoadResponse::Module {
|
|
||||||
specifier: specifier.clone(),
|
|
||||||
content: result.0.clone().into_bytes().into(),
|
|
||||||
maybe_headers: result.1.clone(),
|
|
||||||
}),
|
|
||||||
Err(err) => Err(err),
|
|
||||||
});
|
|
||||||
let result = match result {
|
|
||||||
Some(Ok(result)) => Ok(Some(result)),
|
|
||||||
Some(Err(err)) => Err(anyhow!("{}", err)),
|
|
||||||
None if specifier.scheme() == "data" => {
|
|
||||||
deno_graph::source::load_data_url(specifier)
|
|
||||||
}
|
|
||||||
None => Ok(None),
|
|
||||||
};
|
|
||||||
Box::pin(futures::future::ready(result))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct TestVendorEnvironment {
|
|
||||||
directories: RefCell<HashSet<PathBuf>>,
|
|
||||||
files: RefCell<HashMap<PathBuf, String>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VendorEnvironment for TestVendorEnvironment {
|
|
||||||
fn create_dir_all(&self, dir_path: &Path) -> Result<(), AnyError> {
|
|
||||||
let mut directories = self.directories.borrow_mut();
|
|
||||||
for path in dir_path.ancestors() {
|
|
||||||
if !directories.insert(path.to_path_buf()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_file(&self, file_path: &Path, text: &[u8]) -> Result<(), AnyError> {
|
|
||||||
let parent = file_path.parent().unwrap();
|
|
||||||
if !self.directories.borrow().contains(parent) {
|
|
||||||
bail!("Directory not found: {}", parent.display());
|
|
||||||
}
|
|
||||||
self.files.borrow_mut().insert(
|
|
||||||
file_path.to_path_buf(),
|
|
||||||
String::from_utf8(text.to_vec()).unwrap(),
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct VendorOutput {
|
|
||||||
pub files: Vec<(String, String)>,
|
|
||||||
pub import_map: Option<serde_json::Value>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct VendorTestBuilder {
|
|
||||||
entry_points: Vec<ModuleSpecifier>,
|
|
||||||
loader: TestLoader,
|
|
||||||
maybe_original_import_map: Option<ImportMap>,
|
|
||||||
environment: TestVendorEnvironment,
|
|
||||||
jsx_import_source_config: Option<JsxImportSourceConfig>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VendorTestBuilder {
|
|
||||||
pub fn with_default_setup() -> Self {
|
|
||||||
let mut builder = VendorTestBuilder::default();
|
|
||||||
builder.add_entry_point("/mod.ts");
|
|
||||||
builder
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resolve_to_url(&self, path: &str) -> ModuleSpecifier {
|
|
||||||
ModuleSpecifier::from_file_path(make_path(path)).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_import_map(&self, base_path: &str) -> ImportMap {
|
|
||||||
let base = self.resolve_to_url(base_path);
|
|
||||||
ImportMap::new(base)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_original_import_map(
|
|
||||||
&mut self,
|
|
||||||
import_map: ImportMap,
|
|
||||||
) -> &mut Self {
|
|
||||||
self.maybe_original_import_map = Some(import_map);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_entry_point(&mut self, entry_point: impl AsRef<str>) -> &mut Self {
|
|
||||||
let entry_point = make_path(entry_point.as_ref());
|
|
||||||
self
|
|
||||||
.entry_points
|
|
||||||
.push(ModuleSpecifier::from_file_path(entry_point).unwrap());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_jsx_import_source_config(
|
|
||||||
&mut self,
|
|
||||||
jsx_import_source_config: JsxImportSourceConfig,
|
|
||||||
) -> &mut Self {
|
|
||||||
self.jsx_import_source_config = Some(jsx_import_source_config);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn build(&mut self) -> Result<VendorOutput, AnyError> {
|
|
||||||
let output_dir = make_path("/vendor");
|
|
||||||
let entry_points = self.entry_points.clone();
|
|
||||||
let loader = self.loader.clone();
|
|
||||||
let parsed_source_cache = ParsedSourceCache::default();
|
|
||||||
let resolver = Arc::new(build_resolver(
|
|
||||||
output_dir.parent().unwrap(),
|
|
||||||
self.jsx_import_source_config.clone(),
|
|
||||||
self.maybe_original_import_map.clone(),
|
|
||||||
));
|
|
||||||
super::build::build(super::build::BuildInput {
|
|
||||||
entry_points,
|
|
||||||
build_graph: {
|
|
||||||
let resolver = resolver.clone();
|
|
||||||
move |entry_points| {
|
|
||||||
async move {
|
|
||||||
Ok(
|
|
||||||
build_test_graph(
|
|
||||||
entry_points,
|
|
||||||
loader,
|
|
||||||
resolver.as_graph_resolver(),
|
|
||||||
&DefaultModuleAnalyzer,
|
|
||||||
)
|
|
||||||
.await,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.boxed_local()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
parsed_source_cache: &parsed_source_cache,
|
|
||||||
output_dir: &output_dir,
|
|
||||||
maybe_original_import_map: self.maybe_original_import_map.as_ref(),
|
|
||||||
maybe_jsx_import_source: self.jsx_import_source_config.as_ref(),
|
|
||||||
resolver: resolver.as_graph_resolver(),
|
|
||||||
environment: &self.environment,
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let mut files = self.environment.files.borrow_mut();
|
|
||||||
let import_map = files.remove(&output_dir.join("import_map.json"));
|
|
||||||
let mut files = files
|
|
||||||
.iter()
|
|
||||||
.map(|(path, text)| (path_to_string(path), text.to_string()))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
files.sort_by(|a, b| a.0.cmp(&b.0));
|
|
||||||
|
|
||||||
Ok(VendorOutput {
|
|
||||||
import_map: import_map.map(|text| serde_json::from_str(&text).unwrap()),
|
|
||||||
files,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_loader(&mut self, action: impl Fn(&mut TestLoader)) -> &mut Self {
|
|
||||||
action(&mut self.loader);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_resolver(
|
|
||||||
root_dir: &Path,
|
|
||||||
maybe_jsx_import_source_config: Option<JsxImportSourceConfig>,
|
|
||||||
maybe_original_import_map: Option<ImportMap>,
|
|
||||||
) -> CliGraphResolver {
|
|
||||||
CliGraphResolver::new(CliGraphResolverOptions {
|
|
||||||
node_resolver: None,
|
|
||||||
npm_resolver: None,
|
|
||||||
sloppy_imports_resolver: None,
|
|
||||||
workspace_resolver: Arc::new(WorkspaceResolver::new_raw(
|
|
||||||
Arc::new(ModuleSpecifier::from_directory_path(root_dir).unwrap()),
|
|
||||||
maybe_original_import_map,
|
|
||||||
Vec::new(),
|
|
||||||
Vec::new(),
|
|
||||||
deno_config::workspace::PackageJsonDepResolution::Enabled,
|
|
||||||
)),
|
|
||||||
maybe_jsx_import_source_config,
|
|
||||||
maybe_vendor_dir: None,
|
|
||||||
bare_node_builtins_enabled: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn build_test_graph(
|
|
||||||
roots: Vec<ModuleSpecifier>,
|
|
||||||
loader: TestLoader,
|
|
||||||
resolver: &dyn deno_graph::source::Resolver,
|
|
||||||
analyzer: &dyn deno_graph::ModuleAnalyzer,
|
|
||||||
) -> ModuleGraph {
|
|
||||||
let mut graph = ModuleGraph::new(GraphKind::All);
|
|
||||||
graph
|
|
||||||
.build(
|
|
||||||
roots,
|
|
||||||
&loader,
|
|
||||||
deno_graph::BuildOptions {
|
|
||||||
resolver: Some(resolver),
|
|
||||||
module_analyzer: analyzer,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
graph
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_path(text: &str) -> PathBuf {
|
|
||||||
// This should work all in memory. We're waiting on
|
|
||||||
// https://github.com/servo/rust-url/issues/730 to provide
|
|
||||||
// a cross platform path here
|
|
||||||
assert!(text.starts_with('/'));
|
|
||||||
if cfg!(windows) {
|
|
||||||
PathBuf::from(format!("C:{}", text.replace('/', "\\")))
|
|
||||||
} else {
|
|
||||||
PathBuf::from(text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn path_to_string<P>(path: P) -> String
|
|
||||||
where
|
|
||||||
P: AsRef<Path>,
|
|
||||||
{
|
|
||||||
let path = path.as_ref();
|
|
||||||
// inverse of the function above
|
|
||||||
let path = path.to_string_lossy();
|
|
||||||
if cfg!(windows) {
|
|
||||||
path.replace("C:\\", "\\").replace('\\', "/")
|
|
||||||
} else {
|
|
||||||
path.to_string()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -46,10 +46,6 @@ delete Object.prototype.__proto__;
|
||||||
"UnixListenOptions",
|
"UnixListenOptions",
|
||||||
"createHttpClient",
|
"createHttpClient",
|
||||||
"dlopen",
|
"dlopen",
|
||||||
"flock",
|
|
||||||
"flockSync",
|
|
||||||
"funlock",
|
|
||||||
"funlockSync",
|
|
||||||
"listen",
|
"listen",
|
||||||
"listenDatagram",
|
"listenDatagram",
|
||||||
"openKv",
|
"openKv",
|
||||||
|
@ -1156,7 +1152,6 @@ delete Object.prototype.__proto__;
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"useDefineForClassFields": true,
|
"useDefineForClassFields": true,
|
||||||
"useUnknownInCatchVariables": false,
|
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
"jsxFactory": "React.createElement",
|
"jsxFactory": "React.createElement",
|
||||||
"jsxFragmentFactory": "React.Fragment",
|
"jsxFragmentFactory": "React.Fragment",
|
||||||
|
|
1392
cli/tsc/dts/lib.deno.ns.d.ts
vendored
1392
cli/tsc/dts/lib.deno.ns.d.ts
vendored
File diff suppressed because it is too large
Load diff
6
cli/tsc/dts/lib.deno.shared_globals.d.ts
vendored
6
cli/tsc/dts/lib.deno.shared_globals.d.ts
vendored
|
@ -593,16 +593,12 @@ declare interface Performance extends EventTarget {
|
||||||
endMark?: string,
|
endMark?: string,
|
||||||
): PerformanceMeasure;
|
): PerformanceMeasure;
|
||||||
|
|
||||||
/** Returns a current time from Deno's start in milliseconds.
|
/** Returns a current time from Deno's start in fractional milliseconds.
|
||||||
*
|
|
||||||
* Use the permission flag `--allow-hrtime` to return a precise value.
|
|
||||||
*
|
*
|
||||||
* ```ts
|
* ```ts
|
||||||
* const t = performance.now();
|
* const t = performance.now();
|
||||||
* console.log(`${t} ms since start!`);
|
* console.log(`${t} ms since start!`);
|
||||||
* ```
|
* ```
|
||||||
*
|
|
||||||
* @tags allow-hrtime
|
|
||||||
*/
|
*/
|
||||||
now(): number;
|
now(): number;
|
||||||
|
|
||||||
|
|
133
cli/tsc/dts/lib.deno.unstable.d.ts
vendored
133
cli/tsc/dts/lib.deno.unstable.d.ts
vendored
|
@ -10,18 +10,6 @@
|
||||||
declare namespace Deno {
|
declare namespace Deno {
|
||||||
export {}; // stop default export type behavior
|
export {}; // stop default export type behavior
|
||||||
|
|
||||||
/** Information for a HTTP request.
|
|
||||||
*
|
|
||||||
* @category HTTP Server
|
|
||||||
* @experimental
|
|
||||||
*/
|
|
||||||
export interface ServeHandlerInfo {
|
|
||||||
/** The remote address of the connection. */
|
|
||||||
remoteAddr: Deno.NetAddr;
|
|
||||||
/** The completion promise */
|
|
||||||
completed: Promise<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** **UNSTABLE**: New API, yet to be vetted.
|
/** **UNSTABLE**: New API, yet to be vetted.
|
||||||
*
|
*
|
||||||
* Retrieve the process umask. If `mask` is provided, sets the process umask.
|
* Retrieve the process umask. If `mask` is provided, sets the process umask.
|
||||||
|
@ -852,80 +840,6 @@ declare namespace Deno {
|
||||||
present(): void;
|
present(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** **UNSTABLE**: New API, yet to be vetted.
|
|
||||||
*
|
|
||||||
* These are unstable options which can be used with {@linkcode Deno.run}.
|
|
||||||
*
|
|
||||||
* @category Subprocess
|
|
||||||
* @experimental
|
|
||||||
*/
|
|
||||||
export interface UnstableRunOptions extends RunOptions {
|
|
||||||
/** If `true`, clears the environment variables before executing the
|
|
||||||
* sub-process.
|
|
||||||
*
|
|
||||||
* @default {false} */
|
|
||||||
clearEnv?: boolean;
|
|
||||||
/** For POSIX systems, sets the group ID for the sub process. */
|
|
||||||
gid?: number;
|
|
||||||
/** For POSIX systems, sets the user ID for the sub process. */
|
|
||||||
uid?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** **UNSTABLE**: New API, yet to be vetted.
|
|
||||||
*
|
|
||||||
* Spawns new subprocess. RunOptions must contain at a minimum the `opt.cmd`,
|
|
||||||
* an array of program arguments, the first of which is the binary.
|
|
||||||
*
|
|
||||||
* ```ts
|
|
||||||
* const p = Deno.run({
|
|
||||||
* cmd: ["curl", "https://example.com"],
|
|
||||||
* });
|
|
||||||
* const status = await p.status();
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Subprocess uses same working directory as parent process unless `opt.cwd`
|
|
||||||
* is specified.
|
|
||||||
*
|
|
||||||
* Environmental variables from parent process can be cleared using `opt.clearEnv`.
|
|
||||||
* Doesn't guarantee that only `opt.env` variables are present,
|
|
||||||
* as the OS may set environmental variables for processes.
|
|
||||||
*
|
|
||||||
* Environmental variables for subprocess can be specified using `opt.env`
|
|
||||||
* mapping.
|
|
||||||
*
|
|
||||||
* `opt.uid` sets the child process’s user ID. This translates to a setuid call
|
|
||||||
* in the child process. Failure in the setuid call will cause the spawn to fail.
|
|
||||||
*
|
|
||||||
* `opt.gid` is similar to `opt.uid`, but sets the group ID of the child process.
|
|
||||||
* This has the same semantics as the uid field.
|
|
||||||
*
|
|
||||||
* By default subprocess inherits stdio of parent process. To change
|
|
||||||
* this this, `opt.stdin`, `opt.stdout`, and `opt.stderr` can be set
|
|
||||||
* independently to a resource ID (_rid_) of an open file, `"inherit"`,
|
|
||||||
* `"piped"`, or `"null"`:
|
|
||||||
*
|
|
||||||
* - _number_: the resource ID of an open file/resource. This allows you to
|
|
||||||
* read or write to a file.
|
|
||||||
* - `"inherit"`: The default if unspecified. The subprocess inherits from the
|
|
||||||
* parent.
|
|
||||||
* - `"piped"`: A new pipe should be arranged to connect the parent and child
|
|
||||||
* sub-process.
|
|
||||||
* - `"null"`: This stream will be ignored. This is the equivalent of attaching
|
|
||||||
* the stream to `/dev/null`.
|
|
||||||
*
|
|
||||||
* Details of the spawned process are returned as an instance of
|
|
||||||
* {@linkcode Deno.Process}.
|
|
||||||
*
|
|
||||||
* Requires `allow-run` permission.
|
|
||||||
*
|
|
||||||
* @tags allow-run
|
|
||||||
* @category Subprocess
|
|
||||||
* @experimental
|
|
||||||
*/
|
|
||||||
export function run<T extends UnstableRunOptions = UnstableRunOptions>(
|
|
||||||
opt: T,
|
|
||||||
): Process<T>;
|
|
||||||
|
|
||||||
/** **UNSTABLE**: New API, yet to be vetted.
|
/** **UNSTABLE**: New API, yet to be vetted.
|
||||||
*
|
*
|
||||||
* A custom `HttpClient` for use with {@linkcode fetch} function. This is
|
* A custom `HttpClient` for use with {@linkcode fetch} function. This is
|
||||||
|
@ -1216,44 +1130,6 @@ declare namespace Deno {
|
||||||
options: UnixListenOptions & { transport: "unixpacket" },
|
options: UnixListenOptions & { transport: "unixpacket" },
|
||||||
): DatagramConn;
|
): DatagramConn;
|
||||||
|
|
||||||
/** **UNSTABLE**: New API, yet to be vetted.
|
|
||||||
*
|
|
||||||
* Acquire an advisory file-system lock for the provided file.
|
|
||||||
*
|
|
||||||
* @param [exclusive=false]
|
|
||||||
* @category File System
|
|
||||||
* @experimental
|
|
||||||
*/
|
|
||||||
export function flock(rid: number, exclusive?: boolean): Promise<void>;
|
|
||||||
|
|
||||||
/** **UNSTABLE**: New API, yet to be vetted.
|
|
||||||
*
|
|
||||||
* Acquire an advisory file-system lock synchronously for the provided file.
|
|
||||||
*
|
|
||||||
* @param [exclusive=false]
|
|
||||||
* @category File System
|
|
||||||
* @experimental
|
|
||||||
*/
|
|
||||||
export function flockSync(rid: number, exclusive?: boolean): void;
|
|
||||||
|
|
||||||
/** **UNSTABLE**: New API, yet to be vetted.
|
|
||||||
*
|
|
||||||
* Release an advisory file-system lock for the provided file.
|
|
||||||
*
|
|
||||||
* @category File System
|
|
||||||
* @experimental
|
|
||||||
*/
|
|
||||||
export function funlock(rid: number): Promise<void>;
|
|
||||||
|
|
||||||
/** **UNSTABLE**: New API, yet to be vetted.
|
|
||||||
*
|
|
||||||
* Release an advisory file-system lock for the provided file synchronously.
|
|
||||||
*
|
|
||||||
* @category File System
|
|
||||||
* @experimental
|
|
||||||
*/
|
|
||||||
export function funlockSync(rid: number): void;
|
|
||||||
|
|
||||||
/** **UNSTABLE**: New API, yet to be vetted.
|
/** **UNSTABLE**: New API, yet to be vetted.
|
||||||
*
|
*
|
||||||
* Open a new {@linkcode Deno.Kv} connection to persist data.
|
* Open a new {@linkcode Deno.Kv} connection to persist data.
|
||||||
|
@ -2163,7 +2039,10 @@ declare namespace Deno {
|
||||||
* @category Jupyter
|
* @category Jupyter
|
||||||
* @experimental
|
* @experimental
|
||||||
*/
|
*/
|
||||||
export function display(obj: unknown, options?: DisplayOptions): void;
|
export function display(
|
||||||
|
obj: unknown,
|
||||||
|
options?: DisplayOptions,
|
||||||
|
): Promise<void>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show Markdown in Jupyter frontends with a tagged template function.
|
* Show Markdown in Jupyter frontends with a tagged template function.
|
||||||
|
@ -2236,12 +2115,12 @@ declare namespace Deno {
|
||||||
* Format an object for displaying in Deno
|
* Format an object for displaying in Deno
|
||||||
*
|
*
|
||||||
* @param obj - The object to be displayed
|
* @param obj - The object to be displayed
|
||||||
* @returns MediaBundle
|
* @returns Promise<MediaBundle>
|
||||||
*
|
*
|
||||||
* @category Jupyter
|
* @category Jupyter
|
||||||
* @experimental
|
* @experimental
|
||||||
*/
|
*/
|
||||||
export function format(obj: unknown): MediaBundle;
|
export function format(obj: unknown): Promise<MediaBundle>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Broadcast a message on IO pub channel.
|
* Broadcast a message on IO pub channel.
|
||||||
|
|
6
cli/tsc/dts/lib.dom.d.ts
vendored
6
cli/tsc/dts/lib.dom.d.ts
vendored
|
@ -17550,7 +17550,7 @@ declare var PerformanceServerTiming: {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A legacy interface kept for backwards compatibility and contains properties that offer performance timing information for various events which occur during the loading and use of the current page. You get a PerformanceTiming object describing your page using the window.performance.timing property.
|
* A legacy interface kept for backwards compatibility and contains properties that offer performance timing information for various events which occur during the loading and use of the current page. You get a PerformanceTiming object describing your page using the globalThis.performance.timing property.
|
||||||
* @deprecated This interface is deprecated in the Navigation Timing Level 2 specification. Please use the PerformanceNavigationTiming interface instead.
|
* @deprecated This interface is deprecated in the Navigation Timing Level 2 specification. Please use the PerformanceNavigationTiming interface instead.
|
||||||
*
|
*
|
||||||
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/PerformanceTiming)
|
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/PerformanceTiming)
|
||||||
|
@ -17833,7 +17833,7 @@ declare var Plugin: {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to store a list of Plugin objects describing the available plugins; it's returned by the window.navigator.plugins property. The PluginArray is not a JavaScript array, but has the length property and supports accessing individual items using bracket notation (plugins[2]), as well as via item(index) and namedItem("name") methods.
|
* Used to store a list of Plugin objects describing the available plugins; it's returned by the globalThis.navigator.plugins property. The PluginArray is not a JavaScript array, but has the length property and supports accessing individual items using bracket notation (plugins[2]), as well as via item(index) and namedItem("name") methods.
|
||||||
* @deprecated
|
* @deprecated
|
||||||
*
|
*
|
||||||
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/PluginArray)
|
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/PluginArray)
|
||||||
|
@ -22155,7 +22155,7 @@ declare var SubmitEvent: {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This Web Crypto API interface provides a number of low-level cryptographic functions. It is accessed via the Crypto.subtle properties available in a window context (via Window.crypto).
|
* This Web Crypto API interface provides a number of low-level cryptographic functions. It is accessed via the Crypto.subtle properties available in a window context (via globalThis.crypto).
|
||||||
* Available only in secure contexts.
|
* Available only in secure contexts.
|
||||||
*
|
*
|
||||||
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto)
|
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto)
|
||||||
|
|
4
cli/tsc/dts/lib.webworker.d.ts
vendored
4
cli/tsc/dts/lib.webworker.d.ts
vendored
|
@ -5407,7 +5407,7 @@ declare var StylePropertyMapReadOnly: {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This Web Crypto API interface provides a number of low-level cryptographic functions. It is accessed via the Crypto.subtle properties available in a window context (via Window.crypto).
|
* This Web Crypto API interface provides a number of low-level cryptographic functions. It is accessed via the Crypto.subtle properties available in a window context (via globalThis.crypto).
|
||||||
* Available only in secure contexts.
|
* Available only in secure contexts.
|
||||||
*
|
*
|
||||||
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto)
|
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto)
|
||||||
|
@ -8641,7 +8641,7 @@ declare var WorkerLocation: {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A subset of the Navigator interface allowed to be accessed from a Worker. Such an object is initialized for each worker and is available via the WorkerGlobalScope.navigator property obtained by calling window.self.navigator.
|
* A subset of the Navigator interface allowed to be accessed from a Worker. Such an object is initialized for each worker and is available via the WorkerGlobalScope.navigator property obtained by calling globalThis.self.navigator.
|
||||||
*
|
*
|
||||||
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WorkerNavigator)
|
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WorkerNavigator)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -795,7 +795,7 @@ fn resolve_graph_specifier_types(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_non_graph_specifier_types(
|
fn resolve_non_graph_specifier_types(
|
||||||
specifier: &str,
|
raw_specifier: &str,
|
||||||
referrer: &ModuleSpecifier,
|
referrer: &ModuleSpecifier,
|
||||||
referrer_kind: NodeModuleKind,
|
referrer_kind: NodeModuleKind,
|
||||||
state: &State,
|
state: &State,
|
||||||
|
@ -810,14 +810,16 @@ fn resolve_non_graph_specifier_types(
|
||||||
Ok(Some(NodeResolution::into_specifier_and_media_type(
|
Ok(Some(NodeResolution::into_specifier_and_media_type(
|
||||||
node_resolver
|
node_resolver
|
||||||
.resolve(
|
.resolve(
|
||||||
specifier,
|
raw_specifier,
|
||||||
referrer,
|
referrer,
|
||||||
referrer_kind,
|
referrer_kind,
|
||||||
NodeResolutionMode::Types,
|
NodeResolutionMode::Types,
|
||||||
)
|
)
|
||||||
.ok(),
|
.ok(),
|
||||||
)))
|
)))
|
||||||
} else if let Ok(npm_req_ref) = NpmPackageReqReference::from_str(specifier) {
|
} else if let Ok(npm_req_ref) =
|
||||||
|
NpmPackageReqReference::from_str(raw_specifier)
|
||||||
|
{
|
||||||
debug_assert_eq!(referrer_kind, NodeModuleKind::Esm);
|
debug_assert_eq!(referrer_kind, NodeModuleKind::Esm);
|
||||||
// todo(dsherret): add support for injecting this in the graph so
|
// todo(dsherret): add support for injecting this in the graph so
|
||||||
// we don't need this special code here.
|
// we don't need this special code here.
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use std::env::current_dir;
|
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::Error;
|
use std::io::Error;
|
||||||
use std::io::ErrorKind;
|
use std::io::ErrorKind;
|
||||||
|
@ -18,7 +17,6 @@ use deno_config::glob::WalkEntry;
|
||||||
use deno_core::anyhow::anyhow;
|
use deno_core::anyhow::anyhow;
|
||||||
use deno_core::anyhow::Context;
|
use deno_core::anyhow::Context;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
pub use deno_core::normalize_path;
|
|
||||||
use deno_core::unsync::spawn_blocking;
|
use deno_core::unsync::spawn_blocking;
|
||||||
use deno_core::ModuleSpecifier;
|
use deno_core::ModuleSpecifier;
|
||||||
use deno_runtime::deno_fs::FileSystem;
|
use deno_runtime::deno_fs::FileSystem;
|
||||||
|
@ -255,18 +253,6 @@ fn canonicalize_path_maybe_not_exists_with_custom_fn(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_from_cwd(path: &Path) -> Result<PathBuf, AnyError> {
|
|
||||||
let resolved_path = if path.is_absolute() {
|
|
||||||
path.to_owned()
|
|
||||||
} else {
|
|
||||||
let cwd =
|
|
||||||
current_dir().context("Failed to get current working directory")?;
|
|
||||||
cwd.join(path)
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(normalize_path(resolved_path))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Collects module specifiers that satisfy the given predicate as a file path, by recursively walking `include`.
|
/// Collects module specifiers that satisfy the given predicate as a file path, by recursively walking `include`.
|
||||||
/// Specifiers that start with http and https are left intact.
|
/// Specifiers that start with http and https are left intact.
|
||||||
/// Note: This ignores all .git and node_modules folders.
|
/// Note: This ignores all .git and node_modules folders.
|
||||||
|
@ -510,9 +496,9 @@ pub fn hard_link_dir_recursive(from: &Path, to: &Path) -> Result<(), AnyError> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn symlink_dir(oldpath: &Path, newpath: &Path) -> Result<(), Error> {
|
pub fn symlink_dir(oldpath: &Path, newpath: &Path) -> Result<(), Error> {
|
||||||
let err_mapper = |err: Error| {
|
let err_mapper = |err: Error, kind: Option<ErrorKind>| {
|
||||||
Error::new(
|
Error::new(
|
||||||
err.kind(),
|
kind.unwrap_or_else(|| err.kind()),
|
||||||
format!(
|
format!(
|
||||||
"{}, symlink '{}' -> '{}'",
|
"{}, symlink '{}' -> '{}'",
|
||||||
err,
|
err,
|
||||||
|
@ -524,12 +510,19 @@ pub fn symlink_dir(oldpath: &Path, newpath: &Path) -> Result<(), Error> {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
use std::os::unix::fs::symlink;
|
use std::os::unix::fs::symlink;
|
||||||
symlink(oldpath, newpath).map_err(err_mapper)?;
|
symlink(oldpath, newpath).map_err(|e| err_mapper(e, None))?;
|
||||||
}
|
}
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
{
|
{
|
||||||
use std::os::windows::fs::symlink_dir;
|
use std::os::windows::fs::symlink_dir;
|
||||||
symlink_dir(oldpath, newpath).map_err(err_mapper)?;
|
symlink_dir(oldpath, newpath).map_err(|err| {
|
||||||
|
if let Some(code) = err.raw_os_error() {
|
||||||
|
if code as u32 == winapi::shared::winerror::ERROR_PRIVILEGE_NOT_HELD {
|
||||||
|
return err_mapper(err, Some(ErrorKind::PermissionDenied));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err_mapper(err, None)
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -715,30 +708,13 @@ pub fn specifier_from_file_path(
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use deno_core::futures;
|
use deno_core::futures;
|
||||||
|
use deno_core::normalize_path;
|
||||||
use deno_core::parking_lot::Mutex;
|
use deno_core::parking_lot::Mutex;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use test_util::PathRef;
|
use test_util::PathRef;
|
||||||
use test_util::TempDir;
|
use test_util::TempDir;
|
||||||
use tokio::sync::Notify;
|
use tokio::sync::Notify;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn resolve_from_cwd_child() {
|
|
||||||
let cwd = current_dir().unwrap();
|
|
||||||
assert_eq!(resolve_from_cwd(Path::new("a")).unwrap(), cwd.join("a"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn resolve_from_cwd_dot() {
|
|
||||||
let cwd = current_dir().unwrap();
|
|
||||||
assert_eq!(resolve_from_cwd(Path::new(".")).unwrap(), cwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn resolve_from_cwd_parent() {
|
|
||||||
let cwd = current_dir().unwrap();
|
|
||||||
assert_eq!(resolve_from_cwd(Path::new("a/..")).unwrap(), cwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_normalize_path() {
|
fn test_normalize_path() {
|
||||||
assert_eq!(normalize_path(Path::new("a/../b")), PathBuf::from("b"));
|
assert_eq!(normalize_path(Path::new("a/../b")), PathBuf::from("b"));
|
||||||
|
@ -756,14 +732,6 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn resolve_from_cwd_absolute() {
|
|
||||||
let expected = Path::new("a");
|
|
||||||
let cwd = current_dir().unwrap();
|
|
||||||
let absolute_expected = cwd.join(expected);
|
|
||||||
assert_eq!(resolve_from_cwd(expected).unwrap(), absolute_expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collect_specifiers() {
|
fn test_collect_specifiers() {
|
||||||
fn create_files(dir_path: &PathRef, files: &[&str]) {
|
fn create_files(dir_path: &PathRef, files: &[&str]) {
|
||||||
|
|
|
@ -41,8 +41,10 @@ impl log::Log for CliLogger {
|
||||||
pub fn init(maybe_level: Option<log::Level>) {
|
pub fn init(maybe_level: Option<log::Level>) {
|
||||||
let log_level = maybe_level.unwrap_or(log::Level::Info);
|
let log_level = maybe_level.unwrap_or(log::Level::Info);
|
||||||
let logger = env_logger::Builder::from_env(
|
let logger = env_logger::Builder::from_env(
|
||||||
env_logger::Env::default()
|
env_logger::Env::new()
|
||||||
.default_filter_or(log_level.to_level_filter().to_string()),
|
// Use `DENO_LOG` and `DENO_LOG_STYLE` instead of `RUST_` prefix
|
||||||
|
.filter_or("DENO_LOG", log_level.to_level_filter().to_string())
|
||||||
|
.write_style("DENO_LOG_STYLE"),
|
||||||
)
|
)
|
||||||
// https://github.com/denoland/deno/issues/6641
|
// https://github.com/denoland/deno/issues/6641
|
||||||
.filter_module("rustyline", log::LevelFilter::Off)
|
.filter_module("rustyline", log::LevelFilter::Off)
|
||||||
|
|
|
@ -42,6 +42,21 @@ pub fn get_extension(file_path: &Path) -> Option<String> {
|
||||||
.map(|e| e.to_lowercase());
|
.map(|e| e.to_lowercase());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn specifier_has_extension(
|
||||||
|
specifier: &ModuleSpecifier,
|
||||||
|
searching_ext: &str,
|
||||||
|
) -> bool {
|
||||||
|
let Some((_, ext)) = specifier.path().rsplit_once('.') else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let searching_ext = searching_ext.strip_prefix('.').unwrap_or(searching_ext);
|
||||||
|
debug_assert!(!searching_ext.contains('.')); // exts like .d.ts are not implemented here
|
||||||
|
if ext.len() != searching_ext.len() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ext.eq_ignore_ascii_case(searching_ext)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_atomic_dir_path(file_path: &Path) -> PathBuf {
|
pub fn get_atomic_dir_path(file_path: &Path) -> PathBuf {
|
||||||
let rand = gen_rand_path_component();
|
let rand = gen_rand_path_component();
|
||||||
let new_file_name = format!(
|
let new_file_name = format!(
|
||||||
|
@ -145,34 +160,6 @@ pub fn relative_specifier(
|
||||||
Some(to_percent_decoded_str(&text))
|
Some(to_percent_decoded_str(&text))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a path with the specified file stem suffix.
|
|
||||||
///
|
|
||||||
/// Ex. `file.ts` with suffix `_2` returns `file_2.ts`
|
|
||||||
pub fn path_with_stem_suffix(path: &Path, suffix: &str) -> PathBuf {
|
|
||||||
if let Some(file_name) = path.file_name().map(|f| f.to_string_lossy()) {
|
|
||||||
if let Some(file_stem) = path.file_stem().map(|f| f.to_string_lossy()) {
|
|
||||||
if let Some(ext) = path.extension().map(|f| f.to_string_lossy()) {
|
|
||||||
return if file_stem.to_lowercase().ends_with(".d") {
|
|
||||||
path.with_file_name(format!(
|
|
||||||
"{}{}.{}.{}",
|
|
||||||
&file_stem[..file_stem.len() - ".d".len()],
|
|
||||||
suffix,
|
|
||||||
// maintain casing
|
|
||||||
&file_stem[file_stem.len() - "d".len()..],
|
|
||||||
ext
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
path.with_file_name(format!("{file_stem}{suffix}.{ext}"))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
path.with_file_name(format!("{file_name}{suffix}"))
|
|
||||||
} else {
|
|
||||||
path.with_file_name(suffix)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(windows, allow(dead_code))]
|
#[cfg_attr(windows, allow(dead_code))]
|
||||||
pub fn relative_path(from: &Path, to: &Path) -> Option<PathBuf> {
|
pub fn relative_path(from: &Path, to: &Path) -> Option<PathBuf> {
|
||||||
pathdiff::diff_paths(to, from)
|
pathdiff::diff_paths(to, from)
|
||||||
|
@ -406,43 +393,15 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_path_with_stem_suffix() {
|
fn test_specifier_has_extension() {
|
||||||
assert_eq!(
|
fn get(specifier: &str, ext: &str) -> bool {
|
||||||
path_with_stem_suffix(&PathBuf::from("/"), "_2"),
|
specifier_has_extension(&ModuleSpecifier::parse(specifier).unwrap(), ext)
|
||||||
PathBuf::from("/_2")
|
}
|
||||||
);
|
|
||||||
assert_eq!(
|
assert!(get("file:///a/b/c.ts", "ts"));
|
||||||
path_with_stem_suffix(&PathBuf::from("/test"), "_2"),
|
assert!(get("file:///a/b/c.ts", ".ts"));
|
||||||
PathBuf::from("/test_2")
|
assert!(!get("file:///a/b/c.ts", ".cts"));
|
||||||
);
|
assert!(get("file:///a/b/c.CtS", ".cts"));
|
||||||
assert_eq!(
|
|
||||||
path_with_stem_suffix(&PathBuf::from("/test.txt"), "_2"),
|
|
||||||
PathBuf::from("/test_2.txt")
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
path_with_stem_suffix(&PathBuf::from("/test/subdir"), "_2"),
|
|
||||||
PathBuf::from("/test/subdir_2")
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
path_with_stem_suffix(&PathBuf::from("/test/subdir.other.txt"), "_2"),
|
|
||||||
PathBuf::from("/test/subdir.other_2.txt")
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
path_with_stem_suffix(&PathBuf::from("/test.d.ts"), "_2"),
|
|
||||||
PathBuf::from("/test_2.d.ts")
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
path_with_stem_suffix(&PathBuf::from("/test.D.TS"), "_2"),
|
|
||||||
PathBuf::from("/test_2.D.TS")
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
path_with_stem_suffix(&PathBuf::from("/test.d.mts"), "_2"),
|
|
||||||
PathBuf::from("/test_2.d.mts")
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
path_with_stem_suffix(&PathBuf::from("/test.d.cts"), "_2"),
|
|
||||||
PathBuf::from("/test_2.d.cts")
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -9,6 +9,8 @@ const TYPESCRIPT: &str = env!("TS_VERSION");
|
||||||
const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
|
const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
// TODO(bartlomieju): ideally we could remove this const.
|
// TODO(bartlomieju): ideally we could remove this const.
|
||||||
const IS_CANARY: bool = option_env!("DENO_CANARY").is_some();
|
const IS_CANARY: bool = option_env!("DENO_CANARY").is_some();
|
||||||
|
// TODO(bartlomieju): this is temporary, to allow Homebrew to cut RC releases as well
|
||||||
|
const IS_RC: bool = option_env!("DENO_RC").is_some();
|
||||||
|
|
||||||
pub static DENO_VERSION_INFO: Lazy<DenoVersionInfo> = Lazy::new(|| {
|
pub static DENO_VERSION_INFO: Lazy<DenoVersionInfo> = Lazy::new(|| {
|
||||||
let release_channel = libsui::find_section("denover")
|
let release_channel = libsui::find_section("denover")
|
||||||
|
@ -17,6 +19,8 @@ pub static DENO_VERSION_INFO: Lazy<DenoVersionInfo> = Lazy::new(|| {
|
||||||
.unwrap_or({
|
.unwrap_or({
|
||||||
if IS_CANARY {
|
if IS_CANARY {
|
||||||
ReleaseChannel::Canary
|
ReleaseChannel::Canary
|
||||||
|
} else if IS_RC {
|
||||||
|
ReleaseChannel::Rc
|
||||||
} else {
|
} else {
|
||||||
ReleaseChannel::Stable
|
ReleaseChannel::Stable
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,6 +116,9 @@ pub struct CliMainWorkerOptions {
|
||||||
pub skip_op_registration: bool,
|
pub skip_op_registration: bool,
|
||||||
pub create_hmr_runner: Option<CreateHmrRunnerCb>,
|
pub create_hmr_runner: Option<CreateHmrRunnerCb>,
|
||||||
pub create_coverage_collector: Option<CreateCoverageCollectorCb>,
|
pub create_coverage_collector: Option<CreateCoverageCollectorCb>,
|
||||||
|
pub node_ipc: Option<i64>,
|
||||||
|
pub serve_port: Option<u16>,
|
||||||
|
pub serve_host: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SharedWorkerState {
|
struct SharedWorkerState {
|
||||||
|
@ -135,13 +138,7 @@ struct SharedWorkerState {
|
||||||
maybe_inspector_server: Option<Arc<InspectorServer>>,
|
maybe_inspector_server: Option<Arc<InspectorServer>>,
|
||||||
maybe_lockfile: Option<Arc<CliLockfile>>,
|
maybe_lockfile: Option<Arc<CliLockfile>>,
|
||||||
feature_checker: Arc<FeatureChecker>,
|
feature_checker: Arc<FeatureChecker>,
|
||||||
node_ipc: Option<i64>,
|
|
||||||
enable_future_features: bool,
|
|
||||||
disable_deprecated_api_warning: bool,
|
|
||||||
verbose_deprecated_api_warning: bool,
|
|
||||||
code_cache: Option<Arc<dyn code_cache::CodeCache>>,
|
code_cache: Option<Arc<dyn code_cache::CodeCache>>,
|
||||||
serve_port: Option<u16>,
|
|
||||||
serve_host: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SharedWorkerState {
|
impl SharedWorkerState {
|
||||||
|
@ -434,14 +431,8 @@ impl CliMainWorkerFactory {
|
||||||
maybe_inspector_server: Option<Arc<InspectorServer>>,
|
maybe_inspector_server: Option<Arc<InspectorServer>>,
|
||||||
maybe_lockfile: Option<Arc<CliLockfile>>,
|
maybe_lockfile: Option<Arc<CliLockfile>>,
|
||||||
feature_checker: Arc<FeatureChecker>,
|
feature_checker: Arc<FeatureChecker>,
|
||||||
options: CliMainWorkerOptions,
|
|
||||||
node_ipc: Option<i64>,
|
|
||||||
serve_port: Option<u16>,
|
|
||||||
serve_host: Option<String>,
|
|
||||||
enable_future_features: bool,
|
|
||||||
disable_deprecated_api_warning: bool,
|
|
||||||
verbose_deprecated_api_warning: bool,
|
|
||||||
code_cache: Option<Arc<dyn code_cache::CodeCache>>,
|
code_cache: Option<Arc<dyn code_cache::CodeCache>>,
|
||||||
|
options: CliMainWorkerOptions,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
shared: Arc::new(SharedWorkerState {
|
shared: Arc::new(SharedWorkerState {
|
||||||
|
@ -461,12 +452,6 @@ impl CliMainWorkerFactory {
|
||||||
maybe_inspector_server,
|
maybe_inspector_server,
|
||||||
maybe_lockfile,
|
maybe_lockfile,
|
||||||
feature_checker,
|
feature_checker,
|
||||||
node_ipc,
|
|
||||||
serve_port,
|
|
||||||
serve_host,
|
|
||||||
enable_future_features,
|
|
||||||
disable_deprecated_api_warning,
|
|
||||||
verbose_deprecated_api_warning,
|
|
||||||
code_cache,
|
code_cache,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -602,13 +587,10 @@ impl CliMainWorkerFactory {
|
||||||
has_node_modules_dir: shared.options.has_node_modules_dir,
|
has_node_modules_dir: shared.options.has_node_modules_dir,
|
||||||
argv0: shared.options.argv0.clone(),
|
argv0: shared.options.argv0.clone(),
|
||||||
node_debug: shared.options.node_debug.clone(),
|
node_debug: shared.options.node_debug.clone(),
|
||||||
node_ipc_fd: shared.node_ipc,
|
node_ipc_fd: shared.options.node_ipc,
|
||||||
disable_deprecated_api_warning: shared.disable_deprecated_api_warning,
|
|
||||||
verbose_deprecated_api_warning: shared.verbose_deprecated_api_warning,
|
|
||||||
future: shared.enable_future_features,
|
|
||||||
mode,
|
mode,
|
||||||
serve_port: shared.serve_port,
|
serve_port: shared.options.serve_port,
|
||||||
serve_host: shared.serve_host.clone(),
|
serve_host: shared.options.serve_host.clone(),
|
||||||
},
|
},
|
||||||
extensions: custom_extensions,
|
extensions: custom_extensions,
|
||||||
startup_snapshot: crate::js::deno_isolate_init(),
|
startup_snapshot: crate::js::deno_isolate_init(),
|
||||||
|
@ -801,12 +783,9 @@ fn create_web_worker_callback(
|
||||||
argv0: shared.options.argv0.clone(),
|
argv0: shared.options.argv0.clone(),
|
||||||
node_debug: shared.options.node_debug.clone(),
|
node_debug: shared.options.node_debug.clone(),
|
||||||
node_ipc_fd: None,
|
node_ipc_fd: None,
|
||||||
disable_deprecated_api_warning: shared.disable_deprecated_api_warning,
|
|
||||||
verbose_deprecated_api_warning: shared.verbose_deprecated_api_warning,
|
|
||||||
future: shared.enable_future_features,
|
|
||||||
mode: WorkerExecutionMode::Worker,
|
mode: WorkerExecutionMode::Worker,
|
||||||
serve_port: shared.serve_port,
|
serve_port: shared.options.serve_port,
|
||||||
serve_host: shared.serve_host.clone(),
|
serve_host: shared.options.serve_host.clone(),
|
||||||
},
|
},
|
||||||
extensions: vec![],
|
extensions: vec![],
|
||||||
startup_snapshot: crate::js::deno_isolate_init(),
|
startup_snapshot: crate::js::deno_isolate_init(),
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "deno_broadcast_channel"
|
name = "deno_broadcast_channel"
|
||||||
version = "0.160.0"
|
version = "0.162.0"
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
2
ext/cache/01_cache.js
vendored
2
ext/cache/01_cache.js
vendored
|
@ -105,7 +105,7 @@ class Cache {
|
||||||
const reqUrl = new URL(innerRequest.url());
|
const reqUrl = new URL(innerRequest.url());
|
||||||
if (reqUrl.protocol !== "http:" && reqUrl.protocol !== "https:") {
|
if (reqUrl.protocol !== "http:" && reqUrl.protocol !== "https:") {
|
||||||
throw new TypeError(
|
throw new TypeError(
|
||||||
"Request url protocol must be 'http:' or 'https:'",
|
`Request url protocol must be 'http:' or 'https:': received '${reqUrl.protocol}'`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (innerRequest.method !== "GET") {
|
if (innerRequest.method !== "GET") {
|
||||||
|
|
2
ext/cache/Cargo.toml
vendored
2
ext/cache/Cargo.toml
vendored
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "deno_cache"
|
name = "deno_cache"
|
||||||
version = "0.98.0"
|
version = "0.100.0"
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
2
ext/cache/lib.rs
vendored
2
ext/cache/lib.rs
vendored
|
@ -211,7 +211,7 @@ where
|
||||||
state.put(cache);
|
state.put(cache);
|
||||||
Ok(state.borrow::<CA>().clone())
|
Ok(state.borrow::<CA>().clone())
|
||||||
} else {
|
} else {
|
||||||
Err(type_error("CacheStorage is not available in this context."))
|
Err(type_error("CacheStorage is not available in this context"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "deno_canvas"
|
name = "deno_canvas"
|
||||||
version = "0.35.0"
|
version = "0.37.0"
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
|
@ -179,7 +179,7 @@ class AssertionError extends Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function assert(cond, msg = "Assertion failed.") {
|
function assert(cond, msg = "Assertion failed") {
|
||||||
if (!cond) {
|
if (!cond) {
|
||||||
throw new AssertionError(msg);
|
throw new AssertionError(msg);
|
||||||
}
|
}
|
||||||
|
@ -260,6 +260,7 @@ const colors = {
|
||||||
|
|
||||||
function defineColorAlias(target, alias) {
|
function defineColorAlias(target, alias) {
|
||||||
ObjectDefineProperty(colors, alias, {
|
ObjectDefineProperty(colors, alias, {
|
||||||
|
__proto__: null,
|
||||||
get() {
|
get() {
|
||||||
return this[target];
|
return this[target];
|
||||||
},
|
},
|
||||||
|
@ -3236,8 +3237,8 @@ class Console {
|
||||||
table = (data = undefined, properties = undefined) => {
|
table = (data = undefined, properties = undefined) => {
|
||||||
if (properties !== undefined && !ArrayIsArray(properties)) {
|
if (properties !== undefined && !ArrayIsArray(properties)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"The 'properties' argument must be of type Array. " +
|
"The 'properties' argument must be of type Array: " +
|
||||||
"Received type " + typeof properties,
|
"received type " + typeof properties,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3447,7 +3448,10 @@ function inspect(
|
||||||
function createFilteredInspectProxy({ object, keys, evaluate }) {
|
function createFilteredInspectProxy({ object, keys, evaluate }) {
|
||||||
const obj = class {};
|
const obj = class {};
|
||||||
if (object.constructor?.name) {
|
if (object.constructor?.name) {
|
||||||
ObjectDefineProperty(obj, "name", { value: object.constructor.name });
|
ObjectDefineProperty(obj, "name", {
|
||||||
|
__proto__: null,
|
||||||
|
value: object.constructor.name,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Proxy(new obj(), {
|
return new Proxy(new obj(), {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "deno_console"
|
name = "deno_console"
|
||||||
version = "0.166.0"
|
version = "0.168.0"
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
|
@ -41,7 +41,9 @@ export function formatToCronSchedule(
|
||||||
} else if (end === undefined && every !== undefined) {
|
} else if (end === undefined && every !== undefined) {
|
||||||
return "*/" + every;
|
return "*/" + every;
|
||||||
} else {
|
} else {
|
||||||
throw new TypeError("Invalid cron schedule");
|
throw new TypeError(
|
||||||
|
`Invalid cron schedule: start=${start}, end=${end}, every=${every}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (typeof exact === "number") {
|
if (typeof exact === "number") {
|
||||||
|
@ -103,10 +105,14 @@ function cron(
|
||||||
handler2?: () => Promise<void> | void,
|
handler2?: () => Promise<void> | void,
|
||||||
) {
|
) {
|
||||||
if (name === undefined) {
|
if (name === undefined) {
|
||||||
throw new TypeError("Deno.cron requires a unique name");
|
throw new TypeError(
|
||||||
|
"Cannot create cron job, a unique name is required: received 'undefined'",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (schedule === undefined) {
|
if (schedule === undefined) {
|
||||||
throw new TypeError("Deno.cron requires a valid schedule");
|
throw new TypeError(
|
||||||
|
"Cannot create cron job, a schedule is required: received 'undefined'",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
schedule = parseScheduleToString(schedule);
|
schedule = parseScheduleToString(schedule);
|
||||||
|
@ -119,13 +125,15 @@ function cron(
|
||||||
if (typeof handlerOrOptions1 === "function") {
|
if (typeof handlerOrOptions1 === "function") {
|
||||||
handler = handlerOrOptions1;
|
handler = handlerOrOptions1;
|
||||||
if (handler2 !== undefined) {
|
if (handler2 !== undefined) {
|
||||||
throw new TypeError("Deno.cron requires a single handler");
|
throw new TypeError(
|
||||||
|
"Cannot create cron job, a single handler is required: two handlers were specified",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else if (typeof handler2 === "function") {
|
} else if (typeof handler2 === "function") {
|
||||||
handler = handler2;
|
handler = handler2;
|
||||||
options = handlerOrOptions1;
|
options = handlerOrOptions1;
|
||||||
} else {
|
} else {
|
||||||
throw new TypeError("Deno.cron requires a handler");
|
throw new TypeError("Cannot create cron job: a handler is required");
|
||||||
}
|
}
|
||||||
|
|
||||||
const rid = op_cron_create(
|
const rid = op_cron_create(
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "deno_cron"
|
name = "deno_cron"
|
||||||
version = "0.46.0"
|
version = "0.48.0"
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue