mirror of
https://github.com/denoland/deno.git
synced 2024-11-24 15:19:26 -05:00
Merge branch 'main' into open-flag-on-serve
This commit is contained in:
commit
7dcb5606b0
204 changed files with 4630 additions and 453 deletions
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.
|
||||
// Note: the tools/release/01_bump_crate_versions.ts script will update this version
|
||||
// automatically via regex, so ensure that this line maintains this format.
|
||||
const cacheVersion = 25;
|
||||
const cacheVersion = 26;
|
||||
|
||||
const ubuntuX86Runner = "ubuntu-24.04";
|
||||
const ubuntuX86XlRunner = "ubuntu-24.04-xl";
|
||||
|
|
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
|
@ -361,8 +361,8 @@ jobs:
|
|||
path: |-
|
||||
~/.cargo/registry/index
|
||||
~/.cargo/registry/cache
|
||||
key: '25-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}'
|
||||
restore-keys: '25-cargo-home-${{ matrix.os }}-${{ matrix.arch }}'
|
||||
key: '26-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}'
|
||||
restore-keys: '26-cargo-home-${{ matrix.os }}-${{ matrix.arch }}'
|
||||
if: '!(matrix.skip)'
|
||||
- name: Restore cache build output (PR)
|
||||
uses: actions/cache/restore@v4
|
||||
|
@ -375,7 +375,7 @@ jobs:
|
|||
!./target/*/*.zip
|
||||
!./target/*/*.tar.gz
|
||||
key: never_saved
|
||||
restore-keys: '25-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-'
|
||||
restore-keys: '26-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-'
|
||||
- name: Apply and update mtime cache
|
||||
if: '!(matrix.skip) && (!startsWith(github.ref, ''refs/tags/''))'
|
||||
uses: ./.github/mtime_cache
|
||||
|
@ -685,7 +685,7 @@ jobs:
|
|||
!./target/*/*.zip
|
||||
!./target/*/*.sha256sum
|
||||
!./target/*/*.tar.gz
|
||||
key: '25-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}'
|
||||
key: '26-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}'
|
||||
publish-canary:
|
||||
name: publish canary
|
||||
runs-on: ubuntu-24.04
|
||||
|
|
91
Cargo.lock
generated
91
Cargo.lock
generated
|
@ -1201,7 +1201,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno"
|
||||
version = "2.0.6"
|
||||
version = "2.1.0"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"async-trait",
|
||||
|
@ -1232,6 +1232,7 @@ dependencies = [
|
|||
"deno_resolver",
|
||||
"deno_runtime",
|
||||
"deno_semver",
|
||||
"deno_sqlformat",
|
||||
"deno_task_shell",
|
||||
"deno_terminal 0.2.0",
|
||||
"deno_tower_lsp",
|
||||
|
@ -1291,7 +1292,6 @@ dependencies = [
|
|||
"sha2",
|
||||
"shell-escape",
|
||||
"spki",
|
||||
"sqlformat",
|
||||
"strsim",
|
||||
"tar",
|
||||
"tempfile",
|
||||
|
@ -1371,7 +1371,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_bench_util"
|
||||
version = "0.171.0"
|
||||
version = "0.172.0"
|
||||
dependencies = [
|
||||
"bencher",
|
||||
"deno_core",
|
||||
|
@ -1380,7 +1380,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_broadcast_channel"
|
||||
version = "0.171.0"
|
||||
version = "0.172.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"deno_core",
|
||||
|
@ -1391,7 +1391,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_cache"
|
||||
version = "0.109.0"
|
||||
version = "0.110.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"deno_core",
|
||||
|
@ -1424,7 +1424,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_canvas"
|
||||
version = "0.46.0"
|
||||
version = "0.47.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_webgpu",
|
||||
|
@ -1435,9 +1435,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_config"
|
||||
version = "0.39.1"
|
||||
version = "0.39.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a91aa99751ebe305a7edad12a3ad751f3b3b9f5ecddbfe4a0459e3cdc8493b6"
|
||||
checksum = "38fb809500238be2b10eee42944a47b3ac38974e1edbb47f73afcfca7df143bf"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"deno_package_json",
|
||||
|
@ -1459,7 +1459,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_console"
|
||||
version = "0.177.0"
|
||||
version = "0.178.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
]
|
||||
|
@ -1506,7 +1506,7 @@ checksum = "fe4dccb6147bb3f3ba0c7a48e993bfeb999d2c2e47a81badee80e2b370c8d695"
|
|||
|
||||
[[package]]
|
||||
name = "deno_cron"
|
||||
version = "0.57.0"
|
||||
version = "0.58.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -1519,7 +1519,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_crypto"
|
||||
version = "0.191.0"
|
||||
version = "0.192.0"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"aes-gcm",
|
||||
|
@ -1587,7 +1587,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_fetch"
|
||||
version = "0.201.0"
|
||||
version = "0.202.0"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
|
@ -1621,7 +1621,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_ffi"
|
||||
version = "0.164.0"
|
||||
version = "0.165.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_permissions",
|
||||
|
@ -1641,7 +1641,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_fs"
|
||||
version = "0.87.0"
|
||||
version = "0.88.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"base32",
|
||||
|
@ -1694,7 +1694,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_http"
|
||||
version = "0.175.0"
|
||||
version = "0.176.0"
|
||||
dependencies = [
|
||||
"async-compression",
|
||||
"async-trait",
|
||||
|
@ -1733,7 +1733,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_io"
|
||||
version = "0.87.0"
|
||||
version = "0.88.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"deno_core",
|
||||
|
@ -1754,7 +1754,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_kv"
|
||||
version = "0.85.0"
|
||||
version = "0.86.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -1827,7 +1827,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_napi"
|
||||
version = "0.108.0"
|
||||
version = "0.109.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_permissions",
|
||||
|
@ -1855,7 +1855,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_net"
|
||||
version = "0.169.0"
|
||||
version = "0.170.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_permissions",
|
||||
|
@ -1872,7 +1872,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_node"
|
||||
version = "0.114.0"
|
||||
version = "0.115.0"
|
||||
dependencies = [
|
||||
"aead-gcm-stream",
|
||||
"aes",
|
||||
|
@ -2024,7 +2024,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_permissions"
|
||||
version = "0.37.0"
|
||||
version = "0.38.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_path_util",
|
||||
|
@ -2042,7 +2042,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_resolver"
|
||||
version = "0.9.0"
|
||||
version = "0.10.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base32",
|
||||
|
@ -2061,7 +2061,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_runtime"
|
||||
version = "0.186.0"
|
||||
version = "0.187.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"color-print",
|
||||
|
@ -2147,6 +2147,18 @@ dependencies = [
|
|||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deno_sqlformat"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e196799ec0cc240fac1fb5c5bf813ef92a9602740a059cfcbb20593b2deee52"
|
||||
dependencies = [
|
||||
"nom 7.1.3",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"unicode_categories",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deno_task_shell"
|
||||
version = "0.18.1"
|
||||
|
@ -2186,7 +2198,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_tls"
|
||||
version = "0.164.0"
|
||||
version = "0.165.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_native_certs",
|
||||
|
@ -2235,7 +2247,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_url"
|
||||
version = "0.177.0"
|
||||
version = "0.178.0"
|
||||
dependencies = [
|
||||
"deno_bench_util",
|
||||
"deno_console",
|
||||
|
@ -2247,7 +2259,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_web"
|
||||
version = "0.208.0"
|
||||
version = "0.209.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"base64-simd 0.8.0",
|
||||
|
@ -2269,7 +2281,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_webgpu"
|
||||
version = "0.144.0"
|
||||
version = "0.145.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"raw-window-handle",
|
||||
|
@ -2282,7 +2294,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_webidl"
|
||||
version = "0.177.0"
|
||||
version = "0.178.0"
|
||||
dependencies = [
|
||||
"deno_bench_util",
|
||||
"deno_core",
|
||||
|
@ -2290,7 +2302,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_websocket"
|
||||
version = "0.182.0"
|
||||
version = "0.183.0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"deno_core",
|
||||
|
@ -2312,7 +2324,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_webstorage"
|
||||
version = "0.172.0"
|
||||
version = "0.173.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_web",
|
||||
|
@ -4562,9 +4574,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "markup_fmt"
|
||||
version = "0.15.0"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebae65c91eab3d42231232bf48107f351e5a8d511454927218c53aeb68bbdb6f"
|
||||
checksum = "f303c36143671ac6c54112eb5aa95649b169dae783fdb6ead2c0e88b408c425c"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"css_dataset",
|
||||
|
@ -4740,7 +4752,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "napi_sym"
|
||||
version = "0.107.0"
|
||||
version = "0.108.0"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"serde",
|
||||
|
@ -4795,7 +4807,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "node_resolver"
|
||||
version = "0.16.0"
|
||||
version = "0.17.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -6797,17 +6809,6 @@ dependencies = [
|
|||
"der",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlformat"
|
||||
version = "0.3.1"
|
||||
source = "git+https://github.com/shssoichiro/sqlformat-rs.git?rev=827d639#827d639bef94d8e5a5a0e29b41185c8d572f24e6"
|
||||
dependencies = [
|
||||
"nom 7.1.3",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"unicode_categories",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
|
|
58
Cargo.toml
58
Cargo.toml
|
@ -48,17 +48,17 @@ repository = "https://github.com/denoland/deno"
|
|||
deno_ast = { version = "=0.43.3", features = ["transpiling"] }
|
||||
deno_core = { version = "0.321.0" }
|
||||
|
||||
deno_bench_util = { version = "0.171.0", path = "./bench_util" }
|
||||
deno_config = { version = "=0.39.1", features = ["workspace", "sync"] }
|
||||
deno_bench_util = { version = "0.172.0", path = "./bench_util" }
|
||||
deno_config = { version = "=0.39.2", features = ["workspace", "sync"] }
|
||||
deno_lockfile = "=0.23.1"
|
||||
deno_media_type = { version = "0.2.0", features = ["module_specifier"] }
|
||||
deno_npm = "=0.25.4"
|
||||
deno_path_util = "=0.2.1"
|
||||
deno_permissions = { version = "0.37.0", path = "./runtime/permissions" }
|
||||
deno_runtime = { version = "0.186.0", path = "./runtime" }
|
||||
deno_permissions = { version = "0.38.0", path = "./runtime/permissions" }
|
||||
deno_runtime = { version = "0.187.0", path = "./runtime" }
|
||||
deno_semver = "=0.5.16"
|
||||
deno_terminal = "0.2.0"
|
||||
napi_sym = { version = "0.107.0", path = "./ext/napi/sym" }
|
||||
napi_sym = { version = "0.108.0", path = "./ext/napi/sym" }
|
||||
test_util = { package = "test_server", path = "./tests/util/server" }
|
||||
|
||||
denokv_proto = "0.8.4"
|
||||
|
@ -67,32 +67,32 @@ denokv_remote = "0.8.4"
|
|||
denokv_sqlite = { default-features = false, version = "0.8.4" }
|
||||
|
||||
# exts
|
||||
deno_broadcast_channel = { version = "0.171.0", path = "./ext/broadcast_channel" }
|
||||
deno_cache = { version = "0.109.0", path = "./ext/cache" }
|
||||
deno_canvas = { version = "0.46.0", path = "./ext/canvas" }
|
||||
deno_console = { version = "0.177.0", path = "./ext/console" }
|
||||
deno_cron = { version = "0.57.0", path = "./ext/cron" }
|
||||
deno_crypto = { version = "0.191.0", path = "./ext/crypto" }
|
||||
deno_fetch = { version = "0.201.0", path = "./ext/fetch" }
|
||||
deno_ffi = { version = "0.164.0", path = "./ext/ffi" }
|
||||
deno_fs = { version = "0.87.0", path = "./ext/fs" }
|
||||
deno_http = { version = "0.175.0", path = "./ext/http" }
|
||||
deno_io = { version = "0.87.0", path = "./ext/io" }
|
||||
deno_kv = { version = "0.85.0", path = "./ext/kv" }
|
||||
deno_napi = { version = "0.108.0", path = "./ext/napi" }
|
||||
deno_net = { version = "0.169.0", path = "./ext/net" }
|
||||
deno_node = { version = "0.114.0", path = "./ext/node" }
|
||||
deno_tls = { version = "0.164.0", path = "./ext/tls" }
|
||||
deno_url = { version = "0.177.0", path = "./ext/url" }
|
||||
deno_web = { version = "0.208.0", path = "./ext/web" }
|
||||
deno_webgpu = { version = "0.144.0", path = "./ext/webgpu" }
|
||||
deno_webidl = { version = "0.177.0", path = "./ext/webidl" }
|
||||
deno_websocket = { version = "0.182.0", path = "./ext/websocket" }
|
||||
deno_webstorage = { version = "0.172.0", path = "./ext/webstorage" }
|
||||
deno_broadcast_channel = { version = "0.172.0", path = "./ext/broadcast_channel" }
|
||||
deno_cache = { version = "0.110.0", path = "./ext/cache" }
|
||||
deno_canvas = { version = "0.47.0", path = "./ext/canvas" }
|
||||
deno_console = { version = "0.178.0", path = "./ext/console" }
|
||||
deno_cron = { version = "0.58.0", path = "./ext/cron" }
|
||||
deno_crypto = { version = "0.192.0", path = "./ext/crypto" }
|
||||
deno_fetch = { version = "0.202.0", path = "./ext/fetch" }
|
||||
deno_ffi = { version = "0.165.0", path = "./ext/ffi" }
|
||||
deno_fs = { version = "0.88.0", path = "./ext/fs" }
|
||||
deno_http = { version = "0.176.0", path = "./ext/http" }
|
||||
deno_io = { version = "0.88.0", path = "./ext/io" }
|
||||
deno_kv = { version = "0.86.0", path = "./ext/kv" }
|
||||
deno_napi = { version = "0.109.0", path = "./ext/napi" }
|
||||
deno_net = { version = "0.170.0", path = "./ext/net" }
|
||||
deno_node = { version = "0.115.0", path = "./ext/node" }
|
||||
deno_tls = { version = "0.165.0", path = "./ext/tls" }
|
||||
deno_url = { version = "0.178.0", path = "./ext/url" }
|
||||
deno_web = { version = "0.209.0", path = "./ext/web" }
|
||||
deno_webgpu = { version = "0.145.0", path = "./ext/webgpu" }
|
||||
deno_webidl = { version = "0.178.0", path = "./ext/webidl" }
|
||||
deno_websocket = { version = "0.183.0", path = "./ext/websocket" }
|
||||
deno_webstorage = { version = "0.173.0", path = "./ext/webstorage" }
|
||||
|
||||
# resolvers
|
||||
deno_resolver = { version = "0.9.0", path = "./resolvers/deno" }
|
||||
node_resolver = { version = "0.16.0", path = "./resolvers/node" }
|
||||
deno_resolver = { version = "0.10.0", path = "./resolvers/deno" }
|
||||
node_resolver = { version = "0.17.0", path = "./resolvers/node" }
|
||||
|
||||
aes = "=0.8.3"
|
||||
anyhow = "1.0.57"
|
||||
|
|
70
Releases.md
70
Releases.md
|
@ -6,6 +6,76 @@ https://github.com/denoland/deno/releases
|
|||
We also have one-line install commands at:
|
||||
https://github.com/denoland/deno_install
|
||||
|
||||
### 2.1.0 / 2024.11.21
|
||||
|
||||
- feat(cli): add `--unstable-node-globals` flag (#26617)
|
||||
- feat(cli): support multiple env file argument (#26527)
|
||||
- feat(compile): ability to embed directory in executable (#26939)
|
||||
- feat(compile): ability to embed local data files (#26934)
|
||||
- feat(ext/fetch): Make fetch client parameters configurable (#26909)
|
||||
- feat(ext/fetch): allow embedders to use `hickory_dns_resolver` instead of
|
||||
default `GaiResolver` (#26740)
|
||||
- feat(ext/fs): add ctime to Deno.stats and use it in node compat layer (#24801)
|
||||
- feat(ext/http): Make http server parameters configurable (#26785)
|
||||
- feat(ext/node): perf_hooks.monitorEventLoopDelay() (#26905)
|
||||
- feat(fetch): accept async iterables for body (#26882)
|
||||
- feat(fmt): support SQL (#26750)
|
||||
- feat(info): show location for Web Cache (#26205)
|
||||
- feat(init): add --npm flag to initialize npm projects (#26896)
|
||||
- feat(jupyter): Add `Deno.jupyter.image` API (#26284)
|
||||
- feat(lint): Add checked files list to the JSON output(#26936)
|
||||
- feat(lsp): auto-imports with @deno-types directives (#26821)
|
||||
- feat(node): stabilize detecting if CJS via `"type": "commonjs"` in a
|
||||
package.json (#26439)
|
||||
- feat(permission): support suffix wildcards in `--allow-env` flag (#25255)
|
||||
- feat(publish): add `--set-version <version>` flag (#26141)
|
||||
- feat(runtime): remove public OTEL trace API (#26854)
|
||||
- feat(task): add --eval flag (#26943)
|
||||
- feat(task): dependencies (#26467)
|
||||
- feat(task): support object notation, remove support for JSDocs (#26886)
|
||||
- feat(task): workspace support with --filter and --recursive (#26949)
|
||||
- feat(watch): log which file changed on HMR or watch change (#25801)
|
||||
- feat: OpenTelemetry Tracing API and Exporting (#26710)
|
||||
- feat: Wasm module support (#26668)
|
||||
- feat: fmt and lint respect .gitignore file (#26897)
|
||||
- feat: permission stack traces in ops (#26938)
|
||||
- feat: subcommand to view and update outdated dependencies (#26942)
|
||||
- feat: upgrade V8 to 13.0 (#26851)
|
||||
- fix(cli): preserve comments in doc tests (#26828)
|
||||
- fix(cli): show prefix hint when installing a package globally (#26629)
|
||||
- fix(ext/cache): gracefully error when cache creation failed (#26895)
|
||||
- fix(ext/http): prefer brotli for `accept-encoding: gzip, deflate, br, zstd`
|
||||
(#26814)
|
||||
- fix(ext/node): New async setInterval function to improve the nodejs
|
||||
compatibility (#26703)
|
||||
- fix(ext/node): add autoSelectFamily option to net.createConnection (#26661)
|
||||
- fix(ext/node): handle `--allow-sys=inspector` (#26836)
|
||||
- fix(ext/node): increase tolerance for interval test (#26899)
|
||||
- fix(ext/node): process.getBuiltinModule (#26833)
|
||||
- fix(ext/node): use ERR_NOT_IMPLEMENTED for notImplemented (#26853)
|
||||
- fix(ext/node): zlib.crc32() (#26856)
|
||||
- fix(ext/webgpu): Create GPUQuerySet converter before usage (#26883)
|
||||
- fix(ext/websocket): initialize `error` attribute of WebSocket ErrorEvent
|
||||
(#26796)
|
||||
- fix(ext/webstorage): use error class for sqlite error case (#26806)
|
||||
- fix(fmt): error instead of panic on unstable format (#26859)
|
||||
- fix(fmt): formatting of .svelte files (#26948)
|
||||
- fix(install): percent encodings in interactive progress bar (#26600)
|
||||
- fix(install): re-setup bin entries after running lifecycle scripts (#26752)
|
||||
- fix(lockfile): track dependencies specified in TypeScript compiler options
|
||||
(#26551)
|
||||
- fix(lsp): ignore editor indent settings if deno.json is present (#26912)
|
||||
- fix(lsp): skip code action edits that can't be converted (#26831)
|
||||
- fix(node): handle resolving ".//<something>" in npm packages (#26920)
|
||||
- fix(node/crypto): support promisify on generateKeyPair (#26913)
|
||||
- fix(permissions): say to use --allow-run instead of --allow-all (#26842)
|
||||
- fix(publish): improve error message when missing exports (#26945)
|
||||
- fix: otel resiliency (#26857)
|
||||
- fix: update message for unsupported schemes with npm and jsr (#26884)
|
||||
- perf(compile): code cache (#26528)
|
||||
- perf(windows): delay load webgpu and some other dlls (#26917)
|
||||
- perf: use available system memory for v8 isolate memory limit (#26868)
|
||||
|
||||
### 2.0.6 / 2024.11.10
|
||||
|
||||
- feat(ext/http): abort event when request is cancelled (#26781)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_bench_util"
|
||||
version = "0.171.0"
|
||||
version = "0.172.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno"
|
||||
version = "2.0.6"
|
||||
version = "2.1.0"
|
||||
authors.workspace = true
|
||||
default-run = "deno"
|
||||
edition.workspace = true
|
||||
|
@ -129,7 +129,7 @@ libz-sys.workspace = true
|
|||
log = { workspace = true, features = ["serde"] }
|
||||
lsp-types.workspace = true
|
||||
malva = "=0.11.0"
|
||||
markup_fmt = "=0.15.0"
|
||||
markup_fmt = "=0.16.0"
|
||||
memmem.workspace = true
|
||||
monch.workspace = true
|
||||
notify.workspace = true
|
||||
|
@ -151,8 +151,8 @@ serde_repr.workspace = true
|
|||
sha2.workspace = true
|
||||
shell-escape = "=0.1.5"
|
||||
spki = { version = "0.7", features = ["pem"] }
|
||||
# NOTE(bartlomieju): for now using github URL, because 0.3.2 with important fixes hasn't been released yet.
|
||||
sqlformat = { git = "https://github.com/shssoichiro/sqlformat-rs.git", rev = "827d639" }
|
||||
# NOTE(bartlomieju): using temporary fork for now, revert back to `sqlformat-rs` later
|
||||
sqlformat = { package = "deno_sqlformat", version = "0.3.2" }
|
||||
strsim = "0.11.1"
|
||||
tar.workspace = true
|
||||
tempfile.workspace = true
|
||||
|
|
|
@ -222,6 +222,8 @@ impl FmtFlags {
|
|||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct InitFlags {
|
||||
pub package: Option<String>,
|
||||
pub package_args: Vec<String>,
|
||||
pub dir: Option<String>,
|
||||
pub lib: bool,
|
||||
pub serve: bool,
|
||||
|
@ -382,6 +384,8 @@ pub struct TaskFlags {
|
|||
pub cwd: Option<String>,
|
||||
pub task: Option<String>,
|
||||
pub is_run: bool,
|
||||
pub recursive: bool,
|
||||
pub filter: Option<String>,
|
||||
pub eval: bool,
|
||||
}
|
||||
|
||||
|
@ -467,6 +471,7 @@ pub enum DenoSubcommand {
|
|||
Serve(ServeFlags),
|
||||
Task(TaskFlags),
|
||||
Test(TestFlags),
|
||||
Outdated(OutdatedFlags),
|
||||
Types,
|
||||
Upgrade(UpgradeFlags),
|
||||
Vendor,
|
||||
|
@ -474,6 +479,19 @@ pub enum DenoSubcommand {
|
|||
Help(HelpFlags),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum OutdatedKind {
|
||||
Update { latest: bool },
|
||||
PrintOutdated { compatible: bool },
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct OutdatedFlags {
|
||||
pub filters: Vec<String>,
|
||||
pub recursive: bool,
|
||||
pub kind: OutdatedKind,
|
||||
}
|
||||
|
||||
impl DenoSubcommand {
|
||||
pub fn is_run(&self) -> bool {
|
||||
matches!(self, Self::Run(_))
|
||||
|
@ -1171,6 +1189,7 @@ static ENV_VARIABLES_HELP: &str = cstr!(
|
|||
<g>DENO_NO_PACKAGE_JSON</> Disables auto-resolution of package.json
|
||||
<g>DENO_NO_UPDATE_CHECK</> Set to disable checking if a newer Deno version is available
|
||||
<g>DENO_TLS_CA_STORE</> Comma-separated list of order dependent certificate stores.
|
||||
<g>DENO_TRACE_PERMISSIONS</> Environmental variable to enable stack traces in permission prompts.
|
||||
Possible values: "system", "mozilla".
|
||||
<p(245)>(defaults to "mozilla")</>
|
||||
<g>HTTP_PROXY</> Proxy address for HTTP requests
|
||||
|
@ -1204,6 +1223,7 @@ static DENO_HELP: &str = cstr!(
|
|||
<p(245)>deno add jsr:@std/assert | deno add npm:express</>
|
||||
<g>install</> Installs dependencies either in the local project or globally to a bin directory
|
||||
<g>uninstall</> Uninstalls a dependency or an executable script in the installation root's bin directory
|
||||
<g>outdated</> Find and update outdated dependencies
|
||||
<g>remove</> Remove dependencies from the configuration file
|
||||
|
||||
<y>Tooling:</>
|
||||
|
@ -1379,13 +1399,14 @@ pub fn flags_from_vec(args: Vec<OsString>) -> clap::error::Result<Flags> {
|
|||
"doc" => doc_parse(&mut flags, &mut m)?,
|
||||
"eval" => eval_parse(&mut flags, &mut m)?,
|
||||
"fmt" => fmt_parse(&mut flags, &mut m)?,
|
||||
"init" => init_parse(&mut flags, &mut m),
|
||||
"init" => init_parse(&mut flags, &mut m)?,
|
||||
"info" => info_parse(&mut flags, &mut m)?,
|
||||
"install" => install_parse(&mut flags, &mut m)?,
|
||||
"json_reference" => json_reference_parse(&mut flags, &mut m, app),
|
||||
"jupyter" => jupyter_parse(&mut flags, &mut m),
|
||||
"lint" => lint_parse(&mut flags, &mut m)?,
|
||||
"lsp" => lsp_parse(&mut flags, &mut m),
|
||||
"outdated" => outdated_parse(&mut flags, &mut m)?,
|
||||
"repl" => repl_parse(&mut flags, &mut m)?,
|
||||
"run" => run_parse(&mut flags, &mut m, app, false)?,
|
||||
"serve" => serve_parse(&mut flags, &mut m, app)?,
|
||||
|
@ -1628,6 +1649,7 @@ pub fn clap_root() -> Command {
|
|||
.subcommand(json_reference_subcommand())
|
||||
.subcommand(jupyter_subcommand())
|
||||
.subcommand(uninstall_subcommand())
|
||||
.subcommand(outdated_subcommand())
|
||||
.subcommand(lsp_subcommand())
|
||||
.subcommand(lint_subcommand())
|
||||
.subcommand(publish_subcommand())
|
||||
|
@ -2430,7 +2452,19 @@ fn init_subcommand() -> Command {
|
|||
command("init", "scaffolds a basic Deno project with a script, test, and configuration file", UnstableArgsConfig::None).defer(
|
||||
|cmd| {
|
||||
cmd
|
||||
.arg(Arg::new("dir").value_hint(ValueHint::DirPath))
|
||||
.arg(Arg::new("args")
|
||||
.num_args(0..)
|
||||
.action(ArgAction::Append)
|
||||
.value_name("DIRECTORY OR PACKAGE")
|
||||
.trailing_var_arg(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::new("npm")
|
||||
.long("npm")
|
||||
.help("Generate a npm create-* project")
|
||||
.conflicts_with_all(["lib", "serve"])
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("lib")
|
||||
.long("lib")
|
||||
|
@ -2618,6 +2652,83 @@ fn jupyter_subcommand() -> Command {
|
|||
.conflicts_with("install"))
|
||||
}
|
||||
|
||||
fn outdated_subcommand() -> Command {
|
||||
command(
|
||||
"outdated",
|
||||
cstr!("Find and update outdated dependencies.
|
||||
By default, outdated dependencies are only displayed.
|
||||
|
||||
Display outdated dependencies:
|
||||
<p(245)>deno outdated</>
|
||||
<p(245)>deno outdated --compatible</>
|
||||
|
||||
Update dependencies:
|
||||
<p(245)>deno outdated --update</>
|
||||
<p(245)>deno outdated --update --latest</>
|
||||
<p(245)>deno outdated --update</>
|
||||
|
||||
Filters can be used to select which packages to act on. Filters can include wildcards (*) to match multiple packages.
|
||||
<p(245)>deno outdated --update --latest \"@std/*\"</>
|
||||
<p(245)>deno outdated --update --latest \"react*\"</>
|
||||
Note that filters act on their aliases configured in deno.json / package.json, not the actual package names:
|
||||
Given \"foobar\": \"npm:react@17.0.0\" in deno.json or package.json, the filter \"foobar\" would update npm:react to
|
||||
the latest version.
|
||||
<p(245)>deno outdated --update --latest foobar</>
|
||||
Filters can be combined, and negative filters can be used to exclude results:
|
||||
<p(245)>deno outdated --update --latest \"@std/*\" \"!@std/fmt*\"</>
|
||||
|
||||
Specific version requirements to update to can be specified:
|
||||
<p(245)>deno outdated --update @std/fmt@^1.0.2</>
|
||||
"),
|
||||
UnstableArgsConfig::None,
|
||||
)
|
||||
.defer(|cmd| {
|
||||
cmd
|
||||
.arg(
|
||||
Arg::new("filters")
|
||||
.num_args(0..)
|
||||
.action(ArgAction::Append)
|
||||
.help(concat!("Filters selecting which packages to act on. Can include wildcards (*) to match multiple packages. ",
|
||||
"If a version requirement is specified, the matching packages will be updated to the given requirement."),
|
||||
)
|
||||
)
|
||||
.arg(no_lock_arg())
|
||||
.arg(lock_arg())
|
||||
.arg(
|
||||
Arg::new("latest")
|
||||
.long("latest")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help(
|
||||
"Update to the latest version, regardless of semver constraints",
|
||||
)
|
||||
.requires("update")
|
||||
.conflicts_with("compatible"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("update")
|
||||
.long("update")
|
||||
.short('u')
|
||||
.action(ArgAction::SetTrue)
|
||||
.conflicts_with("compatible")
|
||||
.help("Update dependency versions"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("compatible")
|
||||
.long("compatible")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Only output versions that satisfy semver requirements")
|
||||
.conflicts_with("update"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("recursive")
|
||||
.long("recursive")
|
||||
.short('r')
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("include all workspace members"),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn uninstall_subcommand() -> Command {
|
||||
command(
|
||||
"uninstall",
|
||||
|
@ -2953,6 +3064,20 @@ Evaluate a task from string
|
|||
.help("Specify the directory to run the task in")
|
||||
.value_hint(ValueHint::DirPath),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("recursive")
|
||||
.long("recursive")
|
||||
.short('r')
|
||||
.help("Run the task in all projects in the workspace")
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("filter")
|
||||
.long("filter")
|
||||
.short('f')
|
||||
.help("Filter members of the workspace by name - should be used with --recursive")
|
||||
.value_parser(value_parser!(String)),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("eval")
|
||||
.long("eval")
|
||||
|
@ -3348,6 +3473,8 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
|
|||
<p(245)>--deny-run | --deny-run="whoami,ps"</>
|
||||
<g>--deny-ffi[=<<PATH>...]</> (Unstable) Deny loading dynamic libraries. Optionally specify denied directories or files.
|
||||
<p(245)>--deny-ffi | --deny-ffi="./libfoo.so"</>
|
||||
<g>DENO_TRACE_PERMISSIONS</> Environmental variable to enable stack traces in permission prompts.
|
||||
<p(245)>DENO_TRACE_PERMISSIONS=1 deno run main.ts</>
|
||||
"#))
|
||||
.arg(
|
||||
{
|
||||
|
@ -4352,6 +4479,31 @@ fn remove_parse(flags: &mut Flags, matches: &mut ArgMatches) {
|
|||
});
|
||||
}
|
||||
|
||||
fn outdated_parse(
|
||||
flags: &mut Flags,
|
||||
matches: &mut ArgMatches,
|
||||
) -> clap::error::Result<()> {
|
||||
let filters = match matches.remove_many::<String>("filters") {
|
||||
Some(f) => f.collect(),
|
||||
None => vec![],
|
||||
};
|
||||
let recursive = matches.get_flag("recursive");
|
||||
let update = matches.get_flag("update");
|
||||
let kind = if update {
|
||||
let latest = matches.get_flag("latest");
|
||||
OutdatedKind::Update { latest }
|
||||
} else {
|
||||
let compatible = matches.get_flag("compatible");
|
||||
OutdatedKind::PrintOutdated { compatible }
|
||||
};
|
||||
flags.subcommand = DenoSubcommand::Outdated(OutdatedFlags {
|
||||
filters,
|
||||
recursive,
|
||||
kind,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn bench_parse(
|
||||
flags: &mut Flags,
|
||||
matches: &mut ArgMatches,
|
||||
|
@ -4684,12 +4836,44 @@ fn fmt_parse(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn init_parse(flags: &mut Flags, matches: &mut ArgMatches) {
|
||||
fn init_parse(
|
||||
flags: &mut Flags,
|
||||
matches: &mut ArgMatches,
|
||||
) -> Result<(), clap::Error> {
|
||||
let mut lib = matches.get_flag("lib");
|
||||
let mut serve = matches.get_flag("serve");
|
||||
let mut dir = None;
|
||||
let mut package = None;
|
||||
let mut package_args = vec![];
|
||||
|
||||
if let Some(mut args) = matches.remove_many::<String>("args") {
|
||||
let name = args.next().unwrap();
|
||||
let mut args = args.collect::<Vec<_>>();
|
||||
|
||||
if matches.get_flag("npm") {
|
||||
package = Some(name);
|
||||
package_args = args;
|
||||
} else {
|
||||
dir = Some(name);
|
||||
|
||||
if !args.is_empty() {
|
||||
args.insert(0, "init".to_string());
|
||||
let inner_matches = init_subcommand().try_get_matches_from_mut(args)?;
|
||||
lib = inner_matches.get_flag("lib");
|
||||
serve = inner_matches.get_flag("serve");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flags.subcommand = DenoSubcommand::Init(InitFlags {
|
||||
dir: matches.remove_one::<String>("dir"),
|
||||
lib: matches.get_flag("lib"),
|
||||
serve: matches.get_flag("serve"),
|
||||
package,
|
||||
package_args,
|
||||
dir,
|
||||
lib,
|
||||
serve,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn info_parse(
|
||||
|
@ -5094,10 +5278,15 @@ fn task_parse(
|
|||
unstable_args_parse(flags, matches, UnstableArgsConfig::ResolutionAndRuntime);
|
||||
node_modules_arg_parse(flags, matches);
|
||||
|
||||
let filter = matches.remove_one::<String>("filter");
|
||||
let recursive = matches.get_flag("recursive") || filter.is_some();
|
||||
|
||||
let mut task_flags = TaskFlags {
|
||||
cwd: matches.remove_one::<String>("cwd"),
|
||||
task: None,
|
||||
is_run: false,
|
||||
recursive,
|
||||
filter,
|
||||
eval: matches.get_flag("eval"),
|
||||
};
|
||||
|
||||
|
@ -10300,6 +10489,8 @@ mod tests {
|
|||
cwd: None,
|
||||
task: Some("build".to_string()),
|
||||
is_run: false,
|
||||
recursive: false,
|
||||
filter: None,
|
||||
eval: false,
|
||||
}),
|
||||
argv: svec!["hello", "world"],
|
||||
|
@ -10315,6 +10506,8 @@ mod tests {
|
|||
cwd: None,
|
||||
task: Some("build".to_string()),
|
||||
is_run: false,
|
||||
recursive: false,
|
||||
filter: None,
|
||||
eval: false,
|
||||
}),
|
||||
..Flags::default()
|
||||
|
@ -10329,6 +10522,56 @@ mod tests {
|
|||
cwd: Some("foo".to_string()),
|
||||
task: Some("build".to_string()),
|
||||
is_run: false,
|
||||
recursive: false,
|
||||
filter: None,
|
||||
eval: false,
|
||||
}),
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
||||
let r = flags_from_vec(svec!["deno", "task", "--filter", "*", "build"]);
|
||||
assert_eq!(
|
||||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Task(TaskFlags {
|
||||
cwd: None,
|
||||
task: Some("build".to_string()),
|
||||
is_run: false,
|
||||
recursive: true,
|
||||
filter: Some("*".to_string()),
|
||||
eval: false,
|
||||
}),
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
||||
let r = flags_from_vec(svec!["deno", "task", "--recursive", "build"]);
|
||||
assert_eq!(
|
||||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Task(TaskFlags {
|
||||
cwd: None,
|
||||
task: Some("build".to_string()),
|
||||
is_run: false,
|
||||
recursive: true,
|
||||
filter: None,
|
||||
eval: false,
|
||||
}),
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
||||
let r = flags_from_vec(svec!["deno", "task", "-r", "build"]);
|
||||
assert_eq!(
|
||||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Task(TaskFlags {
|
||||
cwd: None,
|
||||
task: Some("build".to_string()),
|
||||
is_run: false,
|
||||
recursive: true,
|
||||
filter: None,
|
||||
eval: false,
|
||||
}),
|
||||
..Flags::default()
|
||||
|
@ -10343,6 +10586,8 @@ mod tests {
|
|||
cwd: None,
|
||||
task: Some("echo 1".to_string()),
|
||||
is_run: false,
|
||||
recursive: false,
|
||||
filter: None,
|
||||
eval: true,
|
||||
}),
|
||||
..Flags::default()
|
||||
|
@ -10372,6 +10617,8 @@ mod tests {
|
|||
cwd: None,
|
||||
task: Some("build".to_string()),
|
||||
is_run: false,
|
||||
recursive: false,
|
||||
filter: None,
|
||||
eval: false,
|
||||
}),
|
||||
argv: svec!["--", "hello", "world"],
|
||||
|
@ -10390,6 +10637,8 @@ mod tests {
|
|||
cwd: Some("foo".to_string()),
|
||||
task: Some("build".to_string()),
|
||||
is_run: false,
|
||||
recursive: false,
|
||||
filter: None,
|
||||
eval: false,
|
||||
}),
|
||||
argv: svec!["--", "hello", "world"],
|
||||
|
@ -10409,6 +10658,8 @@ mod tests {
|
|||
cwd: None,
|
||||
task: Some("build".to_string()),
|
||||
is_run: false,
|
||||
recursive: false,
|
||||
filter: None,
|
||||
eval: false,
|
||||
}),
|
||||
argv: svec!["--"],
|
||||
|
@ -10427,6 +10678,8 @@ mod tests {
|
|||
cwd: None,
|
||||
task: Some("build".to_string()),
|
||||
is_run: false,
|
||||
recursive: false,
|
||||
filter: None,
|
||||
eval: false,
|
||||
}),
|
||||
argv: svec!["-1", "--test"],
|
||||
|
@ -10445,6 +10698,8 @@ mod tests {
|
|||
cwd: None,
|
||||
task: Some("build".to_string()),
|
||||
is_run: false,
|
||||
recursive: false,
|
||||
filter: None,
|
||||
eval: false,
|
||||
}),
|
||||
argv: svec!["--test"],
|
||||
|
@ -10464,6 +10719,8 @@ mod tests {
|
|||
cwd: None,
|
||||
task: Some("build".to_string()),
|
||||
is_run: false,
|
||||
recursive: false,
|
||||
filter: None,
|
||||
eval: false,
|
||||
}),
|
||||
log_level: Some(log::Level::Error),
|
||||
|
@ -10482,6 +10739,8 @@ mod tests {
|
|||
cwd: None,
|
||||
task: None,
|
||||
is_run: false,
|
||||
recursive: false,
|
||||
filter: None,
|
||||
eval: false,
|
||||
}),
|
||||
..Flags::default()
|
||||
|
@ -10499,6 +10758,8 @@ mod tests {
|
|||
cwd: None,
|
||||
task: None,
|
||||
is_run: false,
|
||||
recursive: false,
|
||||
filter: None,
|
||||
eval: false,
|
||||
}),
|
||||
config_flag: ConfigFlag::Path("deno.jsonc".to_string()),
|
||||
|
@ -10517,6 +10778,8 @@ mod tests {
|
|||
cwd: None,
|
||||
task: None,
|
||||
is_run: false,
|
||||
recursive: false,
|
||||
filter: None,
|
||||
eval: false,
|
||||
}),
|
||||
config_flag: ConfigFlag::Path("deno.jsonc".to_string()),
|
||||
|
@ -10694,6 +10957,8 @@ mod tests {
|
|||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Init(InitFlags {
|
||||
package: None,
|
||||
package_args: vec![],
|
||||
dir: None,
|
||||
lib: false,
|
||||
serve: false,
|
||||
|
@ -10707,6 +10972,8 @@ mod tests {
|
|||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Init(InitFlags {
|
||||
package: None,
|
||||
package_args: vec![],
|
||||
dir: Some(String::from("foo")),
|
||||
lib: false,
|
||||
serve: false,
|
||||
|
@ -10720,6 +10987,8 @@ mod tests {
|
|||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Init(InitFlags {
|
||||
package: None,
|
||||
package_args: vec![],
|
||||
dir: None,
|
||||
lib: false,
|
||||
serve: false,
|
||||
|
@ -10734,6 +11003,8 @@ mod tests {
|
|||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Init(InitFlags {
|
||||
package: None,
|
||||
package_args: vec![],
|
||||
dir: None,
|
||||
lib: true,
|
||||
serve: false,
|
||||
|
@ -10747,6 +11018,8 @@ mod tests {
|
|||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Init(InitFlags {
|
||||
package: None,
|
||||
package_args: vec![],
|
||||
dir: None,
|
||||
lib: false,
|
||||
serve: true,
|
||||
|
@ -10760,6 +11033,8 @@ mod tests {
|
|||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Init(InitFlags {
|
||||
package: None,
|
||||
package_args: vec![],
|
||||
dir: Some(String::from("foo")),
|
||||
lib: true,
|
||||
serve: false,
|
||||
|
@ -10767,6 +11042,57 @@ mod tests {
|
|||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
||||
let r = flags_from_vec(svec!["deno", "init", "--lib", "--npm", "vite"]);
|
||||
assert!(r.is_err());
|
||||
|
||||
let r = flags_from_vec(svec!["deno", "init", "--serve", "--npm", "vite"]);
|
||||
assert!(r.is_err());
|
||||
|
||||
let r = flags_from_vec(svec!["deno", "init", "--npm", "vite", "--lib"]);
|
||||
assert_eq!(
|
||||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Init(InitFlags {
|
||||
package: Some("vite".to_string()),
|
||||
package_args: svec!["--lib"],
|
||||
dir: None,
|
||||
lib: false,
|
||||
serve: false,
|
||||
}),
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
||||
let r = flags_from_vec(svec!["deno", "init", "--npm", "vite", "--serve"]);
|
||||
assert_eq!(
|
||||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Init(InitFlags {
|
||||
package: Some("vite".to_string()),
|
||||
package_args: svec!["--serve"],
|
||||
dir: None,
|
||||
lib: false,
|
||||
serve: false,
|
||||
}),
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
||||
let r = flags_from_vec(svec!["deno", "init", "--npm", "vite", "new_dir"]);
|
||||
assert_eq!(
|
||||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Init(InitFlags {
|
||||
package: Some("vite".to_string()),
|
||||
package_args: svec!["new_dir"],
|
||||
dir: None,
|
||||
lib: false,
|
||||
serve: false,
|
||||
}),
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -11300,4 +11626,77 @@ Usage: deno repl [OPTIONS] [-- [ARGS]...]\n"
|
|||
assert!(r.is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn outdated_subcommand() {
|
||||
let cases = [
|
||||
(
|
||||
svec![],
|
||||
OutdatedFlags {
|
||||
filters: vec![],
|
||||
kind: OutdatedKind::PrintOutdated { compatible: false },
|
||||
recursive: false,
|
||||
},
|
||||
),
|
||||
(
|
||||
svec!["--recursive"],
|
||||
OutdatedFlags {
|
||||
filters: vec![],
|
||||
kind: OutdatedKind::PrintOutdated { compatible: false },
|
||||
recursive: true,
|
||||
},
|
||||
),
|
||||
(
|
||||
svec!["--recursive", "--compatible"],
|
||||
OutdatedFlags {
|
||||
filters: vec![],
|
||||
kind: OutdatedKind::PrintOutdated { compatible: true },
|
||||
recursive: true,
|
||||
},
|
||||
),
|
||||
(
|
||||
svec!["--update"],
|
||||
OutdatedFlags {
|
||||
filters: vec![],
|
||||
kind: OutdatedKind::Update { latest: false },
|
||||
recursive: false,
|
||||
},
|
||||
),
|
||||
(
|
||||
svec!["--update", "--latest"],
|
||||
OutdatedFlags {
|
||||
filters: vec![],
|
||||
kind: OutdatedKind::Update { latest: true },
|
||||
recursive: false,
|
||||
},
|
||||
),
|
||||
(
|
||||
svec!["--update", "--recursive"],
|
||||
OutdatedFlags {
|
||||
filters: vec![],
|
||||
kind: OutdatedKind::Update { latest: false },
|
||||
recursive: true,
|
||||
},
|
||||
),
|
||||
(
|
||||
svec!["--update", "@foo/bar"],
|
||||
OutdatedFlags {
|
||||
filters: svec!["@foo/bar"],
|
||||
kind: OutdatedKind::Update { latest: false },
|
||||
recursive: false,
|
||||
},
|
||||
),
|
||||
];
|
||||
for (input, expected) in cases {
|
||||
let mut args = svec!["deno", "outdated"];
|
||||
args.extend(input);
|
||||
let r = flags_from_vec(args.clone()).unwrap();
|
||||
assert_eq!(
|
||||
r.subcommand,
|
||||
DenoSubcommand::Outdated(expected),
|
||||
"incorrect result for args: {:?}",
|
||||
args
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1628,8 +1628,10 @@ impl CliOptions {
|
|||
DenoSubcommand::Install(_)
|
||||
| DenoSubcommand::Add(_)
|
||||
| DenoSubcommand::Remove(_)
|
||||
| DenoSubcommand::Init(_)
|
||||
| DenoSubcommand::Outdated(_)
|
||||
) {
|
||||
// For `deno install/add/remove` we want to force the managed resolver so it can set up `node_modules/` directory.
|
||||
// For `deno install/add/remove/init` we want to force the managed resolver so it can set up `node_modules/` directory.
|
||||
return false;
|
||||
}
|
||||
if self.node_modules_dir().ok().flatten().is_none()
|
||||
|
@ -1912,6 +1914,10 @@ pub fn resolve_no_prompt(flags: &PermissionFlags) -> bool {
|
|||
flags.no_prompt || has_flag_env_var("DENO_NO_PROMPT")
|
||||
}
|
||||
|
||||
pub fn has_trace_permissions_enabled() -> bool {
|
||||
has_flag_env_var("DENO_TRACE_PERMISSIONS")
|
||||
}
|
||||
|
||||
pub fn has_flag_env_var(name: &str) -> bool {
|
||||
let value = env::var(name);
|
||||
matches!(value.as_ref().map(|s| s.as_str()), Ok("1"))
|
||||
|
|
11
cli/main.rs
11
cli/main.rs
|
@ -144,9 +144,7 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
|||
}
|
||||
DenoSubcommand::Init(init_flags) => {
|
||||
spawn_subcommand(async {
|
||||
// make compiler happy since init_project is sync
|
||||
tokio::task::yield_now().await;
|
||||
tools::init::init_project(init_flags)
|
||||
tools::init::init_project(init_flags).await
|
||||
})
|
||||
}
|
||||
DenoSubcommand::Info(info_flags) => {
|
||||
|
@ -188,6 +186,11 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
|||
tools::lint::lint(flags, lint_flags).await
|
||||
}
|
||||
}),
|
||||
DenoSubcommand::Outdated(update_flags) => {
|
||||
spawn_subcommand(async move {
|
||||
tools::registry::outdated(flags, update_flags).await
|
||||
})
|
||||
}
|
||||
DenoSubcommand::Repl(repl_flags) => {
|
||||
spawn_subcommand(async move { tools::repl::run(flags, repl_flags).await })
|
||||
}
|
||||
|
@ -238,6 +241,8 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
|||
cwd: None,
|
||||
task: Some(run_flags.script.clone()),
|
||||
is_run: true,
|
||||
recursive: false,
|
||||
filter: None,
|
||||
eval: false,
|
||||
};
|
||||
new_flags.subcommand = DenoSubcommand::Task(task_flags.clone());
|
||||
|
|
|
@ -500,7 +500,7 @@ impl ManagedCliNpmResolver {
|
|||
self.resolve_pkg_folder_from_pkg_id(&pkg_id)
|
||||
}
|
||||
|
||||
fn resolve_pkg_id_from_pkg_req(
|
||||
pub fn resolve_pkg_id_from_pkg_req(
|
||||
&self,
|
||||
req: &PackageReq,
|
||||
) -> Result<NpmPackageId, PackageReqNotFoundError> {
|
||||
|
|
|
@ -51,7 +51,7 @@ fn op_bench_get_origin(state: &mut OpState) -> String {
|
|||
#[derive(Clone)]
|
||||
struct PermissionsHolder(Uuid, PermissionsContainer);
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
pub fn op_pledge_test_permissions(
|
||||
state: &mut OpState,
|
||||
|
|
|
@ -46,7 +46,7 @@ deno_core::extension!(deno_test,
|
|||
#[derive(Clone)]
|
||||
struct PermissionsHolder(Uuid, PermissionsContainer);
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
pub fn op_pledge_test_permissions(
|
||||
state: &mut OpState,
|
||||
|
|
|
@ -1,15 +1,28 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use crate::args::DenoSubcommand;
|
||||
use crate::args::Flags;
|
||||
use crate::args::InitFlags;
|
||||
use crate::args::PackagesAllowedScripts;
|
||||
use crate::args::PermissionFlags;
|
||||
use crate::args::RunFlags;
|
||||
use crate::colors;
|
||||
use color_print::cformat;
|
||||
use color_print::cstr;
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json::json;
|
||||
use deno_runtime::WorkerExecutionMode;
|
||||
use log::info;
|
||||
use std::io::IsTerminal;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
pub fn init_project(init_flags: InitFlags) -> Result<(), AnyError> {
|
||||
pub async fn init_project(init_flags: InitFlags) -> Result<i32, AnyError> {
|
||||
if let Some(package) = &init_flags.package {
|
||||
return init_npm(package, init_flags.package_args).await;
|
||||
}
|
||||
|
||||
let cwd =
|
||||
std::env::current_dir().context("Can't read current working directory.")?;
|
||||
let dir = if let Some(dir) = &init_flags.dir {
|
||||
|
@ -235,7 +248,58 @@ Deno.test(function addTest() {
|
|||
info!(" {}", colors::gray("# Run the tests"));
|
||||
info!(" deno test");
|
||||
}
|
||||
Ok(())
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
async fn init_npm(name: &str, args: Vec<String>) -> Result<i32, AnyError> {
|
||||
let script_name = format!("npm:create-{}", name);
|
||||
|
||||
fn print_manual_usage(script_name: &str, args: &[String]) -> i32 {
|
||||
log::info!("{}", cformat!("You can initialize project manually by running <u>deno run {} {}</> and applying desired permissions.", script_name, args.join(" ")));
|
||||
1
|
||||
}
|
||||
|
||||
if std::io::stdin().is_terminal() {
|
||||
log::info!(
|
||||
cstr!("⚠️ Do you fully trust <y>{}</> package? Deno will invoke code from it with all permissions. Do you want to continue? <p(245)>[y/n]</>"),
|
||||
script_name
|
||||
);
|
||||
loop {
|
||||
let _ = std::io::stdout().write(b"> ")?;
|
||||
std::io::stdout().flush()?;
|
||||
let mut answer = String::new();
|
||||
if std::io::stdin().read_line(&mut answer).is_ok() {
|
||||
let answer = answer.trim().to_ascii_lowercase();
|
||||
if answer != "y" {
|
||||
return Ok(print_manual_usage(&script_name, &args));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Ok(print_manual_usage(&script_name, &args));
|
||||
}
|
||||
|
||||
let new_flags = Flags {
|
||||
permissions: PermissionFlags {
|
||||
allow_all: true,
|
||||
..Default::default()
|
||||
},
|
||||
allow_scripts: PackagesAllowedScripts::All,
|
||||
argv: args,
|
||||
subcommand: DenoSubcommand::Run(RunFlags {
|
||||
script: script_name,
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
crate::tools::run::run_script(
|
||||
WorkerExecutionMode::Run,
|
||||
new_flags.into(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
fn create_json_file(
|
||||
|
|
|
@ -175,6 +175,7 @@ struct JsonLintReporter {
|
|||
version: u8,
|
||||
diagnostics: Vec<JsonLintDiagnostic>,
|
||||
errors: Vec<LintError>,
|
||||
checked_files: Vec<String>,
|
||||
}
|
||||
|
||||
impl JsonLintReporter {
|
||||
|
@ -183,6 +184,7 @@ impl JsonLintReporter {
|
|||
version: JSON_SCHEMA_VERSION,
|
||||
diagnostics: Vec::new(),
|
||||
errors: Vec::new(),
|
||||
checked_files: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -209,6 +211,17 @@ impl LintReporter for JsonLintReporter {
|
|||
code: d.code().to_string(),
|
||||
hint: d.hint().map(|h| h.to_string()),
|
||||
});
|
||||
|
||||
let file_path = d
|
||||
.specifier
|
||||
.to_file_path()
|
||||
.unwrap()
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
|
||||
if !self.checked_files.contains(&file_path) {
|
||||
self.checked_files.push(file_path);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_error(&mut self, file_path: &str, err: &AnyError) {
|
||||
|
@ -216,10 +229,15 @@ impl LintReporter for JsonLintReporter {
|
|||
file_path: file_path.to_string(),
|
||||
message: err.to_string(),
|
||||
});
|
||||
|
||||
if !self.checked_files.contains(&file_path.to_string()) {
|
||||
self.checked_files.push(file_path.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
fn close(&mut self, _check_count: usize) {
|
||||
sort_diagnostics(&mut self.diagnostics);
|
||||
self.checked_files.sort();
|
||||
let json = serde_json::to_string_pretty(&self);
|
||||
#[allow(clippy::print_stdout)]
|
||||
{
|
||||
|
|
|
@ -68,6 +68,7 @@ use auth::get_auth_method;
|
|||
use auth::AuthMethod;
|
||||
pub use pm::add;
|
||||
pub use pm::cache_top_level_deps;
|
||||
pub use pm::outdated;
|
||||
pub use pm::remove;
|
||||
pub use pm::AddCommandName;
|
||||
pub use pm::AddRmPackageReq;
|
||||
|
|
|
@ -16,6 +16,7 @@ use deno_semver::package::PackageNv;
|
|||
use deno_semver::package::PackageReq;
|
||||
use deno_semver::Version;
|
||||
use deno_semver::VersionReq;
|
||||
use deps::KeyPath;
|
||||
use jsonc_parser::cst::CstObject;
|
||||
use jsonc_parser::cst::CstObjectProp;
|
||||
use jsonc_parser::cst::CstRootNode;
|
||||
|
@ -32,10 +33,13 @@ use crate::jsr::JsrFetchResolver;
|
|||
use crate::npm::NpmFetchResolver;
|
||||
|
||||
mod cache_deps;
|
||||
pub(crate) mod deps;
|
||||
mod outdated;
|
||||
|
||||
pub use cache_deps::cache_top_level_deps;
|
||||
pub use outdated::outdated;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone, Hash)]
|
||||
enum ConfigKind {
|
||||
DenoJson,
|
||||
PackageJson,
|
||||
|
@ -86,6 +90,28 @@ impl ConfigUpdater {
|
|||
self.cst.to_string()
|
||||
}
|
||||
|
||||
fn get_property_for_mutation(
|
||||
&mut self,
|
||||
key_path: &KeyPath,
|
||||
) -> Option<CstObjectProp> {
|
||||
let mut current_node = self.root_object.clone();
|
||||
|
||||
self.modified = true;
|
||||
|
||||
for (i, part) in key_path.parts.iter().enumerate() {
|
||||
let s = part.as_str();
|
||||
if i < key_path.parts.len().saturating_sub(1) {
|
||||
let object = current_node.object_value(s)?;
|
||||
current_node = object;
|
||||
} else {
|
||||
// last part
|
||||
return current_node.get(s);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn add(&mut self, selected: SelectedPackage, dev: bool) {
|
||||
fn insert_index(object: &CstObject, searching_name: &str) -> usize {
|
||||
object
|
||||
|
@ -824,7 +850,7 @@ async fn npm_install_after_modification(
|
|||
flags: Arc<Flags>,
|
||||
// explicitly provided to prevent redownloading
|
||||
jsr_resolver: Option<Arc<crate::jsr::JsrFetchResolver>>,
|
||||
) -> Result<(), AnyError> {
|
||||
) -> Result<CliFactory, AnyError> {
|
||||
// clear the previously cached package.json from memory before reloading it
|
||||
node_resolver::PackageJsonThreadLocalCache::clear();
|
||||
|
||||
|
@ -842,7 +868,7 @@ async fn npm_install_after_modification(
|
|||
lockfile.write_if_changed()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(cli_factory)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::graph_container::ModuleGraphUpdatePermit;
|
|||
use deno_core::error::AnyError;
|
||||
use deno_core::futures::stream::FuturesUnordered;
|
||||
use deno_core::futures::StreamExt;
|
||||
use deno_semver::package::PackageReq;
|
||||
use deno_semver::jsr::JsrPackageReqReference;
|
||||
|
||||
pub async fn cache_top_level_deps(
|
||||
// todo(dsherret): don't pass the factory into this function. Instead use ctor deps
|
||||
|
@ -56,15 +56,20 @@ pub async fn cache_top_level_deps(
|
|||
match specifier.scheme() {
|
||||
"jsr" => {
|
||||
let specifier_str = specifier.as_str();
|
||||
let specifier_str =
|
||||
specifier_str.strip_prefix("jsr:").unwrap_or(specifier_str);
|
||||
if let Ok(req) = PackageReq::from_str(specifier_str) {
|
||||
if !seen_reqs.insert(req.clone()) {
|
||||
if let Ok(req) = JsrPackageReqReference::from_str(specifier_str) {
|
||||
if let Some(sub_path) = req.sub_path() {
|
||||
if sub_path.ends_with('/') {
|
||||
continue;
|
||||
}
|
||||
roots.push(specifier.clone());
|
||||
continue;
|
||||
}
|
||||
if !seen_reqs.insert(req.req().clone()) {
|
||||
continue;
|
||||
}
|
||||
let jsr_resolver = jsr_resolver.clone();
|
||||
info_futures.push(async move {
|
||||
if let Some(nv) = jsr_resolver.req_to_nv(&req).await {
|
||||
if let Some(nv) = jsr_resolver.req_to_nv(req.req()).await {
|
||||
if let Some(info) = jsr_resolver.package_version_info(&nv).await
|
||||
{
|
||||
return Some((specifier.clone(), info));
|
||||
|
|
964
cli/tools/registry/pm/deps.rs
Normal file
964
cli/tools/registry/pm/deps.rs
Normal file
|
@ -0,0 +1,964 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_ast::ModuleSpecifier;
|
||||
use deno_config::deno_json::ConfigFile;
|
||||
use deno_config::deno_json::ConfigFileRc;
|
||||
use deno_config::workspace::Workspace;
|
||||
use deno_config::workspace::WorkspaceDirectory;
|
||||
use deno_core::anyhow::bail;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::futures::future::try_join;
|
||||
use deno_core::futures::stream::FuturesOrdered;
|
||||
use deno_core::futures::stream::FuturesUnordered;
|
||||
use deno_core::futures::FutureExt;
|
||||
use deno_core::futures::StreamExt;
|
||||
use deno_core::serde_json;
|
||||
use deno_graph::FillFromLockfileOptions;
|
||||
use deno_package_json::PackageJsonDepValue;
|
||||
use deno_package_json::PackageJsonDepValueParseError;
|
||||
use deno_package_json::PackageJsonRc;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_semver::jsr::JsrPackageReqReference;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::package::PackageReq;
|
||||
use deno_semver::package::PackageReqReference;
|
||||
use deno_semver::VersionReq;
|
||||
use import_map::ImportMap;
|
||||
use import_map::ImportMapWithDiagnostics;
|
||||
use import_map::SpecifierMapEntry;
|
||||
use indexmap::IndexMap;
|
||||
use tokio::sync::Semaphore;
|
||||
|
||||
use crate::args::CliLockfile;
|
||||
use crate::graph_container::MainModuleGraphContainer;
|
||||
use crate::graph_container::ModuleGraphContainer;
|
||||
use crate::graph_container::ModuleGraphUpdatePermit;
|
||||
use crate::jsr::JsrFetchResolver;
|
||||
use crate::module_loader::ModuleLoadPreparer;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::npm::NpmFetchResolver;
|
||||
|
||||
use super::ConfigUpdater;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum ImportMapKind {
|
||||
Inline,
|
||||
Outline,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum DepLocation {
|
||||
DenoJson(ConfigFileRc, KeyPath, ImportMapKind),
|
||||
PackageJson(PackageJsonRc, KeyPath),
|
||||
}
|
||||
|
||||
impl DepLocation {
|
||||
pub fn is_deno_json(&self) -> bool {
|
||||
matches!(self, DepLocation::DenoJson(..))
|
||||
}
|
||||
|
||||
pub fn file_path(&self) -> Cow<std::path::Path> {
|
||||
match self {
|
||||
DepLocation::DenoJson(arc, _, _) => {
|
||||
Cow::Owned(arc.specifier.to_file_path().unwrap())
|
||||
}
|
||||
DepLocation::PackageJson(arc, _) => Cow::Borrowed(arc.path.as_ref()),
|
||||
}
|
||||
}
|
||||
fn config_kind(&self) -> super::ConfigKind {
|
||||
match self {
|
||||
DepLocation::DenoJson(_, _, _) => super::ConfigKind::DenoJson,
|
||||
DepLocation::PackageJson(_, _) => super::ConfigKind::PackageJson,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct DebugAdapter<T>(T);
|
||||
|
||||
impl<'a> std::fmt::Debug for DebugAdapter<&'a ConfigFileRc> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("ConfigFile")
|
||||
.field("specifier", &self.0.specifier)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
impl<'a> std::fmt::Debug for DebugAdapter<&'a PackageJsonRc> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("PackageJson")
|
||||
.field("path", &self.0.path)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for DepLocation {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
DepLocation::DenoJson(arc, key_path, kind) => {
|
||||
let mut debug = f.debug_tuple("DenoJson");
|
||||
debug
|
||||
.field(&DebugAdapter(arc))
|
||||
.field(key_path)
|
||||
.field(kind)
|
||||
.finish()
|
||||
}
|
||||
DepLocation::PackageJson(arc, key_path) => {
|
||||
let mut debug = f.debug_tuple("PackageJson");
|
||||
debug.field(&DebugAdapter(arc)).field(key_path).finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum DepKind {
|
||||
Jsr,
|
||||
Npm,
|
||||
}
|
||||
|
||||
impl DepKind {
|
||||
pub fn scheme(&self) -> &'static str {
|
||||
match self {
|
||||
DepKind::Npm => "npm",
|
||||
DepKind::Jsr => "jsr",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum KeyPart {
|
||||
Imports,
|
||||
Scopes,
|
||||
Dependencies,
|
||||
DevDependencies,
|
||||
String(String),
|
||||
}
|
||||
|
||||
impl From<String> for KeyPart {
|
||||
fn from(value: String) -> Self {
|
||||
KeyPart::String(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PackageJsonDepKind> for KeyPart {
|
||||
fn from(value: PackageJsonDepKind) -> Self {
|
||||
match value {
|
||||
PackageJsonDepKind::Normal => Self::Dependencies,
|
||||
PackageJsonDepKind::Dev => Self::DevDependencies,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyPart {
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
KeyPart::Imports => "imports",
|
||||
KeyPart::Scopes => "scopes",
|
||||
KeyPart::Dependencies => "dependencies",
|
||||
KeyPart::DevDependencies => "devDependencies",
|
||||
KeyPart::String(s) => s,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct KeyPath {
|
||||
pub parts: Vec<KeyPart>,
|
||||
}
|
||||
|
||||
impl KeyPath {
|
||||
fn from_parts(parts: impl IntoIterator<Item = KeyPart>) -> Self {
|
||||
Self {
|
||||
parts: parts.into_iter().collect(),
|
||||
}
|
||||
}
|
||||
fn last(&self) -> Option<&KeyPart> {
|
||||
self.parts.last()
|
||||
}
|
||||
fn push(&mut self, part: KeyPart) {
|
||||
self.parts.push(part)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Dep {
|
||||
pub req: PackageReq,
|
||||
pub kind: DepKind,
|
||||
pub location: DepLocation,
|
||||
#[allow(dead_code)]
|
||||
pub id: DepId,
|
||||
#[allow(dead_code)]
|
||||
pub alias: Option<String>,
|
||||
}
|
||||
|
||||
fn import_map_entries(
|
||||
import_map: &ImportMap,
|
||||
) -> impl Iterator<Item = (KeyPath, SpecifierMapEntry<'_>)> {
|
||||
import_map
|
||||
.imports()
|
||||
.entries()
|
||||
.map(|entry| {
|
||||
(
|
||||
KeyPath::from_parts([
|
||||
KeyPart::Imports,
|
||||
KeyPart::String(entry.raw_key.into()),
|
||||
]),
|
||||
entry,
|
||||
)
|
||||
})
|
||||
.chain(import_map.scopes().flat_map(|scope| {
|
||||
let path = KeyPath::from_parts([
|
||||
KeyPart::Scopes,
|
||||
scope.raw_key.to_string().into(),
|
||||
]);
|
||||
|
||||
scope.imports.entries().map(move |entry| {
|
||||
let mut full_path = path.clone();
|
||||
full_path.push(KeyPart::String(entry.raw_key.to_string()));
|
||||
(full_path, entry)
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
fn to_import_map_value_from_imports(
|
||||
deno_json: &ConfigFile,
|
||||
) -> serde_json::Value {
|
||||
let mut value = serde_json::Map::with_capacity(2);
|
||||
if let Some(imports) = &deno_json.json.imports {
|
||||
value.insert("imports".to_string(), imports.clone());
|
||||
}
|
||||
if let Some(scopes) = &deno_json.json.scopes {
|
||||
value.insert("scopes".to_string(), scopes.clone());
|
||||
}
|
||||
serde_json::Value::Object(value)
|
||||
}
|
||||
|
||||
fn deno_json_import_map(
|
||||
deno_json: &ConfigFile,
|
||||
) -> Result<Option<(ImportMapWithDiagnostics, ImportMapKind)>, AnyError> {
|
||||
let (value, kind) =
|
||||
if deno_json.json.imports.is_some() || deno_json.json.scopes.is_some() {
|
||||
(
|
||||
to_import_map_value_from_imports(deno_json),
|
||||
ImportMapKind::Inline,
|
||||
)
|
||||
} else {
|
||||
match deno_json.to_import_map_path()? {
|
||||
Some(path) => {
|
||||
let text = std::fs::read_to_string(&path)?;
|
||||
let value = serde_json::from_str(&text)?;
|
||||
(value, ImportMapKind::Outline)
|
||||
}
|
||||
None => return Ok(None),
|
||||
}
|
||||
};
|
||||
|
||||
import_map::parse_from_value(deno_json.specifier.clone(), value)
|
||||
.map_err(Into::into)
|
||||
.map(|import_map| Some((import_map, kind)))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum PackageJsonDepKind {
|
||||
Normal,
|
||||
Dev,
|
||||
}
|
||||
|
||||
type PackageJsonDeps = IndexMap<
|
||||
String,
|
||||
Result<
|
||||
(PackageJsonDepKind, PackageJsonDepValue),
|
||||
PackageJsonDepValueParseError,
|
||||
>,
|
||||
>;
|
||||
|
||||
/// Resolve the package.json's dependencies.
|
||||
// TODO(nathanwhit): Remove once we update deno_package_json with dev deps split out
|
||||
fn resolve_local_package_json_deps(
|
||||
package_json: &PackageJsonRc,
|
||||
) -> PackageJsonDeps {
|
||||
/// Gets the name and raw version constraint for a registry info or
|
||||
/// package.json dependency entry taking into account npm package aliases.
|
||||
fn parse_dep_entry_name_and_raw_version<'a>(
|
||||
key: &'a str,
|
||||
value: &'a str,
|
||||
) -> (&'a str, &'a str) {
|
||||
if let Some(package_and_version) = value.strip_prefix("npm:") {
|
||||
if let Some((name, version)) = package_and_version.rsplit_once('@') {
|
||||
// if empty, then the name was scoped and there's no version
|
||||
if name.is_empty() {
|
||||
(package_and_version, "*")
|
||||
} else {
|
||||
(name, version)
|
||||
}
|
||||
} else {
|
||||
(package_and_version, "*")
|
||||
}
|
||||
} else {
|
||||
(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_entry(
|
||||
key: &str,
|
||||
value: &str,
|
||||
) -> Result<PackageJsonDepValue, PackageJsonDepValueParseError> {
|
||||
if let Some(workspace_key) = value.strip_prefix("workspace:") {
|
||||
let version_req = VersionReq::parse_from_npm(workspace_key)?;
|
||||
return Ok(PackageJsonDepValue::Workspace(version_req));
|
||||
}
|
||||
if value.starts_with("file:")
|
||||
|| value.starts_with("git:")
|
||||
|| value.starts_with("http:")
|
||||
|| value.starts_with("https:")
|
||||
{
|
||||
return Err(PackageJsonDepValueParseError::Unsupported {
|
||||
scheme: value.split(':').next().unwrap().to_string(),
|
||||
});
|
||||
}
|
||||
let (name, version_req) = parse_dep_entry_name_and_raw_version(key, value);
|
||||
let result = VersionReq::parse_from_npm(version_req);
|
||||
match result {
|
||||
Ok(version_req) => Ok(PackageJsonDepValue::Req(PackageReq {
|
||||
name: name.to_string(),
|
||||
version_req,
|
||||
})),
|
||||
Err(err) => Err(PackageJsonDepValueParseError::VersionReq(err)),
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_deps(
|
||||
deps: Option<&IndexMap<String, String>>,
|
||||
result: &mut PackageJsonDeps,
|
||||
kind: PackageJsonDepKind,
|
||||
) {
|
||||
if let Some(deps) = deps {
|
||||
for (key, value) in deps {
|
||||
result.entry(key.to_string()).or_insert_with(|| {
|
||||
parse_entry(key, value).map(|entry| (kind, entry))
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let deps = package_json.dependencies.as_ref();
|
||||
let dev_deps = package_json.dev_dependencies.as_ref();
|
||||
let mut result = IndexMap::new();
|
||||
|
||||
// favors the deps over dev_deps
|
||||
insert_deps(deps, &mut result, PackageJsonDepKind::Normal);
|
||||
insert_deps(dev_deps, &mut result, PackageJsonDepKind::Dev);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn add_deps_from_deno_json(
|
||||
deno_json: &Arc<ConfigFile>,
|
||||
mut filter: impl DepFilter,
|
||||
deps: &mut Vec<Dep>,
|
||||
) {
|
||||
let (import_map, import_map_kind) = match deno_json_import_map(deno_json) {
|
||||
Ok(Some((import_map, import_map_kind))) => (import_map, import_map_kind),
|
||||
Ok(None) => return,
|
||||
Err(e) => {
|
||||
log::warn!("failed to parse imports from {}: {e}", &deno_json.specifier);
|
||||
return;
|
||||
}
|
||||
};
|
||||
for (key_path, entry) in import_map_entries(&import_map.import_map) {
|
||||
let Some(value) = entry.value else { continue };
|
||||
let kind = match value.scheme() {
|
||||
"npm" => DepKind::Npm,
|
||||
"jsr" => DepKind::Jsr,
|
||||
_ => continue,
|
||||
};
|
||||
let req = match parse_req_reference(value.as_str(), kind) {
|
||||
Ok(req) => req.req.clone(),
|
||||
Err(err) => {
|
||||
log::warn!("failed to parse package req \"{}\": {err}", value.as_str());
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let alias: &str = key_path.last().unwrap().as_str().trim_end_matches('/');
|
||||
let alias = (alias != req.name).then(|| alias.to_string());
|
||||
if !filter.should_include(alias.as_deref(), &req, kind) {
|
||||
continue;
|
||||
}
|
||||
let id = DepId(deps.len());
|
||||
deps.push(Dep {
|
||||
location: DepLocation::DenoJson(
|
||||
deno_json.clone(),
|
||||
key_path,
|
||||
import_map_kind,
|
||||
),
|
||||
kind,
|
||||
req,
|
||||
id,
|
||||
alias,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn add_deps_from_package_json(
|
||||
package_json: &PackageJsonRc,
|
||||
mut filter: impl DepFilter,
|
||||
deps: &mut Vec<Dep>,
|
||||
) {
|
||||
let package_json_deps = resolve_local_package_json_deps(package_json);
|
||||
for (k, v) in package_json_deps {
|
||||
let (package_dep_kind, v) = match v {
|
||||
Ok((k, v)) => (k, v),
|
||||
Err(e) => {
|
||||
log::warn!("bad package json dep value: {e}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
match v {
|
||||
deno_package_json::PackageJsonDepValue::Req(req) => {
|
||||
let alias = k.as_str();
|
||||
let alias = (alias != req.name).then(|| alias.to_string());
|
||||
if !filter.should_include(alias.as_deref(), &req, DepKind::Npm) {
|
||||
continue;
|
||||
}
|
||||
let id = DepId(deps.len());
|
||||
deps.push(Dep {
|
||||
id,
|
||||
kind: DepKind::Npm,
|
||||
location: DepLocation::PackageJson(
|
||||
package_json.clone(),
|
||||
KeyPath::from_parts([package_dep_kind.into(), k.into()]),
|
||||
),
|
||||
req,
|
||||
alias,
|
||||
})
|
||||
}
|
||||
deno_package_json::PackageJsonDepValue::Workspace(_) => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn deps_from_workspace(
|
||||
workspace: &Arc<Workspace>,
|
||||
dep_filter: impl DepFilter,
|
||||
) -> Result<Vec<Dep>, AnyError> {
|
||||
let mut deps = Vec::with_capacity(256);
|
||||
for deno_json in workspace.deno_jsons() {
|
||||
add_deps_from_deno_json(deno_json, dep_filter, &mut deps);
|
||||
}
|
||||
for package_json in workspace.package_jsons() {
|
||||
add_deps_from_package_json(package_json, dep_filter, &mut deps);
|
||||
}
|
||||
|
||||
Ok(deps)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct DepId(usize);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Change {
|
||||
Update(DepId, VersionReq),
|
||||
}
|
||||
|
||||
pub trait DepFilter: Copy {
|
||||
fn should_include(
|
||||
&mut self,
|
||||
alias: Option<&str>,
|
||||
package_req: &PackageReq,
|
||||
dep_kind: DepKind,
|
||||
) -> bool;
|
||||
}
|
||||
|
||||
impl<T> DepFilter for T
|
||||
where
|
||||
T: FnMut(Option<&str>, &PackageReq, DepKind) -> bool + Copy,
|
||||
{
|
||||
fn should_include<'a>(
|
||||
&mut self,
|
||||
alias: Option<&'a str>,
|
||||
package_req: &'a PackageReq,
|
||||
dep_kind: DepKind,
|
||||
) -> bool {
|
||||
(*self)(alias, package_req, dep_kind)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PackageLatestVersion {
|
||||
pub semver_compatible: Option<PackageNv>,
|
||||
pub latest: Option<PackageNv>,
|
||||
}
|
||||
|
||||
pub struct DepManager {
|
||||
deps: Vec<Dep>,
|
||||
resolved_versions: Vec<Option<PackageNv>>,
|
||||
latest_versions: Vec<PackageLatestVersion>,
|
||||
|
||||
pending_changes: Vec<Change>,
|
||||
|
||||
dependencies_resolved: AtomicBool,
|
||||
module_load_preparer: Arc<ModuleLoadPreparer>,
|
||||
// TODO(nathanwhit): probably shouldn't be pub
|
||||
pub(crate) jsr_fetch_resolver: Arc<JsrFetchResolver>,
|
||||
pub(crate) npm_fetch_resolver: Arc<NpmFetchResolver>,
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
permissions_container: PermissionsContainer,
|
||||
main_module_graph_container: Arc<MainModuleGraphContainer>,
|
||||
lockfile: Option<Arc<CliLockfile>>,
|
||||
}
|
||||
|
||||
pub struct DepManagerArgs {
|
||||
pub module_load_preparer: Arc<ModuleLoadPreparer>,
|
||||
pub jsr_fetch_resolver: Arc<JsrFetchResolver>,
|
||||
pub npm_fetch_resolver: Arc<NpmFetchResolver>,
|
||||
pub npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
pub permissions_container: PermissionsContainer,
|
||||
pub main_module_graph_container: Arc<MainModuleGraphContainer>,
|
||||
pub lockfile: Option<Arc<CliLockfile>>,
|
||||
}
|
||||
|
||||
impl DepManager {
|
||||
pub fn reloaded_after_modification(self, args: DepManagerArgs) -> Self {
|
||||
let mut new = Self::with_deps_args(self.deps, args);
|
||||
new.latest_versions = self.latest_versions;
|
||||
new
|
||||
}
|
||||
fn with_deps_args(deps: Vec<Dep>, args: DepManagerArgs) -> Self {
|
||||
let DepManagerArgs {
|
||||
module_load_preparer,
|
||||
jsr_fetch_resolver,
|
||||
npm_fetch_resolver,
|
||||
npm_resolver,
|
||||
permissions_container,
|
||||
main_module_graph_container,
|
||||
lockfile,
|
||||
} = args;
|
||||
Self {
|
||||
deps,
|
||||
resolved_versions: Vec::new(),
|
||||
latest_versions: Vec::new(),
|
||||
jsr_fetch_resolver,
|
||||
dependencies_resolved: AtomicBool::new(false),
|
||||
module_load_preparer,
|
||||
npm_fetch_resolver,
|
||||
npm_resolver,
|
||||
permissions_container,
|
||||
main_module_graph_container,
|
||||
lockfile,
|
||||
pending_changes: Vec::new(),
|
||||
}
|
||||
}
|
||||
pub fn from_workspace_dir(
|
||||
workspace_dir: &Arc<WorkspaceDirectory>,
|
||||
dep_filter: impl DepFilter,
|
||||
args: DepManagerArgs,
|
||||
) -> Result<Self, AnyError> {
|
||||
let mut deps = Vec::with_capacity(256);
|
||||
if let Some(deno_json) = workspace_dir.maybe_deno_json() {
|
||||
if deno_json.specifier.scheme() != "file" {
|
||||
bail!("remote deno.json files are not supported");
|
||||
}
|
||||
let path = deno_json.specifier.to_file_path().unwrap();
|
||||
if path.parent().unwrap() == workspace_dir.dir_path() {
|
||||
add_deps_from_deno_json(deno_json, dep_filter, &mut deps);
|
||||
}
|
||||
}
|
||||
if let Some(package_json) = workspace_dir.maybe_pkg_json() {
|
||||
add_deps_from_package_json(package_json, dep_filter, &mut deps);
|
||||
}
|
||||
|
||||
Ok(Self::with_deps_args(deps, args))
|
||||
}
|
||||
pub fn from_workspace(
|
||||
workspace: &Arc<Workspace>,
|
||||
dep_filter: impl DepFilter,
|
||||
args: DepManagerArgs,
|
||||
) -> Result<Self, AnyError> {
|
||||
let deps = deps_from_workspace(workspace, dep_filter)?;
|
||||
Ok(Self::with_deps_args(deps, args))
|
||||
}
|
||||
|
||||
async fn run_dependency_resolution(&self) -> Result<(), AnyError> {
|
||||
if self
|
||||
.dependencies_resolved
|
||||
.load(std::sync::atomic::Ordering::Relaxed)
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut graph_permit = self
|
||||
.main_module_graph_container
|
||||
.acquire_update_permit()
|
||||
.await;
|
||||
let graph = graph_permit.graph_mut();
|
||||
// populate the information from the lockfile
|
||||
if let Some(lockfile) = &self.lockfile {
|
||||
let lockfile = lockfile.lock();
|
||||
graph.fill_from_lockfile(FillFromLockfileOptions {
|
||||
redirects: lockfile
|
||||
.content
|
||||
.redirects
|
||||
.iter()
|
||||
.map(|(from, to)| (from.as_str(), to.as_str())),
|
||||
package_specifiers: lockfile
|
||||
.content
|
||||
.packages
|
||||
.specifiers
|
||||
.iter()
|
||||
.map(|(dep, id)| (dep, id.as_str())),
|
||||
});
|
||||
}
|
||||
|
||||
let npm_resolver = self.npm_resolver.as_managed().unwrap();
|
||||
if self.deps.iter().all(|dep| match dep.kind {
|
||||
DepKind::Npm => {
|
||||
npm_resolver.resolve_pkg_id_from_pkg_req(&dep.req).is_ok()
|
||||
}
|
||||
DepKind::Jsr => graph.packages.mappings().contains_key(&dep.req),
|
||||
}) {
|
||||
self
|
||||
.dependencies_resolved
|
||||
.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||
graph_permit.commit();
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
npm_resolver.ensure_top_level_package_json_install().await?;
|
||||
let mut roots = Vec::new();
|
||||
let mut info_futures = FuturesUnordered::new();
|
||||
for dep in &self.deps {
|
||||
if dep.location.is_deno_json() {
|
||||
match dep.kind {
|
||||
DepKind::Npm => roots.push(
|
||||
ModuleSpecifier::parse(&format!("npm:/{}/", dep.req)).unwrap(),
|
||||
),
|
||||
DepKind::Jsr => info_futures.push(async {
|
||||
if let Some(nv) = self.jsr_fetch_resolver.req_to_nv(&dep.req).await
|
||||
{
|
||||
if let Some(info) =
|
||||
self.jsr_fetch_resolver.package_version_info(&nv).await
|
||||
{
|
||||
let specifier =
|
||||
ModuleSpecifier::parse(&format!("jsr:/{}/", dep.req))
|
||||
.unwrap();
|
||||
return Some((specifier, info));
|
||||
}
|
||||
}
|
||||
None
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while let Some(info_future) = info_futures.next().await {
|
||||
if let Some((specifier, info)) = info_future {
|
||||
let exports = info.exports();
|
||||
for (k, _) in exports {
|
||||
if let Ok(spec) = specifier.join(k) {
|
||||
roots.push(spec);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self
|
||||
.module_load_preparer
|
||||
.prepare_module_load(
|
||||
graph,
|
||||
&roots,
|
||||
false,
|
||||
deno_config::deno_json::TsTypeLib::DenoWindow,
|
||||
self.permissions_container.clone(),
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
graph_permit.commit();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn resolved_version(&self, id: DepId) -> Option<&PackageNv> {
|
||||
self.resolved_versions[id.0].as_ref()
|
||||
}
|
||||
|
||||
pub async fn resolve_current_versions(&mut self) -> Result<(), AnyError> {
|
||||
self.run_dependency_resolution().await?;
|
||||
|
||||
let graph = self.main_module_graph_container.graph();
|
||||
|
||||
let mut resolved = Vec::with_capacity(self.deps.len());
|
||||
let snapshot = self.npm_resolver.as_managed().unwrap().snapshot();
|
||||
let resolved_npm = snapshot.package_reqs();
|
||||
let resolved_jsr = graph.packages.mappings();
|
||||
for dep in &self.deps {
|
||||
match dep.kind {
|
||||
DepKind::Npm => {
|
||||
let resolved_version = resolved_npm.get(&dep.req).cloned();
|
||||
resolved.push(resolved_version);
|
||||
}
|
||||
DepKind::Jsr => {
|
||||
let resolved_version = resolved_jsr.get(&dep.req).cloned();
|
||||
resolved.push(resolved_version)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.resolved_versions = resolved;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn load_latest_versions(
|
||||
&self,
|
||||
) -> Result<Vec<PackageLatestVersion>, AnyError> {
|
||||
if self.latest_versions.len() == self.deps.len() {
|
||||
return Ok(self.latest_versions.clone());
|
||||
}
|
||||
let latest_tag_req = deno_semver::VersionReq::from_raw_text_and_inner(
|
||||
"latest".into(),
|
||||
deno_semver::RangeSetOrTag::Tag("latest".into()),
|
||||
);
|
||||
let mut latest_versions = Vec::with_capacity(self.deps.len());
|
||||
|
||||
let npm_sema = Semaphore::new(32);
|
||||
let jsr_sema = Semaphore::new(32);
|
||||
let mut futs = FuturesOrdered::new();
|
||||
|
||||
for dep in &self.deps {
|
||||
match dep.kind {
|
||||
DepKind::Npm => futs.push_back(
|
||||
async {
|
||||
let semver_req = &dep.req;
|
||||
let latest_req = PackageReq {
|
||||
name: dep.req.name.clone(),
|
||||
version_req: latest_tag_req.clone(),
|
||||
};
|
||||
let _permit = npm_sema.acquire().await;
|
||||
let semver_compatible =
|
||||
self.npm_fetch_resolver.req_to_nv(semver_req).await;
|
||||
let latest = self.npm_fetch_resolver.req_to_nv(&latest_req).await;
|
||||
PackageLatestVersion {
|
||||
latest,
|
||||
semver_compatible,
|
||||
}
|
||||
}
|
||||
.boxed_local(),
|
||||
),
|
||||
DepKind::Jsr => futs.push_back(
|
||||
async {
|
||||
let semver_req = &dep.req;
|
||||
let latest_req = PackageReq {
|
||||
name: dep.req.name.clone(),
|
||||
version_req: deno_semver::WILDCARD_VERSION_REQ.clone(),
|
||||
};
|
||||
let _permit = jsr_sema.acquire().await;
|
||||
let semver_compatible =
|
||||
self.jsr_fetch_resolver.req_to_nv(semver_req).await;
|
||||
let latest = self.jsr_fetch_resolver.req_to_nv(&latest_req).await;
|
||||
PackageLatestVersion {
|
||||
latest,
|
||||
semver_compatible,
|
||||
}
|
||||
}
|
||||
.boxed_local(),
|
||||
),
|
||||
}
|
||||
}
|
||||
while let Some(nv) = futs.next().await {
|
||||
latest_versions.push(nv);
|
||||
}
|
||||
|
||||
Ok(latest_versions)
|
||||
}
|
||||
|
||||
pub async fn resolve_versions(&mut self) -> Result<(), AnyError> {
|
||||
let (_, latest_versions) = try_join(
|
||||
self.run_dependency_resolution(),
|
||||
self.load_latest_versions(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
self.latest_versions = latest_versions;
|
||||
|
||||
self.resolve_current_versions().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn deps_with_resolved_latest_versions(
|
||||
&self,
|
||||
) -> impl IntoIterator<Item = (DepId, Option<PackageNv>, PackageLatestVersion)> + '_
|
||||
{
|
||||
self
|
||||
.resolved_versions
|
||||
.iter()
|
||||
.zip(self.latest_versions.iter())
|
||||
.enumerate()
|
||||
.map(|(i, (resolved, latest))| {
|
||||
(DepId(i), resolved.clone(), latest.clone())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_dep(&self, id: DepId) -> &Dep {
|
||||
&self.deps[id.0]
|
||||
}
|
||||
|
||||
pub fn update_dep(&mut self, dep_id: DepId, new_version_req: VersionReq) {
|
||||
self
|
||||
.pending_changes
|
||||
.push(Change::Update(dep_id, new_version_req));
|
||||
}
|
||||
|
||||
pub fn commit_changes(&mut self) -> Result<(), AnyError> {
|
||||
let changes = std::mem::take(&mut self.pending_changes);
|
||||
let mut config_updaters = HashMap::new();
|
||||
for change in changes {
|
||||
match change {
|
||||
Change::Update(dep_id, version_req) => {
|
||||
// TODO: move most of this to ConfigUpdater
|
||||
let dep = &mut self.deps[dep_id.0];
|
||||
dep.req.version_req = version_req.clone();
|
||||
match &dep.location {
|
||||
DepLocation::DenoJson(arc, key_path, import_map_kind) => {
|
||||
if matches!(import_map_kind, ImportMapKind::Outline) {
|
||||
// not supported
|
||||
continue;
|
||||
}
|
||||
let updater =
|
||||
get_or_create_updater(&mut config_updaters, &dep.location)?;
|
||||
|
||||
let Some(property) = updater.get_property_for_mutation(key_path)
|
||||
else {
|
||||
log::warn!(
|
||||
"failed to find property at path {key_path:?} for file {}",
|
||||
arc.specifier
|
||||
);
|
||||
continue;
|
||||
};
|
||||
let Some(string_value) = cst_string_literal(&property) else {
|
||||
continue;
|
||||
};
|
||||
let mut req_reference = match dep.kind {
|
||||
DepKind::Npm => NpmPackageReqReference::from_str(&string_value)
|
||||
.unwrap()
|
||||
.into_inner(),
|
||||
DepKind::Jsr => JsrPackageReqReference::from_str(&string_value)
|
||||
.unwrap()
|
||||
.into_inner(),
|
||||
};
|
||||
req_reference.req.version_req = version_req;
|
||||
let mut new_value =
|
||||
format!("{}:{}", dep.kind.scheme(), req_reference);
|
||||
if string_value.ends_with('/') && !new_value.ends_with('/') {
|
||||
// the display impl for PackageReqReference maps `/` to the root
|
||||
// subpath, but for the import map the trailing `/` is significant
|
||||
new_value.push('/');
|
||||
}
|
||||
if string_value
|
||||
.trim_start_matches(format!("{}:", dep.kind.scheme()).as_str())
|
||||
.starts_with('/')
|
||||
{
|
||||
// this is gross
|
||||
new_value = new_value.replace(':', ":/");
|
||||
}
|
||||
property
|
||||
.set_value(jsonc_parser::cst::CstInputValue::String(new_value));
|
||||
}
|
||||
DepLocation::PackageJson(arc, key_path) => {
|
||||
let updater =
|
||||
get_or_create_updater(&mut config_updaters, &dep.location)?;
|
||||
let Some(property) = updater.get_property_for_mutation(key_path)
|
||||
else {
|
||||
log::warn!(
|
||||
"failed to find property at path {key_path:?} for file {}",
|
||||
arc.path.display()
|
||||
);
|
||||
continue;
|
||||
};
|
||||
let Some(string_value) = cst_string_literal(&property) else {
|
||||
continue;
|
||||
};
|
||||
let new_value = if string_value.starts_with("npm:") {
|
||||
// aliased
|
||||
let rest = string_value.trim_start_matches("npm:");
|
||||
let mut parts = rest.split('@');
|
||||
let first = parts.next().unwrap();
|
||||
if first.is_empty() {
|
||||
let scope_and_name = parts.next().unwrap();
|
||||
format!("npm:@{scope_and_name}@{version_req}")
|
||||
} else {
|
||||
format!("npm:{first}@{version_req}")
|
||||
}
|
||||
} else if string_value.contains(":") {
|
||||
bail!("Unexpected package json dependency string: \"{string_value}\" in {}", arc.path.display());
|
||||
} else {
|
||||
version_req.to_string()
|
||||
};
|
||||
property
|
||||
.set_value(jsonc_parser::cst::CstInputValue::String(new_value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (_, updater) in config_updaters {
|
||||
updater.commit()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_or_create_updater<'a>(
|
||||
config_updaters: &'a mut HashMap<std::path::PathBuf, ConfigUpdater>,
|
||||
location: &DepLocation,
|
||||
) -> Result<&'a mut ConfigUpdater, AnyError> {
|
||||
match config_updaters.entry(location.file_path().into_owned()) {
|
||||
std::collections::hash_map::Entry::Occupied(occupied_entry) => {
|
||||
Ok(occupied_entry.into_mut())
|
||||
}
|
||||
std::collections::hash_map::Entry::Vacant(vacant_entry) => {
|
||||
let updater = ConfigUpdater::new(
|
||||
location.config_kind(),
|
||||
location.file_path().into_owned(),
|
||||
)?;
|
||||
Ok(vacant_entry.insert(updater))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn cst_string_literal(
|
||||
property: &jsonc_parser::cst::CstObjectProp,
|
||||
) -> Option<String> {
|
||||
// TODO(nathanwhit): ensure this unwrap is safe
|
||||
let value = property.value().unwrap();
|
||||
let Some(string) = value.as_string_lit() else {
|
||||
log::warn!("malformed entry");
|
||||
return None;
|
||||
};
|
||||
let Ok(string_value) = string.decoded_value() else {
|
||||
log::warn!("malformed string: {string:?}");
|
||||
return None;
|
||||
};
|
||||
Some(string_value)
|
||||
}
|
||||
|
||||
fn parse_req_reference(
|
||||
input: &str,
|
||||
kind: DepKind,
|
||||
) -> Result<
|
||||
PackageReqReference,
|
||||
deno_semver::package::PackageReqReferenceParseError,
|
||||
> {
|
||||
Ok(match kind {
|
||||
DepKind::Npm => NpmPackageReqReference::from_str(input)?.into_inner(),
|
||||
DepKind::Jsr => JsrPackageReqReference::from_str(input)?.into_inner(),
|
||||
})
|
||||
}
|
661
cli/tools/registry/pm/outdated.rs
Normal file
661
cli/tools/registry/pm/outdated.rs
Normal file
|
@ -0,0 +1,661 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_core::error::AnyError;
|
||||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::package::PackageReq;
|
||||
use deno_semver::VersionReq;
|
||||
use deno_terminal::colors;
|
||||
|
||||
use crate::args::CacheSetting;
|
||||
use crate::args::CliOptions;
|
||||
use crate::args::Flags;
|
||||
use crate::args::OutdatedFlags;
|
||||
use crate::factory::CliFactory;
|
||||
use crate::file_fetcher::FileFetcher;
|
||||
use crate::jsr::JsrFetchResolver;
|
||||
use crate::npm::NpmFetchResolver;
|
||||
use crate::tools::registry::pm::deps::DepKind;
|
||||
|
||||
use super::deps::Dep;
|
||||
use super::deps::DepManager;
|
||||
use super::deps::DepManagerArgs;
|
||||
use super::deps::PackageLatestVersion;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct OutdatedPackage {
|
||||
kind: DepKind,
|
||||
latest: String,
|
||||
semver_compatible: String,
|
||||
current: String,
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[allow(clippy::print_stdout)]
|
||||
fn print_outdated_table(packages: &[OutdatedPackage]) {
|
||||
const HEADINGS: &[&str] = &["Package", "Current", "Update", "Latest"];
|
||||
|
||||
let mut longest_package = 0;
|
||||
let mut longest_current = 0;
|
||||
let mut longest_update = 0;
|
||||
let mut longest_latest = 0;
|
||||
|
||||
for package in packages {
|
||||
let name_len = package.kind.scheme().len() + 1 + package.name.len();
|
||||
longest_package = longest_package.max(name_len);
|
||||
longest_current = longest_current.max(package.current.len());
|
||||
longest_update = longest_update.max(package.semver_compatible.len());
|
||||
longest_latest = longest_latest.max(package.latest.len());
|
||||
}
|
||||
|
||||
let package_column_width = longest_package.max(HEADINGS[0].len()) + 2;
|
||||
let current_column_width = longest_current.max(HEADINGS[1].len()) + 2;
|
||||
let update_column_width = longest_update.max(HEADINGS[2].len()) + 2;
|
||||
let latest_column_width = longest_latest.max(HEADINGS[3].len()) + 2;
|
||||
|
||||
let package_fill = "─".repeat(package_column_width);
|
||||
let current_fill = "─".repeat(current_column_width);
|
||||
let update_fill = "─".repeat(update_column_width);
|
||||
let latest_fill = "─".repeat(latest_column_width);
|
||||
|
||||
println!("┌{package_fill}┬{current_fill}┬{update_fill}┬{latest_fill}┐");
|
||||
println!(
|
||||
"│ {}{} │ {}{} │ {}{} │ {}{} │",
|
||||
colors::intense_blue(HEADINGS[0]),
|
||||
" ".repeat(package_column_width - 2 - HEADINGS[0].len()),
|
||||
colors::intense_blue(HEADINGS[1]),
|
||||
" ".repeat(current_column_width - 2 - HEADINGS[1].len()),
|
||||
colors::intense_blue(HEADINGS[2]),
|
||||
" ".repeat(update_column_width - 2 - HEADINGS[2].len()),
|
||||
colors::intense_blue(HEADINGS[3]),
|
||||
" ".repeat(latest_column_width - 2 - HEADINGS[3].len())
|
||||
);
|
||||
for package in packages {
|
||||
println!("├{package_fill}┼{current_fill}┼{update_fill}┼{latest_fill}┤",);
|
||||
|
||||
print!(
|
||||
"│ {:<package_column_width$} ",
|
||||
format!("{}:{}", package.kind.scheme(), package.name),
|
||||
package_column_width = package_column_width - 2
|
||||
);
|
||||
print!(
|
||||
"│ {:<current_column_width$} ",
|
||||
package.current,
|
||||
current_column_width = current_column_width - 2
|
||||
);
|
||||
print!(
|
||||
"│ {:<update_column_width$} ",
|
||||
package.semver_compatible,
|
||||
update_column_width = update_column_width - 2
|
||||
);
|
||||
println!(
|
||||
"│ {:<latest_column_width$} │",
|
||||
package.latest,
|
||||
latest_column_width = latest_column_width - 2
|
||||
);
|
||||
}
|
||||
|
||||
println!("└{package_fill}┴{current_fill}┴{update_fill}┴{latest_fill}┘",);
|
||||
}
|
||||
|
||||
fn print_outdated(
|
||||
deps: &mut DepManager,
|
||||
compatible: bool,
|
||||
) -> Result<(), AnyError> {
|
||||
let mut outdated = Vec::new();
|
||||
let mut seen = std::collections::BTreeSet::new();
|
||||
for (dep_id, resolved, latest_versions) in
|
||||
deps.deps_with_resolved_latest_versions()
|
||||
{
|
||||
let dep = deps.get_dep(dep_id);
|
||||
|
||||
let Some(resolved) = resolved else { continue };
|
||||
|
||||
let latest = {
|
||||
let preferred = if compatible {
|
||||
&latest_versions.semver_compatible
|
||||
} else {
|
||||
&latest_versions.latest
|
||||
};
|
||||
if let Some(v) = preferred {
|
||||
v
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
if latest > &resolved
|
||||
&& seen.insert((dep.kind, dep.req.name.clone(), resolved.version.clone()))
|
||||
{
|
||||
outdated.push(OutdatedPackage {
|
||||
kind: dep.kind,
|
||||
name: dep.req.name.clone(),
|
||||
current: resolved.version.to_string(),
|
||||
latest: latest_versions
|
||||
.latest
|
||||
.map(|l| l.version.to_string())
|
||||
.unwrap_or_default(),
|
||||
semver_compatible: latest_versions
|
||||
.semver_compatible
|
||||
.map(|l| l.version.to_string())
|
||||
.unwrap_or_default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if !outdated.is_empty() {
|
||||
outdated.sort();
|
||||
print_outdated_table(&outdated);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn outdated(
|
||||
flags: Arc<Flags>,
|
||||
update_flags: OutdatedFlags,
|
||||
) -> Result<(), AnyError> {
|
||||
let factory = CliFactory::from_flags(flags.clone());
|
||||
let cli_options = factory.cli_options()?;
|
||||
let workspace = cli_options.workspace();
|
||||
let http_client = factory.http_client_provider();
|
||||
let deps_http_cache = factory.global_http_cache()?;
|
||||
let mut file_fetcher = FileFetcher::new(
|
||||
deps_http_cache.clone(),
|
||||
CacheSetting::RespectHeaders,
|
||||
true,
|
||||
http_client.clone(),
|
||||
Default::default(),
|
||||
None,
|
||||
);
|
||||
file_fetcher.set_download_log_level(log::Level::Trace);
|
||||
let file_fetcher = Arc::new(file_fetcher);
|
||||
let npm_fetch_resolver = Arc::new(NpmFetchResolver::new(
|
||||
file_fetcher.clone(),
|
||||
cli_options.npmrc().clone(),
|
||||
));
|
||||
let jsr_fetch_resolver =
|
||||
Arc::new(JsrFetchResolver::new(file_fetcher.clone()));
|
||||
|
||||
let args = dep_manager_args(
|
||||
&factory,
|
||||
cli_options,
|
||||
npm_fetch_resolver.clone(),
|
||||
jsr_fetch_resolver.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let filter_set = filter::FilterSet::from_filter_strings(
|
||||
update_flags.filters.iter().map(|s| s.as_str()),
|
||||
)?;
|
||||
|
||||
let filter_fn = |alias: Option<&str>, req: &PackageReq, _: DepKind| {
|
||||
if filter_set.is_empty() {
|
||||
return true;
|
||||
}
|
||||
let name = alias.unwrap_or(&req.name);
|
||||
filter_set.matches(name)
|
||||
};
|
||||
let mut deps = if update_flags.recursive {
|
||||
super::deps::DepManager::from_workspace(workspace, filter_fn, args)?
|
||||
} else {
|
||||
super::deps::DepManager::from_workspace_dir(
|
||||
&cli_options.start_dir,
|
||||
filter_fn,
|
||||
args,
|
||||
)?
|
||||
};
|
||||
|
||||
deps.resolve_versions().await?;
|
||||
|
||||
match update_flags.kind {
|
||||
crate::args::OutdatedKind::Update { latest } => {
|
||||
update(deps, latest, &filter_set, flags).await?;
|
||||
}
|
||||
crate::args::OutdatedKind::PrintOutdated { compatible } => {
|
||||
print_outdated(&mut deps, compatible)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn choose_new_version_req(
|
||||
dep: &Dep,
|
||||
resolved: Option<&PackageNv>,
|
||||
latest_versions: &PackageLatestVersion,
|
||||
update_to_latest: bool,
|
||||
filter_set: &filter::FilterSet,
|
||||
) -> Option<VersionReq> {
|
||||
let explicit_version_req = filter_set
|
||||
.matching_filter(dep.alias.as_deref().unwrap_or(&dep.req.name))
|
||||
.version_spec()
|
||||
.cloned();
|
||||
|
||||
if let Some(version_req) = explicit_version_req {
|
||||
if let Some(resolved) = resolved {
|
||||
// todo(nathanwhit): handle tag
|
||||
if version_req.tag().is_none() && version_req.matches(&resolved.version) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Some(version_req)
|
||||
} else {
|
||||
let preferred = if update_to_latest {
|
||||
latest_versions.latest.as_ref()?
|
||||
} else {
|
||||
latest_versions.semver_compatible.as_ref()?
|
||||
};
|
||||
if preferred.version <= resolved?.version {
|
||||
return None;
|
||||
}
|
||||
Some(
|
||||
VersionReq::parse_from_specifier(
|
||||
format!("^{}", preferred.version).as_str(),
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async fn update(
|
||||
mut deps: DepManager,
|
||||
update_to_latest: bool,
|
||||
filter_set: &filter::FilterSet,
|
||||
flags: Arc<Flags>,
|
||||
) -> Result<(), AnyError> {
|
||||
let mut updated = Vec::new();
|
||||
|
||||
for (dep_id, resolved, latest_versions) in deps
|
||||
.deps_with_resolved_latest_versions()
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>()
|
||||
{
|
||||
let dep = deps.get_dep(dep_id);
|
||||
let new_version_req = choose_new_version_req(
|
||||
dep,
|
||||
resolved.as_ref(),
|
||||
&latest_versions,
|
||||
update_to_latest,
|
||||
filter_set,
|
||||
);
|
||||
let Some(new_version_req) = new_version_req else {
|
||||
continue;
|
||||
};
|
||||
|
||||
updated.push((
|
||||
dep_id,
|
||||
format!("{}:{}", dep.kind.scheme(), dep.req.name),
|
||||
deps.resolved_version(dep.id).cloned(),
|
||||
new_version_req.clone(),
|
||||
));
|
||||
|
||||
deps.update_dep(dep_id, new_version_req);
|
||||
}
|
||||
|
||||
deps.commit_changes()?;
|
||||
|
||||
if !updated.is_empty() {
|
||||
let factory = super::npm_install_after_modification(
|
||||
flags.clone(),
|
||||
Some(deps.jsr_fetch_resolver.clone()),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let mut updated_to_versions = HashSet::new();
|
||||
let cli_options = factory.cli_options()?;
|
||||
let args = dep_manager_args(
|
||||
&factory,
|
||||
cli_options,
|
||||
deps.npm_fetch_resolver.clone(),
|
||||
deps.jsr_fetch_resolver.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let mut deps = deps.reloaded_after_modification(args);
|
||||
deps.resolve_current_versions().await?;
|
||||
for (dep_id, package_name, maybe_current_version, new_version_req) in
|
||||
updated
|
||||
{
|
||||
if let Some(nv) = deps.resolved_version(dep_id) {
|
||||
updated_to_versions.insert((
|
||||
package_name,
|
||||
maybe_current_version,
|
||||
nv.version.clone(),
|
||||
));
|
||||
} else {
|
||||
log::warn!(
|
||||
"Failed to resolve version for new version requirement: {} -> {}",
|
||||
package_name,
|
||||
new_version_req
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
log::info!(
|
||||
"Updated {} dependenc{}:",
|
||||
updated_to_versions.len(),
|
||||
if updated_to_versions.len() == 1 {
|
||||
"y"
|
||||
} else {
|
||||
"ies"
|
||||
}
|
||||
);
|
||||
let mut updated_to_versions =
|
||||
updated_to_versions.into_iter().collect::<Vec<_>>();
|
||||
updated_to_versions.sort_by(|(k, _, _), (k2, _, _)| k.cmp(k2));
|
||||
let max_name = updated_to_versions
|
||||
.iter()
|
||||
.map(|(name, _, _)| name.len())
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
let max_old = updated_to_versions
|
||||
.iter()
|
||||
.map(|(_, maybe_current, _)| {
|
||||
maybe_current
|
||||
.as_ref()
|
||||
.map(|v| v.version.to_string().len())
|
||||
.unwrap_or(0)
|
||||
})
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
let max_new = updated_to_versions
|
||||
.iter()
|
||||
.map(|(_, _, new_version)| new_version.to_string().len())
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
|
||||
for (package_name, maybe_current_version, new_version) in
|
||||
updated_to_versions
|
||||
{
|
||||
let current_version = if let Some(current_version) = maybe_current_version
|
||||
{
|
||||
current_version.version.to_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
|
||||
log::info!(
|
||||
" - {}{} {}{} -> {}{}",
|
||||
format!(
|
||||
"{}{}",
|
||||
colors::gray(package_name[0..4].to_string()),
|
||||
package_name[4..].to_string()
|
||||
),
|
||||
" ".repeat(max_name - package_name.len()),
|
||||
" ".repeat(max_old - current_version.len()),
|
||||
colors::gray(¤t_version),
|
||||
" ".repeat(max_new - new_version.to_string().len()),
|
||||
colors::green(&new_version),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
log::info!(
|
||||
"All {}dependencies are up to date.",
|
||||
if filter_set.is_empty() {
|
||||
""
|
||||
} else {
|
||||
"matching "
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn dep_manager_args(
|
||||
factory: &CliFactory,
|
||||
cli_options: &CliOptions,
|
||||
npm_fetch_resolver: Arc<NpmFetchResolver>,
|
||||
jsr_fetch_resolver: Arc<JsrFetchResolver>,
|
||||
) -> Result<DepManagerArgs, AnyError> {
|
||||
Ok(DepManagerArgs {
|
||||
module_load_preparer: factory.module_load_preparer().await?.clone(),
|
||||
jsr_fetch_resolver,
|
||||
npm_fetch_resolver,
|
||||
npm_resolver: factory.npm_resolver().await?.clone(),
|
||||
permissions_container: factory.root_permissions_container()?.clone(),
|
||||
main_module_graph_container: factory
|
||||
.main_module_graph_container()
|
||||
.await?
|
||||
.clone(),
|
||||
lockfile: cli_options.maybe_lockfile().cloned(),
|
||||
})
|
||||
}
|
||||
|
||||
mod filter {
|
||||
use deno_core::anyhow::anyhow;
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_semver::VersionReq;
|
||||
|
||||
enum FilterKind {
|
||||
Exclude,
|
||||
Include,
|
||||
}
|
||||
pub struct Filter {
|
||||
kind: FilterKind,
|
||||
regex: regex::Regex,
|
||||
version_spec: Option<VersionReq>,
|
||||
}
|
||||
|
||||
fn pattern_to_regex(pattern: &str) -> Result<regex::Regex, AnyError> {
|
||||
let escaped = regex::escape(pattern);
|
||||
let unescaped_star = escaped.replace(r"\*", ".*");
|
||||
Ok(regex::Regex::new(&format!("^{}$", unescaped_star))?)
|
||||
}
|
||||
|
||||
impl Filter {
|
||||
pub fn version_spec(&self) -> Option<&VersionReq> {
|
||||
self.version_spec.as_ref()
|
||||
}
|
||||
pub fn from_str(input: &str) -> Result<Self, AnyError> {
|
||||
let (kind, first_idx) = if input.starts_with('!') {
|
||||
(FilterKind::Exclude, 1)
|
||||
} else {
|
||||
(FilterKind::Include, 0)
|
||||
};
|
||||
let s = &input[first_idx..];
|
||||
let (pattern, version_spec) =
|
||||
if let Some(scope_name) = s.strip_prefix('@') {
|
||||
if let Some(idx) = scope_name.find('@') {
|
||||
let (pattern, version_spec) = s.split_at(idx + 1);
|
||||
(
|
||||
pattern,
|
||||
Some(
|
||||
VersionReq::parse_from_specifier(
|
||||
version_spec.trim_start_matches('@'),
|
||||
)
|
||||
.with_context(|| format!("Invalid filter \"{input}\""))?,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
(s, None)
|
||||
}
|
||||
} else {
|
||||
let mut parts = s.split('@');
|
||||
let Some(pattern) = parts.next() else {
|
||||
return Err(anyhow!("Invalid filter \"{input}\""));
|
||||
};
|
||||
(
|
||||
pattern,
|
||||
parts
|
||||
.next()
|
||||
.map(VersionReq::parse_from_specifier)
|
||||
.transpose()
|
||||
.with_context(|| format!("Invalid filter \"{input}\""))?,
|
||||
)
|
||||
};
|
||||
|
||||
Ok(Filter {
|
||||
kind,
|
||||
regex: pattern_to_regex(pattern)
|
||||
.with_context(|| format!("Invalid filter \"{input}\""))?,
|
||||
version_spec,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn matches(&self, name: &str) -> bool {
|
||||
self.regex.is_match(name)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FilterSet {
|
||||
filters: Vec<Filter>,
|
||||
has_exclude: bool,
|
||||
has_include: bool,
|
||||
}
|
||||
impl FilterSet {
|
||||
pub fn from_filter_strings<'a>(
|
||||
filter_strings: impl IntoIterator<Item = &'a str>,
|
||||
) -> Result<Self, AnyError> {
|
||||
let filters = filter_strings
|
||||
.into_iter()
|
||||
.map(Filter::from_str)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let has_exclude = filters
|
||||
.iter()
|
||||
.any(|f| matches!(f.kind, FilterKind::Exclude));
|
||||
let has_include = filters
|
||||
.iter()
|
||||
.any(|f| matches!(f.kind, FilterKind::Include));
|
||||
Ok(FilterSet {
|
||||
filters,
|
||||
has_exclude,
|
||||
has_include,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.filters.is_empty()
|
||||
}
|
||||
|
||||
pub fn matches(&self, name: &str) -> bool {
|
||||
self.matching_filter(name).is_included()
|
||||
}
|
||||
|
||||
pub fn matching_filter(&self, name: &str) -> MatchResult<'_> {
|
||||
if self.filters.is_empty() {
|
||||
return MatchResult::Included;
|
||||
}
|
||||
let mut matched = None;
|
||||
for filter in &self.filters {
|
||||
match filter.kind {
|
||||
FilterKind::Include => {
|
||||
if matched.is_none() && filter.matches(name) {
|
||||
matched = Some(filter);
|
||||
}
|
||||
}
|
||||
FilterKind::Exclude => {
|
||||
if filter.matches(name) {
|
||||
return MatchResult::Excluded;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(filter) = matched {
|
||||
MatchResult::Matches(filter)
|
||||
} else if self.has_exclude && !self.has_include {
|
||||
MatchResult::Included
|
||||
} else {
|
||||
MatchResult::Excluded
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum MatchResult<'a> {
|
||||
Matches(&'a Filter),
|
||||
Included,
|
||||
Excluded,
|
||||
}
|
||||
|
||||
impl MatchResult<'_> {
|
||||
pub fn version_spec(&self) -> Option<&VersionReq> {
|
||||
match self {
|
||||
MatchResult::Matches(filter) => filter.version_spec(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn is_included(&self) -> bool {
|
||||
matches!(self, MatchResult::Included | MatchResult::Matches(_))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
fn matches_filters<'a, 'b>(
|
||||
filters: impl IntoIterator<Item = &'a str>,
|
||||
name: &str,
|
||||
) -> bool {
|
||||
let filters = super::FilterSet::from_filter_strings(filters).unwrap();
|
||||
filters.matches(name)
|
||||
}
|
||||
|
||||
fn version_spec(s: &str) -> deno_semver::VersionReq {
|
||||
deno_semver::VersionReq::parse_from_specifier(s).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_glob() {
|
||||
assert!(matches_filters(["foo*"], "foo"));
|
||||
assert!(matches_filters(["foo*"], "foobar"));
|
||||
assert!(!matches_filters(["foo*"], "barfoo"));
|
||||
|
||||
assert!(matches_filters(["*foo"], "foo"));
|
||||
assert!(matches_filters(["*foo"], "barfoo"));
|
||||
assert!(!matches_filters(["*foo"], "foobar"));
|
||||
|
||||
assert!(matches_filters(["@scope/foo*"], "@scope/foobar"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_glob_with_version() {
|
||||
assert!(matches_filters(["foo*@1"], "foo",));
|
||||
assert!(matches_filters(["foo*@1"], "foobar",));
|
||||
assert!(matches_filters(["foo*@1"], "foo-bar",));
|
||||
assert!(!matches_filters(["foo*@1"], "barfoo",));
|
||||
assert!(matches_filters(["@scope/*@1"], "@scope/foo"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn glob_exclude() {
|
||||
assert!(!matches_filters(["!foo*"], "foo"));
|
||||
assert!(!matches_filters(["!foo*"], "foobar"));
|
||||
assert!(matches_filters(["!foo*"], "barfoo"));
|
||||
|
||||
assert!(!matches_filters(["!*foo"], "foo"));
|
||||
assert!(!matches_filters(["!*foo"], "barfoo"));
|
||||
assert!(matches_filters(["!*foo"], "foobar"));
|
||||
|
||||
assert!(!matches_filters(["!@scope/foo*"], "@scope/foobar"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_globs() {
|
||||
assert!(matches_filters(["foo*", "bar*"], "foo"));
|
||||
assert!(matches_filters(["foo*", "bar*"], "bar"));
|
||||
assert!(!matches_filters(["foo*", "bar*"], "baz"));
|
||||
|
||||
assert!(matches_filters(["foo*", "!bar*"], "foo"));
|
||||
assert!(!matches_filters(["foo*", "!bar*"], "bar"));
|
||||
assert!(matches_filters(["foo*", "!bar*"], "foobar"));
|
||||
assert!(!matches_filters(["foo*", "!*bar"], "foobar"));
|
||||
assert!(!matches_filters(["foo*", "!*bar"], "baz"));
|
||||
|
||||
let filters =
|
||||
super::FilterSet::from_filter_strings(["foo*@1", "bar*@2"]).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
filters.matching_filter("foo").version_spec().cloned(),
|
||||
Some(version_spec("1"))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
filters.matching_filter("bar").version_spec().cloned(),
|
||||
Some(version_spec("2"))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ use std::path::PathBuf;
|
|||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_config::workspace::FolderConfigs;
|
||||
use deno_config::workspace::TaskDefinition;
|
||||
use deno_config::workspace::TaskOrScript;
|
||||
use deno_config::workspace::WorkspaceDirectory;
|
||||
|
@ -25,6 +26,7 @@ use deno_path_util::normalize_path;
|
|||
use deno_runtime::deno_node::NodeResolver;
|
||||
use deno_task_shell::ShellCommand;
|
||||
use indexmap::IndexMap;
|
||||
use regex::Regex;
|
||||
|
||||
use crate::args::CliOptions;
|
||||
use crate::args::Flags;
|
||||
|
@ -35,6 +37,12 @@ use crate::npm::CliNpmResolver;
|
|||
use crate::task_runner;
|
||||
use crate::util::fs::canonicalize_path;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct PackageTaskInfo {
|
||||
matched_tasks: Vec<String>,
|
||||
tasks_config: WorkspaceTasksConfig,
|
||||
}
|
||||
|
||||
pub async fn execute_script(
|
||||
flags: Arc<Flags>,
|
||||
task_flags: TaskFlags,
|
||||
|
@ -55,7 +63,128 @@ pub async fn execute_script(
|
|||
v == "1"
|
||||
})
|
||||
.unwrap_or(false);
|
||||
|
||||
fn arg_to_regex(input: &str) -> Result<regex::Regex, regex::Error> {
|
||||
let mut regex_str = regex::escape(input);
|
||||
regex_str = regex_str.replace("\\*", ".*");
|
||||
|
||||
Regex::new(®ex_str)
|
||||
}
|
||||
|
||||
let packages_task_configs: Vec<PackageTaskInfo> = if let Some(filter) =
|
||||
&task_flags.filter
|
||||
{
|
||||
let task_name = task_flags.task.as_ref().unwrap();
|
||||
|
||||
// Filter based on package name
|
||||
let package_regex = arg_to_regex(filter)?;
|
||||
let task_regex = arg_to_regex(task_name)?;
|
||||
|
||||
let mut packages_task_info: Vec<PackageTaskInfo> = vec![];
|
||||
|
||||
fn matches_package(
|
||||
config: &FolderConfigs,
|
||||
force_use_pkg_json: bool,
|
||||
regex: &Regex,
|
||||
) -> bool {
|
||||
if !force_use_pkg_json {
|
||||
if let Some(deno_json) = &config.deno_json {
|
||||
if let Some(name) = &deno_json.json.name {
|
||||
if regex.is_match(name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(package_json) = &config.pkg_json {
|
||||
if let Some(name) = &package_json.name {
|
||||
if regex.is_match(name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
let workspace = cli_options.workspace();
|
||||
for folder in workspace.config_folders() {
|
||||
if !matches_package(folder.1, force_use_pkg_json, &package_regex) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let member_dir = workspace.resolve_member_dir(folder.0);
|
||||
let mut tasks_config = member_dir.to_tasks_config()?;
|
||||
if force_use_pkg_json {
|
||||
tasks_config = tasks_config.with_only_pkg_json();
|
||||
}
|
||||
|
||||
// Any of the matched tasks could be a child task of another matched
|
||||
// one. Therefore we need to filter these out to ensure that every
|
||||
// task is only run once.
|
||||
let mut matched: HashSet<String> = HashSet::new();
|
||||
let mut visited: HashSet<String> = HashSet::new();
|
||||
|
||||
fn visit_task(
|
||||
tasks_config: &WorkspaceTasksConfig,
|
||||
visited: &mut HashSet<String>,
|
||||
name: &str,
|
||||
) {
|
||||
if visited.contains(name) {
|
||||
return;
|
||||
}
|
||||
|
||||
visited.insert(name.to_string());
|
||||
|
||||
if let Some((_, TaskOrScript::Task(_, task))) = &tasks_config.task(name)
|
||||
{
|
||||
for dep in &task.dependencies {
|
||||
visit_task(tasks_config, visited, dep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Match tasks in deno.json
|
||||
for name in tasks_config.task_names() {
|
||||
if task_regex.is_match(name) && !visited.contains(name) {
|
||||
matched.insert(name.to_string());
|
||||
visit_task(&tasks_config, &mut visited, name);
|
||||
}
|
||||
}
|
||||
|
||||
packages_task_info.push(PackageTaskInfo {
|
||||
matched_tasks: matched
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect::<Vec<_>>(),
|
||||
tasks_config,
|
||||
});
|
||||
}
|
||||
|
||||
// Logging every task definition would be too spammy. Pnpm only
|
||||
// logs a simple message too.
|
||||
if packages_task_info
|
||||
.iter()
|
||||
.all(|config| config.matched_tasks.is_empty())
|
||||
{
|
||||
log::warn!(
|
||||
"{}",
|
||||
colors::red(format!(
|
||||
"No matching task or script '{}' found in selected packages.",
|
||||
task_name
|
||||
))
|
||||
);
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
// FIXME: Sort packages topologically
|
||||
//
|
||||
|
||||
packages_task_info
|
||||
} else {
|
||||
let mut tasks_config = start_dir.to_tasks_config()?;
|
||||
|
||||
if force_use_pkg_json {
|
||||
tasks_config = tasks_config.with_only_pkg_json()
|
||||
}
|
||||
|
@ -69,6 +198,12 @@ pub async fn execute_script(
|
|||
return Ok(0);
|
||||
};
|
||||
|
||||
vec![PackageTaskInfo {
|
||||
tasks_config,
|
||||
matched_tasks: vec![task_name.to_string()],
|
||||
}]
|
||||
};
|
||||
|
||||
let npm_resolver = factory.npm_resolver().await?;
|
||||
let node_resolver = factory.node_resolver().await?;
|
||||
let env_vars = task_runner::real_env_vars();
|
||||
|
@ -81,7 +216,6 @@ pub async fn execute_script(
|
|||
.unwrap_or_else(|| NonZeroUsize::new(2).unwrap());
|
||||
|
||||
let task_runner = TaskRunner {
|
||||
tasks_config,
|
||||
task_flags: &task_flags,
|
||||
npm_resolver: npm_resolver.as_ref(),
|
||||
node_resolver: node_resolver.as_ref(),
|
||||
|
@ -94,7 +228,7 @@ pub async fn execute_script(
|
|||
return task_runner
|
||||
.run_deno_task(
|
||||
&Url::from_directory_path(cli_options.initial_cwd()).unwrap(),
|
||||
&"".to_string(),
|
||||
"",
|
||||
&TaskDefinition {
|
||||
command: task_flags.task.as_ref().unwrap().to_string(),
|
||||
dependencies: vec![],
|
||||
|
@ -103,7 +237,15 @@ pub async fn execute_script(
|
|||
)
|
||||
.await;
|
||||
}
|
||||
task_runner.run_task(task_name).await
|
||||
|
||||
for task_config in &packages_task_configs {
|
||||
let exit_code = task_runner.run_tasks(task_config).await?;
|
||||
if exit_code > 0 {
|
||||
return Ok(exit_code);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
struct RunSingleOptions<'a> {
|
||||
|
@ -114,7 +256,6 @@ struct RunSingleOptions<'a> {
|
|||
}
|
||||
|
||||
struct TaskRunner<'a> {
|
||||
tasks_config: WorkspaceTasksConfig,
|
||||
task_flags: &'a TaskFlags,
|
||||
npm_resolver: &'a dyn CliNpmResolver,
|
||||
node_resolver: &'a NodeResolver,
|
||||
|
@ -124,12 +265,16 @@ struct TaskRunner<'a> {
|
|||
}
|
||||
|
||||
impl<'a> TaskRunner<'a> {
|
||||
pub async fn run_task(
|
||||
pub async fn run_tasks(
|
||||
&self,
|
||||
task_name: &str,
|
||||
pkg_tasks_config: &PackageTaskInfo,
|
||||
) -> Result<i32, deno_core::anyhow::Error> {
|
||||
match sort_tasks_topo(task_name, &self.tasks_config) {
|
||||
Ok(sorted) => self.run_tasks_in_parallel(sorted).await,
|
||||
match sort_tasks_topo(pkg_tasks_config) {
|
||||
Ok(sorted) => {
|
||||
self
|
||||
.run_tasks_in_parallel(&pkg_tasks_config.tasks_config, sorted)
|
||||
.await
|
||||
}
|
||||
Err(err) => match err {
|
||||
TaskError::NotFound(name) => {
|
||||
if self.task_flags.is_run {
|
||||
|
@ -138,7 +283,7 @@ impl<'a> TaskRunner<'a> {
|
|||
|
||||
log::error!("Task not found: {}", name);
|
||||
if log::log_enabled!(log::Level::Error) {
|
||||
self.print_available_tasks()?;
|
||||
self.print_available_tasks(&pkg_tasks_config.tasks_config)?;
|
||||
}
|
||||
Ok(1)
|
||||
}
|
||||
|
@ -150,16 +295,20 @@ impl<'a> TaskRunner<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn print_available_tasks(&self) -> Result<(), std::io::Error> {
|
||||
pub fn print_available_tasks(
|
||||
&self,
|
||||
tasks_config: &WorkspaceTasksConfig,
|
||||
) -> Result<(), std::io::Error> {
|
||||
print_available_tasks(
|
||||
&mut std::io::stderr(),
|
||||
&self.cli_options.start_dir,
|
||||
&self.tasks_config,
|
||||
tasks_config,
|
||||
)
|
||||
}
|
||||
|
||||
async fn run_tasks_in_parallel(
|
||||
&self,
|
||||
tasks_config: &WorkspaceTasksConfig,
|
||||
task_names: Vec<String>,
|
||||
) -> Result<i32, deno_core::anyhow::Error> {
|
||||
struct PendingTasksContext {
|
||||
|
@ -181,22 +330,23 @@ impl<'a> TaskRunner<'a> {
|
|||
fn get_next_task<'a>(
|
||||
&mut self,
|
||||
runner: &'a TaskRunner<'a>,
|
||||
tasks_config: &'a WorkspaceTasksConfig,
|
||||
) -> Option<LocalBoxFuture<'a, Result<(i32, String), AnyError>>> {
|
||||
for name in &self.task_names {
|
||||
if self.completed.contains(name) || self.running.contains(name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let should_run = if let Ok((_, def)) = runner.get_task(name) {
|
||||
match def {
|
||||
let Some((folder_url, task_or_script)) = tasks_config.task(name)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let should_run = match task_or_script {
|
||||
TaskOrScript::Task(_, def) => def
|
||||
.dependencies
|
||||
.iter()
|
||||
.all(|dep| self.completed.contains(dep)),
|
||||
TaskOrScript::Script(_, _) => true,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if !should_run {
|
||||
|
@ -207,9 +357,14 @@ impl<'a> TaskRunner<'a> {
|
|||
let name = name.clone();
|
||||
return Some(
|
||||
async move {
|
||||
runner
|
||||
.run_task_no_dependencies(&name)
|
||||
.await
|
||||
match task_or_script {
|
||||
TaskOrScript::Task(_, def) => {
|
||||
runner.run_deno_task(folder_url, &name, def).await
|
||||
}
|
||||
TaskOrScript::Script(scripts, _) => {
|
||||
runner.run_npm_script(folder_url, &name, scripts).await
|
||||
}
|
||||
}
|
||||
.map(|exit_code| (exit_code, name))
|
||||
}
|
||||
.boxed_local(),
|
||||
|
@ -229,7 +384,7 @@ impl<'a> TaskRunner<'a> {
|
|||
|
||||
while context.has_remaining_tasks() {
|
||||
while queue.len() < self.concurrency {
|
||||
if let Some(task) = context.get_next_task(self) {
|
||||
if let Some(task) = context.get_next_task(self, tasks_config) {
|
||||
queue.push(task);
|
||||
} else {
|
||||
break;
|
||||
|
@ -253,37 +408,10 @@ impl<'a> TaskRunner<'a> {
|
|||
Ok(0)
|
||||
}
|
||||
|
||||
fn get_task(
|
||||
&self,
|
||||
task_name: &str,
|
||||
) -> Result<(&Url, TaskOrScript), TaskError> {
|
||||
let Some(result) = self.tasks_config.task(task_name) else {
|
||||
return Err(TaskError::NotFound(task_name.to_string()));
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
async fn run_task_no_dependencies(
|
||||
&self,
|
||||
task_name: &String,
|
||||
) -> Result<i32, deno_core::anyhow::Error> {
|
||||
let (dir_url, task_or_script) = self.get_task(task_name.as_str()).unwrap();
|
||||
|
||||
match task_or_script {
|
||||
TaskOrScript::Task(_tasks, definition) => {
|
||||
self.run_deno_task(dir_url, task_name, definition).await
|
||||
}
|
||||
TaskOrScript::Script(scripts, _script) => {
|
||||
self.run_npm_script(dir_url, task_name, scripts).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn run_deno_task(
|
||||
pub async fn run_deno_task(
|
||||
&self,
|
||||
dir_url: &Url,
|
||||
task_name: &String,
|
||||
task_name: &str,
|
||||
definition: &TaskDefinition,
|
||||
) -> Result<i32, deno_core::anyhow::Error> {
|
||||
let cwd = match &self.task_flags.cwd {
|
||||
|
@ -306,10 +434,10 @@ impl<'a> TaskRunner<'a> {
|
|||
.await
|
||||
}
|
||||
|
||||
async fn run_npm_script(
|
||||
pub async fn run_npm_script(
|
||||
&self,
|
||||
dir_url: &Url,
|
||||
task_name: &String,
|
||||
task_name: &str,
|
||||
scripts: &IndexMap<String, String>,
|
||||
) -> Result<i32, deno_core::anyhow::Error> {
|
||||
// ensure the npm packages are installed if using a managed resolver
|
||||
|
@ -327,7 +455,7 @@ impl<'a> TaskRunner<'a> {
|
|||
// dealing with package.json here and not deno.json
|
||||
let task_names = vec![
|
||||
format!("pre{}", task_name),
|
||||
task_name.clone(),
|
||||
task_name.to_string(),
|
||||
format!("post{}", task_name),
|
||||
];
|
||||
let custom_commands = task_runner::resolve_custom_commands(
|
||||
|
@ -394,8 +522,7 @@ enum TaskError {
|
|||
}
|
||||
|
||||
fn sort_tasks_topo(
|
||||
name: &str,
|
||||
task_config: &WorkspaceTasksConfig,
|
||||
pkg_task_config: &PackageTaskInfo,
|
||||
) -> Result<Vec<String>, TaskError> {
|
||||
fn sort_visit<'a>(
|
||||
name: &'a str,
|
||||
|
@ -416,12 +543,12 @@ fn sort_tasks_topo(
|
|||
});
|
||||
}
|
||||
|
||||
let Some(def) = tasks_config.task(name) else {
|
||||
let Some((_, task_or_script)) = tasks_config.task(name) else {
|
||||
return Err(TaskError::NotFound(name.to_string()));
|
||||
};
|
||||
|
||||
if let TaskOrScript::Task(_, actual_def) = def.1 {
|
||||
for dep in &actual_def.dependencies {
|
||||
if let TaskOrScript::Task(_, task) = task_or_script {
|
||||
for dep in &task.dependencies {
|
||||
let mut path = path.clone();
|
||||
path.push(name);
|
||||
sort_visit(dep, sorted, path, tasks_config)?
|
||||
|
@ -435,7 +562,9 @@ fn sort_tasks_topo(
|
|||
|
||||
let mut sorted: Vec<String> = vec![];
|
||||
|
||||
sort_visit(name, &mut sorted, Vec::new(), task_config)?;
|
||||
for name in &pkg_task_config.matched_tasks {
|
||||
sort_visit(name, &mut sorted, Vec::new(), &pkg_task_config.tasks_config)?;
|
||||
}
|
||||
|
||||
Ok(sorted)
|
||||
}
|
||||
|
|
58
cli/tsc/dts/lib.deno.shared_globals.d.ts
vendored
58
cli/tsc/dts/lib.deno.shared_globals.d.ts
vendored
|
@ -15,14 +15,14 @@
|
|||
/// <reference lib="deno.crypto" />
|
||||
/// <reference lib="deno.ns" />
|
||||
|
||||
/** @category WASM */
|
||||
/** @category Wasm */
|
||||
declare namespace WebAssembly {
|
||||
/**
|
||||
* The `WebAssembly.CompileError` object indicates an error during WebAssembly decoding or validation.
|
||||
*
|
||||
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/CompileError)
|
||||
*
|
||||
* @category WASM
|
||||
* @category Wasm
|
||||
*/
|
||||
export class CompileError extends Error {
|
||||
/** Creates a new `WebAssembly.CompileError` object. */
|
||||
|
@ -36,7 +36,7 @@ declare namespace WebAssembly {
|
|||
*
|
||||
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Global)
|
||||
*
|
||||
* @category WASM
|
||||
* @category Wasm
|
||||
*/
|
||||
export class Global {
|
||||
/** Creates a new `Global` object. */
|
||||
|
@ -59,7 +59,7 @@ declare namespace WebAssembly {
|
|||
*
|
||||
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Instance)
|
||||
*
|
||||
* @category WASM
|
||||
* @category Wasm
|
||||
*/
|
||||
export class Instance {
|
||||
/** Creates a new Instance object. */
|
||||
|
@ -79,7 +79,7 @@ declare namespace WebAssembly {
|
|||
*
|
||||
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/LinkError)
|
||||
*
|
||||
* @category WASM
|
||||
* @category Wasm
|
||||
*/
|
||||
export class LinkError extends Error {
|
||||
/** Creates a new WebAssembly.LinkError object. */
|
||||
|
@ -95,7 +95,7 @@ declare namespace WebAssembly {
|
|||
*
|
||||
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory)
|
||||
*
|
||||
* @category WASM
|
||||
* @category Wasm
|
||||
*/
|
||||
export class Memory {
|
||||
/** Creates a new `Memory` object. */
|
||||
|
@ -117,7 +117,7 @@ declare namespace WebAssembly {
|
|||
*
|
||||
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module)
|
||||
*
|
||||
* @category WASM
|
||||
* @category Wasm
|
||||
*/
|
||||
export class Module {
|
||||
/** Creates a new `Module` object. */
|
||||
|
@ -145,7 +145,7 @@ declare namespace WebAssembly {
|
|||
*
|
||||
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/RuntimeError)
|
||||
*
|
||||
* @category WASM
|
||||
* @category Wasm
|
||||
*/
|
||||
export class RuntimeError extends Error {
|
||||
/** Creates a new `WebAssembly.RuntimeError` object. */
|
||||
|
@ -160,7 +160,7 @@ declare namespace WebAssembly {
|
|||
*
|
||||
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table)
|
||||
*
|
||||
* @category WASM
|
||||
* @category Wasm
|
||||
*/
|
||||
export class Table {
|
||||
/** Creates a new `Table` object. */
|
||||
|
@ -182,7 +182,7 @@ declare namespace WebAssembly {
|
|||
/** The `GlobalDescriptor` describes the options you can pass to
|
||||
* `new WebAssembly.Global()`.
|
||||
*
|
||||
* @category WASM
|
||||
* @category Wasm
|
||||
*/
|
||||
export interface GlobalDescriptor {
|
||||
mutable?: boolean;
|
||||
|
@ -192,7 +192,7 @@ declare namespace WebAssembly {
|
|||
/** The `MemoryDescriptor` describes the options you can pass to
|
||||
* `new WebAssembly.Memory()`.
|
||||
*
|
||||
* @category WASM
|
||||
* @category Wasm
|
||||
*/
|
||||
export interface MemoryDescriptor {
|
||||
initial: number;
|
||||
|
@ -203,7 +203,7 @@ declare namespace WebAssembly {
|
|||
/** A `ModuleExportDescriptor` is the description of a declared export in a
|
||||
* `WebAssembly.Module`.
|
||||
*
|
||||
* @category WASM
|
||||
* @category Wasm
|
||||
*/
|
||||
export interface ModuleExportDescriptor {
|
||||
kind: ImportExportKind;
|
||||
|
@ -213,7 +213,7 @@ declare namespace WebAssembly {
|
|||
/** A `ModuleImportDescriptor` is the description of a declared import in a
|
||||
* `WebAssembly.Module`.
|
||||
*
|
||||
* @category WASM
|
||||
* @category Wasm
|
||||
*/
|
||||
export interface ModuleImportDescriptor {
|
||||
kind: ImportExportKind;
|
||||
|
@ -224,7 +224,7 @@ declare namespace WebAssembly {
|
|||
/** The `TableDescriptor` describes the options you can pass to
|
||||
* `new WebAssembly.Table()`.
|
||||
*
|
||||
* @category WASM
|
||||
* @category Wasm
|
||||
*/
|
||||
export interface TableDescriptor {
|
||||
element: TableKind;
|
||||
|
@ -234,7 +234,7 @@ declare namespace WebAssembly {
|
|||
|
||||
/** The value returned from `WebAssembly.instantiate`.
|
||||
*
|
||||
* @category WASM
|
||||
* @category Wasm
|
||||
*/
|
||||
export interface WebAssemblyInstantiatedSource {
|
||||
/* A `WebAssembly.Instance` object that contains all the exported WebAssembly functions. */
|
||||
|
@ -247,21 +247,21 @@ declare namespace WebAssembly {
|
|||
module: Module;
|
||||
}
|
||||
|
||||
/** @category WASM */
|
||||
/** @category Wasm */
|
||||
export type ImportExportKind = "function" | "global" | "memory" | "table";
|
||||
/** @category WASM */
|
||||
/** @category Wasm */
|
||||
export type TableKind = "anyfunc";
|
||||
/** @category WASM */
|
||||
/** @category Wasm */
|
||||
export type ValueType = "f32" | "f64" | "i32" | "i64";
|
||||
/** @category WASM */
|
||||
/** @category Wasm */
|
||||
export type ExportValue = Function | Global | Memory | Table;
|
||||
/** @category WASM */
|
||||
/** @category Wasm */
|
||||
export type Exports = Record<string, ExportValue>;
|
||||
/** @category WASM */
|
||||
/** @category Wasm */
|
||||
export type ImportValue = ExportValue | number;
|
||||
/** @category WASM */
|
||||
/** @category Wasm */
|
||||
export type ModuleImports = Record<string, ImportValue>;
|
||||
/** @category WASM */
|
||||
/** @category Wasm */
|
||||
export type Imports = Record<string, ModuleImports>;
|
||||
|
||||
/**
|
||||
|
@ -272,7 +272,7 @@ declare namespace WebAssembly {
|
|||
*
|
||||
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/compile)
|
||||
*
|
||||
* @category WASM
|
||||
* @category Wasm
|
||||
*/
|
||||
export function compile(bytes: BufferSource): Promise<Module>;
|
||||
|
||||
|
@ -284,7 +284,7 @@ declare namespace WebAssembly {
|
|||
*
|
||||
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/compileStreaming)
|
||||
*
|
||||
* @category WASM
|
||||
* @category Wasm
|
||||
*/
|
||||
export function compileStreaming(
|
||||
source: Response | Promise<Response>,
|
||||
|
@ -301,7 +301,7 @@ declare namespace WebAssembly {
|
|||
*
|
||||
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiate)
|
||||
*
|
||||
* @category WASM
|
||||
* @category Wasm
|
||||
*/
|
||||
export function instantiate(
|
||||
bytes: BufferSource,
|
||||
|
@ -318,7 +318,7 @@ declare namespace WebAssembly {
|
|||
*
|
||||
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiate)
|
||||
*
|
||||
* @category WASM
|
||||
* @category Wasm
|
||||
*/
|
||||
export function instantiate(
|
||||
moduleObject: Module,
|
||||
|
@ -332,7 +332,7 @@ declare namespace WebAssembly {
|
|||
*
|
||||
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiateStreaming)
|
||||
*
|
||||
* @category WASM
|
||||
* @category Wasm
|
||||
*/
|
||||
export function instantiateStreaming(
|
||||
response: Response | PromiseLike<Response>,
|
||||
|
@ -346,7 +346,7 @@ declare namespace WebAssembly {
|
|||
*
|
||||
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/validate)
|
||||
*
|
||||
* @category WASM
|
||||
* @category Wasm
|
||||
*/
|
||||
export function validate(bytes: BufferSource): boolean;
|
||||
}
|
||||
|
|
|
@ -617,6 +617,8 @@ impl CliMainWorkerFactory {
|
|||
origin_storage_dir,
|
||||
stdio,
|
||||
skip_op_registration: shared.options.skip_op_registration,
|
||||
enable_stack_trace_arg_in_ops: crate::args::has_trace_permissions_enabled(
|
||||
),
|
||||
};
|
||||
|
||||
let mut worker = MainWorker::bootstrap_from_options(
|
||||
|
@ -813,6 +815,8 @@ fn create_web_worker_callback(
|
|||
strace_ops: shared.options.strace_ops.clone(),
|
||||
close_on_idle: args.close_on_idle,
|
||||
maybe_worker_metadata: args.maybe_worker_metadata,
|
||||
enable_stack_trace_arg_in_ops: crate::args::has_trace_permissions_enabled(
|
||||
),
|
||||
};
|
||||
|
||||
WebWorker::bootstrap_from_options(services, options)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_broadcast_channel"
|
||||
version = "0.171.0"
|
||||
version = "0.172.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
2
ext/cache/Cargo.toml
vendored
2
ext/cache/Cargo.toml
vendored
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_cache"
|
||||
version = "0.109.0"
|
||||
version = "0.110.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_canvas"
|
||||
version = "0.46.0"
|
||||
version = "0.47.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_console"
|
||||
version = "0.177.0"
|
||||
version = "0.178.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_cron"
|
||||
version = "0.57.0"
|
||||
version = "0.58.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_crypto"
|
||||
version = "0.191.0"
|
||||
version = "0.192.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_fetch"
|
||||
version = "0.201.0"
|
||||
version = "0.202.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -397,7 +397,7 @@ impl FetchPermissions for deno_permissions::PermissionsContainer {
|
|||
}
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn op_fetch<FP>(
|
||||
|
@ -866,7 +866,7 @@ fn default_true() -> bool {
|
|||
true
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[smi]
|
||||
pub fn op_fetch_custom_client<FP>(
|
||||
state: &mut OpState,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_ffi"
|
||||
version = "0.164.0"
|
||||
version = "0.165.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -287,7 +287,7 @@ fn ffi_call(
|
|||
}
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
#[serde]
|
||||
pub fn op_ffi_call_ptr_nonblocking<FP>(
|
||||
scope: &mut v8::HandleScope,
|
||||
|
@ -385,7 +385,7 @@ pub fn op_ffi_call_nonblocking(
|
|||
})
|
||||
}
|
||||
|
||||
#[op2(reentrant)]
|
||||
#[op2(reentrant, stack_trace)]
|
||||
#[serde]
|
||||
pub fn op_ffi_call_ptr<FP>(
|
||||
scope: &mut v8::HandleScope,
|
||||
|
|
|
@ -561,7 +561,7 @@ pub struct RegisterCallbackArgs {
|
|||
result: NativeType,
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
pub fn op_ffi_unsafe_callback_create<FP, 'scope>(
|
||||
state: &mut OpState,
|
||||
scope: &mut v8::HandleScope<'scope>,
|
||||
|
|
|
@ -124,7 +124,7 @@ pub struct FfiLoadArgs {
|
|||
symbols: HashMap<String, ForeignSymbol>,
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
pub fn op_ffi_load<'scope, FP>(
|
||||
scope: &mut v8::HandleScope<'scope>,
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
|
|
@ -49,7 +49,7 @@ pub enum ReprError {
|
|||
Permission(#[from] deno_permissions::PermissionCheckError),
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_ffi_ptr_create<FP>(
|
||||
state: &mut OpState,
|
||||
#[bigint] ptr_number: usize,
|
||||
|
@ -63,7 +63,7 @@ where
|
|||
Ok(ptr_number as *mut c_void)
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_ffi_ptr_equals<FP>(
|
||||
state: &mut OpState,
|
||||
a: *const c_void,
|
||||
|
@ -78,7 +78,7 @@ where
|
|||
Ok(a == b)
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
pub fn op_ffi_ptr_of<FP>(
|
||||
state: &mut OpState,
|
||||
#[anybuffer] buf: *const u8,
|
||||
|
@ -92,7 +92,7 @@ where
|
|||
Ok(buf as *mut c_void)
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_ffi_ptr_of_exact<FP>(
|
||||
state: &mut OpState,
|
||||
buf: v8::Local<v8::ArrayBufferView>,
|
||||
|
@ -112,7 +112,7 @@ where
|
|||
Ok(buf.as_ptr() as _)
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_ffi_ptr_offset<FP>(
|
||||
state: &mut OpState,
|
||||
ptr: *mut c_void,
|
||||
|
@ -142,7 +142,7 @@ unsafe extern "C" fn noop_deleter_callback(
|
|||
) {
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
#[bigint]
|
||||
pub fn op_ffi_ptr_value<FP>(
|
||||
state: &mut OpState,
|
||||
|
@ -157,7 +157,7 @@ where
|
|||
Ok(ptr as usize)
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
pub fn op_ffi_get_buf<FP, 'scope>(
|
||||
scope: &mut v8::HandleScope<'scope>,
|
||||
state: &mut OpState,
|
||||
|
@ -189,7 +189,7 @@ where
|
|||
Ok(array_buffer)
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
pub fn op_ffi_buf_copy_into<FP>(
|
||||
state: &mut OpState,
|
||||
src: *mut c_void,
|
||||
|
@ -219,7 +219,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
pub fn op_ffi_cstr_read<FP, 'scope>(
|
||||
scope: &mut v8::HandleScope<'scope>,
|
||||
state: &mut OpState,
|
||||
|
@ -244,7 +244,7 @@ where
|
|||
Ok(value)
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_ffi_read_bool<FP>(
|
||||
state: &mut OpState,
|
||||
ptr: *mut c_void,
|
||||
|
@ -264,7 +264,7 @@ where
|
|||
Ok(unsafe { ptr::read_unaligned::<bool>(ptr.offset(offset) as *const bool) })
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_ffi_read_u8<FP>(
|
||||
state: &mut OpState,
|
||||
ptr: *mut c_void,
|
||||
|
@ -286,7 +286,7 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_ffi_read_i8<FP>(
|
||||
state: &mut OpState,
|
||||
ptr: *mut c_void,
|
||||
|
@ -308,7 +308,7 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_ffi_read_u16<FP>(
|
||||
state: &mut OpState,
|
||||
ptr: *mut c_void,
|
||||
|
@ -330,7 +330,7 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_ffi_read_i16<FP>(
|
||||
state: &mut OpState,
|
||||
ptr: *mut c_void,
|
||||
|
@ -352,7 +352,7 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_ffi_read_u32<FP>(
|
||||
state: &mut OpState,
|
||||
ptr: *mut c_void,
|
||||
|
@ -372,7 +372,7 @@ where
|
|||
Ok(unsafe { ptr::read_unaligned::<u32>(ptr.offset(offset) as *const u32) })
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_ffi_read_i32<FP>(
|
||||
state: &mut OpState,
|
||||
ptr: *mut c_void,
|
||||
|
@ -392,7 +392,7 @@ where
|
|||
Ok(unsafe { ptr::read_unaligned::<i32>(ptr.offset(offset) as *const i32) })
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
#[bigint]
|
||||
pub fn op_ffi_read_u64<FP>(
|
||||
state: &mut OpState,
|
||||
|
@ -418,7 +418,7 @@ where
|
|||
Ok(value)
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
#[bigint]
|
||||
pub fn op_ffi_read_i64<FP>(
|
||||
state: &mut OpState,
|
||||
|
@ -444,7 +444,7 @@ where
|
|||
Ok(value)
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_ffi_read_f32<FP>(
|
||||
state: &mut OpState,
|
||||
ptr: *mut c_void,
|
||||
|
@ -464,7 +464,7 @@ where
|
|||
Ok(unsafe { ptr::read_unaligned::<f32>(ptr.offset(offset) as *const f32) })
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_ffi_read_f64<FP>(
|
||||
state: &mut OpState,
|
||||
ptr: *mut c_void,
|
||||
|
@ -484,7 +484,7 @@ where
|
|||
Ok(unsafe { ptr::read_unaligned::<f64>(ptr.offset(offset) as *const f64) })
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_ffi_read_ptr<FP>(
|
||||
state: &mut OpState,
|
||||
ptr: *mut c_void,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_fs"
|
||||
version = "0.87.0"
|
||||
version = "0.88.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -146,7 +146,7 @@ fn map_permission_error(
|
|||
}
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[string]
|
||||
pub fn op_fs_cwd<P>(state: &mut OpState) -> Result<String, FsOpsError>
|
||||
where
|
||||
|
@ -161,7 +161,7 @@ where
|
|||
Ok(path_str)
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_fs_chdir<P>(
|
||||
state: &mut OpState,
|
||||
#[string] directory: &str,
|
||||
|
@ -188,7 +188,7 @@ where
|
|||
state.borrow::<FileSystemRc>().umask(mask).context("umask")
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[smi]
|
||||
pub fn op_fs_open_sync<P>(
|
||||
state: &mut OpState,
|
||||
|
@ -215,7 +215,7 @@ where
|
|||
Ok(rid)
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
#[smi]
|
||||
pub async fn op_fs_open_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
@ -243,7 +243,7 @@ where
|
|||
Ok(rid)
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
pub fn op_fs_mkdir_sync<P>(
|
||||
state: &mut OpState,
|
||||
#[string] path: String,
|
||||
|
@ -266,7 +266,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
pub async fn op_fs_mkdir_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
#[string] path: String,
|
||||
|
@ -291,7 +291,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_fs_chmod_sync<P>(
|
||||
state: &mut OpState,
|
||||
#[string] path: String,
|
||||
|
@ -308,7 +308,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
pub async fn op_fs_chmod_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
#[string] path: String,
|
||||
|
@ -328,7 +328,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
pub fn op_fs_chown_sync<P>(
|
||||
state: &mut OpState,
|
||||
#[string] path: String,
|
||||
|
@ -347,7 +347,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
pub async fn op_fs_chown_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
#[string] path: String,
|
||||
|
@ -368,7 +368,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_fs_remove_sync<P>(
|
||||
state: &mut OpState,
|
||||
#[string] path: &str,
|
||||
|
@ -388,7 +388,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
pub async fn op_fs_remove_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
#[string] path: String,
|
||||
|
@ -419,7 +419,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_fs_copy_file_sync<P>(
|
||||
state: &mut OpState,
|
||||
#[string] from: &str,
|
||||
|
@ -439,7 +439,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
pub async fn op_fs_copy_file_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
#[string] from: String,
|
||||
|
@ -463,7 +463,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_fs_stat_sync<P>(
|
||||
state: &mut OpState,
|
||||
#[string] path: String,
|
||||
|
@ -482,7 +482,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
#[serde]
|
||||
pub async fn op_fs_stat_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
@ -504,7 +504,7 @@ where
|
|||
Ok(SerializableStat::from(stat))
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_fs_lstat_sync<P>(
|
||||
state: &mut OpState,
|
||||
#[string] path: String,
|
||||
|
@ -523,7 +523,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
#[serde]
|
||||
pub async fn op_fs_lstat_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
@ -545,7 +545,7 @@ where
|
|||
Ok(SerializableStat::from(stat))
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[string]
|
||||
pub fn op_fs_realpath_sync<P>(
|
||||
state: &mut OpState,
|
||||
|
@ -568,7 +568,7 @@ where
|
|||
Ok(path_string)
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
#[string]
|
||||
pub async fn op_fs_realpath_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
@ -596,7 +596,7 @@ where
|
|||
Ok(path_string)
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
pub fn op_fs_read_dir_sync<P>(
|
||||
state: &mut OpState,
|
||||
|
@ -615,7 +615,7 @@ where
|
|||
Ok(entries)
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
#[serde]
|
||||
pub async fn op_fs_read_dir_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
@ -640,7 +640,7 @@ where
|
|||
Ok(entries)
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_fs_rename_sync<P>(
|
||||
state: &mut OpState,
|
||||
#[string] oldpath: String,
|
||||
|
@ -661,7 +661,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
pub async fn op_fs_rename_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
#[string] oldpath: String,
|
||||
|
@ -686,7 +686,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_fs_link_sync<P>(
|
||||
state: &mut OpState,
|
||||
#[string] oldpath: &str,
|
||||
|
@ -708,7 +708,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
pub async fn op_fs_link_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
#[string] oldpath: String,
|
||||
|
@ -734,7 +734,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
pub fn op_fs_symlink_sync<P>(
|
||||
state: &mut OpState,
|
||||
#[string] oldpath: &str,
|
||||
|
@ -758,7 +758,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
pub async fn op_fs_symlink_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
#[string] oldpath: String,
|
||||
|
@ -786,7 +786,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[string]
|
||||
pub fn op_fs_read_link_sync<P>(
|
||||
state: &mut OpState,
|
||||
|
@ -806,7 +806,7 @@ where
|
|||
Ok(target_string)
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
#[string]
|
||||
pub async fn op_fs_read_link_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
@ -831,7 +831,7 @@ where
|
|||
Ok(target_string)
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_fs_truncate_sync<P>(
|
||||
state: &mut OpState,
|
||||
#[string] path: &str,
|
||||
|
@ -851,7 +851,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
pub async fn op_fs_truncate_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
#[string] path: String,
|
||||
|
@ -875,7 +875,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_fs_utime_sync<P>(
|
||||
state: &mut OpState,
|
||||
#[string] path: &str,
|
||||
|
@ -896,7 +896,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
pub async fn op_fs_utime_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
#[string] path: String,
|
||||
|
@ -927,7 +927,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[string]
|
||||
pub fn op_fs_make_temp_dir_sync<P>(
|
||||
state: &mut OpState,
|
||||
|
@ -969,7 +969,7 @@ where
|
|||
.context("tmpdir")
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
#[string]
|
||||
pub async fn op_fs_make_temp_dir_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
@ -1015,7 +1015,7 @@ where
|
|||
.context("tmpdir")
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[string]
|
||||
pub fn op_fs_make_temp_file_sync<P>(
|
||||
state: &mut OpState,
|
||||
|
@ -1063,7 +1063,7 @@ where
|
|||
.context("tmpfile")
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
#[string]
|
||||
pub async fn op_fs_make_temp_file_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
@ -1235,7 +1235,7 @@ fn tmp_name(
|
|||
Ok(path)
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
pub fn op_fs_write_file_sync<P>(
|
||||
state: &mut OpState,
|
||||
#[string] path: String,
|
||||
|
@ -1261,7 +1261,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn op_fs_write_file_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
@ -1315,7 +1315,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
pub fn op_fs_read_file_sync<P>(
|
||||
state: &mut OpState,
|
||||
|
@ -1336,7 +1336,7 @@ where
|
|||
Ok(buf.into())
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
#[serde]
|
||||
pub async fn op_fs_read_file_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
@ -1378,7 +1378,7 @@ where
|
|||
Ok(buf.into())
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[string]
|
||||
pub fn op_fs_read_file_text_sync<P>(
|
||||
state: &mut OpState,
|
||||
|
@ -1399,7 +1399,7 @@ where
|
|||
Ok(str)
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
#[string]
|
||||
pub async fn op_fs_read_file_text_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_http"
|
||||
version = "0.175.0"
|
||||
version = "0.176.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_io"
|
||||
version = "0.87.0"
|
||||
version = "0.88.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_kv"
|
||||
version = "0.85.0"
|
||||
version = "0.86.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -178,7 +178,7 @@ pub enum KvErrorKind {
|
|||
InvalidRange,
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
#[smi]
|
||||
async fn op_kv_database_open<DBH>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_napi"
|
||||
version = "0.108.0"
|
||||
version = "0.109.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -530,7 +530,7 @@ static NAPI_LOADED_MODULES: std::sync::LazyLock<
|
|||
RwLock<HashMap<PathBuf, NapiModuleHandle>>,
|
||||
> = std::sync::LazyLock::new(|| RwLock::new(HashMap::new()));
|
||||
|
||||
#[op2(reentrant)]
|
||||
#[op2(reentrant, stack_trace)]
|
||||
fn op_napi_open<NP, 'scope>(
|
||||
scope: &mut v8::HandleScope<'scope>,
|
||||
isolate: *mut v8::Isolate,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "napi_sym"
|
||||
version = "0.107.0"
|
||||
version = "0.108.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_net"
|
||||
version = "0.169.0"
|
||||
version = "0.170.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -182,7 +182,7 @@ pub async fn op_net_recv_udp(
|
|||
Ok((nread, IpAddr::from(remote_addr)))
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
#[number]
|
||||
pub async fn op_net_send_udp<NP>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
@ -343,7 +343,7 @@ pub async fn op_net_set_multi_ttl_udp(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
#[serde]
|
||||
pub async fn op_net_connect_tcp<NP>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
@ -401,7 +401,7 @@ impl Resource for UdpSocketResource {
|
|||
}
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
pub fn op_net_listen_tcp<NP>(
|
||||
state: &mut OpState,
|
||||
|
@ -501,7 +501,7 @@ where
|
|||
Ok((rid, IpAddr::from(local_addr)))
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
pub fn op_net_listen_udp<NP>(
|
||||
state: &mut OpState,
|
||||
|
@ -516,7 +516,7 @@ where
|
|||
net_listen_udp::<NP>(state, addr, reuse_address, loopback)
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
pub fn op_node_unstable_net_listen_udp<NP>(
|
||||
state: &mut OpState,
|
||||
|
@ -601,7 +601,7 @@ pub struct NameServer {
|
|||
port: u16,
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
#[serde]
|
||||
pub async fn op_dns_resolve<NP>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
|
|
@ -251,7 +251,7 @@ pub fn op_tls_cert_resolver_resolve_error(
|
|||
lookup.resolve(sni, Err(error))
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
pub fn op_tls_start<NP>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
@ -340,7 +340,7 @@ where
|
|||
Ok((rid, IpAddr::from(local_addr), IpAddr::from(remote_addr)))
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
#[serde]
|
||||
pub async fn op_net_connect_tls<NP>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
@ -445,7 +445,7 @@ pub struct ListenTlsArgs {
|
|||
load_balanced: bool,
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
pub fn op_net_listen_tls<NP>(
|
||||
state: &mut OpState,
|
||||
|
|
|
@ -85,7 +85,7 @@ pub async fn op_net_accept_unix(
|
|||
Ok((rid, local_addr_path, remote_addr_path))
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
#[serde]
|
||||
pub async fn op_net_connect_unix<NP>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
@ -118,7 +118,7 @@ where
|
|||
Ok((rid, local_addr_path, remote_addr_path))
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
#[serde]
|
||||
pub async fn op_net_recv_unixpacket(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
@ -140,7 +140,7 @@ pub async fn op_net_recv_unixpacket(
|
|||
Ok((nread, path))
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
#[number]
|
||||
pub async fn op_net_send_unixpacket<NP>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
@ -171,7 +171,7 @@ where
|
|||
Ok(nwritten)
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
pub fn op_net_listen_unix<NP>(
|
||||
state: &mut OpState,
|
||||
|
@ -222,7 +222,7 @@ where
|
|||
Ok((rid, pathname))
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
pub fn op_net_listen_unixpacket<NP>(
|
||||
state: &mut OpState,
|
||||
|
@ -235,7 +235,7 @@ where
|
|||
net_listen_unixpacket::<NP>(state, path)
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
pub fn op_node_unstable_net_listen_unixpacket<NP>(
|
||||
state: &mut OpState,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_node"
|
||||
version = "0.114.0"
|
||||
version = "0.115.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -26,7 +26,7 @@ pub enum FsError {
|
|||
Fs(#[from] deno_io::fs::FsError),
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_node_fs_exists_sync<P>(
|
||||
state: &mut OpState,
|
||||
#[string] path: String,
|
||||
|
@ -41,7 +41,7 @@ where
|
|||
Ok(fs.exists_sync(&path))
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
pub async fn op_node_fs_exists<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
#[string] path: String,
|
||||
|
@ -60,7 +60,7 @@ where
|
|||
Ok(fs.exists_async(path).await?)
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_node_cp_sync<P>(
|
||||
state: &mut OpState,
|
||||
#[string] path: &str,
|
||||
|
@ -81,7 +81,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
pub async fn op_node_cp<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
#[string] path: String,
|
||||
|
@ -117,7 +117,7 @@ pub struct StatFs {
|
|||
pub ffree: u64,
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
pub fn op_node_statfs<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
@ -258,7 +258,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_node_lutimes_sync<P>(
|
||||
state: &mut OpState,
|
||||
#[string] path: &str,
|
||||
|
@ -279,7 +279,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
pub async fn op_node_lutimes<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
#[string] path: String,
|
||||
|
@ -305,7 +305,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
pub fn op_node_lchown_sync<P>(
|
||||
state: &mut OpState,
|
||||
#[string] path: String,
|
||||
|
@ -323,7 +323,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
pub async fn op_node_lchown<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
#[string] path: String,
|
||||
|
|
|
@ -49,7 +49,7 @@ use std::cmp::min;
|
|||
use tokio::io::AsyncReadExt;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
pub fn op_node_http_request<P>(
|
||||
state: &mut OpState,
|
||||
|
|
|
@ -20,7 +20,7 @@ pub fn op_inspector_enabled() -> bool {
|
|||
false
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
pub fn op_inspector_open<P>(
|
||||
_state: &mut OpState,
|
||||
_port: Option<u16>,
|
||||
|
@ -85,7 +85,7 @@ struct JSInspectorSession {
|
|||
|
||||
impl GarbageCollected for JSInspectorSession {}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[cppgc]
|
||||
pub fn op_inspector_connect<'s, P>(
|
||||
isolate: *mut v8::Isolate,
|
||||
|
|
|
@ -21,7 +21,7 @@ pub enum OsError {
|
|||
FailedToGetUserInfo(#[source] std::io::Error),
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_node_os_get_priority<P>(
|
||||
state: &mut OpState,
|
||||
pid: u32,
|
||||
|
@ -37,7 +37,7 @@ where
|
|||
priority::get_priority(pid).map_err(OsError::Priority)
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_node_os_set_priority<P>(
|
||||
state: &mut OpState,
|
||||
pid: u32,
|
||||
|
@ -193,7 +193,7 @@ fn get_user_info(_uid: u32) -> Result<UserInfo, OsError> {
|
|||
})
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
pub fn op_node_os_user_info<P>(
|
||||
state: &mut OpState,
|
||||
|
@ -212,7 +212,7 @@ where
|
|||
get_user_info(uid)
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_geteuid<P>(
|
||||
state: &mut OpState,
|
||||
) -> Result<u32, deno_core::error::AnyError>
|
||||
|
@ -233,7 +233,7 @@ where
|
|||
Ok(euid)
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_getegid<P>(
|
||||
state: &mut OpState,
|
||||
) -> Result<u32, deno_core::error::AnyError>
|
||||
|
@ -254,7 +254,7 @@ where
|
|||
Ok(egid)
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
pub fn op_cpus<P>(state: &mut OpState) -> Result<Vec<cpus::CpuInfo>, OsError>
|
||||
where
|
||||
|
@ -268,7 +268,7 @@ where
|
|||
cpus::cpu_info().ok_or(OsError::FailedToGetCpuInfo)
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[string]
|
||||
pub fn op_homedir<P>(
|
||||
state: &mut OpState,
|
||||
|
|
|
@ -45,7 +45,7 @@ fn kill(pid: i32, _sig: i32) -> i32 {
|
|||
}
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_node_process_kill(
|
||||
state: &mut OpState,
|
||||
#[smi] pid: i32,
|
||||
|
|
|
@ -125,7 +125,7 @@ pub fn op_require_init_paths() -> Vec<String> {
|
|||
vec![]
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
pub fn op_require_node_module_paths<P>(
|
||||
state: &mut OpState,
|
||||
|
@ -295,7 +295,7 @@ pub fn op_require_path_is_absolute(#[string] p: String) -> bool {
|
|||
PathBuf::from(p).is_absolute()
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_require_stat<P>(
|
||||
state: &mut OpState,
|
||||
#[string] path: String,
|
||||
|
@ -317,7 +317,7 @@ where
|
|||
Ok(-1)
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[string]
|
||||
pub fn op_require_real_path<P>(
|
||||
state: &mut OpState,
|
||||
|
@ -381,7 +381,7 @@ pub fn op_require_path_basename(
|
|||
}
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[string]
|
||||
pub fn op_require_try_self_parent_path<P>(
|
||||
state: &mut OpState,
|
||||
|
@ -412,7 +412,7 @@ where
|
|||
Ok(None)
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[string]
|
||||
pub fn op_require_try_self<P>(
|
||||
state: &mut OpState,
|
||||
|
@ -476,7 +476,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[string]
|
||||
pub fn op_require_read_file<P>(
|
||||
state: &mut OpState,
|
||||
|
@ -507,7 +507,7 @@ pub fn op_require_as_file_path(#[string] file_or_url: String) -> String {
|
|||
file_or_url
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[string]
|
||||
pub fn op_require_resolve_exports<P>(
|
||||
state: &mut OpState,
|
||||
|
@ -583,7 +583,7 @@ pub fn op_require_is_maybe_cjs(
|
|||
loader.is_maybe_cjs(&url)
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
pub fn op_require_read_package_scope<P>(
|
||||
state: &mut OpState,
|
||||
|
@ -604,7 +604,7 @@ where
|
|||
.flatten()
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[string]
|
||||
pub fn op_require_package_imports_resolve<P>(
|
||||
state: &mut OpState,
|
||||
|
|
|
@ -45,7 +45,7 @@ pub enum WorkerThreadsFilenameError {
|
|||
}
|
||||
|
||||
// todo(dsherret): we should remove this and do all this work inside op_create_worker
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[string]
|
||||
pub fn op_worker_threads_filename<P>(
|
||||
state: &mut OpState,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_tls"
|
||||
version = "0.164.0"
|
||||
version = "0.165.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_url"
|
||||
version = "0.177.0"
|
||||
version = "0.178.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_web"
|
||||
version = "0.208.0"
|
||||
version = "0.209.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_webgpu"
|
||||
version = "0.144.0"
|
||||
version = "0.145.0"
|
||||
authors = ["the Deno authors"]
|
||||
edition.workspace = true
|
||||
license = "MIT"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_webidl"
|
||||
version = "0.177.0"
|
||||
version = "0.178.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_websocket"
|
||||
version = "0.182.0"
|
||||
version = "0.183.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -148,7 +148,7 @@ impl Resource for WsCancelResource {
|
|||
// This op is needed because creating a WS instance in JavaScript is a sync
|
||||
// operation and should throw error when permissions are not fulfilled,
|
||||
// but actual op that connects WS is async.
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[smi]
|
||||
pub fn op_ws_check_permission_and_cancel_handle<WP>(
|
||||
state: &mut OpState,
|
||||
|
@ -443,7 +443,7 @@ fn populate_common_request_headers(
|
|||
Ok(request)
|
||||
}
|
||||
|
||||
#[op2(async)]
|
||||
#[op2(async, stack_trace)]
|
||||
#[serde]
|
||||
pub async fn op_ws_create<WP>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_webstorage"
|
||||
version = "0.172.0"
|
||||
version = "0.173.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_resolver"
|
||||
version = "0.9.0"
|
||||
version = "0.10.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
@ -25,6 +25,7 @@ deno_package_json.features = ["sync"]
|
|||
deno_path_util.workspace = true
|
||||
deno_semver.workspace = true
|
||||
node_resolver.workspace = true
|
||||
node_resolver.features = ["sync"]
|
||||
thiserror.workspace = true
|
||||
url.workspace = true
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "node_resolver"
|
||||
version = "0.16.0"
|
||||
version = "0.17.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_runtime"
|
||||
version = "0.186.0"
|
||||
version = "0.187.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -162,7 +162,7 @@ fn start_watcher(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[smi]
|
||||
fn op_fs_events_open(
|
||||
state: &mut OpState,
|
||||
|
|
|
@ -87,7 +87,7 @@ pub enum OsError {
|
|||
Io(#[from] std::io::Error),
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[string]
|
||||
fn op_exec_path(state: &mut OpState) -> Result<String, OsError> {
|
||||
let current_exe = env::current_exe().unwrap();
|
||||
|
@ -103,7 +103,7 @@ fn op_exec_path(state: &mut OpState) -> Result<String, OsError> {
|
|||
.map_err(OsError::InvalidUtf8)
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
fn op_set_env(
|
||||
state: &mut OpState,
|
||||
#[string] key: &str,
|
||||
|
@ -123,7 +123,7 @@ fn op_set_env(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
fn op_env(
|
||||
state: &mut OpState,
|
||||
|
@ -132,7 +132,7 @@ fn op_env(
|
|||
Ok(env::vars().collect())
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[string]
|
||||
fn op_get_env(
|
||||
state: &mut OpState,
|
||||
|
@ -159,7 +159,7 @@ fn op_get_env(
|
|||
Ok(r)
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
fn op_delete_env(
|
||||
state: &mut OpState,
|
||||
#[string] key: String,
|
||||
|
@ -189,7 +189,7 @@ fn op_exit(state: &mut OpState) {
|
|||
crate::exit(code)
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
fn op_loadavg(
|
||||
state: &mut OpState,
|
||||
|
@ -200,7 +200,7 @@ fn op_loadavg(
|
|||
Ok(sys_info::loadavg())
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace, stack_trace)]
|
||||
#[string]
|
||||
fn op_hostname(
|
||||
state: &mut OpState,
|
||||
|
@ -211,7 +211,7 @@ fn op_hostname(
|
|||
Ok(sys_info::hostname())
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[string]
|
||||
fn op_os_release(
|
||||
state: &mut OpState,
|
||||
|
@ -222,7 +222,7 @@ fn op_os_release(
|
|||
Ok(sys_info::os_release())
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
fn op_network_interfaces(
|
||||
state: &mut OpState,
|
||||
|
@ -274,7 +274,7 @@ impl From<netif::Interface> for NetworkInterface {
|
|||
}
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
fn op_system_memory_info(
|
||||
state: &mut OpState,
|
||||
|
@ -286,7 +286,7 @@ fn op_system_memory_info(
|
|||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[smi]
|
||||
fn op_gid(
|
||||
state: &mut OpState,
|
||||
|
@ -302,7 +302,7 @@ fn op_gid(
|
|||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[smi]
|
||||
fn op_gid(
|
||||
state: &mut OpState,
|
||||
|
@ -314,7 +314,7 @@ fn op_gid(
|
|||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[smi]
|
||||
fn op_uid(
|
||||
state: &mut OpState,
|
||||
|
@ -330,7 +330,7 @@ fn op_uid(
|
|||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[smi]
|
||||
fn op_uid(
|
||||
state: &mut OpState,
|
||||
|
@ -519,7 +519,7 @@ fn os_uptime(state: &mut OpState) -> Result<u64, deno_core::error::AnyError> {
|
|||
Ok(sys_info::os_uptime())
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
#[number]
|
||||
fn op_os_uptime(
|
||||
state: &mut OpState,
|
||||
|
|
|
@ -99,7 +99,7 @@ pub fn op_revoke_permission(
|
|||
Ok(PermissionStatus::from(perm))
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
pub fn op_request_permission(
|
||||
state: &mut OpState,
|
||||
|
|
|
@ -802,7 +802,7 @@ fn get_requires_allow_all_env_vars(env: &RunEnv) -> Vec<&str> {
|
|||
found_envs
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
fn op_spawn_child(
|
||||
state: &mut OpState,
|
||||
|
@ -844,7 +844,7 @@ async fn op_spawn_wait(
|
|||
Ok(result)
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
fn op_spawn_sync(
|
||||
state: &mut OpState,
|
||||
|
@ -928,7 +928,7 @@ mod deprecated {
|
|||
stderr_rid: Option<ResourceId>,
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
pub fn op_run(
|
||||
state: &mut OpState,
|
||||
|
@ -1129,7 +1129,7 @@ mod deprecated {
|
|||
}
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
#[op2(fast, stack_trace)]
|
||||
pub fn op_kill(
|
||||
state: &mut OpState,
|
||||
#[smi] pid: i32,
|
||||
|
|
|
@ -133,7 +133,7 @@ pub enum CreateWorkerError {
|
|||
}
|
||||
|
||||
/// Create worker as the host
|
||||
#[op2]
|
||||
#[op2(stack_trace)]
|
||||
#[serde]
|
||||
fn op_create_worker(
|
||||
state: &mut OpState,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_permissions"
|
||||
version = "0.37.0"
|
||||
version = "0.38.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -294,7 +294,7 @@ impl UnitPermission {
|
|||
/// A normalized environment variable name. On Windows this will
|
||||
/// be uppercase and on other platforms it will stay as-is.
|
||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
||||
struct EnvVarName {
|
||||
pub struct EnvVarName {
|
||||
inner: String,
|
||||
}
|
||||
|
||||
|
@ -1114,15 +1114,37 @@ impl ImportDescriptor {
|
|||
pub struct EnvDescriptorParseError;
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
||||
pub struct EnvDescriptor(EnvVarName);
|
||||
pub enum EnvDescriptor {
|
||||
Name(EnvVarName),
|
||||
PrefixPattern(EnvVarName),
|
||||
}
|
||||
|
||||
impl EnvDescriptor {
|
||||
pub fn new(env: impl AsRef<str>) -> Self {
|
||||
Self(EnvVarName::new(env))
|
||||
if let Some(prefix_pattern) = env.as_ref().strip_suffix('*') {
|
||||
Self::PrefixPattern(EnvVarName::new(prefix_pattern))
|
||||
} else {
|
||||
Self::Name(EnvVarName::new(env))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl QueryDescriptor for EnvDescriptor {
|
||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
||||
enum EnvQueryDescriptorInner {
|
||||
Name(EnvVarName),
|
||||
PrefixPattern(EnvVarName),
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
||||
pub struct EnvQueryDescriptor(EnvQueryDescriptorInner);
|
||||
|
||||
impl EnvQueryDescriptor {
|
||||
pub fn new(env: impl AsRef<str>) -> Self {
|
||||
Self(EnvQueryDescriptorInner::Name(EnvVarName::new(env)))
|
||||
}
|
||||
}
|
||||
|
||||
impl QueryDescriptor for EnvQueryDescriptor {
|
||||
type AllowDesc = EnvDescriptor;
|
||||
type DenyDesc = EnvDescriptor;
|
||||
|
||||
|
@ -1131,19 +1153,45 @@ impl QueryDescriptor for EnvDescriptor {
|
|||
}
|
||||
|
||||
fn display_name(&self) -> Cow<str> {
|
||||
Cow::from(self.0.as_ref())
|
||||
Cow::from(match &self.0 {
|
||||
EnvQueryDescriptorInner::Name(env_var_name) => env_var_name.as_ref(),
|
||||
EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
|
||||
env_var_name.as_ref()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn from_allow(allow: &Self::AllowDesc) -> Self {
|
||||
allow.clone()
|
||||
match allow {
|
||||
Self::AllowDesc::Name(s) => {
|
||||
Self(EnvQueryDescriptorInner::Name(s.clone()))
|
||||
}
|
||||
Self::AllowDesc::PrefixPattern(s) => {
|
||||
Self(EnvQueryDescriptorInner::PrefixPattern(s.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn as_allow(&self) -> Option<Self::AllowDesc> {
|
||||
Some(self.clone())
|
||||
Some(match &self.0 {
|
||||
EnvQueryDescriptorInner::Name(env_var_name) => {
|
||||
Self::AllowDesc::Name(env_var_name.clone())
|
||||
}
|
||||
EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
|
||||
Self::AllowDesc::PrefixPattern(env_var_name.clone())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn as_deny(&self) -> Self::DenyDesc {
|
||||
self.clone()
|
||||
match &self.0 {
|
||||
EnvQueryDescriptorInner::Name(env_var_name) => {
|
||||
Self::DenyDesc::Name(env_var_name.clone())
|
||||
}
|
||||
EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
|
||||
Self::DenyDesc::PrefixPattern(env_var_name.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_in_permission(
|
||||
|
@ -1156,19 +1204,79 @@ impl QueryDescriptor for EnvDescriptor {
|
|||
}
|
||||
|
||||
fn matches_allow(&self, other: &Self::AllowDesc) -> bool {
|
||||
self == other
|
||||
match other {
|
||||
Self::AllowDesc::Name(n) => match &self.0 {
|
||||
EnvQueryDescriptorInner::Name(env_var_name) => n == env_var_name,
|
||||
EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
|
||||
env_var_name.as_ref().starts_with(n.as_ref())
|
||||
}
|
||||
},
|
||||
Self::AllowDesc::PrefixPattern(p) => match &self.0 {
|
||||
EnvQueryDescriptorInner::Name(env_var_name) => {
|
||||
env_var_name.as_ref().starts_with(p.as_ref())
|
||||
}
|
||||
EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
|
||||
env_var_name.as_ref().starts_with(p.as_ref())
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn matches_deny(&self, other: &Self::DenyDesc) -> bool {
|
||||
self == other
|
||||
match other {
|
||||
Self::AllowDesc::Name(n) => match &self.0 {
|
||||
EnvQueryDescriptorInner::Name(env_var_name) => n == env_var_name,
|
||||
EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
|
||||
env_var_name.as_ref().starts_with(n.as_ref())
|
||||
}
|
||||
},
|
||||
Self::AllowDesc::PrefixPattern(p) => match &self.0 {
|
||||
EnvQueryDescriptorInner::Name(env_var_name) => {
|
||||
env_var_name.as_ref().starts_with(p.as_ref())
|
||||
}
|
||||
EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
|
||||
p == env_var_name
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn revokes(&self, other: &Self::AllowDesc) -> bool {
|
||||
self == other
|
||||
match other {
|
||||
Self::AllowDesc::Name(n) => match &self.0 {
|
||||
EnvQueryDescriptorInner::Name(env_var_name) => n == env_var_name,
|
||||
EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
|
||||
env_var_name.as_ref().starts_with(n.as_ref())
|
||||
}
|
||||
},
|
||||
Self::AllowDesc::PrefixPattern(p) => match &self.0 {
|
||||
EnvQueryDescriptorInner::Name(env_var_name) => {
|
||||
env_var_name.as_ref().starts_with(p.as_ref())
|
||||
}
|
||||
EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
|
||||
p == env_var_name
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn stronger_than_deny(&self, other: &Self::DenyDesc) -> bool {
|
||||
self == other
|
||||
match other {
|
||||
Self::AllowDesc::Name(n) => match &self.0 {
|
||||
EnvQueryDescriptorInner::Name(env_var_name) => n == env_var_name,
|
||||
EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
|
||||
env_var_name.as_ref().starts_with(n.as_ref())
|
||||
}
|
||||
},
|
||||
Self::AllowDesc::PrefixPattern(p) => match &self.0 {
|
||||
EnvQueryDescriptorInner::Name(env_var_name) => {
|
||||
env_var_name.as_ref().starts_with(p.as_ref())
|
||||
}
|
||||
EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
|
||||
p == env_var_name
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn overlaps_deny(&self, _other: &Self::DenyDesc) -> bool {
|
||||
|
@ -1176,9 +1284,14 @@ impl QueryDescriptor for EnvDescriptor {
|
|||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for EnvDescriptor {
|
||||
impl AsRef<str> for EnvQueryDescriptor {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.0.as_ref()
|
||||
match &self.0 {
|
||||
EnvQueryDescriptorInner::Name(env_var_name) => env_var_name.as_ref(),
|
||||
EnvQueryDescriptorInner::PrefixPattern(env_var_name) => {
|
||||
env_var_name.as_ref()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1749,20 +1862,20 @@ impl UnaryPermission<ImportDescriptor> {
|
|||
}
|
||||
}
|
||||
|
||||
impl UnaryPermission<EnvDescriptor> {
|
||||
impl UnaryPermission<EnvQueryDescriptor> {
|
||||
pub fn query(&self, env: Option<&str>) -> PermissionState {
|
||||
self.query_desc(
|
||||
env.map(EnvDescriptor::new).as_ref(),
|
||||
env.map(EnvQueryDescriptor::new).as_ref(),
|
||||
AllowPartial::TreatAsPartialGranted,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn request(&mut self, env: Option<&str>) -> PermissionState {
|
||||
self.request_desc(env.map(EnvDescriptor::new).as_ref())
|
||||
self.request_desc(env.map(EnvQueryDescriptor::new).as_ref())
|
||||
}
|
||||
|
||||
pub fn revoke(&mut self, env: Option<&str>) -> PermissionState {
|
||||
self.revoke_desc(env.map(EnvDescriptor::new).as_ref())
|
||||
self.revoke_desc(env.map(EnvQueryDescriptor::new).as_ref())
|
||||
}
|
||||
|
||||
pub fn check(
|
||||
|
@ -1771,7 +1884,7 @@ impl UnaryPermission<EnvDescriptor> {
|
|||
api_name: Option<&str>,
|
||||
) -> Result<(), PermissionDeniedError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
self.check_desc(Some(&EnvDescriptor::new(env)), false, api_name)
|
||||
self.check_desc(Some(&EnvQueryDescriptor::new(env)), false, api_name)
|
||||
}
|
||||
|
||||
pub fn check_all(&mut self) -> Result<(), PermissionDeniedError> {
|
||||
|
@ -1905,7 +2018,7 @@ pub struct Permissions {
|
|||
pub read: UnaryPermission<ReadQueryDescriptor>,
|
||||
pub write: UnaryPermission<WriteQueryDescriptor>,
|
||||
pub net: UnaryPermission<NetDescriptor>,
|
||||
pub env: UnaryPermission<EnvDescriptor>,
|
||||
pub env: UnaryPermission<EnvQueryDescriptor>,
|
||||
pub sys: UnaryPermission<SysDescriptor>,
|
||||
pub run: UnaryPermission<RunQueryDescriptor>,
|
||||
pub ffi: UnaryPermission<FfiQueryDescriptor>,
|
||||
|
@ -4564,6 +4677,56 @@ mod tests {
|
|||
assert_eq!(perms.env.revoke(Some("HomE")), PermissionState::Prompt);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_env_wildcards() {
|
||||
set_prompter(Box::new(TestPrompter));
|
||||
let _prompt_value = PERMISSION_PROMPT_STUB_VALUE_SETTER.lock();
|
||||
let mut perms = Permissions::allow_all();
|
||||
perms.env = UnaryPermission {
|
||||
granted_global: false,
|
||||
..Permissions::new_unary(
|
||||
Some(HashSet::from([EnvDescriptor::new("HOME_*")])),
|
||||
None,
|
||||
false,
|
||||
)
|
||||
};
|
||||
assert_eq!(perms.env.query(Some("HOME")), PermissionState::Prompt);
|
||||
assert_eq!(perms.env.query(Some("HOME_")), PermissionState::Granted);
|
||||
assert_eq!(perms.env.query(Some("HOME_TEST")), PermissionState::Granted);
|
||||
|
||||
// assert no privilege escalation
|
||||
let parser = TestPermissionDescriptorParser;
|
||||
assert!(perms
|
||||
.env
|
||||
.create_child_permissions(
|
||||
ChildUnaryPermissionArg::GrantedList(vec!["HOME_SUB".to_string()]),
|
||||
|value| parser.parse_env_descriptor(value).map(Some),
|
||||
)
|
||||
.is_ok());
|
||||
assert!(perms
|
||||
.env
|
||||
.create_child_permissions(
|
||||
ChildUnaryPermissionArg::GrantedList(vec!["HOME*".to_string()]),
|
||||
|value| parser.parse_env_descriptor(value).map(Some),
|
||||
)
|
||||
.is_err());
|
||||
assert!(perms
|
||||
.env
|
||||
.create_child_permissions(
|
||||
ChildUnaryPermissionArg::GrantedList(vec!["OUTSIDE".to_string()]),
|
||||
|value| parser.parse_env_descriptor(value).map(Some),
|
||||
)
|
||||
.is_err());
|
||||
assert!(perms
|
||||
.env
|
||||
.create_child_permissions(
|
||||
// ok because this is a subset of HOME_*
|
||||
ChildUnaryPermissionArg::GrantedList(vec!["HOME_S*".to_string()]),
|
||||
|value| parser.parse_env_descriptor(value).map(Some),
|
||||
)
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check_partial_denied() {
|
||||
let parser = TestPermissionDescriptorParser;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use crate::is_standalone;
|
||||
use deno_core::error::JsStackFrame;
|
||||
use deno_core::parking_lot::Mutex;
|
||||
use deno_terminal::colors;
|
||||
use once_cell::sync::Lazy;
|
||||
|
@ -10,8 +12,6 @@ use std::io::StderrLock;
|
|||
use std::io::StdinLock;
|
||||
use std::io::Write as IoWrite;
|
||||
|
||||
use crate::is_standalone;
|
||||
|
||||
/// Helper function to make control characters visible so users can see the underlying filename.
|
||||
fn escape_control_characters(s: &str) -> std::borrow::Cow<str> {
|
||||
if !s.contains(|c: char| c.is_ascii_control() || c.is_control()) {
|
||||
|
@ -53,6 +53,13 @@ static MAYBE_BEFORE_PROMPT_CALLBACK: Lazy<Mutex<Option<PromptCallback>>> =
|
|||
static MAYBE_AFTER_PROMPT_CALLBACK: Lazy<Mutex<Option<PromptCallback>>> =
|
||||
Lazy::new(|| Mutex::new(None));
|
||||
|
||||
static MAYBE_CURRENT_STACKTRACE: Lazy<Mutex<Option<Vec<JsStackFrame>>>> =
|
||||
Lazy::new(|| Mutex::new(None));
|
||||
|
||||
pub fn set_current_stacktrace(trace: Vec<JsStackFrame>) {
|
||||
*MAYBE_CURRENT_STACKTRACE.lock() = Some(trace);
|
||||
}
|
||||
|
||||
pub fn permission_prompt(
|
||||
message: &str,
|
||||
flag: &str,
|
||||
|
@ -62,9 +69,10 @@ pub fn permission_prompt(
|
|||
if let Some(before_callback) = MAYBE_BEFORE_PROMPT_CALLBACK.lock().as_mut() {
|
||||
before_callback();
|
||||
}
|
||||
let stack = MAYBE_CURRENT_STACKTRACE.lock().take();
|
||||
let r = PERMISSION_PROMPTER
|
||||
.lock()
|
||||
.prompt(message, flag, api_name, is_unary);
|
||||
.prompt(message, flag, api_name, is_unary, stack);
|
||||
if let Some(after_callback) = MAYBE_AFTER_PROMPT_CALLBACK.lock().as_mut() {
|
||||
after_callback();
|
||||
}
|
||||
|
@ -92,6 +100,7 @@ pub trait PermissionPrompter: Send + Sync {
|
|||
name: &str,
|
||||
api_name: Option<&str>,
|
||||
is_unary: bool,
|
||||
stack: Option<Vec<JsStackFrame>>,
|
||||
) -> PromptResponse;
|
||||
}
|
||||
|
||||
|
@ -298,6 +307,7 @@ impl PermissionPrompter for TtyPrompter {
|
|||
name: &str,
|
||||
api_name: Option<&str>,
|
||||
is_unary: bool,
|
||||
stack: Option<Vec<JsStackFrame>>,
|
||||
) -> PromptResponse {
|
||||
if !std::io::stdin().is_terminal() || !std::io::stderr().is_terminal() {
|
||||
return PromptResponse::Deny;
|
||||
|
@ -340,7 +350,7 @@ impl PermissionPrompter for TtyPrompter {
|
|||
};
|
||||
|
||||
// output everything in one shot to make the tests more reliable
|
||||
{
|
||||
let stack_lines_count = {
|
||||
let mut output = String::new();
|
||||
write!(&mut output, "┏ {PERMISSION_EMOJI} ").unwrap();
|
||||
write!(&mut output, "{}", colors::bold("Deno requests ")).unwrap();
|
||||
|
@ -354,6 +364,27 @@ impl PermissionPrompter for TtyPrompter {
|
|||
)
|
||||
.unwrap();
|
||||
}
|
||||
let stack_lines_count = if let Some(stack) = stack {
|
||||
let len = stack.len();
|
||||
for (idx, frame) in stack.into_iter().enumerate() {
|
||||
writeln!(
|
||||
&mut output,
|
||||
"┃ {} {}",
|
||||
colors::gray(if idx != len - 1 { "├─" } else { "└─" }),
|
||||
colors::gray(deno_core::error::format_frame::<
|
||||
deno_core::error::NoAnsiColors,
|
||||
>(&frame))
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
len
|
||||
} else {
|
||||
writeln!(
|
||||
&mut output,
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.",
|
||||
).unwrap();
|
||||
1
|
||||
};
|
||||
let msg = format!(
|
||||
"Learn more at: {}",
|
||||
colors::cyan_with_underline(&format!(
|
||||
|
@ -372,7 +403,9 @@ impl PermissionPrompter for TtyPrompter {
|
|||
write!(&mut output, " {opts} > ").unwrap();
|
||||
|
||||
stderr_lock.write_all(output.as_bytes()).unwrap();
|
||||
}
|
||||
|
||||
stack_lines_count
|
||||
};
|
||||
|
||||
let value = loop {
|
||||
// Clear stdin each time we loop around in case the user accidentally pasted
|
||||
|
@ -391,30 +424,24 @@ impl PermissionPrompter for TtyPrompter {
|
|||
if result.is_err() || input.len() != 1 {
|
||||
break PromptResponse::Deny;
|
||||
};
|
||||
|
||||
let clear_n = if api_name.is_some() { 5 } else { 4 } + stack_lines_count;
|
||||
|
||||
match input.as_bytes()[0] as char {
|
||||
'y' | 'Y' => {
|
||||
clear_n_lines(
|
||||
&mut stderr_lock,
|
||||
if api_name.is_some() { 5 } else { 4 },
|
||||
);
|
||||
clear_n_lines(&mut stderr_lock, clear_n);
|
||||
let msg = format!("Granted {message}.");
|
||||
writeln!(stderr_lock, "✅ {}", colors::bold(&msg)).unwrap();
|
||||
break PromptResponse::Allow;
|
||||
}
|
||||
'n' | 'N' | '\x1b' => {
|
||||
clear_n_lines(
|
||||
&mut stderr_lock,
|
||||
if api_name.is_some() { 5 } else { 4 },
|
||||
);
|
||||
clear_n_lines(&mut stderr_lock, clear_n);
|
||||
let msg = format!("Denied {message}.");
|
||||
writeln!(stderr_lock, "❌ {}", colors::bold(&msg)).unwrap();
|
||||
break PromptResponse::Deny;
|
||||
}
|
||||
'A' if is_unary => {
|
||||
clear_n_lines(
|
||||
&mut stderr_lock,
|
||||
if api_name.is_some() { 5 } else { 4 },
|
||||
);
|
||||
clear_n_lines(&mut stderr_lock, clear_n);
|
||||
let msg = format!("Granted all {name} access.");
|
||||
writeln!(stderr_lock, "✅ {}", colors::bold(&msg)).unwrap();
|
||||
break PromptResponse::AllowAll;
|
||||
|
@ -475,6 +502,7 @@ pub mod tests {
|
|||
_name: &str,
|
||||
_api_name: Option<&str>,
|
||||
_is_unary: bool,
|
||||
_stack: Option<Vec<JsStackFrame>>,
|
||||
) -> PromptResponse {
|
||||
if STUB_PROMPT_VALUE.load(Ordering::SeqCst) {
|
||||
PromptResponse::Allow
|
||||
|
|
|
@ -373,6 +373,7 @@ pub struct WebWorkerOptions {
|
|||
pub strace_ops: Option<Vec<String>>,
|
||||
pub close_on_idle: bool,
|
||||
pub maybe_worker_metadata: Option<WorkerMetadata>,
|
||||
pub enable_stack_trace_arg_in_ops: bool,
|
||||
}
|
||||
|
||||
/// This struct is an implementation of `Worker` Web API
|
||||
|
@ -585,6 +586,13 @@ impl WebWorker {
|
|||
validate_import_attributes_callback,
|
||||
)),
|
||||
import_assertions_support: deno_core::ImportAssertionsSupport::Error,
|
||||
maybe_op_stack_trace_callback: if options.enable_stack_trace_arg_in_ops {
|
||||
Some(Box::new(|stack| {
|
||||
deno_permissions::prompter::set_current_stacktrace(stack)
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
|
|
|
@ -207,6 +207,7 @@ pub struct WorkerOptions {
|
|||
pub cache_storage_dir: Option<std::path::PathBuf>,
|
||||
pub origin_storage_dir: Option<std::path::PathBuf>,
|
||||
pub stdio: Stdio,
|
||||
pub enable_stack_trace_arg_in_ops: bool,
|
||||
}
|
||||
|
||||
impl Default for WorkerOptions {
|
||||
|
@ -231,6 +232,7 @@ impl Default for WorkerOptions {
|
|||
create_params: Default::default(),
|
||||
bootstrap: Default::default(),
|
||||
stdio: Default::default(),
|
||||
enable_stack_trace_arg_in_ops: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -544,6 +546,11 @@ impl MainWorker {
|
|||
) as Box<dyn Fn(_, _, &_)>,
|
||||
)
|
||||
}),
|
||||
maybe_op_stack_trace_callback: if options.enable_stack_trace_arg_in_ops {
|
||||
Some(Box::new(|stack| {
|
||||
deno_permissions::prompter::set_current_stacktrace(stack)
|
||||
}))
|
||||
} else { None },
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
|
|
|
@ -179,6 +179,7 @@ fn _090_run_permissions_request() {
|
|||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests run access to \"ls\".\r\n",
|
||||
"┠─ Requested by `Deno.permissions.request()` API.\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-run\r\n",
|
||||
"┠─ Run again with --allow-run to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all run permissions)",
|
||||
|
@ -189,6 +190,7 @@ fn _090_run_permissions_request() {
|
|||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests run access to \"cat\".\r\n",
|
||||
"┠─ Requested by `Deno.permissions.request()` API.\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-run\r\n",
|
||||
"┠─ Run again with --allow-run to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all run permissions)",
|
||||
|
@ -210,6 +212,7 @@ fn _090_run_permissions_request_sync() {
|
|||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests run access to \"ls\".\r\n",
|
||||
"┠─ Requested by `Deno.permissions.request()` API.\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-run\r\n",
|
||||
"┠─ Run again with --allow-run to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all run permissions)",
|
||||
|
@ -220,6 +223,7 @@ fn _090_run_permissions_request_sync() {
|
|||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests run access to \"cat\".\r\n",
|
||||
"┠─ Requested by `Deno.permissions.request()` API.\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-run\r\n",
|
||||
"┠─ Run again with --allow-run to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all run permissions)",
|
||||
|
@ -242,6 +246,7 @@ fn permissions_prompt_allow_all() {
|
|||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests run access to \"FOO\".\r\n",
|
||||
"┠─ Requested by `Deno.permissions.request()` API.\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-run\r\n",
|
||||
"┠─ Run again with --allow-run to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all run permissions)",
|
||||
|
@ -253,6 +258,7 @@ fn permissions_prompt_allow_all() {
|
|||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests read access to \"FOO\".\r\n",
|
||||
"┠─ Requested by `Deno.permissions.request()` API.\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-read\r\n",
|
||||
"┠─ Run again with --allow-read to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)",
|
||||
|
@ -264,6 +270,7 @@ fn permissions_prompt_allow_all() {
|
|||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests write access to \"FOO\".\r\n",
|
||||
"┠─ Requested by `Deno.permissions.request()` API.\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-write\r\n",
|
||||
"┠─ Run again with --allow-write to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all write permissions)",
|
||||
|
@ -275,6 +282,7 @@ fn permissions_prompt_allow_all() {
|
|||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests net access to \"foo\".\r\n",
|
||||
"┠─ Requested by `Deno.permissions.request()` API.\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-net\r\n",
|
||||
"┠─ Run again with --allow-net to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all net permissions)",
|
||||
|
@ -286,6 +294,7 @@ fn permissions_prompt_allow_all() {
|
|||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests env access to \"FOO\".\r\n",
|
||||
"┠─ Requested by `Deno.permissions.request()` API.\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-env\r\n",
|
||||
"┠─ Run again with --allow-env to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all env permissions)",
|
||||
|
@ -297,6 +306,7 @@ fn permissions_prompt_allow_all() {
|
|||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests sys access to \"loadavg\".\r\n",
|
||||
"┠─ Requested by `Deno.permissions.request()` API.\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-sys\r\n",
|
||||
"┠─ Run again with --allow-sys to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all sys permissions)",
|
||||
|
@ -308,6 +318,7 @@ fn permissions_prompt_allow_all() {
|
|||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests ffi access to \"FOO\".\r\n",
|
||||
"┠─ Requested by `Deno.permissions.request()` API.\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-ffi\r\n",
|
||||
"┠─ Run again with --allow-ffi to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all ffi permissions)",
|
||||
|
@ -328,6 +339,7 @@ fn permissions_prompt_allow_all_2() {
|
|||
// "env" permissions
|
||||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests env access to \"FOO\".\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-env\r\n",
|
||||
"┠─ Run again with --allow-env to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all env permissions)",
|
||||
|
@ -340,6 +352,7 @@ fn permissions_prompt_allow_all_2() {
|
|||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests sys access to \"loadavg\".\r\n",
|
||||
"┠─ Requested by `Deno.loadavg()` API.\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-sys\r\n",
|
||||
"┠─ Run again with --allow-sys to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all sys permissions)",
|
||||
|
@ -352,6 +365,7 @@ fn permissions_prompt_allow_all_2() {
|
|||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests read access to <CWD>.\r\n",
|
||||
"┠─ Requested by `Deno.cwd()` API.\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-read\r\n",
|
||||
"┠─ Run again with --allow-read to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)",
|
||||
|
@ -372,6 +386,7 @@ fn permissions_prompt_allow_all_lowercase_a() {
|
|||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests run access to \"FOO\".\r\n",
|
||||
"┠─ Requested by `Deno.permissions.request()` API.\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-run\r\n",
|
||||
"┠─ Run again with --allow-run to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all run permissions)",
|
||||
|
@ -406,6 +421,7 @@ fn permissions_cache() {
|
|||
"prompt\r\n",
|
||||
"┏ ⚠️ Deno requests read access to \"foo\".\r\n",
|
||||
"┠─ Requested by `Deno.permissions.request()` API.\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-read\r\n",
|
||||
"┠─ Run again with --allow-read to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)",
|
||||
|
@ -418,6 +434,32 @@ fn permissions_cache() {
|
|||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn permissions_trace() {
|
||||
TestContext::default()
|
||||
.new_command()
|
||||
.env("DENO_TRACE_PERMISSIONS", "1")
|
||||
.args_vec(["run", "--quiet", "run/permissions_trace.ts"])
|
||||
.with_pty(|mut console| {
|
||||
let text = console.read_until("Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all sys permissions)");
|
||||
test_util::assertions::assert_wildcard_match(&text, concat!(
|
||||
"┏ ⚠️ Deno requests sys access to \"hostname\".\r\n",
|
||||
"┠─ Requested by `Deno.hostname()` API.\r\n",
|
||||
"┃ ├─ Object.hostname (ext:runtime/30_os.js:43:10)\r\n",
|
||||
"┃ ├─ foo (file://[WILDCARD]/run/permissions_trace.ts:2:8)\r\n",
|
||||
"┃ ├─ bar (file://[WILDCARD]/run/permissions_trace.ts:6:3)\r\n",
|
||||
"┃ └─ file://[WILDCARD]/run/permissions_trace.ts:9:1\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-sys\r\n",
|
||||
"┠─ Run again with --allow-sys to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all sys permissions)",
|
||||
));
|
||||
|
||||
console.human_delay();
|
||||
console.write_line_raw("y");
|
||||
console.expect("✅ Granted sys access to \"hostname\".");
|
||||
});
|
||||
}
|
||||
|
||||
itest!(lock_write_fetch {
|
||||
args:
|
||||
"run --quiet --allow-import --allow-read --allow-write --allow-env --allow-run run/lock_write_fetch/main.ts",
|
||||
|
@ -1512,6 +1554,7 @@ mod permissions {
|
|||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests read access to \"foo\".\r\n",
|
||||
"┠─ Requested by `Deno.permissions.request()` API.\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-read\r\n",
|
||||
"┠─ Run again with --allow-read to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)",
|
||||
|
@ -1521,6 +1564,7 @@ mod permissions {
|
|||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests read access to \"bar\".\r\n",
|
||||
"┠─ Requested by `Deno.permissions.request()` API.\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-read\r\n",
|
||||
"┠─ Run again with --allow-read to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)",
|
||||
|
@ -1542,6 +1586,7 @@ mod permissions {
|
|||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests read access to \"foo\".\r\n",
|
||||
"┠─ Requested by `Deno.permissions.request()` API.\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-read\r\n",
|
||||
"┠─ Run again with --allow-read to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)",
|
||||
|
@ -1551,6 +1596,7 @@ mod permissions {
|
|||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests read access to \"bar\".\r\n",
|
||||
"┠─ Requested by `Deno.permissions.request()` API.\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-read\r\n",
|
||||
"┠─ Run again with --allow-read to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)",
|
||||
|
@ -1572,6 +1618,7 @@ mod permissions {
|
|||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests read access.\r\n",
|
||||
"┠─ Requested by `Deno.permissions.request()` API.\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-read\r\n",
|
||||
"┠─ Run again with --allow-read to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)",
|
||||
|
@ -1596,6 +1643,7 @@ mod permissions {
|
|||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests read access.\r\n",
|
||||
"┠─ Requested by `Deno.permissions.request()` API.\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-read\r\n",
|
||||
"┠─ Run again with --allow-read to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)",
|
||||
|
@ -1673,6 +1721,7 @@ fn issue9750() {
|
|||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests env access.\r\n",
|
||||
"┠─ Requested by `Deno.permissions.request()` API.\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-env\r\n",
|
||||
"┠─ Run again with --allow-env to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all env permissions)",
|
||||
|
@ -1682,6 +1731,7 @@ fn issue9750() {
|
|||
console.expect("Denied env access.");
|
||||
console.expect(concat!(
|
||||
"┏ ⚠️ Deno requests env access to \"SECRET\".\r\n",
|
||||
"┠─ To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable.\r\n",
|
||||
"┠─ Learn more at: https://docs.deno.com/go/--allow-env\r\n",
|
||||
"┠─ Run again with --allow-env to bypass this prompt.\r\n",
|
||||
"┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all env permissions)",
|
||||
|
@ -2723,7 +2773,7 @@ fn stdio_streams_are_locked_in_permission_prompt() {
|
|||
console.human_delay();
|
||||
console.write_line_raw("y");
|
||||
// We ensure that nothing gets written here between the permission prompt and this text, despire the delay
|
||||
console.expect_raw_next(format!("y{newline}\x1b[5A\x1b[0J✅ Granted read access to \""));
|
||||
console.expect_raw_next(format!("y{newline}\x1b[6A\x1b[0J✅ Granted read access to \""));
|
||||
|
||||
// Back to spamming!
|
||||
console.expect(malicious_output);
|
||||
|
|
4
tests/registry/jsr/@denotest/add/0.2.1/mod.ts
Normal file
4
tests/registry/jsr/@denotest/add/0.2.1/mod.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
// This is renamed to `add()` in 1.0.0.
|
||||
export function sum(a: number, b: number): number {
|
||||
return a + b;
|
||||
}
|
8
tests/registry/jsr/@denotest/add/0.2.1_meta.json
Normal file
8
tests/registry/jsr/@denotest/add/0.2.1_meta.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"exports": {
|
||||
".": "./mod.ts"
|
||||
},
|
||||
"moduleGraph1": {
|
||||
"/mod.ts": {}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
"yanked": true
|
||||
},
|
||||
"1.0.0": {},
|
||||
"0.2.0": {}
|
||||
"0.2.0": {},
|
||||
"0.2.1": {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from "jsr:@denotest/add@1";
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"a": 1
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export * from "jsr:@denotest/subtract@1";
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"exports": {
|
||||
"./add": "./add.ts",
|
||||
"./subtract": "./subtract.ts",
|
||||
"./data-json": "./data.json"
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export * from "jsr:@denotest/add@1";
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"a": 1
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export * from "jsr:@denotest/subtract@1";
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"exports": {
|
||||
"./add": "./add.ts",
|
||||
"./subtract": "./subtract.ts",
|
||||
"./data-json": "./data.json"
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
{
|
||||
"versions": {
|
||||
"1.0.0": {}
|
||||
"1.0.0": {},
|
||||
"0.5.0": {},
|
||||
"0.2.0": {}
|
||||
}
|
||||
}
|
||||
|
|
3
tests/registry/jsr/@denotest/subtract/0.2.0/mod.ts
Normal file
3
tests/registry/jsr/@denotest/subtract/0.2.0/mod.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export function sub(a: number, b: number): number {
|
||||
return a - b;
|
||||
}
|
8
tests/registry/jsr/@denotest/subtract/0.2.0_meta.json
Normal file
8
tests/registry/jsr/@denotest/subtract/0.2.0_meta.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"exports": {
|
||||
".": "./mod.ts"
|
||||
},
|
||||
"moduleGraph1": {
|
||||
"/mod.ts": {}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
{
|
||||
"latest": "1.0.0",
|
||||
"versions": {
|
||||
"1.0.0": {}
|
||||
"1.0.0": {},
|
||||
"0.2.0": {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"name": "@denotest/has-patch-versions",
|
||||
"version": "0.1.0"
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"name": "@denotest/has-patch-versions",
|
||||
"version": "0.1.1"
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "@denotest/has-patch-versions",
|
||||
"version": "0.2.0"
|
||||
}
|
6
tests/specs/init/npm/__test__.jsonc
Normal file
6
tests/specs/init/npm/__test__.jsonc
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"tempDir": true,
|
||||
"args": "init --npm vite my-project",
|
||||
"output": "init.out",
|
||||
"exitCode": 1
|
||||
}
|
1
tests/specs/init/npm/init.out
Normal file
1
tests/specs/init/npm/init.out
Normal file
|
@ -0,0 +1 @@
|
|||
You can initialize project manually by running deno run npm:create-vite my-project and applying desired permissions.
|
|
@ -61,5 +61,10 @@
|
|||
"file_path": "[WILDCARD]malformed.js",
|
||||
"message": "Expected '{', got 'B' at [WILDCARD]malformed.js:4:16\n\n export class A B C\n ~"
|
||||
}
|
||||
],
|
||||
"checked_files": [
|
||||
"[WILDCARD]file1.js",
|
||||
"[WILDCARD]file2.ts",
|
||||
"[WILDCARD]malformed.js"
|
||||
]
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue