1
0
Fork 0
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:
HasanAlrimawi 2024-11-21 10:05:51 +02:00 committed by GitHub
commit 7dcb5606b0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
204 changed files with 4630 additions and 453 deletions

View file

@ -5,7 +5,7 @@ import { stringify } from "jsr:@std/yaml@^0.221/stringify";
// Bump this number when you want to purge the cache. // Bump this number when you want to purge the cache.
// Note: the tools/release/01_bump_crate_versions.ts script will update this version // Note: the tools/release/01_bump_crate_versions.ts script will update this version
// automatically via regex, so ensure that this line maintains this format. // automatically via regex, so ensure that this line maintains this format.
const cacheVersion = 25; const cacheVersion = 26;
const ubuntuX86Runner = "ubuntu-24.04"; const ubuntuX86Runner = "ubuntu-24.04";
const ubuntuX86XlRunner = "ubuntu-24.04-xl"; const ubuntuX86XlRunner = "ubuntu-24.04-xl";

View file

@ -361,8 +361,8 @@ jobs:
path: |- path: |-
~/.cargo/registry/index ~/.cargo/registry/index
~/.cargo/registry/cache ~/.cargo/registry/cache
key: '25-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}' key: '26-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}'
restore-keys: '25-cargo-home-${{ matrix.os }}-${{ matrix.arch }}' restore-keys: '26-cargo-home-${{ matrix.os }}-${{ matrix.arch }}'
if: '!(matrix.skip)' if: '!(matrix.skip)'
- name: Restore cache build output (PR) - name: Restore cache build output (PR)
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
@ -375,7 +375,7 @@ jobs:
!./target/*/*.zip !./target/*/*.zip
!./target/*/*.tar.gz !./target/*/*.tar.gz
key: never_saved 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 - name: Apply and update mtime cache
if: '!(matrix.skip) && (!startsWith(github.ref, ''refs/tags/''))' if: '!(matrix.skip) && (!startsWith(github.ref, ''refs/tags/''))'
uses: ./.github/mtime_cache uses: ./.github/mtime_cache
@ -685,7 +685,7 @@ jobs:
!./target/*/*.zip !./target/*/*.zip
!./target/*/*.sha256sum !./target/*/*.sha256sum
!./target/*/*.tar.gz !./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: publish-canary:
name: publish canary name: publish canary
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04

91
Cargo.lock generated
View file

@ -1201,7 +1201,7 @@ dependencies = [
[[package]] [[package]]
name = "deno" name = "deno"
version = "2.0.6" version = "2.1.0"
dependencies = [ dependencies = [
"anstream", "anstream",
"async-trait", "async-trait",
@ -1232,6 +1232,7 @@ dependencies = [
"deno_resolver", "deno_resolver",
"deno_runtime", "deno_runtime",
"deno_semver", "deno_semver",
"deno_sqlformat",
"deno_task_shell", "deno_task_shell",
"deno_terminal 0.2.0", "deno_terminal 0.2.0",
"deno_tower_lsp", "deno_tower_lsp",
@ -1291,7 +1292,6 @@ dependencies = [
"sha2", "sha2",
"shell-escape", "shell-escape",
"spki", "spki",
"sqlformat",
"strsim", "strsim",
"tar", "tar",
"tempfile", "tempfile",
@ -1371,7 +1371,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_bench_util" name = "deno_bench_util"
version = "0.171.0" version = "0.172.0"
dependencies = [ dependencies = [
"bencher", "bencher",
"deno_core", "deno_core",
@ -1380,7 +1380,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_broadcast_channel" name = "deno_broadcast_channel"
version = "0.171.0" version = "0.172.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"deno_core", "deno_core",
@ -1391,7 +1391,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_cache" name = "deno_cache"
version = "0.109.0" version = "0.110.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"deno_core", "deno_core",
@ -1424,7 +1424,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_canvas" name = "deno_canvas"
version = "0.46.0" version = "0.47.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"deno_webgpu", "deno_webgpu",
@ -1435,9 +1435,9 @@ dependencies = [
[[package]] [[package]]
name = "deno_config" name = "deno_config"
version = "0.39.1" version = "0.39.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a91aa99751ebe305a7edad12a3ad751f3b3b9f5ecddbfe4a0459e3cdc8493b6" checksum = "38fb809500238be2b10eee42944a47b3ac38974e1edbb47f73afcfca7df143bf"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"deno_package_json", "deno_package_json",
@ -1459,7 +1459,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_console" name = "deno_console"
version = "0.177.0" version = "0.178.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
] ]
@ -1506,7 +1506,7 @@ checksum = "fe4dccb6147bb3f3ba0c7a48e993bfeb999d2c2e47a81badee80e2b370c8d695"
[[package]] [[package]]
name = "deno_cron" name = "deno_cron"
version = "0.57.0" version = "0.58.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -1519,7 +1519,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_crypto" name = "deno_crypto"
version = "0.191.0" version = "0.192.0"
dependencies = [ dependencies = [
"aes", "aes",
"aes-gcm", "aes-gcm",
@ -1587,7 +1587,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_fetch" name = "deno_fetch"
version = "0.201.0" version = "0.202.0"
dependencies = [ dependencies = [
"base64 0.21.7", "base64 0.21.7",
"bytes", "bytes",
@ -1621,7 +1621,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_ffi" name = "deno_ffi"
version = "0.164.0" version = "0.165.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"deno_permissions", "deno_permissions",
@ -1641,7 +1641,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_fs" name = "deno_fs"
version = "0.87.0" version = "0.88.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"base32", "base32",
@ -1694,7 +1694,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_http" name = "deno_http"
version = "0.175.0" version = "0.176.0"
dependencies = [ dependencies = [
"async-compression", "async-compression",
"async-trait", "async-trait",
@ -1733,7 +1733,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_io" name = "deno_io"
version = "0.87.0" version = "0.88.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"deno_core", "deno_core",
@ -1754,7 +1754,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_kv" name = "deno_kv"
version = "0.85.0" version = "0.86.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -1827,7 +1827,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_napi" name = "deno_napi"
version = "0.108.0" version = "0.109.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"deno_permissions", "deno_permissions",
@ -1855,7 +1855,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_net" name = "deno_net"
version = "0.169.0" version = "0.170.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"deno_permissions", "deno_permissions",
@ -1872,7 +1872,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_node" name = "deno_node"
version = "0.114.0" version = "0.115.0"
dependencies = [ dependencies = [
"aead-gcm-stream", "aead-gcm-stream",
"aes", "aes",
@ -2024,7 +2024,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_permissions" name = "deno_permissions"
version = "0.37.0" version = "0.38.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"deno_path_util", "deno_path_util",
@ -2042,7 +2042,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_resolver" name = "deno_resolver"
version = "0.9.0" version = "0.10.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"base32", "base32",
@ -2061,7 +2061,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_runtime" name = "deno_runtime"
version = "0.186.0" version = "0.187.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"color-print", "color-print",
@ -2147,6 +2147,18 @@ dependencies = [
"url", "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]] [[package]]
name = "deno_task_shell" name = "deno_task_shell"
version = "0.18.1" version = "0.18.1"
@ -2186,7 +2198,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_tls" name = "deno_tls"
version = "0.164.0" version = "0.165.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"deno_native_certs", "deno_native_certs",
@ -2235,7 +2247,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_url" name = "deno_url"
version = "0.177.0" version = "0.178.0"
dependencies = [ dependencies = [
"deno_bench_util", "deno_bench_util",
"deno_console", "deno_console",
@ -2247,7 +2259,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_web" name = "deno_web"
version = "0.208.0" version = "0.209.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"base64-simd 0.8.0", "base64-simd 0.8.0",
@ -2269,7 +2281,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_webgpu" name = "deno_webgpu"
version = "0.144.0" version = "0.145.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"raw-window-handle", "raw-window-handle",
@ -2282,7 +2294,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_webidl" name = "deno_webidl"
version = "0.177.0" version = "0.178.0"
dependencies = [ dependencies = [
"deno_bench_util", "deno_bench_util",
"deno_core", "deno_core",
@ -2290,7 +2302,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_websocket" name = "deno_websocket"
version = "0.182.0" version = "0.183.0"
dependencies = [ dependencies = [
"bytes", "bytes",
"deno_core", "deno_core",
@ -2312,7 +2324,7 @@ dependencies = [
[[package]] [[package]]
name = "deno_webstorage" name = "deno_webstorage"
version = "0.172.0" version = "0.173.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"deno_web", "deno_web",
@ -4562,9 +4574,9 @@ dependencies = [
[[package]] [[package]]
name = "markup_fmt" name = "markup_fmt"
version = "0.15.0" version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebae65c91eab3d42231232bf48107f351e5a8d511454927218c53aeb68bbdb6f" checksum = "f303c36143671ac6c54112eb5aa95649b169dae783fdb6ead2c0e88b408c425c"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"css_dataset", "css_dataset",
@ -4740,7 +4752,7 @@ dependencies = [
[[package]] [[package]]
name = "napi_sym" name = "napi_sym"
version = "0.107.0" version = "0.108.0"
dependencies = [ dependencies = [
"quote", "quote",
"serde", "serde",
@ -4795,7 +4807,7 @@ dependencies = [
[[package]] [[package]]
name = "node_resolver" name = "node_resolver"
version = "0.16.0" version = "0.17.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -6797,17 +6809,6 @@ dependencies = [
"der", "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]] [[package]]
name = "stable_deref_trait" name = "stable_deref_trait"
version = "1.2.0" version = "1.2.0"

View file

@ -48,17 +48,17 @@ repository = "https://github.com/denoland/deno"
deno_ast = { version = "=0.43.3", features = ["transpiling"] } deno_ast = { version = "=0.43.3", features = ["transpiling"] }
deno_core = { version = "0.321.0" } deno_core = { version = "0.321.0" }
deno_bench_util = { version = "0.171.0", path = "./bench_util" } deno_bench_util = { version = "0.172.0", path = "./bench_util" }
deno_config = { version = "=0.39.1", features = ["workspace", "sync"] } deno_config = { version = "=0.39.2", features = ["workspace", "sync"] }
deno_lockfile = "=0.23.1" deno_lockfile = "=0.23.1"
deno_media_type = { version = "0.2.0", features = ["module_specifier"] } deno_media_type = { version = "0.2.0", features = ["module_specifier"] }
deno_npm = "=0.25.4" deno_npm = "=0.25.4"
deno_path_util = "=0.2.1" deno_path_util = "=0.2.1"
deno_permissions = { version = "0.37.0", path = "./runtime/permissions" } deno_permissions = { version = "0.38.0", path = "./runtime/permissions" }
deno_runtime = { version = "0.186.0", path = "./runtime" } deno_runtime = { version = "0.187.0", path = "./runtime" }
deno_semver = "=0.5.16" deno_semver = "=0.5.16"
deno_terminal = "0.2.0" 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" } test_util = { package = "test_server", path = "./tests/util/server" }
denokv_proto = "0.8.4" denokv_proto = "0.8.4"
@ -67,32 +67,32 @@ denokv_remote = "0.8.4"
denokv_sqlite = { default-features = false, version = "0.8.4" } denokv_sqlite = { default-features = false, version = "0.8.4" }
# exts # exts
deno_broadcast_channel = { version = "0.171.0", path = "./ext/broadcast_channel" } deno_broadcast_channel = { version = "0.172.0", path = "./ext/broadcast_channel" }
deno_cache = { version = "0.109.0", path = "./ext/cache" } deno_cache = { version = "0.110.0", path = "./ext/cache" }
deno_canvas = { version = "0.46.0", path = "./ext/canvas" } deno_canvas = { version = "0.47.0", path = "./ext/canvas" }
deno_console = { version = "0.177.0", path = "./ext/console" } deno_console = { version = "0.178.0", path = "./ext/console" }
deno_cron = { version = "0.57.0", path = "./ext/cron" } deno_cron = { version = "0.58.0", path = "./ext/cron" }
deno_crypto = { version = "0.191.0", path = "./ext/crypto" } deno_crypto = { version = "0.192.0", path = "./ext/crypto" }
deno_fetch = { version = "0.201.0", path = "./ext/fetch" } deno_fetch = { version = "0.202.0", path = "./ext/fetch" }
deno_ffi = { version = "0.164.0", path = "./ext/ffi" } deno_ffi = { version = "0.165.0", path = "./ext/ffi" }
deno_fs = { version = "0.87.0", path = "./ext/fs" } deno_fs = { version = "0.88.0", path = "./ext/fs" }
deno_http = { version = "0.175.0", path = "./ext/http" } deno_http = { version = "0.176.0", path = "./ext/http" }
deno_io = { version = "0.87.0", path = "./ext/io" } deno_io = { version = "0.88.0", path = "./ext/io" }
deno_kv = { version = "0.85.0", path = "./ext/kv" } deno_kv = { version = "0.86.0", path = "./ext/kv" }
deno_napi = { version = "0.108.0", path = "./ext/napi" } deno_napi = { version = "0.109.0", path = "./ext/napi" }
deno_net = { version = "0.169.0", path = "./ext/net" } deno_net = { version = "0.170.0", path = "./ext/net" }
deno_node = { version = "0.114.0", path = "./ext/node" } deno_node = { version = "0.115.0", path = "./ext/node" }
deno_tls = { version = "0.164.0", path = "./ext/tls" } deno_tls = { version = "0.165.0", path = "./ext/tls" }
deno_url = { version = "0.177.0", path = "./ext/url" } deno_url = { version = "0.178.0", path = "./ext/url" }
deno_web = { version = "0.208.0", path = "./ext/web" } deno_web = { version = "0.209.0", path = "./ext/web" }
deno_webgpu = { version = "0.144.0", path = "./ext/webgpu" } deno_webgpu = { version = "0.145.0", path = "./ext/webgpu" }
deno_webidl = { version = "0.177.0", path = "./ext/webidl" } deno_webidl = { version = "0.178.0", path = "./ext/webidl" }
deno_websocket = { version = "0.182.0", path = "./ext/websocket" } deno_websocket = { version = "0.183.0", path = "./ext/websocket" }
deno_webstorage = { version = "0.172.0", path = "./ext/webstorage" } deno_webstorage = { version = "0.173.0", path = "./ext/webstorage" }
# resolvers # resolvers
deno_resolver = { version = "0.9.0", path = "./resolvers/deno" } deno_resolver = { version = "0.10.0", path = "./resolvers/deno" }
node_resolver = { version = "0.16.0", path = "./resolvers/node" } node_resolver = { version = "0.17.0", path = "./resolvers/node" }
aes = "=0.8.3" aes = "=0.8.3"
anyhow = "1.0.57" anyhow = "1.0.57"

View file

@ -6,6 +6,76 @@ https://github.com/denoland/deno/releases
We also have one-line install commands at: We also have one-line install commands at:
https://github.com/denoland/deno_install https://github.com/denoland/deno_install
### 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 ### 2.0.6 / 2024.11.10
- feat(ext/http): abort event when request is cancelled (#26781) - feat(ext/http): abort event when request is cancelled (#26781)

View file

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

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno" name = "deno"
version = "2.0.6" version = "2.1.0"
authors.workspace = true authors.workspace = true
default-run = "deno" default-run = "deno"
edition.workspace = true edition.workspace = true
@ -129,7 +129,7 @@ libz-sys.workspace = true
log = { workspace = true, features = ["serde"] } log = { workspace = true, features = ["serde"] }
lsp-types.workspace = true lsp-types.workspace = true
malva = "=0.11.0" malva = "=0.11.0"
markup_fmt = "=0.15.0" markup_fmt = "=0.16.0"
memmem.workspace = true memmem.workspace = true
monch.workspace = true monch.workspace = true
notify.workspace = true notify.workspace = true
@ -151,8 +151,8 @@ serde_repr.workspace = true
sha2.workspace = true sha2.workspace = true
shell-escape = "=0.1.5" shell-escape = "=0.1.5"
spki = { version = "0.7", features = ["pem"] } 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. # NOTE(bartlomieju): using temporary fork for now, revert back to `sqlformat-rs` later
sqlformat = { git = "https://github.com/shssoichiro/sqlformat-rs.git", rev = "827d639" } sqlformat = { package = "deno_sqlformat", version = "0.3.2" }
strsim = "0.11.1" strsim = "0.11.1"
tar.workspace = true tar.workspace = true
tempfile.workspace = true tempfile.workspace = true

View file

@ -222,6 +222,8 @@ impl FmtFlags {
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct InitFlags { pub struct InitFlags {
pub package: Option<String>,
pub package_args: Vec<String>,
pub dir: Option<String>, pub dir: Option<String>,
pub lib: bool, pub lib: bool,
pub serve: bool, pub serve: bool,
@ -382,6 +384,8 @@ pub struct TaskFlags {
pub cwd: Option<String>, pub cwd: Option<String>,
pub task: Option<String>, pub task: Option<String>,
pub is_run: bool, pub is_run: bool,
pub recursive: bool,
pub filter: Option<String>,
pub eval: bool, pub eval: bool,
} }
@ -467,6 +471,7 @@ pub enum DenoSubcommand {
Serve(ServeFlags), Serve(ServeFlags),
Task(TaskFlags), Task(TaskFlags),
Test(TestFlags), Test(TestFlags),
Outdated(OutdatedFlags),
Types, Types,
Upgrade(UpgradeFlags), Upgrade(UpgradeFlags),
Vendor, Vendor,
@ -474,6 +479,19 @@ pub enum DenoSubcommand {
Help(HelpFlags), 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 { impl DenoSubcommand {
pub fn is_run(&self) -> bool { pub fn is_run(&self) -> bool {
matches!(self, Self::Run(_)) 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_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_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_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". Possible values: "system", "mozilla".
<p(245)>(defaults to "mozilla")</> <p(245)>(defaults to "mozilla")</>
<g>HTTP_PROXY</> Proxy address for HTTP requests <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</> <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>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>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 <g>remove</> Remove dependencies from the configuration file
<y>Tooling:</> <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)?, "doc" => doc_parse(&mut flags, &mut m)?,
"eval" => eval_parse(&mut flags, &mut m)?, "eval" => eval_parse(&mut flags, &mut m)?,
"fmt" => fmt_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)?, "info" => info_parse(&mut flags, &mut m)?,
"install" => install_parse(&mut flags, &mut m)?, "install" => install_parse(&mut flags, &mut m)?,
"json_reference" => json_reference_parse(&mut flags, &mut m, app), "json_reference" => json_reference_parse(&mut flags, &mut m, app),
"jupyter" => jupyter_parse(&mut flags, &mut m), "jupyter" => jupyter_parse(&mut flags, &mut m),
"lint" => lint_parse(&mut flags, &mut m)?, "lint" => lint_parse(&mut flags, &mut m)?,
"lsp" => lsp_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)?, "repl" => repl_parse(&mut flags, &mut m)?,
"run" => run_parse(&mut flags, &mut m, app, false)?, "run" => run_parse(&mut flags, &mut m, app, false)?,
"serve" => serve_parse(&mut flags, &mut m, app)?, "serve" => serve_parse(&mut flags, &mut m, app)?,
@ -1628,6 +1649,7 @@ pub fn clap_root() -> Command {
.subcommand(json_reference_subcommand()) .subcommand(json_reference_subcommand())
.subcommand(jupyter_subcommand()) .subcommand(jupyter_subcommand())
.subcommand(uninstall_subcommand()) .subcommand(uninstall_subcommand())
.subcommand(outdated_subcommand())
.subcommand(lsp_subcommand()) .subcommand(lsp_subcommand())
.subcommand(lint_subcommand()) .subcommand(lint_subcommand())
.subcommand(publish_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( command("init", "scaffolds a basic Deno project with a script, test, and configuration file", UnstableArgsConfig::None).defer(
|cmd| { |cmd| {
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(
Arg::new("lib") Arg::new("lib")
.long("lib") .long("lib")
@ -2618,6 +2652,83 @@ fn jupyter_subcommand() -> Command {
.conflicts_with("install")) .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 { fn uninstall_subcommand() -> Command {
command( command(
"uninstall", "uninstall",
@ -2953,6 +3064,20 @@ Evaluate a task from string
.help("Specify the directory to run the task in") .help("Specify the directory to run the task in")
.value_hint(ValueHint::DirPath), .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(
Arg::new("eval") Arg::new("eval")
.long("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"</> <p(245)>--deny-run | --deny-run="whoami,ps"</>
<g>--deny-ffi[=<<PATH>...]</> (Unstable) Deny loading dynamic libraries. Optionally specify denied directories or files. <g>--deny-ffi[=<<PATH>...]</> (Unstable) Deny loading dynamic libraries. Optionally specify denied directories or files.
<p(245)>--deny-ffi | --deny-ffi="./libfoo.so"</> <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( .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( fn bench_parse(
flags: &mut Flags, flags: &mut Flags,
matches: &mut ArgMatches, matches: &mut ArgMatches,
@ -4684,12 +4836,44 @@ fn fmt_parse(
Ok(()) 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 { flags.subcommand = DenoSubcommand::Init(InitFlags {
dir: matches.remove_one::<String>("dir"), package,
lib: matches.get_flag("lib"), package_args,
serve: matches.get_flag("serve"), dir,
lib,
serve,
}); });
Ok(())
} }
fn info_parse( fn info_parse(
@ -5094,10 +5278,15 @@ fn task_parse(
unstable_args_parse(flags, matches, UnstableArgsConfig::ResolutionAndRuntime); unstable_args_parse(flags, matches, UnstableArgsConfig::ResolutionAndRuntime);
node_modules_arg_parse(flags, matches); 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 { let mut task_flags = TaskFlags {
cwd: matches.remove_one::<String>("cwd"), cwd: matches.remove_one::<String>("cwd"),
task: None, task: None,
is_run: false, is_run: false,
recursive,
filter,
eval: matches.get_flag("eval"), eval: matches.get_flag("eval"),
}; };
@ -10300,6 +10489,8 @@ mod tests {
cwd: None, cwd: None,
task: Some("build".to_string()), task: Some("build".to_string()),
is_run: false, is_run: false,
recursive: false,
filter: None,
eval: false, eval: false,
}), }),
argv: svec!["hello", "world"], argv: svec!["hello", "world"],
@ -10315,6 +10506,8 @@ mod tests {
cwd: None, cwd: None,
task: Some("build".to_string()), task: Some("build".to_string()),
is_run: false, is_run: false,
recursive: false,
filter: None,
eval: false, eval: false,
}), }),
..Flags::default() ..Flags::default()
@ -10329,6 +10522,56 @@ mod tests {
cwd: Some("foo".to_string()), cwd: Some("foo".to_string()),
task: Some("build".to_string()), task: Some("build".to_string()),
is_run: false, 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, eval: false,
}), }),
..Flags::default() ..Flags::default()
@ -10343,6 +10586,8 @@ mod tests {
cwd: None, cwd: None,
task: Some("echo 1".to_string()), task: Some("echo 1".to_string()),
is_run: false, is_run: false,
recursive: false,
filter: None,
eval: true, eval: true,
}), }),
..Flags::default() ..Flags::default()
@ -10372,6 +10617,8 @@ mod tests {
cwd: None, cwd: None,
task: Some("build".to_string()), task: Some("build".to_string()),
is_run: false, is_run: false,
recursive: false,
filter: None,
eval: false, eval: false,
}), }),
argv: svec!["--", "hello", "world"], argv: svec!["--", "hello", "world"],
@ -10390,6 +10637,8 @@ mod tests {
cwd: Some("foo".to_string()), cwd: Some("foo".to_string()),
task: Some("build".to_string()), task: Some("build".to_string()),
is_run: false, is_run: false,
recursive: false,
filter: None,
eval: false, eval: false,
}), }),
argv: svec!["--", "hello", "world"], argv: svec!["--", "hello", "world"],
@ -10409,6 +10658,8 @@ mod tests {
cwd: None, cwd: None,
task: Some("build".to_string()), task: Some("build".to_string()),
is_run: false, is_run: false,
recursive: false,
filter: None,
eval: false, eval: false,
}), }),
argv: svec!["--"], argv: svec!["--"],
@ -10427,6 +10678,8 @@ mod tests {
cwd: None, cwd: None,
task: Some("build".to_string()), task: Some("build".to_string()),
is_run: false, is_run: false,
recursive: false,
filter: None,
eval: false, eval: false,
}), }),
argv: svec!["-1", "--test"], argv: svec!["-1", "--test"],
@ -10445,6 +10698,8 @@ mod tests {
cwd: None, cwd: None,
task: Some("build".to_string()), task: Some("build".to_string()),
is_run: false, is_run: false,
recursive: false,
filter: None,
eval: false, eval: false,
}), }),
argv: svec!["--test"], argv: svec!["--test"],
@ -10464,6 +10719,8 @@ mod tests {
cwd: None, cwd: None,
task: Some("build".to_string()), task: Some("build".to_string()),
is_run: false, is_run: false,
recursive: false,
filter: None,
eval: false, eval: false,
}), }),
log_level: Some(log::Level::Error), log_level: Some(log::Level::Error),
@ -10482,6 +10739,8 @@ mod tests {
cwd: None, cwd: None,
task: None, task: None,
is_run: false, is_run: false,
recursive: false,
filter: None,
eval: false, eval: false,
}), }),
..Flags::default() ..Flags::default()
@ -10499,6 +10758,8 @@ mod tests {
cwd: None, cwd: None,
task: None, task: None,
is_run: false, is_run: false,
recursive: false,
filter: None,
eval: false, eval: false,
}), }),
config_flag: ConfigFlag::Path("deno.jsonc".to_string()), config_flag: ConfigFlag::Path("deno.jsonc".to_string()),
@ -10517,6 +10778,8 @@ mod tests {
cwd: None, cwd: None,
task: None, task: None,
is_run: false, is_run: false,
recursive: false,
filter: None,
eval: false, eval: false,
}), }),
config_flag: ConfigFlag::Path("deno.jsonc".to_string()), config_flag: ConfigFlag::Path("deno.jsonc".to_string()),
@ -10694,6 +10957,8 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Init(InitFlags { subcommand: DenoSubcommand::Init(InitFlags {
package: None,
package_args: vec![],
dir: None, dir: None,
lib: false, lib: false,
serve: false, serve: false,
@ -10707,6 +10972,8 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Init(InitFlags { subcommand: DenoSubcommand::Init(InitFlags {
package: None,
package_args: vec![],
dir: Some(String::from("foo")), dir: Some(String::from("foo")),
lib: false, lib: false,
serve: false, serve: false,
@ -10720,6 +10987,8 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Init(InitFlags { subcommand: DenoSubcommand::Init(InitFlags {
package: None,
package_args: vec![],
dir: None, dir: None,
lib: false, lib: false,
serve: false, serve: false,
@ -10734,6 +11003,8 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Init(InitFlags { subcommand: DenoSubcommand::Init(InitFlags {
package: None,
package_args: vec![],
dir: None, dir: None,
lib: true, lib: true,
serve: false, serve: false,
@ -10747,6 +11018,8 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Init(InitFlags { subcommand: DenoSubcommand::Init(InitFlags {
package: None,
package_args: vec![],
dir: None, dir: None,
lib: false, lib: false,
serve: true, serve: true,
@ -10760,6 +11033,8 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Init(InitFlags { subcommand: DenoSubcommand::Init(InitFlags {
package: None,
package_args: vec![],
dir: Some(String::from("foo")), dir: Some(String::from("foo")),
lib: true, lib: true,
serve: false, serve: false,
@ -10767,6 +11042,57 @@ mod tests {
..Flags::default() ..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] #[test]
@ -11300,4 +11626,77 @@ Usage: deno repl [OPTIONS] [-- [ARGS]...]\n"
assert!(r.is_err()); 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
);
}
}
} }

View file

@ -1628,8 +1628,10 @@ impl CliOptions {
DenoSubcommand::Install(_) DenoSubcommand::Install(_)
| DenoSubcommand::Add(_) | DenoSubcommand::Add(_)
| DenoSubcommand::Remove(_) | 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; return false;
} }
if self.node_modules_dir().ok().flatten().is_none() 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") 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 { pub fn has_flag_env_var(name: &str) -> bool {
let value = env::var(name); let value = env::var(name);
matches!(value.as_ref().map(|s| s.as_str()), Ok("1")) matches!(value.as_ref().map(|s| s.as_str()), Ok("1"))

View file

@ -144,9 +144,7 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
} }
DenoSubcommand::Init(init_flags) => { DenoSubcommand::Init(init_flags) => {
spawn_subcommand(async { spawn_subcommand(async {
// make compiler happy since init_project is sync tools::init::init_project(init_flags).await
tokio::task::yield_now().await;
tools::init::init_project(init_flags)
}) })
} }
DenoSubcommand::Info(info_flags) => { 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 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) => { DenoSubcommand::Repl(repl_flags) => {
spawn_subcommand(async move { tools::repl::run(flags, repl_flags).await }) 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, cwd: None,
task: Some(run_flags.script.clone()), task: Some(run_flags.script.clone()),
is_run: true, is_run: true,
recursive: false,
filter: None,
eval: false, eval: false,
}; };
new_flags.subcommand = DenoSubcommand::Task(task_flags.clone()); new_flags.subcommand = DenoSubcommand::Task(task_flags.clone());

View file

@ -500,7 +500,7 @@ impl ManagedCliNpmResolver {
self.resolve_pkg_folder_from_pkg_id(&pkg_id) 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, &self,
req: &PackageReq, req: &PackageReq,
) -> Result<NpmPackageId, PackageReqNotFoundError> { ) -> Result<NpmPackageId, PackageReqNotFoundError> {

View file

@ -51,7 +51,7 @@ fn op_bench_get_origin(state: &mut OpState) -> String {
#[derive(Clone)] #[derive(Clone)]
struct PermissionsHolder(Uuid, PermissionsContainer); struct PermissionsHolder(Uuid, PermissionsContainer);
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
pub fn op_pledge_test_permissions( pub fn op_pledge_test_permissions(
state: &mut OpState, state: &mut OpState,

View file

@ -46,7 +46,7 @@ deno_core::extension!(deno_test,
#[derive(Clone)] #[derive(Clone)]
struct PermissionsHolder(Uuid, PermissionsContainer); struct PermissionsHolder(Uuid, PermissionsContainer);
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
pub fn op_pledge_test_permissions( pub fn op_pledge_test_permissions(
state: &mut OpState, state: &mut OpState,

View file

@ -1,15 +1,28 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use crate::args::DenoSubcommand;
use crate::args::Flags;
use crate::args::InitFlags; use crate::args::InitFlags;
use crate::args::PackagesAllowedScripts;
use crate::args::PermissionFlags;
use crate::args::RunFlags;
use crate::colors; use crate::colors;
use color_print::cformat;
use color_print::cstr;
use deno_core::anyhow::Context; use deno_core::anyhow::Context;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::serde_json::json; use deno_core::serde_json::json;
use deno_runtime::WorkerExecutionMode;
use log::info; use log::info;
use std::io::IsTerminal;
use std::io::Write; use std::io::Write;
use std::path::Path; 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 = let cwd =
std::env::current_dir().context("Can't read current working directory.")?; std::env::current_dir().context("Can't read current working directory.")?;
let dir = if let Some(dir) = &init_flags.dir { let dir = if let Some(dir) = &init_flags.dir {
@ -235,7 +248,58 @@ Deno.test(function addTest() {
info!(" {}", colors::gray("# Run the tests")); info!(" {}", colors::gray("# Run the tests"));
info!(" deno test"); 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( fn create_json_file(

View file

@ -175,6 +175,7 @@ struct JsonLintReporter {
version: u8, version: u8,
diagnostics: Vec<JsonLintDiagnostic>, diagnostics: Vec<JsonLintDiagnostic>,
errors: Vec<LintError>, errors: Vec<LintError>,
checked_files: Vec<String>,
} }
impl JsonLintReporter { impl JsonLintReporter {
@ -183,6 +184,7 @@ impl JsonLintReporter {
version: JSON_SCHEMA_VERSION, version: JSON_SCHEMA_VERSION,
diagnostics: Vec::new(), diagnostics: Vec::new(),
errors: Vec::new(), errors: Vec::new(),
checked_files: Vec::new(),
} }
} }
} }
@ -209,6 +211,17 @@ impl LintReporter for JsonLintReporter {
code: d.code().to_string(), code: d.code().to_string(),
hint: d.hint().map(|h| h.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) { fn visit_error(&mut self, file_path: &str, err: &AnyError) {
@ -216,10 +229,15 @@ impl LintReporter for JsonLintReporter {
file_path: file_path.to_string(), file_path: file_path.to_string(),
message: err.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) { fn close(&mut self, _check_count: usize) {
sort_diagnostics(&mut self.diagnostics); sort_diagnostics(&mut self.diagnostics);
self.checked_files.sort();
let json = serde_json::to_string_pretty(&self); let json = serde_json::to_string_pretty(&self);
#[allow(clippy::print_stdout)] #[allow(clippy::print_stdout)]
{ {

View file

@ -68,6 +68,7 @@ use auth::get_auth_method;
use auth::AuthMethod; use auth::AuthMethod;
pub use pm::add; pub use pm::add;
pub use pm::cache_top_level_deps; pub use pm::cache_top_level_deps;
pub use pm::outdated;
pub use pm::remove; pub use pm::remove;
pub use pm::AddCommandName; pub use pm::AddCommandName;
pub use pm::AddRmPackageReq; pub use pm::AddRmPackageReq;

View file

@ -16,6 +16,7 @@ use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq; use deno_semver::package::PackageReq;
use deno_semver::Version; use deno_semver::Version;
use deno_semver::VersionReq; use deno_semver::VersionReq;
use deps::KeyPath;
use jsonc_parser::cst::CstObject; use jsonc_parser::cst::CstObject;
use jsonc_parser::cst::CstObjectProp; use jsonc_parser::cst::CstObjectProp;
use jsonc_parser::cst::CstRootNode; use jsonc_parser::cst::CstRootNode;
@ -32,10 +33,13 @@ use crate::jsr::JsrFetchResolver;
use crate::npm::NpmFetchResolver; use crate::npm::NpmFetchResolver;
mod cache_deps; mod cache_deps;
pub(crate) mod deps;
mod outdated;
pub use cache_deps::cache_top_level_deps; pub use cache_deps::cache_top_level_deps;
pub use outdated::outdated;
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone, Hash)]
enum ConfigKind { enum ConfigKind {
DenoJson, DenoJson,
PackageJson, PackageJson,
@ -86,6 +90,28 @@ impl ConfigUpdater {
self.cst.to_string() 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 add(&mut self, selected: SelectedPackage, dev: bool) {
fn insert_index(object: &CstObject, searching_name: &str) -> usize { fn insert_index(object: &CstObject, searching_name: &str) -> usize {
object object
@ -824,7 +850,7 @@ async fn npm_install_after_modification(
flags: Arc<Flags>, flags: Arc<Flags>,
// explicitly provided to prevent redownloading // explicitly provided to prevent redownloading
jsr_resolver: Option<Arc<crate::jsr::JsrFetchResolver>>, jsr_resolver: Option<Arc<crate::jsr::JsrFetchResolver>>,
) -> Result<(), AnyError> { ) -> Result<CliFactory, AnyError> {
// clear the previously cached package.json from memory before reloading it // clear the previously cached package.json from memory before reloading it
node_resolver::PackageJsonThreadLocalCache::clear(); node_resolver::PackageJsonThreadLocalCache::clear();
@ -842,7 +868,7 @@ async fn npm_install_after_modification(
lockfile.write_if_changed()?; lockfile.write_if_changed()?;
} }
Ok(()) Ok(cli_factory)
} }
#[cfg(test)] #[cfg(test)]

View file

@ -8,7 +8,7 @@ use crate::graph_container::ModuleGraphUpdatePermit;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::futures::stream::FuturesUnordered; use deno_core::futures::stream::FuturesUnordered;
use deno_core::futures::StreamExt; use deno_core::futures::StreamExt;
use deno_semver::package::PackageReq; use deno_semver::jsr::JsrPackageReqReference;
pub async fn cache_top_level_deps( pub async fn cache_top_level_deps(
// todo(dsherret): don't pass the factory into this function. Instead use ctor 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() { match specifier.scheme() {
"jsr" => { "jsr" => {
let specifier_str = specifier.as_str(); let specifier_str = specifier.as_str();
let specifier_str = if let Ok(req) = JsrPackageReqReference::from_str(specifier_str) {
specifier_str.strip_prefix("jsr:").unwrap_or(specifier_str); if let Some(sub_path) = req.sub_path() {
if let Ok(req) = PackageReq::from_str(specifier_str) { if sub_path.ends_with('/') {
if !seen_reqs.insert(req.clone()) { continue;
}
roots.push(specifier.clone());
continue;
}
if !seen_reqs.insert(req.req().clone()) {
continue; continue;
} }
let jsr_resolver = jsr_resolver.clone(); let jsr_resolver = jsr_resolver.clone();
info_futures.push(async move { 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 if let Some(info) = jsr_resolver.package_version_info(&nv).await
{ {
return Some((specifier.clone(), info)); return Some((specifier.clone(), info));

View 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(),
})
}

View 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(&current_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"))
);
}
}
}

View file

@ -8,6 +8,7 @@ use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use deno_config::workspace::FolderConfigs;
use deno_config::workspace::TaskDefinition; use deno_config::workspace::TaskDefinition;
use deno_config::workspace::TaskOrScript; use deno_config::workspace::TaskOrScript;
use deno_config::workspace::WorkspaceDirectory; use deno_config::workspace::WorkspaceDirectory;
@ -25,6 +26,7 @@ use deno_path_util::normalize_path;
use deno_runtime::deno_node::NodeResolver; use deno_runtime::deno_node::NodeResolver;
use deno_task_shell::ShellCommand; use deno_task_shell::ShellCommand;
use indexmap::IndexMap; use indexmap::IndexMap;
use regex::Regex;
use crate::args::CliOptions; use crate::args::CliOptions;
use crate::args::Flags; use crate::args::Flags;
@ -35,6 +37,12 @@ use crate::npm::CliNpmResolver;
use crate::task_runner; use crate::task_runner;
use crate::util::fs::canonicalize_path; use crate::util::fs::canonicalize_path;
#[derive(Debug)]
struct PackageTaskInfo {
matched_tasks: Vec<String>,
tasks_config: WorkspaceTasksConfig,
}
pub async fn execute_script( pub async fn execute_script(
flags: Arc<Flags>, flags: Arc<Flags>,
task_flags: TaskFlags, task_flags: TaskFlags,
@ -55,7 +63,128 @@ pub async fn execute_script(
v == "1" v == "1"
}) })
.unwrap_or(false); .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(&regex_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()?; let mut tasks_config = start_dir.to_tasks_config()?;
if force_use_pkg_json { if force_use_pkg_json {
tasks_config = tasks_config.with_only_pkg_json() tasks_config = tasks_config.with_only_pkg_json()
} }
@ -69,6 +198,12 @@ pub async fn execute_script(
return Ok(0); return Ok(0);
}; };
vec![PackageTaskInfo {
tasks_config,
matched_tasks: vec![task_name.to_string()],
}]
};
let npm_resolver = factory.npm_resolver().await?; let npm_resolver = factory.npm_resolver().await?;
let node_resolver = factory.node_resolver().await?; let node_resolver = factory.node_resolver().await?;
let env_vars = task_runner::real_env_vars(); let env_vars = task_runner::real_env_vars();
@ -81,7 +216,6 @@ pub async fn execute_script(
.unwrap_or_else(|| NonZeroUsize::new(2).unwrap()); .unwrap_or_else(|| NonZeroUsize::new(2).unwrap());
let task_runner = TaskRunner { let task_runner = TaskRunner {
tasks_config,
task_flags: &task_flags, task_flags: &task_flags,
npm_resolver: npm_resolver.as_ref(), npm_resolver: npm_resolver.as_ref(),
node_resolver: node_resolver.as_ref(), node_resolver: node_resolver.as_ref(),
@ -94,7 +228,7 @@ pub async fn execute_script(
return task_runner return task_runner
.run_deno_task( .run_deno_task(
&Url::from_directory_path(cli_options.initial_cwd()).unwrap(), &Url::from_directory_path(cli_options.initial_cwd()).unwrap(),
&"".to_string(), "",
&TaskDefinition { &TaskDefinition {
command: task_flags.task.as_ref().unwrap().to_string(), command: task_flags.task.as_ref().unwrap().to_string(),
dependencies: vec![], dependencies: vec![],
@ -103,7 +237,15 @@ pub async fn execute_script(
) )
.await; .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> { struct RunSingleOptions<'a> {
@ -114,7 +256,6 @@ struct RunSingleOptions<'a> {
} }
struct TaskRunner<'a> { struct TaskRunner<'a> {
tasks_config: WorkspaceTasksConfig,
task_flags: &'a TaskFlags, task_flags: &'a TaskFlags,
npm_resolver: &'a dyn CliNpmResolver, npm_resolver: &'a dyn CliNpmResolver,
node_resolver: &'a NodeResolver, node_resolver: &'a NodeResolver,
@ -124,12 +265,16 @@ struct TaskRunner<'a> {
} }
impl<'a> TaskRunner<'a> { impl<'a> TaskRunner<'a> {
pub async fn run_task( pub async fn run_tasks(
&self, &self,
task_name: &str, pkg_tasks_config: &PackageTaskInfo,
) -> Result<i32, deno_core::anyhow::Error> { ) -> Result<i32, deno_core::anyhow::Error> {
match sort_tasks_topo(task_name, &self.tasks_config) { match sort_tasks_topo(pkg_tasks_config) {
Ok(sorted) => self.run_tasks_in_parallel(sorted).await, Ok(sorted) => {
self
.run_tasks_in_parallel(&pkg_tasks_config.tasks_config, sorted)
.await
}
Err(err) => match err { Err(err) => match err {
TaskError::NotFound(name) => { TaskError::NotFound(name) => {
if self.task_flags.is_run { if self.task_flags.is_run {
@ -138,7 +283,7 @@ impl<'a> TaskRunner<'a> {
log::error!("Task not found: {}", name); log::error!("Task not found: {}", name);
if log::log_enabled!(log::Level::Error) { if log::log_enabled!(log::Level::Error) {
self.print_available_tasks()?; self.print_available_tasks(&pkg_tasks_config.tasks_config)?;
} }
Ok(1) 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( print_available_tasks(
&mut std::io::stderr(), &mut std::io::stderr(),
&self.cli_options.start_dir, &self.cli_options.start_dir,
&self.tasks_config, tasks_config,
) )
} }
async fn run_tasks_in_parallel( async fn run_tasks_in_parallel(
&self, &self,
tasks_config: &WorkspaceTasksConfig,
task_names: Vec<String>, task_names: Vec<String>,
) -> Result<i32, deno_core::anyhow::Error> { ) -> Result<i32, deno_core::anyhow::Error> {
struct PendingTasksContext { struct PendingTasksContext {
@ -181,22 +330,23 @@ impl<'a> TaskRunner<'a> {
fn get_next_task<'a>( fn get_next_task<'a>(
&mut self, &mut self,
runner: &'a TaskRunner<'a>, runner: &'a TaskRunner<'a>,
tasks_config: &'a WorkspaceTasksConfig,
) -> Option<LocalBoxFuture<'a, Result<(i32, String), AnyError>>> { ) -> Option<LocalBoxFuture<'a, Result<(i32, String), AnyError>>> {
for name in &self.task_names { for name in &self.task_names {
if self.completed.contains(name) || self.running.contains(name) { if self.completed.contains(name) || self.running.contains(name) {
continue; continue;
} }
let should_run = if let Ok((_, def)) = runner.get_task(name) { let Some((folder_url, task_or_script)) = tasks_config.task(name)
match def { else {
continue;
};
let should_run = match task_or_script {
TaskOrScript::Task(_, def) => def TaskOrScript::Task(_, def) => def
.dependencies .dependencies
.iter() .iter()
.all(|dep| self.completed.contains(dep)), .all(|dep| self.completed.contains(dep)),
TaskOrScript::Script(_, _) => true, TaskOrScript::Script(_, _) => true,
}
} else {
false
}; };
if !should_run { if !should_run {
@ -207,9 +357,14 @@ impl<'a> TaskRunner<'a> {
let name = name.clone(); let name = name.clone();
return Some( return Some(
async move { async move {
runner match task_or_script {
.run_task_no_dependencies(&name) TaskOrScript::Task(_, def) => {
.await 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)) .map(|exit_code| (exit_code, name))
} }
.boxed_local(), .boxed_local(),
@ -229,7 +384,7 @@ impl<'a> TaskRunner<'a> {
while context.has_remaining_tasks() { while context.has_remaining_tasks() {
while queue.len() < self.concurrency { 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); queue.push(task);
} else { } else {
break; break;
@ -253,37 +408,10 @@ impl<'a> TaskRunner<'a> {
Ok(0) Ok(0)
} }
fn get_task( pub async fn run_deno_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(
&self, &self,
dir_url: &Url, dir_url: &Url,
task_name: &String, task_name: &str,
definition: &TaskDefinition, definition: &TaskDefinition,
) -> Result<i32, deno_core::anyhow::Error> { ) -> Result<i32, deno_core::anyhow::Error> {
let cwd = match &self.task_flags.cwd { let cwd = match &self.task_flags.cwd {
@ -306,10 +434,10 @@ impl<'a> TaskRunner<'a> {
.await .await
} }
async fn run_npm_script( pub async fn run_npm_script(
&self, &self,
dir_url: &Url, dir_url: &Url,
task_name: &String, task_name: &str,
scripts: &IndexMap<String, String>, scripts: &IndexMap<String, String>,
) -> Result<i32, deno_core::anyhow::Error> { ) -> Result<i32, deno_core::anyhow::Error> {
// ensure the npm packages are installed if using a managed resolver // 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 // dealing with package.json here and not deno.json
let task_names = vec![ let task_names = vec![
format!("pre{}", task_name), format!("pre{}", task_name),
task_name.clone(), task_name.to_string(),
format!("post{}", task_name), format!("post{}", task_name),
]; ];
let custom_commands = task_runner::resolve_custom_commands( let custom_commands = task_runner::resolve_custom_commands(
@ -394,8 +522,7 @@ enum TaskError {
} }
fn sort_tasks_topo( fn sort_tasks_topo(
name: &str, pkg_task_config: &PackageTaskInfo,
task_config: &WorkspaceTasksConfig,
) -> Result<Vec<String>, TaskError> { ) -> Result<Vec<String>, TaskError> {
fn sort_visit<'a>( fn sort_visit<'a>(
name: &'a str, 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())); return Err(TaskError::NotFound(name.to_string()));
}; };
if let TaskOrScript::Task(_, actual_def) = def.1 { if let TaskOrScript::Task(_, task) = task_or_script {
for dep in &actual_def.dependencies { for dep in &task.dependencies {
let mut path = path.clone(); let mut path = path.clone();
path.push(name); path.push(name);
sort_visit(dep, sorted, path, tasks_config)? sort_visit(dep, sorted, path, tasks_config)?
@ -435,7 +562,9 @@ fn sort_tasks_topo(
let mut sorted: Vec<String> = vec![]; 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) Ok(sorted)
} }

View file

@ -15,14 +15,14 @@
/// <reference lib="deno.crypto" /> /// <reference lib="deno.crypto" />
/// <reference lib="deno.ns" /> /// <reference lib="deno.ns" />
/** @category WASM */ /** @category Wasm */
declare namespace WebAssembly { declare namespace WebAssembly {
/** /**
* The `WebAssembly.CompileError` object indicates an error during WebAssembly decoding or validation. * 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) * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/CompileError)
* *
* @category WASM * @category Wasm
*/ */
export class CompileError extends Error { export class CompileError extends Error {
/** Creates a new `WebAssembly.CompileError` object. */ /** 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) * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Global)
* *
* @category WASM * @category Wasm
*/ */
export class Global { export class Global {
/** Creates a new `Global` object. */ /** 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) * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Instance)
* *
* @category WASM * @category Wasm
*/ */
export class Instance { export class Instance {
/** Creates a new Instance object. */ /** 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) * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/LinkError)
* *
* @category WASM * @category Wasm
*/ */
export class LinkError extends Error { export class LinkError extends Error {
/** Creates a new WebAssembly.LinkError object. */ /** 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) * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory)
* *
* @category WASM * @category Wasm
*/ */
export class Memory { export class Memory {
/** Creates a new `Memory` object. */ /** 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) * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module)
* *
* @category WASM * @category Wasm
*/ */
export class Module { export class Module {
/** Creates a new `Module` object. */ /** 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) * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/RuntimeError)
* *
* @category WASM * @category Wasm
*/ */
export class RuntimeError extends Error { export class RuntimeError extends Error {
/** Creates a new `WebAssembly.RuntimeError` object. */ /** 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) * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table)
* *
* @category WASM * @category Wasm
*/ */
export class Table { export class Table {
/** Creates a new `Table` object. */ /** Creates a new `Table` object. */
@ -182,7 +182,7 @@ declare namespace WebAssembly {
/** The `GlobalDescriptor` describes the options you can pass to /** The `GlobalDescriptor` describes the options you can pass to
* `new WebAssembly.Global()`. * `new WebAssembly.Global()`.
* *
* @category WASM * @category Wasm
*/ */
export interface GlobalDescriptor { export interface GlobalDescriptor {
mutable?: boolean; mutable?: boolean;
@ -192,7 +192,7 @@ declare namespace WebAssembly {
/** The `MemoryDescriptor` describes the options you can pass to /** The `MemoryDescriptor` describes the options you can pass to
* `new WebAssembly.Memory()`. * `new WebAssembly.Memory()`.
* *
* @category WASM * @category Wasm
*/ */
export interface MemoryDescriptor { export interface MemoryDescriptor {
initial: number; initial: number;
@ -203,7 +203,7 @@ declare namespace WebAssembly {
/** A `ModuleExportDescriptor` is the description of a declared export in a /** A `ModuleExportDescriptor` is the description of a declared export in a
* `WebAssembly.Module`. * `WebAssembly.Module`.
* *
* @category WASM * @category Wasm
*/ */
export interface ModuleExportDescriptor { export interface ModuleExportDescriptor {
kind: ImportExportKind; kind: ImportExportKind;
@ -213,7 +213,7 @@ declare namespace WebAssembly {
/** A `ModuleImportDescriptor` is the description of a declared import in a /** A `ModuleImportDescriptor` is the description of a declared import in a
* `WebAssembly.Module`. * `WebAssembly.Module`.
* *
* @category WASM * @category Wasm
*/ */
export interface ModuleImportDescriptor { export interface ModuleImportDescriptor {
kind: ImportExportKind; kind: ImportExportKind;
@ -224,7 +224,7 @@ declare namespace WebAssembly {
/** The `TableDescriptor` describes the options you can pass to /** The `TableDescriptor` describes the options you can pass to
* `new WebAssembly.Table()`. * `new WebAssembly.Table()`.
* *
* @category WASM * @category Wasm
*/ */
export interface TableDescriptor { export interface TableDescriptor {
element: TableKind; element: TableKind;
@ -234,7 +234,7 @@ declare namespace WebAssembly {
/** The value returned from `WebAssembly.instantiate`. /** The value returned from `WebAssembly.instantiate`.
* *
* @category WASM * @category Wasm
*/ */
export interface WebAssemblyInstantiatedSource { export interface WebAssemblyInstantiatedSource {
/* A `WebAssembly.Instance` object that contains all the exported WebAssembly functions. */ /* A `WebAssembly.Instance` object that contains all the exported WebAssembly functions. */
@ -247,21 +247,21 @@ declare namespace WebAssembly {
module: Module; module: Module;
} }
/** @category WASM */ /** @category Wasm */
export type ImportExportKind = "function" | "global" | "memory" | "table"; export type ImportExportKind = "function" | "global" | "memory" | "table";
/** @category WASM */ /** @category Wasm */
export type TableKind = "anyfunc"; export type TableKind = "anyfunc";
/** @category WASM */ /** @category Wasm */
export type ValueType = "f32" | "f64" | "i32" | "i64"; export type ValueType = "f32" | "f64" | "i32" | "i64";
/** @category WASM */ /** @category Wasm */
export type ExportValue = Function | Global | Memory | Table; export type ExportValue = Function | Global | Memory | Table;
/** @category WASM */ /** @category Wasm */
export type Exports = Record<string, ExportValue>; export type Exports = Record<string, ExportValue>;
/** @category WASM */ /** @category Wasm */
export type ImportValue = ExportValue | number; export type ImportValue = ExportValue | number;
/** @category WASM */ /** @category Wasm */
export type ModuleImports = Record<string, ImportValue>; export type ModuleImports = Record<string, ImportValue>;
/** @category WASM */ /** @category Wasm */
export type Imports = Record<string, ModuleImports>; 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) * [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>; 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) * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/compileStreaming)
* *
* @category WASM * @category Wasm
*/ */
export function compileStreaming( export function compileStreaming(
source: Response | Promise<Response>, 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) * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiate)
* *
* @category WASM * @category Wasm
*/ */
export function instantiate( export function instantiate(
bytes: BufferSource, bytes: BufferSource,
@ -318,7 +318,7 @@ declare namespace WebAssembly {
* *
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiate) * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiate)
* *
* @category WASM * @category Wasm
*/ */
export function instantiate( export function instantiate(
moduleObject: Module, moduleObject: Module,
@ -332,7 +332,7 @@ declare namespace WebAssembly {
* *
* [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiateStreaming) * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiateStreaming)
* *
* @category WASM * @category Wasm
*/ */
export function instantiateStreaming( export function instantiateStreaming(
response: Response | PromiseLike<Response>, 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) * [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; export function validate(bytes: BufferSource): boolean;
} }

View file

@ -617,6 +617,8 @@ impl CliMainWorkerFactory {
origin_storage_dir, origin_storage_dir,
stdio, stdio,
skip_op_registration: shared.options.skip_op_registration, 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( let mut worker = MainWorker::bootstrap_from_options(
@ -813,6 +815,8 @@ fn create_web_worker_callback(
strace_ops: shared.options.strace_ops.clone(), strace_ops: shared.options.strace_ops.clone(),
close_on_idle: args.close_on_idle, close_on_idle: args.close_on_idle,
maybe_worker_metadata: args.maybe_worker_metadata, 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) WebWorker::bootstrap_from_options(services, options)

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_broadcast_channel" name = "deno_broadcast_channel"
version = "0.171.0" version = "0.172.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_cache" name = "deno_cache"
version = "0.109.0" version = "0.110.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_canvas" name = "deno_canvas"
version = "0.46.0" version = "0.47.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_console" name = "deno_console"
version = "0.177.0" version = "0.178.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_cron" name = "deno_cron"
version = "0.57.0" version = "0.58.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_crypto" name = "deno_crypto"
version = "0.191.0" version = "0.192.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

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

View file

@ -397,7 +397,7 @@ impl FetchPermissions for deno_permissions::PermissionsContainer {
} }
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn op_fetch<FP>( pub fn op_fetch<FP>(
@ -866,7 +866,7 @@ fn default_true() -> bool {
true true
} }
#[op2] #[op2(stack_trace)]
#[smi] #[smi]
pub fn op_fetch_custom_client<FP>( pub fn op_fetch_custom_client<FP>(
state: &mut OpState, state: &mut OpState,

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_ffi" name = "deno_ffi"
version = "0.164.0" version = "0.165.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -287,7 +287,7 @@ fn ffi_call(
} }
} }
#[op2(async)] #[op2(async, stack_trace)]
#[serde] #[serde]
pub fn op_ffi_call_ptr_nonblocking<FP>( pub fn op_ffi_call_ptr_nonblocking<FP>(
scope: &mut v8::HandleScope, scope: &mut v8::HandleScope,
@ -385,7 +385,7 @@ pub fn op_ffi_call_nonblocking(
}) })
} }
#[op2(reentrant)] #[op2(reentrant, stack_trace)]
#[serde] #[serde]
pub fn op_ffi_call_ptr<FP>( pub fn op_ffi_call_ptr<FP>(
scope: &mut v8::HandleScope, scope: &mut v8::HandleScope,

View file

@ -561,7 +561,7 @@ pub struct RegisterCallbackArgs {
result: NativeType, result: NativeType,
} }
#[op2] #[op2(stack_trace)]
pub fn op_ffi_unsafe_callback_create<FP, 'scope>( pub fn op_ffi_unsafe_callback_create<FP, 'scope>(
state: &mut OpState, state: &mut OpState,
scope: &mut v8::HandleScope<'scope>, scope: &mut v8::HandleScope<'scope>,

View file

@ -124,7 +124,7 @@ pub struct FfiLoadArgs {
symbols: HashMap<String, ForeignSymbol>, symbols: HashMap<String, ForeignSymbol>,
} }
#[op2] #[op2(stack_trace)]
pub fn op_ffi_load<'scope, FP>( pub fn op_ffi_load<'scope, FP>(
scope: &mut v8::HandleScope<'scope>, scope: &mut v8::HandleScope<'scope>,
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,

View file

@ -49,7 +49,7 @@ pub enum ReprError {
Permission(#[from] deno_permissions::PermissionCheckError), Permission(#[from] deno_permissions::PermissionCheckError),
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_ffi_ptr_create<FP>( pub fn op_ffi_ptr_create<FP>(
state: &mut OpState, state: &mut OpState,
#[bigint] ptr_number: usize, #[bigint] ptr_number: usize,
@ -63,7 +63,7 @@ where
Ok(ptr_number as *mut c_void) Ok(ptr_number as *mut c_void)
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_ffi_ptr_equals<FP>( pub fn op_ffi_ptr_equals<FP>(
state: &mut OpState, state: &mut OpState,
a: *const c_void, a: *const c_void,
@ -78,7 +78,7 @@ where
Ok(a == b) Ok(a == b)
} }
#[op2] #[op2(stack_trace)]
pub fn op_ffi_ptr_of<FP>( pub fn op_ffi_ptr_of<FP>(
state: &mut OpState, state: &mut OpState,
#[anybuffer] buf: *const u8, #[anybuffer] buf: *const u8,
@ -92,7 +92,7 @@ where
Ok(buf as *mut c_void) Ok(buf as *mut c_void)
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_ffi_ptr_of_exact<FP>( pub fn op_ffi_ptr_of_exact<FP>(
state: &mut OpState, state: &mut OpState,
buf: v8::Local<v8::ArrayBufferView>, buf: v8::Local<v8::ArrayBufferView>,
@ -112,7 +112,7 @@ where
Ok(buf.as_ptr() as _) Ok(buf.as_ptr() as _)
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_ffi_ptr_offset<FP>( pub fn op_ffi_ptr_offset<FP>(
state: &mut OpState, state: &mut OpState,
ptr: *mut c_void, ptr: *mut c_void,
@ -142,7 +142,7 @@ unsafe extern "C" fn noop_deleter_callback(
) { ) {
} }
#[op2(fast)] #[op2(fast, stack_trace)]
#[bigint] #[bigint]
pub fn op_ffi_ptr_value<FP>( pub fn op_ffi_ptr_value<FP>(
state: &mut OpState, state: &mut OpState,
@ -157,7 +157,7 @@ where
Ok(ptr as usize) Ok(ptr as usize)
} }
#[op2] #[op2(stack_trace)]
pub fn op_ffi_get_buf<FP, 'scope>( pub fn op_ffi_get_buf<FP, 'scope>(
scope: &mut v8::HandleScope<'scope>, scope: &mut v8::HandleScope<'scope>,
state: &mut OpState, state: &mut OpState,
@ -189,7 +189,7 @@ where
Ok(array_buffer) Ok(array_buffer)
} }
#[op2] #[op2(stack_trace)]
pub fn op_ffi_buf_copy_into<FP>( pub fn op_ffi_buf_copy_into<FP>(
state: &mut OpState, state: &mut OpState,
src: *mut c_void, src: *mut c_void,
@ -219,7 +219,7 @@ where
} }
} }
#[op2] #[op2(stack_trace)]
pub fn op_ffi_cstr_read<FP, 'scope>( pub fn op_ffi_cstr_read<FP, 'scope>(
scope: &mut v8::HandleScope<'scope>, scope: &mut v8::HandleScope<'scope>,
state: &mut OpState, state: &mut OpState,
@ -244,7 +244,7 @@ where
Ok(value) Ok(value)
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_ffi_read_bool<FP>( pub fn op_ffi_read_bool<FP>(
state: &mut OpState, state: &mut OpState,
ptr: *mut c_void, ptr: *mut c_void,
@ -264,7 +264,7 @@ where
Ok(unsafe { ptr::read_unaligned::<bool>(ptr.offset(offset) as *const bool) }) 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>( pub fn op_ffi_read_u8<FP>(
state: &mut OpState, state: &mut OpState,
ptr: *mut c_void, ptr: *mut c_void,
@ -286,7 +286,7 @@ where
}) })
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_ffi_read_i8<FP>( pub fn op_ffi_read_i8<FP>(
state: &mut OpState, state: &mut OpState,
ptr: *mut c_void, ptr: *mut c_void,
@ -308,7 +308,7 @@ where
}) })
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_ffi_read_u16<FP>( pub fn op_ffi_read_u16<FP>(
state: &mut OpState, state: &mut OpState,
ptr: *mut c_void, ptr: *mut c_void,
@ -330,7 +330,7 @@ where
}) })
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_ffi_read_i16<FP>( pub fn op_ffi_read_i16<FP>(
state: &mut OpState, state: &mut OpState,
ptr: *mut c_void, ptr: *mut c_void,
@ -352,7 +352,7 @@ where
}) })
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_ffi_read_u32<FP>( pub fn op_ffi_read_u32<FP>(
state: &mut OpState, state: &mut OpState,
ptr: *mut c_void, ptr: *mut c_void,
@ -372,7 +372,7 @@ where
Ok(unsafe { ptr::read_unaligned::<u32>(ptr.offset(offset) as *const u32) }) 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>( pub fn op_ffi_read_i32<FP>(
state: &mut OpState, state: &mut OpState,
ptr: *mut c_void, ptr: *mut c_void,
@ -392,7 +392,7 @@ where
Ok(unsafe { ptr::read_unaligned::<i32>(ptr.offset(offset) as *const i32) }) Ok(unsafe { ptr::read_unaligned::<i32>(ptr.offset(offset) as *const i32) })
} }
#[op2(fast)] #[op2(fast, stack_trace)]
#[bigint] #[bigint]
pub fn op_ffi_read_u64<FP>( pub fn op_ffi_read_u64<FP>(
state: &mut OpState, state: &mut OpState,
@ -418,7 +418,7 @@ where
Ok(value) Ok(value)
} }
#[op2(fast)] #[op2(fast, stack_trace)]
#[bigint] #[bigint]
pub fn op_ffi_read_i64<FP>( pub fn op_ffi_read_i64<FP>(
state: &mut OpState, state: &mut OpState,
@ -444,7 +444,7 @@ where
Ok(value) Ok(value)
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_ffi_read_f32<FP>( pub fn op_ffi_read_f32<FP>(
state: &mut OpState, state: &mut OpState,
ptr: *mut c_void, ptr: *mut c_void,
@ -464,7 +464,7 @@ where
Ok(unsafe { ptr::read_unaligned::<f32>(ptr.offset(offset) as *const f32) }) 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>( pub fn op_ffi_read_f64<FP>(
state: &mut OpState, state: &mut OpState,
ptr: *mut c_void, ptr: *mut c_void,
@ -484,7 +484,7 @@ where
Ok(unsafe { ptr::read_unaligned::<f64>(ptr.offset(offset) as *const f64) }) 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>( pub fn op_ffi_read_ptr<FP>(
state: &mut OpState, state: &mut OpState,
ptr: *mut c_void, ptr: *mut c_void,

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_fs" name = "deno_fs"
version = "0.87.0" version = "0.88.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -146,7 +146,7 @@ fn map_permission_error(
} }
} }
#[op2] #[op2(stack_trace)]
#[string] #[string]
pub fn op_fs_cwd<P>(state: &mut OpState) -> Result<String, FsOpsError> pub fn op_fs_cwd<P>(state: &mut OpState) -> Result<String, FsOpsError>
where where
@ -161,7 +161,7 @@ where
Ok(path_str) Ok(path_str)
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_fs_chdir<P>( pub fn op_fs_chdir<P>(
state: &mut OpState, state: &mut OpState,
#[string] directory: &str, #[string] directory: &str,
@ -188,7 +188,7 @@ where
state.borrow::<FileSystemRc>().umask(mask).context("umask") state.borrow::<FileSystemRc>().umask(mask).context("umask")
} }
#[op2] #[op2(stack_trace)]
#[smi] #[smi]
pub fn op_fs_open_sync<P>( pub fn op_fs_open_sync<P>(
state: &mut OpState, state: &mut OpState,
@ -215,7 +215,7 @@ where
Ok(rid) Ok(rid)
} }
#[op2(async)] #[op2(async, stack_trace)]
#[smi] #[smi]
pub async fn op_fs_open_async<P>( pub async fn op_fs_open_async<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
@ -243,7 +243,7 @@ where
Ok(rid) Ok(rid)
} }
#[op2] #[op2(stack_trace)]
pub fn op_fs_mkdir_sync<P>( pub fn op_fs_mkdir_sync<P>(
state: &mut OpState, state: &mut OpState,
#[string] path: String, #[string] path: String,
@ -266,7 +266,7 @@ where
Ok(()) Ok(())
} }
#[op2(async)] #[op2(async, stack_trace)]
pub async fn op_fs_mkdir_async<P>( pub async fn op_fs_mkdir_async<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[string] path: String, #[string] path: String,
@ -291,7 +291,7 @@ where
Ok(()) Ok(())
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_fs_chmod_sync<P>( pub fn op_fs_chmod_sync<P>(
state: &mut OpState, state: &mut OpState,
#[string] path: String, #[string] path: String,
@ -308,7 +308,7 @@ where
Ok(()) Ok(())
} }
#[op2(async)] #[op2(async, stack_trace)]
pub async fn op_fs_chmod_async<P>( pub async fn op_fs_chmod_async<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[string] path: String, #[string] path: String,
@ -328,7 +328,7 @@ where
Ok(()) Ok(())
} }
#[op2] #[op2(stack_trace)]
pub fn op_fs_chown_sync<P>( pub fn op_fs_chown_sync<P>(
state: &mut OpState, state: &mut OpState,
#[string] path: String, #[string] path: String,
@ -347,7 +347,7 @@ where
Ok(()) Ok(())
} }
#[op2(async)] #[op2(async, stack_trace)]
pub async fn op_fs_chown_async<P>( pub async fn op_fs_chown_async<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[string] path: String, #[string] path: String,
@ -368,7 +368,7 @@ where
Ok(()) Ok(())
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_fs_remove_sync<P>( pub fn op_fs_remove_sync<P>(
state: &mut OpState, state: &mut OpState,
#[string] path: &str, #[string] path: &str,
@ -388,7 +388,7 @@ where
Ok(()) Ok(())
} }
#[op2(async)] #[op2(async, stack_trace)]
pub async fn op_fs_remove_async<P>( pub async fn op_fs_remove_async<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[string] path: String, #[string] path: String,
@ -419,7 +419,7 @@ where
Ok(()) Ok(())
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_fs_copy_file_sync<P>( pub fn op_fs_copy_file_sync<P>(
state: &mut OpState, state: &mut OpState,
#[string] from: &str, #[string] from: &str,
@ -439,7 +439,7 @@ where
Ok(()) Ok(())
} }
#[op2(async)] #[op2(async, stack_trace)]
pub async fn op_fs_copy_file_async<P>( pub async fn op_fs_copy_file_async<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[string] from: String, #[string] from: String,
@ -463,7 +463,7 @@ where
Ok(()) Ok(())
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_fs_stat_sync<P>( pub fn op_fs_stat_sync<P>(
state: &mut OpState, state: &mut OpState,
#[string] path: String, #[string] path: String,
@ -482,7 +482,7 @@ where
Ok(()) Ok(())
} }
#[op2(async)] #[op2(async, stack_trace)]
#[serde] #[serde]
pub async fn op_fs_stat_async<P>( pub async fn op_fs_stat_async<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
@ -504,7 +504,7 @@ where
Ok(SerializableStat::from(stat)) Ok(SerializableStat::from(stat))
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_fs_lstat_sync<P>( pub fn op_fs_lstat_sync<P>(
state: &mut OpState, state: &mut OpState,
#[string] path: String, #[string] path: String,
@ -523,7 +523,7 @@ where
Ok(()) Ok(())
} }
#[op2(async)] #[op2(async, stack_trace)]
#[serde] #[serde]
pub async fn op_fs_lstat_async<P>( pub async fn op_fs_lstat_async<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
@ -545,7 +545,7 @@ where
Ok(SerializableStat::from(stat)) Ok(SerializableStat::from(stat))
} }
#[op2] #[op2(stack_trace)]
#[string] #[string]
pub fn op_fs_realpath_sync<P>( pub fn op_fs_realpath_sync<P>(
state: &mut OpState, state: &mut OpState,
@ -568,7 +568,7 @@ where
Ok(path_string) Ok(path_string)
} }
#[op2(async)] #[op2(async, stack_trace)]
#[string] #[string]
pub async fn op_fs_realpath_async<P>( pub async fn op_fs_realpath_async<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
@ -596,7 +596,7 @@ where
Ok(path_string) Ok(path_string)
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
pub fn op_fs_read_dir_sync<P>( pub fn op_fs_read_dir_sync<P>(
state: &mut OpState, state: &mut OpState,
@ -615,7 +615,7 @@ where
Ok(entries) Ok(entries)
} }
#[op2(async)] #[op2(async, stack_trace)]
#[serde] #[serde]
pub async fn op_fs_read_dir_async<P>( pub async fn op_fs_read_dir_async<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
@ -640,7 +640,7 @@ where
Ok(entries) Ok(entries)
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_fs_rename_sync<P>( pub fn op_fs_rename_sync<P>(
state: &mut OpState, state: &mut OpState,
#[string] oldpath: String, #[string] oldpath: String,
@ -661,7 +661,7 @@ where
Ok(()) Ok(())
} }
#[op2(async)] #[op2(async, stack_trace)]
pub async fn op_fs_rename_async<P>( pub async fn op_fs_rename_async<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[string] oldpath: String, #[string] oldpath: String,
@ -686,7 +686,7 @@ where
Ok(()) Ok(())
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_fs_link_sync<P>( pub fn op_fs_link_sync<P>(
state: &mut OpState, state: &mut OpState,
#[string] oldpath: &str, #[string] oldpath: &str,
@ -708,7 +708,7 @@ where
Ok(()) Ok(())
} }
#[op2(async)] #[op2(async, stack_trace)]
pub async fn op_fs_link_async<P>( pub async fn op_fs_link_async<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[string] oldpath: String, #[string] oldpath: String,
@ -734,7 +734,7 @@ where
Ok(()) Ok(())
} }
#[op2] #[op2(stack_trace)]
pub fn op_fs_symlink_sync<P>( pub fn op_fs_symlink_sync<P>(
state: &mut OpState, state: &mut OpState,
#[string] oldpath: &str, #[string] oldpath: &str,
@ -758,7 +758,7 @@ where
Ok(()) Ok(())
} }
#[op2(async)] #[op2(async, stack_trace)]
pub async fn op_fs_symlink_async<P>( pub async fn op_fs_symlink_async<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[string] oldpath: String, #[string] oldpath: String,
@ -786,7 +786,7 @@ where
Ok(()) Ok(())
} }
#[op2] #[op2(stack_trace)]
#[string] #[string]
pub fn op_fs_read_link_sync<P>( pub fn op_fs_read_link_sync<P>(
state: &mut OpState, state: &mut OpState,
@ -806,7 +806,7 @@ where
Ok(target_string) Ok(target_string)
} }
#[op2(async)] #[op2(async, stack_trace)]
#[string] #[string]
pub async fn op_fs_read_link_async<P>( pub async fn op_fs_read_link_async<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
@ -831,7 +831,7 @@ where
Ok(target_string) Ok(target_string)
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_fs_truncate_sync<P>( pub fn op_fs_truncate_sync<P>(
state: &mut OpState, state: &mut OpState,
#[string] path: &str, #[string] path: &str,
@ -851,7 +851,7 @@ where
Ok(()) Ok(())
} }
#[op2(async)] #[op2(async, stack_trace)]
pub async fn op_fs_truncate_async<P>( pub async fn op_fs_truncate_async<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[string] path: String, #[string] path: String,
@ -875,7 +875,7 @@ where
Ok(()) Ok(())
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_fs_utime_sync<P>( pub fn op_fs_utime_sync<P>(
state: &mut OpState, state: &mut OpState,
#[string] path: &str, #[string] path: &str,
@ -896,7 +896,7 @@ where
Ok(()) Ok(())
} }
#[op2(async)] #[op2(async, stack_trace)]
pub async fn op_fs_utime_async<P>( pub async fn op_fs_utime_async<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[string] path: String, #[string] path: String,
@ -927,7 +927,7 @@ where
Ok(()) Ok(())
} }
#[op2] #[op2(stack_trace)]
#[string] #[string]
pub fn op_fs_make_temp_dir_sync<P>( pub fn op_fs_make_temp_dir_sync<P>(
state: &mut OpState, state: &mut OpState,
@ -969,7 +969,7 @@ where
.context("tmpdir") .context("tmpdir")
} }
#[op2(async)] #[op2(async, stack_trace)]
#[string] #[string]
pub async fn op_fs_make_temp_dir_async<P>( pub async fn op_fs_make_temp_dir_async<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
@ -1015,7 +1015,7 @@ where
.context("tmpdir") .context("tmpdir")
} }
#[op2] #[op2(stack_trace)]
#[string] #[string]
pub fn op_fs_make_temp_file_sync<P>( pub fn op_fs_make_temp_file_sync<P>(
state: &mut OpState, state: &mut OpState,
@ -1063,7 +1063,7 @@ where
.context("tmpfile") .context("tmpfile")
} }
#[op2(async)] #[op2(async, stack_trace)]
#[string] #[string]
pub async fn op_fs_make_temp_file_async<P>( pub async fn op_fs_make_temp_file_async<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
@ -1235,7 +1235,7 @@ fn tmp_name(
Ok(path) Ok(path)
} }
#[op2] #[op2(stack_trace)]
pub fn op_fs_write_file_sync<P>( pub fn op_fs_write_file_sync<P>(
state: &mut OpState, state: &mut OpState,
#[string] path: String, #[string] path: String,
@ -1261,7 +1261,7 @@ where
Ok(()) Ok(())
} }
#[op2(async)] #[op2(async, stack_trace)]
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub async fn op_fs_write_file_async<P>( pub async fn op_fs_write_file_async<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
@ -1315,7 +1315,7 @@ where
Ok(()) Ok(())
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
pub fn op_fs_read_file_sync<P>( pub fn op_fs_read_file_sync<P>(
state: &mut OpState, state: &mut OpState,
@ -1336,7 +1336,7 @@ where
Ok(buf.into()) Ok(buf.into())
} }
#[op2(async)] #[op2(async, stack_trace)]
#[serde] #[serde]
pub async fn op_fs_read_file_async<P>( pub async fn op_fs_read_file_async<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
@ -1378,7 +1378,7 @@ where
Ok(buf.into()) Ok(buf.into())
} }
#[op2] #[op2(stack_trace)]
#[string] #[string]
pub fn op_fs_read_file_text_sync<P>( pub fn op_fs_read_file_text_sync<P>(
state: &mut OpState, state: &mut OpState,
@ -1399,7 +1399,7 @@ where
Ok(str) Ok(str)
} }
#[op2(async)] #[op2(async, stack_trace)]
#[string] #[string]
pub async fn op_fs_read_file_text_async<P>( pub async fn op_fs_read_file_text_async<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_http" name = "deno_http"
version = "0.175.0" version = "0.176.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_io" name = "deno_io"
version = "0.87.0" version = "0.88.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_kv" name = "deno_kv"
version = "0.85.0" version = "0.86.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -178,7 +178,7 @@ pub enum KvErrorKind {
InvalidRange, InvalidRange,
} }
#[op2(async)] #[op2(async, stack_trace)]
#[smi] #[smi]
async fn op_kv_database_open<DBH>( async fn op_kv_database_open<DBH>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_napi" name = "deno_napi"
version = "0.108.0" version = "0.109.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -530,7 +530,7 @@ static NAPI_LOADED_MODULES: std::sync::LazyLock<
RwLock<HashMap<PathBuf, NapiModuleHandle>>, RwLock<HashMap<PathBuf, NapiModuleHandle>>,
> = std::sync::LazyLock::new(|| RwLock::new(HashMap::new())); > = std::sync::LazyLock::new(|| RwLock::new(HashMap::new()));
#[op2(reentrant)] #[op2(reentrant, stack_trace)]
fn op_napi_open<NP, 'scope>( fn op_napi_open<NP, 'scope>(
scope: &mut v8::HandleScope<'scope>, scope: &mut v8::HandleScope<'scope>,
isolate: *mut v8::Isolate, isolate: *mut v8::Isolate,

View file

@ -2,7 +2,7 @@
[package] [package]
name = "napi_sym" name = "napi_sym"
version = "0.107.0" version = "0.108.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_net" name = "deno_net"
version = "0.169.0" version = "0.170.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -182,7 +182,7 @@ pub async fn op_net_recv_udp(
Ok((nread, IpAddr::from(remote_addr))) Ok((nread, IpAddr::from(remote_addr)))
} }
#[op2(async)] #[op2(async, stack_trace)]
#[number] #[number]
pub async fn op_net_send_udp<NP>( pub async fn op_net_send_udp<NP>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
@ -343,7 +343,7 @@ pub async fn op_net_set_multi_ttl_udp(
Ok(()) Ok(())
} }
#[op2(async)] #[op2(async, stack_trace)]
#[serde] #[serde]
pub async fn op_net_connect_tcp<NP>( pub async fn op_net_connect_tcp<NP>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
@ -401,7 +401,7 @@ impl Resource for UdpSocketResource {
} }
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
pub fn op_net_listen_tcp<NP>( pub fn op_net_listen_tcp<NP>(
state: &mut OpState, state: &mut OpState,
@ -501,7 +501,7 @@ where
Ok((rid, IpAddr::from(local_addr))) Ok((rid, IpAddr::from(local_addr)))
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
pub fn op_net_listen_udp<NP>( pub fn op_net_listen_udp<NP>(
state: &mut OpState, state: &mut OpState,
@ -516,7 +516,7 @@ where
net_listen_udp::<NP>(state, addr, reuse_address, loopback) net_listen_udp::<NP>(state, addr, reuse_address, loopback)
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
pub fn op_node_unstable_net_listen_udp<NP>( pub fn op_node_unstable_net_listen_udp<NP>(
state: &mut OpState, state: &mut OpState,
@ -601,7 +601,7 @@ pub struct NameServer {
port: u16, port: u16,
} }
#[op2(async)] #[op2(async, stack_trace)]
#[serde] #[serde]
pub async fn op_dns_resolve<NP>( pub async fn op_dns_resolve<NP>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,

View file

@ -251,7 +251,7 @@ pub fn op_tls_cert_resolver_resolve_error(
lookup.resolve(sni, Err(error)) lookup.resolve(sni, Err(error))
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
pub fn op_tls_start<NP>( pub fn op_tls_start<NP>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
@ -340,7 +340,7 @@ where
Ok((rid, IpAddr::from(local_addr), IpAddr::from(remote_addr))) Ok((rid, IpAddr::from(local_addr), IpAddr::from(remote_addr)))
} }
#[op2(async)] #[op2(async, stack_trace)]
#[serde] #[serde]
pub async fn op_net_connect_tls<NP>( pub async fn op_net_connect_tls<NP>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
@ -445,7 +445,7 @@ pub struct ListenTlsArgs {
load_balanced: bool, load_balanced: bool,
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
pub fn op_net_listen_tls<NP>( pub fn op_net_listen_tls<NP>(
state: &mut OpState, state: &mut OpState,

View file

@ -85,7 +85,7 @@ pub async fn op_net_accept_unix(
Ok((rid, local_addr_path, remote_addr_path)) Ok((rid, local_addr_path, remote_addr_path))
} }
#[op2(async)] #[op2(async, stack_trace)]
#[serde] #[serde]
pub async fn op_net_connect_unix<NP>( pub async fn op_net_connect_unix<NP>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
@ -118,7 +118,7 @@ where
Ok((rid, local_addr_path, remote_addr_path)) Ok((rid, local_addr_path, remote_addr_path))
} }
#[op2(async)] #[op2(async, stack_trace)]
#[serde] #[serde]
pub async fn op_net_recv_unixpacket( pub async fn op_net_recv_unixpacket(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
@ -140,7 +140,7 @@ pub async fn op_net_recv_unixpacket(
Ok((nread, path)) Ok((nread, path))
} }
#[op2(async)] #[op2(async, stack_trace)]
#[number] #[number]
pub async fn op_net_send_unixpacket<NP>( pub async fn op_net_send_unixpacket<NP>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
@ -171,7 +171,7 @@ where
Ok(nwritten) Ok(nwritten)
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
pub fn op_net_listen_unix<NP>( pub fn op_net_listen_unix<NP>(
state: &mut OpState, state: &mut OpState,
@ -222,7 +222,7 @@ where
Ok((rid, pathname)) Ok((rid, pathname))
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
pub fn op_net_listen_unixpacket<NP>( pub fn op_net_listen_unixpacket<NP>(
state: &mut OpState, state: &mut OpState,
@ -235,7 +235,7 @@ where
net_listen_unixpacket::<NP>(state, path) net_listen_unixpacket::<NP>(state, path)
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
pub fn op_node_unstable_net_listen_unixpacket<NP>( pub fn op_node_unstable_net_listen_unixpacket<NP>(
state: &mut OpState, state: &mut OpState,

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_node" name = "deno_node"
version = "0.114.0" version = "0.115.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -26,7 +26,7 @@ pub enum FsError {
Fs(#[from] deno_io::fs::FsError), Fs(#[from] deno_io::fs::FsError),
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_node_fs_exists_sync<P>( pub fn op_node_fs_exists_sync<P>(
state: &mut OpState, state: &mut OpState,
#[string] path: String, #[string] path: String,
@ -41,7 +41,7 @@ where
Ok(fs.exists_sync(&path)) Ok(fs.exists_sync(&path))
} }
#[op2(async)] #[op2(async, stack_trace)]
pub async fn op_node_fs_exists<P>( pub async fn op_node_fs_exists<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[string] path: String, #[string] path: String,
@ -60,7 +60,7 @@ where
Ok(fs.exists_async(path).await?) Ok(fs.exists_async(path).await?)
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_node_cp_sync<P>( pub fn op_node_cp_sync<P>(
state: &mut OpState, state: &mut OpState,
#[string] path: &str, #[string] path: &str,
@ -81,7 +81,7 @@ where
Ok(()) Ok(())
} }
#[op2(async)] #[op2(async, stack_trace)]
pub async fn op_node_cp<P>( pub async fn op_node_cp<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[string] path: String, #[string] path: String,
@ -117,7 +117,7 @@ pub struct StatFs {
pub ffree: u64, pub ffree: u64,
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
pub fn op_node_statfs<P>( pub fn op_node_statfs<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
@ -258,7 +258,7 @@ where
} }
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_node_lutimes_sync<P>( pub fn op_node_lutimes_sync<P>(
state: &mut OpState, state: &mut OpState,
#[string] path: &str, #[string] path: &str,
@ -279,7 +279,7 @@ where
Ok(()) Ok(())
} }
#[op2(async)] #[op2(async, stack_trace)]
pub async fn op_node_lutimes<P>( pub async fn op_node_lutimes<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[string] path: String, #[string] path: String,
@ -305,7 +305,7 @@ where
Ok(()) Ok(())
} }
#[op2] #[op2(stack_trace)]
pub fn op_node_lchown_sync<P>( pub fn op_node_lchown_sync<P>(
state: &mut OpState, state: &mut OpState,
#[string] path: String, #[string] path: String,
@ -323,7 +323,7 @@ where
Ok(()) Ok(())
} }
#[op2(async)] #[op2(async, stack_trace)]
pub async fn op_node_lchown<P>( pub async fn op_node_lchown<P>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[string] path: String, #[string] path: String,

View file

@ -49,7 +49,7 @@ use std::cmp::min;
use tokio::io::AsyncReadExt; use tokio::io::AsyncReadExt;
use tokio::io::AsyncWriteExt; use tokio::io::AsyncWriteExt;
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
pub fn op_node_http_request<P>( pub fn op_node_http_request<P>(
state: &mut OpState, state: &mut OpState,

View file

@ -20,7 +20,7 @@ pub fn op_inspector_enabled() -> bool {
false false
} }
#[op2] #[op2(stack_trace)]
pub fn op_inspector_open<P>( pub fn op_inspector_open<P>(
_state: &mut OpState, _state: &mut OpState,
_port: Option<u16>, _port: Option<u16>,
@ -85,7 +85,7 @@ struct JSInspectorSession {
impl GarbageCollected for JSInspectorSession {} impl GarbageCollected for JSInspectorSession {}
#[op2] #[op2(stack_trace)]
#[cppgc] #[cppgc]
pub fn op_inspector_connect<'s, P>( pub fn op_inspector_connect<'s, P>(
isolate: *mut v8::Isolate, isolate: *mut v8::Isolate,

View file

@ -21,7 +21,7 @@ pub enum OsError {
FailedToGetUserInfo(#[source] std::io::Error), FailedToGetUserInfo(#[source] std::io::Error),
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_node_os_get_priority<P>( pub fn op_node_os_get_priority<P>(
state: &mut OpState, state: &mut OpState,
pid: u32, pid: u32,
@ -37,7 +37,7 @@ where
priority::get_priority(pid).map_err(OsError::Priority) priority::get_priority(pid).map_err(OsError::Priority)
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_node_os_set_priority<P>( pub fn op_node_os_set_priority<P>(
state: &mut OpState, state: &mut OpState,
pid: u32, pid: u32,
@ -193,7 +193,7 @@ fn get_user_info(_uid: u32) -> Result<UserInfo, OsError> {
}) })
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
pub fn op_node_os_user_info<P>( pub fn op_node_os_user_info<P>(
state: &mut OpState, state: &mut OpState,
@ -212,7 +212,7 @@ where
get_user_info(uid) get_user_info(uid)
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_geteuid<P>( pub fn op_geteuid<P>(
state: &mut OpState, state: &mut OpState,
) -> Result<u32, deno_core::error::AnyError> ) -> Result<u32, deno_core::error::AnyError>
@ -233,7 +233,7 @@ where
Ok(euid) Ok(euid)
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_getegid<P>( pub fn op_getegid<P>(
state: &mut OpState, state: &mut OpState,
) -> Result<u32, deno_core::error::AnyError> ) -> Result<u32, deno_core::error::AnyError>
@ -254,7 +254,7 @@ where
Ok(egid) Ok(egid)
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
pub fn op_cpus<P>(state: &mut OpState) -> Result<Vec<cpus::CpuInfo>, OsError> pub fn op_cpus<P>(state: &mut OpState) -> Result<Vec<cpus::CpuInfo>, OsError>
where where
@ -268,7 +268,7 @@ where
cpus::cpu_info().ok_or(OsError::FailedToGetCpuInfo) cpus::cpu_info().ok_or(OsError::FailedToGetCpuInfo)
} }
#[op2] #[op2(stack_trace)]
#[string] #[string]
pub fn op_homedir<P>( pub fn op_homedir<P>(
state: &mut OpState, state: &mut OpState,

View file

@ -45,7 +45,7 @@ fn kill(pid: i32, _sig: i32) -> i32 {
} }
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_node_process_kill( pub fn op_node_process_kill(
state: &mut OpState, state: &mut OpState,
#[smi] pid: i32, #[smi] pid: i32,

View file

@ -125,7 +125,7 @@ pub fn op_require_init_paths() -> Vec<String> {
vec![] vec![]
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
pub fn op_require_node_module_paths<P>( pub fn op_require_node_module_paths<P>(
state: &mut OpState, state: &mut OpState,
@ -295,7 +295,7 @@ pub fn op_require_path_is_absolute(#[string] p: String) -> bool {
PathBuf::from(p).is_absolute() PathBuf::from(p).is_absolute()
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_require_stat<P>( pub fn op_require_stat<P>(
state: &mut OpState, state: &mut OpState,
#[string] path: String, #[string] path: String,
@ -317,7 +317,7 @@ where
Ok(-1) Ok(-1)
} }
#[op2] #[op2(stack_trace)]
#[string] #[string]
pub fn op_require_real_path<P>( pub fn op_require_real_path<P>(
state: &mut OpState, state: &mut OpState,
@ -381,7 +381,7 @@ pub fn op_require_path_basename(
} }
} }
#[op2] #[op2(stack_trace)]
#[string] #[string]
pub fn op_require_try_self_parent_path<P>( pub fn op_require_try_self_parent_path<P>(
state: &mut OpState, state: &mut OpState,
@ -412,7 +412,7 @@ where
Ok(None) Ok(None)
} }
#[op2] #[op2(stack_trace)]
#[string] #[string]
pub fn op_require_try_self<P>( pub fn op_require_try_self<P>(
state: &mut OpState, state: &mut OpState,
@ -476,7 +476,7 @@ where
} }
} }
#[op2] #[op2(stack_trace)]
#[string] #[string]
pub fn op_require_read_file<P>( pub fn op_require_read_file<P>(
state: &mut OpState, state: &mut OpState,
@ -507,7 +507,7 @@ pub fn op_require_as_file_path(#[string] file_or_url: String) -> String {
file_or_url file_or_url
} }
#[op2] #[op2(stack_trace)]
#[string] #[string]
pub fn op_require_resolve_exports<P>( pub fn op_require_resolve_exports<P>(
state: &mut OpState, state: &mut OpState,
@ -583,7 +583,7 @@ pub fn op_require_is_maybe_cjs(
loader.is_maybe_cjs(&url) loader.is_maybe_cjs(&url)
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
pub fn op_require_read_package_scope<P>( pub fn op_require_read_package_scope<P>(
state: &mut OpState, state: &mut OpState,
@ -604,7 +604,7 @@ where
.flatten() .flatten()
} }
#[op2] #[op2(stack_trace)]
#[string] #[string]
pub fn op_require_package_imports_resolve<P>( pub fn op_require_package_imports_resolve<P>(
state: &mut OpState, state: &mut OpState,

View file

@ -45,7 +45,7 @@ pub enum WorkerThreadsFilenameError {
} }
// todo(dsherret): we should remove this and do all this work inside op_create_worker // todo(dsherret): we should remove this and do all this work inside op_create_worker
#[op2] #[op2(stack_trace)]
#[string] #[string]
pub fn op_worker_threads_filename<P>( pub fn op_worker_threads_filename<P>(
state: &mut OpState, state: &mut OpState,

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_tls" name = "deno_tls"
version = "0.164.0" version = "0.165.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_url" name = "deno_url"
version = "0.177.0" version = "0.178.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_web" name = "deno_web"
version = "0.208.0" version = "0.209.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_webgpu" name = "deno_webgpu"
version = "0.144.0" version = "0.145.0"
authors = ["the Deno authors"] authors = ["the Deno authors"]
edition.workspace = true edition.workspace = true
license = "MIT" license = "MIT"

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_webidl" name = "deno_webidl"
version = "0.177.0" version = "0.178.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_websocket" name = "deno_websocket"
version = "0.182.0" version = "0.183.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -148,7 +148,7 @@ impl Resource for WsCancelResource {
// This op is needed because creating a WS instance in JavaScript is a sync // This op is needed because creating a WS instance in JavaScript is a sync
// operation and should throw error when permissions are not fulfilled, // operation and should throw error when permissions are not fulfilled,
// but actual op that connects WS is async. // but actual op that connects WS is async.
#[op2] #[op2(stack_trace)]
#[smi] #[smi]
pub fn op_ws_check_permission_and_cancel_handle<WP>( pub fn op_ws_check_permission_and_cancel_handle<WP>(
state: &mut OpState, state: &mut OpState,
@ -443,7 +443,7 @@ fn populate_common_request_headers(
Ok(request) Ok(request)
} }
#[op2(async)] #[op2(async, stack_trace)]
#[serde] #[serde]
pub async fn op_ws_create<WP>( pub async fn op_ws_create<WP>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_webstorage" name = "deno_webstorage"
version = "0.172.0" version = "0.173.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_resolver" name = "deno_resolver"
version = "0.9.0" version = "0.10.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true
@ -25,6 +25,7 @@ deno_package_json.features = ["sync"]
deno_path_util.workspace = true deno_path_util.workspace = true
deno_semver.workspace = true deno_semver.workspace = true
node_resolver.workspace = true node_resolver.workspace = true
node_resolver.features = ["sync"]
thiserror.workspace = true thiserror.workspace = true
url.workspace = true url.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "node_resolver" name = "node_resolver"
version = "0.16.0" version = "0.17.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_runtime" name = "deno_runtime"
version = "0.186.0" version = "0.187.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -162,7 +162,7 @@ fn start_watcher(
Ok(()) Ok(())
} }
#[op2] #[op2(stack_trace)]
#[smi] #[smi]
fn op_fs_events_open( fn op_fs_events_open(
state: &mut OpState, state: &mut OpState,

View file

@ -87,7 +87,7 @@ pub enum OsError {
Io(#[from] std::io::Error), Io(#[from] std::io::Error),
} }
#[op2] #[op2(stack_trace)]
#[string] #[string]
fn op_exec_path(state: &mut OpState) -> Result<String, OsError> { fn op_exec_path(state: &mut OpState) -> Result<String, OsError> {
let current_exe = env::current_exe().unwrap(); 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) .map_err(OsError::InvalidUtf8)
} }
#[op2(fast)] #[op2(fast, stack_trace)]
fn op_set_env( fn op_set_env(
state: &mut OpState, state: &mut OpState,
#[string] key: &str, #[string] key: &str,
@ -123,7 +123,7 @@ fn op_set_env(
Ok(()) Ok(())
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
fn op_env( fn op_env(
state: &mut OpState, state: &mut OpState,
@ -132,7 +132,7 @@ fn op_env(
Ok(env::vars().collect()) Ok(env::vars().collect())
} }
#[op2] #[op2(stack_trace)]
#[string] #[string]
fn op_get_env( fn op_get_env(
state: &mut OpState, state: &mut OpState,
@ -159,7 +159,7 @@ fn op_get_env(
Ok(r) Ok(r)
} }
#[op2(fast)] #[op2(fast, stack_trace)]
fn op_delete_env( fn op_delete_env(
state: &mut OpState, state: &mut OpState,
#[string] key: String, #[string] key: String,
@ -189,7 +189,7 @@ fn op_exit(state: &mut OpState) {
crate::exit(code) crate::exit(code)
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
fn op_loadavg( fn op_loadavg(
state: &mut OpState, state: &mut OpState,
@ -200,7 +200,7 @@ fn op_loadavg(
Ok(sys_info::loadavg()) Ok(sys_info::loadavg())
} }
#[op2] #[op2(stack_trace, stack_trace)]
#[string] #[string]
fn op_hostname( fn op_hostname(
state: &mut OpState, state: &mut OpState,
@ -211,7 +211,7 @@ fn op_hostname(
Ok(sys_info::hostname()) Ok(sys_info::hostname())
} }
#[op2] #[op2(stack_trace)]
#[string] #[string]
fn op_os_release( fn op_os_release(
state: &mut OpState, state: &mut OpState,
@ -222,7 +222,7 @@ fn op_os_release(
Ok(sys_info::os_release()) Ok(sys_info::os_release())
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
fn op_network_interfaces( fn op_network_interfaces(
state: &mut OpState, state: &mut OpState,
@ -274,7 +274,7 @@ impl From<netif::Interface> for NetworkInterface {
} }
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
fn op_system_memory_info( fn op_system_memory_info(
state: &mut OpState, state: &mut OpState,
@ -286,7 +286,7 @@ fn op_system_memory_info(
} }
#[cfg(not(windows))] #[cfg(not(windows))]
#[op2] #[op2(stack_trace)]
#[smi] #[smi]
fn op_gid( fn op_gid(
state: &mut OpState, state: &mut OpState,
@ -302,7 +302,7 @@ fn op_gid(
} }
#[cfg(windows)] #[cfg(windows)]
#[op2] #[op2(stack_trace)]
#[smi] #[smi]
fn op_gid( fn op_gid(
state: &mut OpState, state: &mut OpState,
@ -314,7 +314,7 @@ fn op_gid(
} }
#[cfg(not(windows))] #[cfg(not(windows))]
#[op2] #[op2(stack_trace)]
#[smi] #[smi]
fn op_uid( fn op_uid(
state: &mut OpState, state: &mut OpState,
@ -330,7 +330,7 @@ fn op_uid(
} }
#[cfg(windows)] #[cfg(windows)]
#[op2] #[op2(stack_trace)]
#[smi] #[smi]
fn op_uid( fn op_uid(
state: &mut OpState, state: &mut OpState,
@ -519,7 +519,7 @@ fn os_uptime(state: &mut OpState) -> Result<u64, deno_core::error::AnyError> {
Ok(sys_info::os_uptime()) Ok(sys_info::os_uptime())
} }
#[op2(fast)] #[op2(fast, stack_trace)]
#[number] #[number]
fn op_os_uptime( fn op_os_uptime(
state: &mut OpState, state: &mut OpState,

View file

@ -99,7 +99,7 @@ pub fn op_revoke_permission(
Ok(PermissionStatus::from(perm)) Ok(PermissionStatus::from(perm))
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
pub fn op_request_permission( pub fn op_request_permission(
state: &mut OpState, state: &mut OpState,

View file

@ -802,7 +802,7 @@ fn get_requires_allow_all_env_vars(env: &RunEnv) -> Vec<&str> {
found_envs found_envs
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
fn op_spawn_child( fn op_spawn_child(
state: &mut OpState, state: &mut OpState,
@ -844,7 +844,7 @@ async fn op_spawn_wait(
Ok(result) Ok(result)
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
fn op_spawn_sync( fn op_spawn_sync(
state: &mut OpState, state: &mut OpState,
@ -928,7 +928,7 @@ mod deprecated {
stderr_rid: Option<ResourceId>, stderr_rid: Option<ResourceId>,
} }
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
pub fn op_run( pub fn op_run(
state: &mut OpState, state: &mut OpState,
@ -1129,7 +1129,7 @@ mod deprecated {
} }
} }
#[op2(fast)] #[op2(fast, stack_trace)]
pub fn op_kill( pub fn op_kill(
state: &mut OpState, state: &mut OpState,
#[smi] pid: i32, #[smi] pid: i32,

View file

@ -133,7 +133,7 @@ pub enum CreateWorkerError {
} }
/// Create worker as the host /// Create worker as the host
#[op2] #[op2(stack_trace)]
#[serde] #[serde]
fn op_create_worker( fn op_create_worker(
state: &mut OpState, state: &mut OpState,

View file

@ -2,7 +2,7 @@
[package] [package]
name = "deno_permissions" name = "deno_permissions"
version = "0.37.0" version = "0.38.0"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View file

@ -294,7 +294,7 @@ impl UnitPermission {
/// A normalized environment variable name. On Windows this will /// A normalized environment variable name. On Windows this will
/// be uppercase and on other platforms it will stay as-is. /// be uppercase and on other platforms it will stay as-is.
#[derive(Clone, Eq, PartialEq, Hash, Debug)] #[derive(Clone, Eq, PartialEq, Hash, Debug)]
struct EnvVarName { pub struct EnvVarName {
inner: String, inner: String,
} }
@ -1114,15 +1114,37 @@ impl ImportDescriptor {
pub struct EnvDescriptorParseError; pub struct EnvDescriptorParseError;
#[derive(Clone, Eq, PartialEq, Hash, Debug)] #[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct EnvDescriptor(EnvVarName); pub enum EnvDescriptor {
Name(EnvVarName),
PrefixPattern(EnvVarName),
}
impl EnvDescriptor { impl EnvDescriptor {
pub fn new(env: impl AsRef<str>) -> Self { 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 AllowDesc = EnvDescriptor;
type DenyDesc = EnvDescriptor; type DenyDesc = EnvDescriptor;
@ -1131,19 +1153,45 @@ impl QueryDescriptor for EnvDescriptor {
} }
fn display_name(&self) -> Cow<str> { 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 { 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> { 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 { 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( fn check_in_permission(
@ -1156,19 +1204,79 @@ impl QueryDescriptor for EnvDescriptor {
} }
fn matches_allow(&self, other: &Self::AllowDesc) -> bool { 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 { 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 { 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 { 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 { 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 { 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 { pub fn query(&self, env: Option<&str>) -> PermissionState {
self.query_desc( self.query_desc(
env.map(EnvDescriptor::new).as_ref(), env.map(EnvQueryDescriptor::new).as_ref(),
AllowPartial::TreatAsPartialGranted, AllowPartial::TreatAsPartialGranted,
) )
} }
pub fn request(&mut self, env: Option<&str>) -> PermissionState { 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 { 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( pub fn check(
@ -1771,7 +1884,7 @@ impl UnaryPermission<EnvDescriptor> {
api_name: Option<&str>, api_name: Option<&str>,
) -> Result<(), PermissionDeniedError> { ) -> Result<(), PermissionDeniedError> {
skip_check_if_is_permission_fully_granted!(self); 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> { pub fn check_all(&mut self) -> Result<(), PermissionDeniedError> {
@ -1905,7 +2018,7 @@ pub struct Permissions {
pub read: UnaryPermission<ReadQueryDescriptor>, pub read: UnaryPermission<ReadQueryDescriptor>,
pub write: UnaryPermission<WriteQueryDescriptor>, pub write: UnaryPermission<WriteQueryDescriptor>,
pub net: UnaryPermission<NetDescriptor>, pub net: UnaryPermission<NetDescriptor>,
pub env: UnaryPermission<EnvDescriptor>, pub env: UnaryPermission<EnvQueryDescriptor>,
pub sys: UnaryPermission<SysDescriptor>, pub sys: UnaryPermission<SysDescriptor>,
pub run: UnaryPermission<RunQueryDescriptor>, pub run: UnaryPermission<RunQueryDescriptor>,
pub ffi: UnaryPermission<FfiQueryDescriptor>, pub ffi: UnaryPermission<FfiQueryDescriptor>,
@ -4564,6 +4677,56 @@ mod tests {
assert_eq!(perms.env.revoke(Some("HomE")), PermissionState::Prompt); 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] #[test]
fn test_check_partial_denied() { fn test_check_partial_denied() {
let parser = TestPermissionDescriptorParser; let parser = TestPermissionDescriptorParser;

View file

@ -1,5 +1,7 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // 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_core::parking_lot::Mutex;
use deno_terminal::colors; use deno_terminal::colors;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
@ -10,8 +12,6 @@ use std::io::StderrLock;
use std::io::StdinLock; use std::io::StdinLock;
use std::io::Write as IoWrite; use std::io::Write as IoWrite;
use crate::is_standalone;
/// Helper function to make control characters visible so users can see the underlying filename. /// Helper function to make control characters visible so users can see the underlying filename.
fn escape_control_characters(s: &str) -> std::borrow::Cow<str> { fn escape_control_characters(s: &str) -> std::borrow::Cow<str> {
if !s.contains(|c: char| c.is_ascii_control() || c.is_control()) { 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>>> = static MAYBE_AFTER_PROMPT_CALLBACK: Lazy<Mutex<Option<PromptCallback>>> =
Lazy::new(|| Mutex::new(None)); 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( pub fn permission_prompt(
message: &str, message: &str,
flag: &str, flag: &str,
@ -62,9 +69,10 @@ pub fn permission_prompt(
if let Some(before_callback) = MAYBE_BEFORE_PROMPT_CALLBACK.lock().as_mut() { if let Some(before_callback) = MAYBE_BEFORE_PROMPT_CALLBACK.lock().as_mut() {
before_callback(); before_callback();
} }
let stack = MAYBE_CURRENT_STACKTRACE.lock().take();
let r = PERMISSION_PROMPTER let r = PERMISSION_PROMPTER
.lock() .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() { if let Some(after_callback) = MAYBE_AFTER_PROMPT_CALLBACK.lock().as_mut() {
after_callback(); after_callback();
} }
@ -92,6 +100,7 @@ pub trait PermissionPrompter: Send + Sync {
name: &str, name: &str,
api_name: Option<&str>, api_name: Option<&str>,
is_unary: bool, is_unary: bool,
stack: Option<Vec<JsStackFrame>>,
) -> PromptResponse; ) -> PromptResponse;
} }
@ -298,6 +307,7 @@ impl PermissionPrompter for TtyPrompter {
name: &str, name: &str,
api_name: Option<&str>, api_name: Option<&str>,
is_unary: bool, is_unary: bool,
stack: Option<Vec<JsStackFrame>>,
) -> PromptResponse { ) -> PromptResponse {
if !std::io::stdin().is_terminal() || !std::io::stderr().is_terminal() { if !std::io::stdin().is_terminal() || !std::io::stderr().is_terminal() {
return PromptResponse::Deny; return PromptResponse::Deny;
@ -340,7 +350,7 @@ impl PermissionPrompter for TtyPrompter {
}; };
// output everything in one shot to make the tests more reliable // output everything in one shot to make the tests more reliable
{ let stack_lines_count = {
let mut output = String::new(); let mut output = String::new();
write!(&mut output, "┏ {PERMISSION_EMOJI} ").unwrap(); write!(&mut output, "┏ {PERMISSION_EMOJI} ").unwrap();
write!(&mut output, "{}", colors::bold("Deno requests ")).unwrap(); write!(&mut output, "{}", colors::bold("Deno requests ")).unwrap();
@ -354,6 +364,27 @@ impl PermissionPrompter for TtyPrompter {
) )
.unwrap(); .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!( let msg = format!(
"Learn more at: {}", "Learn more at: {}",
colors::cyan_with_underline(&format!( colors::cyan_with_underline(&format!(
@ -372,7 +403,9 @@ impl PermissionPrompter for TtyPrompter {
write!(&mut output, " {opts} > ").unwrap(); write!(&mut output, " {opts} > ").unwrap();
stderr_lock.write_all(output.as_bytes()).unwrap(); stderr_lock.write_all(output.as_bytes()).unwrap();
}
stack_lines_count
};
let value = loop { let value = loop {
// Clear stdin each time we loop around in case the user accidentally pasted // 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 { if result.is_err() || input.len() != 1 {
break PromptResponse::Deny; break PromptResponse::Deny;
}; };
let clear_n = if api_name.is_some() { 5 } else { 4 } + stack_lines_count;
match input.as_bytes()[0] as char { match input.as_bytes()[0] as char {
'y' | 'Y' => { 'y' | 'Y' => {
clear_n_lines( clear_n_lines(&mut stderr_lock, clear_n);
&mut stderr_lock,
if api_name.is_some() { 5 } else { 4 },
);
let msg = format!("Granted {message}."); let msg = format!("Granted {message}.");
writeln!(stderr_lock, "✅ {}", colors::bold(&msg)).unwrap(); writeln!(stderr_lock, "✅ {}", colors::bold(&msg)).unwrap();
break PromptResponse::Allow; break PromptResponse::Allow;
} }
'n' | 'N' | '\x1b' => { 'n' | 'N' | '\x1b' => {
clear_n_lines( clear_n_lines(&mut stderr_lock, clear_n);
&mut stderr_lock,
if api_name.is_some() { 5 } else { 4 },
);
let msg = format!("Denied {message}."); let msg = format!("Denied {message}.");
writeln!(stderr_lock, "❌ {}", colors::bold(&msg)).unwrap(); writeln!(stderr_lock, "❌ {}", colors::bold(&msg)).unwrap();
break PromptResponse::Deny; break PromptResponse::Deny;
} }
'A' if is_unary => { 'A' if is_unary => {
clear_n_lines( clear_n_lines(&mut stderr_lock, clear_n);
&mut stderr_lock,
if api_name.is_some() { 5 } else { 4 },
);
let msg = format!("Granted all {name} access."); let msg = format!("Granted all {name} access.");
writeln!(stderr_lock, "✅ {}", colors::bold(&msg)).unwrap(); writeln!(stderr_lock, "✅ {}", colors::bold(&msg)).unwrap();
break PromptResponse::AllowAll; break PromptResponse::AllowAll;
@ -475,6 +502,7 @@ pub mod tests {
_name: &str, _name: &str,
_api_name: Option<&str>, _api_name: Option<&str>,
_is_unary: bool, _is_unary: bool,
_stack: Option<Vec<JsStackFrame>>,
) -> PromptResponse { ) -> PromptResponse {
if STUB_PROMPT_VALUE.load(Ordering::SeqCst) { if STUB_PROMPT_VALUE.load(Ordering::SeqCst) {
PromptResponse::Allow PromptResponse::Allow

View file

@ -373,6 +373,7 @@ pub struct WebWorkerOptions {
pub strace_ops: Option<Vec<String>>, pub strace_ops: Option<Vec<String>>,
pub close_on_idle: bool, pub close_on_idle: bool,
pub maybe_worker_metadata: Option<WorkerMetadata>, pub maybe_worker_metadata: Option<WorkerMetadata>,
pub enable_stack_trace_arg_in_ops: bool,
} }
/// This struct is an implementation of `Worker` Web API /// This struct is an implementation of `Worker` Web API
@ -585,6 +586,13 @@ impl WebWorker {
validate_import_attributes_callback, validate_import_attributes_callback,
)), )),
import_assertions_support: deno_core::ImportAssertionsSupport::Error, 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() ..Default::default()
}); });

View file

@ -207,6 +207,7 @@ pub struct WorkerOptions {
pub cache_storage_dir: Option<std::path::PathBuf>, pub cache_storage_dir: Option<std::path::PathBuf>,
pub origin_storage_dir: Option<std::path::PathBuf>, pub origin_storage_dir: Option<std::path::PathBuf>,
pub stdio: Stdio, pub stdio: Stdio,
pub enable_stack_trace_arg_in_ops: bool,
} }
impl Default for WorkerOptions { impl Default for WorkerOptions {
@ -231,6 +232,7 @@ impl Default for WorkerOptions {
create_params: Default::default(), create_params: Default::default(),
bootstrap: Default::default(), bootstrap: Default::default(),
stdio: Default::default(), stdio: Default::default(),
enable_stack_trace_arg_in_ops: false,
} }
} }
} }
@ -544,6 +546,11 @@ impl MainWorker {
) as Box<dyn Fn(_, _, &_)>, ) 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() ..Default::default()
}); });

View file

@ -179,6 +179,7 @@ fn _090_run_permissions_request() {
console.expect(concat!( console.expect(concat!(
"┏ ⚠️ Deno requests run access to \"ls\".\r\n", "┏ ⚠️ Deno requests run access to \"ls\".\r\n",
"┠─ Requested by `Deno.permissions.request()` API.\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", "┠─ Learn more at: https://docs.deno.com/go/--allow-run\r\n",
"┠─ Run again with --allow-run to bypass this prompt.\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)", "┗ 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!( console.expect(concat!(
"┏ ⚠️ Deno requests run access to \"cat\".\r\n", "┏ ⚠️ Deno requests run access to \"cat\".\r\n",
"┠─ Requested by `Deno.permissions.request()` API.\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", "┠─ Learn more at: https://docs.deno.com/go/--allow-run\r\n",
"┠─ Run again with --allow-run to bypass this prompt.\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)", "┗ 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!( console.expect(concat!(
"┏ ⚠️ Deno requests run access to \"ls\".\r\n", "┏ ⚠️ Deno requests run access to \"ls\".\r\n",
"┠─ Requested by `Deno.permissions.request()` API.\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", "┠─ Learn more at: https://docs.deno.com/go/--allow-run\r\n",
"┠─ Run again with --allow-run to bypass this prompt.\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)", "┗ 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!( console.expect(concat!(
"┏ ⚠️ Deno requests run access to \"cat\".\r\n", "┏ ⚠️ Deno requests run access to \"cat\".\r\n",
"┠─ Requested by `Deno.permissions.request()` API.\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", "┠─ Learn more at: https://docs.deno.com/go/--allow-run\r\n",
"┠─ Run again with --allow-run to bypass this prompt.\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)", "┗ 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!( console.expect(concat!(
"┏ ⚠️ Deno requests run access to \"FOO\".\r\n", "┏ ⚠️ Deno requests run access to \"FOO\".\r\n",
"┠─ Requested by `Deno.permissions.request()` API.\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", "┠─ Learn more at: https://docs.deno.com/go/--allow-run\r\n",
"┠─ Run again with --allow-run to bypass this prompt.\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)", "┗ 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!( console.expect(concat!(
"┏ ⚠️ Deno requests read access to \"FOO\".\r\n", "┏ ⚠️ Deno requests read access to \"FOO\".\r\n",
"┠─ Requested by `Deno.permissions.request()` API.\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", "┠─ Learn more at: https://docs.deno.com/go/--allow-read\r\n",
"┠─ Run again with --allow-read to bypass this prompt.\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)", "┗ 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!( console.expect(concat!(
"┏ ⚠️ Deno requests write access to \"FOO\".\r\n", "┏ ⚠️ Deno requests write access to \"FOO\".\r\n",
"┠─ Requested by `Deno.permissions.request()` API.\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", "┠─ Learn more at: https://docs.deno.com/go/--allow-write\r\n",
"┠─ Run again with --allow-write to bypass this prompt.\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)", "┗ 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!( console.expect(concat!(
"┏ ⚠️ Deno requests net access to \"foo\".\r\n", "┏ ⚠️ Deno requests net access to \"foo\".\r\n",
"┠─ Requested by `Deno.permissions.request()` API.\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", "┠─ Learn more at: https://docs.deno.com/go/--allow-net\r\n",
"┠─ Run again with --allow-net to bypass this prompt.\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)", "┗ 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!( console.expect(concat!(
"┏ ⚠️ Deno requests env access to \"FOO\".\r\n", "┏ ⚠️ Deno requests env access to \"FOO\".\r\n",
"┠─ Requested by `Deno.permissions.request()` API.\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", "┠─ Learn more at: https://docs.deno.com/go/--allow-env\r\n",
"┠─ Run again with --allow-env to bypass this prompt.\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)", "┗ 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!( console.expect(concat!(
"┏ ⚠️ Deno requests sys access to \"loadavg\".\r\n", "┏ ⚠️ Deno requests sys access to \"loadavg\".\r\n",
"┠─ Requested by `Deno.permissions.request()` API.\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", "┠─ Learn more at: https://docs.deno.com/go/--allow-sys\r\n",
"┠─ Run again with --allow-sys to bypass this prompt.\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)", "┗ 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!( console.expect(concat!(
"┏ ⚠️ Deno requests ffi access to \"FOO\".\r\n", "┏ ⚠️ Deno requests ffi access to \"FOO\".\r\n",
"┠─ Requested by `Deno.permissions.request()` API.\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", "┠─ Learn more at: https://docs.deno.com/go/--allow-ffi\r\n",
"┠─ Run again with --allow-ffi to bypass this prompt.\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)", "┗ 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 // "env" permissions
console.expect(concat!( console.expect(concat!(
"┏ ⚠️ Deno requests env access to \"FOO\".\r\n", "┏ ⚠️ 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", "┠─ Learn more at: https://docs.deno.com/go/--allow-env\r\n",
"┠─ Run again with --allow-env to bypass this prompt.\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)", "┗ 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!( console.expect(concat!(
"┏ ⚠️ Deno requests sys access to \"loadavg\".\r\n", "┏ ⚠️ Deno requests sys access to \"loadavg\".\r\n",
"┠─ Requested by `Deno.loadavg()` API.\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", "┠─ Learn more at: https://docs.deno.com/go/--allow-sys\r\n",
"┠─ Run again with --allow-sys to bypass this prompt.\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)", "┗ 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!( console.expect(concat!(
"┏ ⚠️ Deno requests read access to <CWD>.\r\n", "┏ ⚠️ Deno requests read access to <CWD>.\r\n",
"┠─ Requested by `Deno.cwd()` API.\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", "┠─ Learn more at: https://docs.deno.com/go/--allow-read\r\n",
"┠─ Run again with --allow-read to bypass this prompt.\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)", "┗ 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!( console.expect(concat!(
"┏ ⚠️ Deno requests run access to \"FOO\".\r\n", "┏ ⚠️ Deno requests run access to \"FOO\".\r\n",
"┠─ Requested by `Deno.permissions.request()` API.\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", "┠─ Learn more at: https://docs.deno.com/go/--allow-run\r\n",
"┠─ Run again with --allow-run to bypass this prompt.\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)", "┗ 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", "prompt\r\n",
"┏ ⚠️ Deno requests read access to \"foo\".\r\n", "┏ ⚠️ Deno requests read access to \"foo\".\r\n",
"┠─ Requested by `Deno.permissions.request()` API.\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", "┠─ Learn more at: https://docs.deno.com/go/--allow-read\r\n",
"┠─ Run again with --allow-read to bypass this prompt.\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)", "┗ 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 { itest!(lock_write_fetch {
args: args:
"run --quiet --allow-import --allow-read --allow-write --allow-env --allow-run run/lock_write_fetch/main.ts", "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!( console.expect(concat!(
"┏ ⚠️ Deno requests read access to \"foo\".\r\n", "┏ ⚠️ Deno requests read access to \"foo\".\r\n",
"┠─ Requested by `Deno.permissions.request()` API.\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", "┠─ Learn more at: https://docs.deno.com/go/--allow-read\r\n",
"┠─ Run again with --allow-read to bypass this prompt.\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)", "┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)",
@ -1521,6 +1564,7 @@ mod permissions {
console.expect(concat!( console.expect(concat!(
"┏ ⚠️ Deno requests read access to \"bar\".\r\n", "┏ ⚠️ Deno requests read access to \"bar\".\r\n",
"┠─ Requested by `Deno.permissions.request()` API.\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", "┠─ Learn more at: https://docs.deno.com/go/--allow-read\r\n",
"┠─ Run again with --allow-read to bypass this prompt.\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)", "┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)",
@ -1542,6 +1586,7 @@ mod permissions {
console.expect(concat!( console.expect(concat!(
"┏ ⚠️ Deno requests read access to \"foo\".\r\n", "┏ ⚠️ Deno requests read access to \"foo\".\r\n",
"┠─ Requested by `Deno.permissions.request()` API.\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", "┠─ Learn more at: https://docs.deno.com/go/--allow-read\r\n",
"┠─ Run again with --allow-read to bypass this prompt.\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)", "┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)",
@ -1551,6 +1596,7 @@ mod permissions {
console.expect(concat!( console.expect(concat!(
"┏ ⚠️ Deno requests read access to \"bar\".\r\n", "┏ ⚠️ Deno requests read access to \"bar\".\r\n",
"┠─ Requested by `Deno.permissions.request()` API.\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", "┠─ Learn more at: https://docs.deno.com/go/--allow-read\r\n",
"┠─ Run again with --allow-read to bypass this prompt.\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)", "┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)",
@ -1572,6 +1618,7 @@ mod permissions {
console.expect(concat!( console.expect(concat!(
"┏ ⚠️ Deno requests read access.\r\n", "┏ ⚠️ Deno requests read access.\r\n",
"┠─ Requested by `Deno.permissions.request()` API.\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", "┠─ Learn more at: https://docs.deno.com/go/--allow-read\r\n",
"┠─ Run again with --allow-read to bypass this prompt.\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)", "┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)",
@ -1596,6 +1643,7 @@ mod permissions {
console.expect(concat!( console.expect(concat!(
"┏ ⚠️ Deno requests read access.\r\n", "┏ ⚠️ Deno requests read access.\r\n",
"┠─ Requested by `Deno.permissions.request()` API.\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", "┠─ Learn more at: https://docs.deno.com/go/--allow-read\r\n",
"┠─ Run again with --allow-read to bypass this prompt.\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)", "┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)",
@ -1673,6 +1721,7 @@ fn issue9750() {
console.expect(concat!( console.expect(concat!(
"┏ ⚠️ Deno requests env access.\r\n", "┏ ⚠️ Deno requests env access.\r\n",
"┠─ Requested by `Deno.permissions.request()` API.\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", "┠─ Learn more at: https://docs.deno.com/go/--allow-env\r\n",
"┠─ Run again with --allow-env to bypass this prompt.\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)", "┗ 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("Denied env access.");
console.expect(concat!( console.expect(concat!(
"┏ ⚠️ Deno requests env access to \"SECRET\".\r\n", "┏ ⚠️ 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", "┠─ Learn more at: https://docs.deno.com/go/--allow-env\r\n",
"┠─ Run again with --allow-env to bypass this prompt.\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)", "┗ 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.human_delay();
console.write_line_raw("y"); console.write_line_raw("y");
// We ensure that nothing gets written here between the permission prompt and this text, despire the delay // 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! // Back to spamming!
console.expect(malicious_output); console.expect(malicious_output);

View 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;
}

View file

@ -0,0 +1,8 @@
{
"exports": {
".": "./mod.ts"
},
"moduleGraph1": {
"/mod.ts": {}
}
}

View file

@ -4,6 +4,7 @@
"yanked": true "yanked": true
}, },
"1.0.0": {}, "1.0.0": {},
"0.2.0": {} "0.2.0": {},
"0.2.1": {}
} }
} }

View file

@ -0,0 +1 @@
export * from "jsr:@denotest/add@1";

View file

@ -0,0 +1,3 @@
{
"a": 1
}

View file

@ -0,0 +1 @@
export * from "jsr:@denotest/subtract@1";

View file

@ -0,0 +1,7 @@
{
"exports": {
"./add": "./add.ts",
"./subtract": "./subtract.ts",
"./data-json": "./data.json"
}
}

View file

@ -0,0 +1 @@
export * from "jsr:@denotest/add@1";

View file

@ -0,0 +1,3 @@
{
"a": 1
}

View file

@ -0,0 +1 @@
export * from "jsr:@denotest/subtract@1";

View file

@ -0,0 +1,7 @@
{
"exports": {
"./add": "./add.ts",
"./subtract": "./subtract.ts",
"./data-json": "./data.json"
}
}

View file

@ -1,5 +1,7 @@
{ {
"versions": { "versions": {
"1.0.0": {} "1.0.0": {},
"0.5.0": {},
"0.2.0": {}
} }
} }

View file

@ -0,0 +1,3 @@
export function sub(a: number, b: number): number {
return a - b;
}

View file

@ -0,0 +1,8 @@
{
"exports": {
".": "./mod.ts"
},
"moduleGraph1": {
"/mod.ts": {}
}
}

View file

@ -1,5 +1,7 @@
{ {
"latest": "1.0.0",
"versions": { "versions": {
"1.0.0": {} "1.0.0": {},
"0.2.0": {}
} }
} }

View file

@ -0,0 +1,5 @@
{
"name": "@denotest/has-patch-versions",
"version": "0.1.0"
}

View file

@ -0,0 +1,5 @@
{
"name": "@denotest/has-patch-versions",
"version": "0.1.1"
}

View file

@ -0,0 +1,4 @@
{
"name": "@denotest/has-patch-versions",
"version": "0.2.0"
}

View file

@ -0,0 +1,6 @@
{
"tempDir": true,
"args": "init --npm vite my-project",
"output": "init.out",
"exitCode": 1
}

View file

@ -0,0 +1 @@
You can initialize project manually by running deno run npm:create-vite my-project and applying desired permissions.

View file

@ -61,5 +61,10 @@
"file_path": "[WILDCARD]malformed.js", "file_path": "[WILDCARD]malformed.js",
"message": "Expected '{', got 'B' at [WILDCARD]malformed.js:4:16\n\n export class A B C\n ~" "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