diff --git a/.dprint.json b/.dprint.json index b9c2d1ebc1..bd1279fd4a 100644 --- a/.dprint.json +++ b/.dprint.json @@ -13,7 +13,7 @@ }, "exec": { "commands": [{ - "command": "rustfmt --config imports_granularity=item", + "command": "rustfmt --config imports_granularity=item --config group_imports=StdExternalCrate", "exts": ["rs"] }] }, diff --git a/.github/mtime_cache/action.js b/.github/mtime_cache/action.js index 72821749e3..1bf5b492fc 100644 --- a/.github/mtime_cache/action.js +++ b/.github/mtime_cache/action.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // This file contains the implementation of a Github Action. Github uses // Node.js v20.x to run actions, so this is Node code and not Deno code. diff --git a/.github/workflows/ci.generate.ts b/.github/workflows/ci.generate.ts index bc3f15380b..cd0f3a382b 100755 --- a/.github/workflows/ci.generate.ts +++ b/.github/workflows/ci.generate.ts @@ -1,11 +1,11 @@ #!/usr/bin/env -S deno run --allow-write=. --lock=./tools/deno.lock.json -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { stringify } from "jsr:@std/yaml@^0.221/stringify"; // Bump this number when you want to purge the cache. // Note: the tools/release/01_bump_crate_versions.ts script will update this version // automatically via regex, so ensure that this line maintains this format. -const cacheVersion = 32; +const cacheVersion = 36; const ubuntuX86Runner = "ubuntu-24.04"; const ubuntuX86XlRunner = "ubuntu-24.04-xl"; @@ -14,7 +14,7 @@ const windowsX86Runner = "windows-2022"; const windowsX86XlRunner = "windows-2022-xl"; const macosX86Runner = "macos-13"; const macosArmRunner = "macos-14"; -const selfHostedMacosArmRunner = "self-hosted"; +const selfHostedMacosArmRunner = "ghcr.io/cirruslabs/macos-runner:sonoma"; const Runners = { linuxX86: { @@ -41,8 +41,14 @@ const Runners = { macosArm: { os: "macos", arch: "aarch64", + runner: macosArmRunner, + }, + macosArmSelfHosted: { + os: "macos", + arch: "aarch64", + // Actually use self-hosted runner only in denoland/deno on `main` branch and for tags (release) builds. runner: - `\${{ github.repository == 'denoland/deno' && startsWith(github.ref, 'refs/tags/') && '${selfHostedMacosArmRunner}' || '${macosArmRunner}' }}`, + `\${{ github.repository == 'denoland/deno' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')) && '${selfHostedMacosArmRunner}' || '${macosArmRunner}' }}`, }, windowsX86: { os: "windows", @@ -360,7 +366,7 @@ const ci = { needs: ["pre_build"], if: "${{ needs.pre_build.outputs.skip_build != 'true' }}", "runs-on": "${{ matrix.runner }}", - "timeout-minutes": 180, + "timeout-minutes": 240, defaults: { run: { // GH actions does not fail fast by default on @@ -384,7 +390,7 @@ const ci = { job: "test", profile: "debug", }, { - ...Runners.macosArm, + ...Runners.macosArmSelfHosted, job: "test", profile: "release", skip_pr: true, @@ -486,7 +492,7 @@ const ci = { }, { name: "Cache Cargo home", - uses: "actions/cache@v4", + uses: "cirruslabs/cache@v4", with: { // See https://doc.rust-lang.org/cargo/guide/cargo-home.html#caching-the-cargo-home-in-ci // Note that with the new sparse registry format, we no longer have to cache a `.git` dir diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cc1aa89669..fd9aaaf741 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,7 +48,7 @@ jobs: - pre_build if: '${{ needs.pre_build.outputs.skip_build != ''true'' }}' runs-on: '${{ matrix.runner }}' - timeout-minutes: 180 + timeout-minutes: 240 defaults: run: shell: bash @@ -68,12 +68,12 @@ jobs: skip: '${{ !contains(github.event.pull_request.labels.*.name, ''ci-full'') && (github.event_name == ''pull_request'') }}' - os: macos arch: aarch64 - runner: '${{ github.repository == ''denoland/deno'' && startsWith(github.ref, ''refs/tags/'') && ''self-hosted'' || ''macos-14'' }}' + runner: macos-14 job: test profile: debug - os: macos arch: aarch64 - runner: '${{ (!contains(github.event.pull_request.labels.*.name, ''ci-full'') && (github.event_name == ''pull_request'')) && ''ubuntu-24.04'' || github.repository == ''denoland/deno'' && startsWith(github.ref, ''refs/tags/'') && ''self-hosted'' || ''macos-14'' }}' + runner: '${{ (!contains(github.event.pull_request.labels.*.name, ''ci-full'') && (github.event_name == ''pull_request'')) && ''ubuntu-24.04'' || github.repository == ''denoland/deno'' && (github.ref == ''refs/heads/main'' || startsWith(github.ref, ''refs/tags/'')) && ''ghcr.io/cirruslabs/macos-runner:sonoma'' || ''macos-14'' }}' job: test profile: release skip: '${{ !contains(github.event.pull_request.labels.*.name, ''ci-full'') && (github.event_name == ''pull_request'') }}' @@ -175,7 +175,7 @@ jobs: tar --exclude=".git*" --exclude=target --exclude=third_party/prebuilt \ -czvf target/release/deno_src.tar.gz -C .. deno - name: Cache Cargo home - uses: actions/cache@v4 + uses: cirruslabs/cache@v4 with: path: |- ~/.cargo/.crates.toml @@ -184,8 +184,8 @@ jobs: ~/.cargo/registry/index ~/.cargo/registry/cache ~/.cargo/git/db - key: '32-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}' - restore-keys: '32-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-' + key: '36-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}' + restore-keys: '36-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-' if: '!(matrix.skip)' - uses: dsherret/rust-toolchain-file@v1 if: '!(matrix.skip)' @@ -379,7 +379,7 @@ jobs: !./target/*/*.zip !./target/*/*.tar.gz key: never_saved - restore-keys: '32-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-' + restore-keys: '36-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-' - name: Apply and update mtime cache if: '!(matrix.skip) && (!startsWith(github.ref, ''refs/tags/''))' uses: ./.github/mtime_cache @@ -689,7 +689,7 @@ jobs: !./target/*/gn_root !./target/*/*.zip !./target/*/*.tar.gz - key: '32-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}' + key: '36-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}' publish-canary: name: publish canary runs-on: ubuntu-24.04 diff --git a/Cargo.lock b/Cargo.lock index 9ee40077a6..3fdee9f8a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1244,7 +1244,7 @@ dependencies = [ [[package]] name = "deno" -version = "2.1.4" +version = "2.1.6" dependencies = [ "anstream", "async-trait", @@ -1270,12 +1270,13 @@ dependencies = [ "deno_doc", "deno_error", "deno_graph", + "deno_lib", "deno_lint", "deno_lockfile", "deno_npm", "deno_npm_cache", "deno_package_json", - "deno_path_util 0.3.0", + "deno_path_util", "deno_resolver", "deno_runtime", "deno_semver", @@ -1355,7 +1356,7 @@ dependencies = [ "typed-arena", "uuid", "walkdir", - "which 4.4.2", + "which", "winapi", "winres", "zeromq", @@ -1421,7 +1422,7 @@ dependencies = [ [[package]] name = "deno_bench_util" -version = "0.178.0" +version = "0.180.0" dependencies = [ "bencher", "deno_core", @@ -1430,10 +1431,11 @@ dependencies = [ [[package]] name = "deno_broadcast_channel" -version = "0.178.0" +version = "0.180.0" dependencies = [ "async-trait", "deno_core", + "deno_error", "thiserror 2.0.3", "tokio", "uuid", @@ -1441,10 +1443,11 @@ dependencies = [ [[package]] name = "deno_cache" -version = "0.116.0" +version = "0.118.0" dependencies = [ "async-trait", "deno_core", + "deno_error", "rusqlite", "serde", "sha2", @@ -1467,7 +1470,7 @@ dependencies = [ "data-url", "deno_error", "deno_media_type", - "deno_path_util 0.3.0", + "deno_path_util", "http 1.1.0", "indexmap 2.3.0", "log", @@ -1483,9 +1486,10 @@ dependencies = [ [[package]] name = "deno_canvas" -version = "0.53.0" +version = "0.55.0" dependencies = [ "deno_core", + "deno_error", "deno_webgpu", "image", "serde", @@ -1494,13 +1498,15 @@ dependencies = [ [[package]] name = "deno_config" -version = "0.42.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45aaf31e58ca915d5c0746bf8e2d07b94635154ad9e5afe5ff265cae6187b19" +checksum = "47a47412627aa0d08414eca0e8329128013ab70bdb2cdfdc5456c2214cf24c8f" dependencies = [ - "anyhow", + "boxed_error", + "capacity_builder 0.5.0", + "deno_error", "deno_package_json", - "deno_path_util 0.3.0", + "deno_path_util", "deno_semver", "glob", "ignore", @@ -1513,22 +1519,22 @@ dependencies = [ "serde", "serde_json", "sys_traits", - "thiserror 1.0.64", + "thiserror 2.0.3", "url", ] [[package]] name = "deno_console" -version = "0.184.0" +version = "0.186.0" dependencies = [ "deno_core", ] [[package]] name = "deno_core" -version = "0.327.0" +version = "0.330.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf8dff204b9c2415deb47b9f30d4d38b0925d0d88f1f9074e8e76f59e6d7ded" +checksum = "fd38bbbd68ed873165ccb630322704b44140d3a8c8d50f898beac4d1a8a3358c" dependencies = [ "anyhow", "az", @@ -1539,6 +1545,7 @@ dependencies = [ "capacity_builder 0.1.3", "cooked-waker", "deno_core_icudata", + "deno_error", "deno_ops", "deno_unsync", "futures", @@ -1554,6 +1561,7 @@ dependencies = [ "smallvec", "sourcemap 8.0.1", "static_assertions", + "thiserror 2.0.3", "tokio", "url", "v8", @@ -1568,12 +1576,13 @@ checksum = "fe4dccb6147bb3f3ba0c7a48e993bfeb999d2c2e47a81badee80e2b370c8d695" [[package]] name = "deno_cron" -version = "0.64.0" +version = "0.66.0" dependencies = [ "anyhow", "async-trait", "chrono", "deno_core", + "deno_error", "saffron", "thiserror 2.0.3", "tokio", @@ -1581,7 +1590,7 @@ dependencies = [ [[package]] name = "deno_crypto" -version = "0.198.0" +version = "0.200.0" dependencies = [ "aes", "aes-gcm", @@ -1592,6 +1601,7 @@ dependencies = [ "ctr", "curve25519-dalek", "deno_core", + "deno_error", "deno_web", "ed448-goldilocks", "elliptic-curve", @@ -1618,16 +1628,17 @@ dependencies = [ [[package]] name = "deno_doc" -version = "0.161.3" +version = "0.164.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353a39c70d248af04600928cefc8066a9e4535fb6e7d7c518411e5efc822819f" +checksum = "ad1edb02603c7e8a4003c84af2482a05e5eda3a14f1af275434fda89223f054d" dependencies = [ "anyhow", "cfg-if", "comrak", "deno_ast", "deno_graph", - "deno_path_util 0.2.2", + "deno_path_util", + "deno_terminal 0.2.0", "handlebars", "html-escape", "import_map", @@ -1647,22 +1658,23 @@ dependencies = [ [[package]] name = "deno_error" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "199c66ffd17ee1a948904d33f3d3f364573951c1f9fb3f859bfe7770bf33862a" +checksum = "c4da6a58de6932a96f84e133c072fd3b525966ee122a71f3efd48bbff2eed5ac" dependencies = [ "deno_error_macro", "libc", "serde", "serde_json", + "tokio", "url", ] [[package]] name = "deno_error_macro" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cd99df6ae75443907e1f959fc42ec6dcea67a7bd083e76cf23a117102c9a2ce" +checksum = "46351dff93aed2039407c91e2ded2a5591e42d2795ab3d111288625bb710d3d2" dependencies = [ "proc-macro2", "quote", @@ -1671,13 +1683,14 @@ dependencies = [ [[package]] name = "deno_fetch" -version = "0.208.0" +version = "0.210.0" dependencies = [ "base64 0.21.7", "bytes", "data-url", "deno_core", - "deno_path_util 0.3.0", + "deno_error", + "deno_path_util", "deno_permissions", "deno_tls", "dyn-clone", @@ -1707,9 +1720,10 @@ dependencies = [ [[package]] name = "deno_ffi" -version = "0.171.0" +version = "0.173.0" dependencies = [ "deno_core", + "deno_error", "deno_permissions", "dlopen2", "dynasmrt", @@ -1727,14 +1741,15 @@ dependencies = [ [[package]] name = "deno_fs" -version = "0.94.0" +version = "0.96.0" dependencies = [ "async-trait", "base32", "boxed_error", "deno_core", + "deno_error", "deno_io", - "deno_path_util 0.3.0", + "deno_path_util", "deno_permissions", "filetime", "junction", @@ -1750,16 +1765,17 @@ dependencies = [ [[package]] name = "deno_graph" -version = "0.86.6" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83af194ca492ea7b624d21055f933676d3f3d27586de93be31c8f1babcc73510" +checksum = "f56d4eb4b7c81ae920b6d18c45a1866924f93110caee80bbbc362dc28143f2bb" dependencies = [ - "anyhow", "async-trait", "capacity_builder 0.5.0", "data-url", "deno_ast", - "deno_path_util 0.3.0", + "deno_error", + "deno_media_type", + "deno_path_util", "deno_semver", "deno_unsync", "encoding_rs", @@ -1783,7 +1799,7 @@ dependencies = [ [[package]] name = "deno_http" -version = "0.182.0" +version = "0.184.0" dependencies = [ "async-compression", "async-trait", @@ -1793,6 +1809,7 @@ dependencies = [ "bytes", "cache_control", "deno_core", + "deno_error", "deno_net", "deno_websocket", "flate2", @@ -1822,10 +1839,11 @@ dependencies = [ [[package]] name = "deno_io" -version = "0.94.0" +version = "0.96.0" dependencies = [ "async-trait", "deno_core", + "deno_error", "filetime", "fs3", "libc", @@ -1843,7 +1861,7 @@ dependencies = [ [[package]] name = "deno_kv" -version = "0.92.0" +version = "0.94.0" dependencies = [ "anyhow", "async-trait", @@ -1852,8 +1870,9 @@ dependencies = [ "bytes", "chrono", "deno_core", + "deno_error", "deno_fetch", - "deno_path_util 0.3.0", + "deno_path_util", "deno_permissions", "deno_tls", "denokv_proto", @@ -1873,6 +1892,31 @@ dependencies = [ "url", ] +[[package]] +name = "deno_lib" +version = "0.2.0" +dependencies = [ + "deno_cache_dir", + "deno_error", + "deno_fs", + "deno_node", + "deno_path_util", + "deno_resolver", + "deno_runtime", + "deno_terminal 0.2.0", + "faster-hex", + "log", + "node_resolver", + "parking_lot", + "ring", + "serde", + "sys_traits", + "test_server", + "thiserror 2.0.3", + "tokio", + "url", +] + [[package]] name = "deno_lint" version = "0.68.2" @@ -1905,9 +1949,9 @@ dependencies = [ [[package]] name = "deno_media_type" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaa135b8a9febc9a51c16258e294e268a1276750780d69e46edb31cced2826e4" +checksum = "a417f8bd3f1074185c4c8ccb6ea6261ae173781596cc358e68ad07aaac11009d" dependencies = [ "data-url", "serde", @@ -1916,9 +1960,10 @@ dependencies = [ [[package]] name = "deno_napi" -version = "0.115.0" +version = "0.117.0" dependencies = [ "deno_core", + "deno_error", "deno_permissions", "libc", "libloading 0.7.4", @@ -1944,9 +1989,10 @@ dependencies = [ [[package]] name = "deno_net" -version = "0.176.0" +version = "0.178.0" dependencies = [ "deno_core", + "deno_error", "deno_permissions", "deno_tls", "hickory-proto", @@ -1962,7 +2008,7 @@ dependencies = [ [[package]] name = "deno_node" -version = "0.122.0" +version = "0.124.0" dependencies = [ "aead-gcm-stream", "aes", @@ -1976,14 +2022,16 @@ dependencies = [ "const-oid", "data-encoding", "deno_core", + "deno_error", "deno_fetch", "deno_fs", "deno_io", "deno_media_type", "deno_net", "deno_package_json", - "deno_path_util 0.3.0", + "deno_path_util", "deno_permissions", + "deno_process", "deno_whoami", "der", "digest", @@ -1996,7 +2044,6 @@ dependencies = [ "faster-hex", "h2 0.4.4", "hkdf", - "home", "http 1.1.0", "http-body-util", "hyper 1.4.1", @@ -2023,7 +2070,6 @@ dependencies = [ "p384", "path-clean", "pbkdf2", - "pin-project-lite", "pkcs8", "rand", "regex", @@ -2057,9 +2103,9 @@ dependencies = [ [[package]] name = "deno_npm" -version = "0.27.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f818ad5dc4c206b50b5cfa6f10b4b94b127e15c8342c152768eba40c225ca23" +checksum = "4adceb4c34f10e837d0e3ae76e88dddefb13e83c05c1ef1699fa5519241c9d27" dependencies = [ "async-trait", "capacity_builder 0.5.0", @@ -2077,17 +2123,15 @@ dependencies = [ [[package]] name = "deno_npm_cache" -version = "0.3.0" +version = "0.5.0" dependencies = [ - "anyhow", "async-trait", "base64 0.21.7", "boxed_error", "deno_cache_dir", - "deno_core", "deno_error", "deno_npm", - "deno_path_util 0.3.0", + "deno_path_util", "deno_semver", "deno_unsync", "faster-hex", @@ -2109,10 +2153,11 @@ dependencies = [ [[package]] name = "deno_ops" -version = "0.203.0" +version = "0.206.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b146ca74cac431843486ade58e2accc16c11315fb2c6934590a52a73c56b7ec3" +checksum = "4c25ffa9d088ea00748dbef870bba110ac22ebf8cf7b2e9eb288409c5d852af3" dependencies = [ + "indexmap 2.3.0", "proc-macro-rules", "proc-macro2", "quote", @@ -2120,7 +2165,28 @@ dependencies = [ "strum", "strum_macros", "syn 2.0.87", - "thiserror 1.0.64", + "thiserror 2.0.3", +] + +[[package]] +name = "deno_os" +version = "0.3.0" +dependencies = [ + "deno_core", + "deno_error", + "deno_path_util", + "deno_permissions", + "deno_telemetry", + "libc", + "netif", + "ntapi", + "once_cell", + "serde", + "signal-hook", + "signal-hook-registry", + "thiserror 2.0.3", + "tokio", + "winapi", ] [[package]] @@ -2131,7 +2197,7 @@ checksum = "e1d3c0f699ba2040669204ce24ab73720499fc290af843e4ce0fc8a9b3d67735" dependencies = [ "boxed_error", "deno_error", - "deno_path_util 0.3.0", + "deno_path_util", "deno_semver", "indexmap 2.3.0", "serde", @@ -2141,18 +2207,6 @@ dependencies = [ "url", ] -[[package]] -name = "deno_path_util" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b02c7d341e1b2cf089daff0f4fb2b4be8f3b5511b1d96040b3f7ed63a66c737b" -dependencies = [ - "deno_error", - "percent-encoding", - "thiserror 2.0.3", - "url", -] - [[package]] name = "deno_path_util" version = "0.3.0" @@ -2168,11 +2222,12 @@ dependencies = [ [[package]] name = "deno_permissions" -version = "0.43.0" +version = "0.45.0" dependencies = [ "capacity_builder 0.5.0", "deno_core", - "deno_path_util 0.3.0", + "deno_error", + "deno_path_util", "deno_terminal 0.2.0", "fqdn", "libc", @@ -2181,24 +2236,57 @@ dependencies = [ "percent-encoding", "serde", "thiserror 2.0.3", - "which 4.4.2", + "which", "winapi", ] +[[package]] +name = "deno_process" +version = "0.1.0" +dependencies = [ + "deno_core", + "deno_error", + "deno_fs", + "deno_io", + "deno_os", + "deno_path_util", + "deno_permissions", + "libc", + "log", + "memchr", + "nix", + "pin-project-lite", + "rand", + "serde", + "simd-json", + "tempfile", + "thiserror 2.0.3", + "tokio", + "which", + "winapi", + "windows-sys 0.59.0", +] + [[package]] name = "deno_resolver" -version = "0.15.0" +version = "0.17.0" dependencies = [ "anyhow", + "async-trait", "base32", "boxed_error", "dashmap", + "deno_cache_dir", "deno_config", + "deno_error", "deno_media_type", + "deno_npm", "deno_package_json", - "deno_path_util 0.3.0", + "deno_path_util", "deno_semver", + "log", "node_resolver", + "parking_lot", "sys_traits", "test_server", "thiserror 2.0.3", @@ -2207,7 +2295,7 @@ dependencies = [ [[package]] name = "deno_runtime" -version = "0.192.0" +version = "0.194.0" dependencies = [ "color-print", "deno_ast", @@ -2218,6 +2306,7 @@ dependencies = [ "deno_core", "deno_cron", "deno_crypto", + "deno_error", "deno_fetch", "deno_ffi", "deno_fs", @@ -2227,8 +2316,11 @@ dependencies = [ "deno_napi", "deno_net", "deno_node", - "deno_path_util 0.3.0", + "deno_os", + "deno_path_util", "deno_permissions", + "deno_process", + "deno_resolver", "deno_telemetry", "deno_terminal 0.2.0", "deno_tls", @@ -2249,7 +2341,6 @@ dependencies = [ "hyper-util", "libc", "log", - "netif", "nix", "node_resolver", "notify", @@ -2260,8 +2351,6 @@ dependencies = [ "rustyline", "same-file", "serde", - "signal-hook", - "signal-hook-registry", "sys_traits", "tempfile", "test_server", @@ -2270,7 +2359,7 @@ dependencies = [ "tokio-metrics", "twox-hash", "uuid", - "which 4.4.2", + "which", "winapi", "windows-sys 0.59.0", ] @@ -2312,10 +2401,11 @@ dependencies = [ [[package]] name = "deno_telemetry" -version = "0.6.0" +version = "0.8.0" dependencies = [ "async-trait", "deno_core", + "deno_error", "http-body-util", "hyper 1.4.1", "hyper-util", @@ -2328,6 +2418,7 @@ dependencies = [ "opentelemetry_sdk", "pin-project", "serde", + "thiserror 2.0.3", "tokio", ] @@ -2353,9 +2444,10 @@ dependencies = [ [[package]] name = "deno_tls" -version = "0.171.0" +version = "0.173.0" dependencies = [ "deno_core", + "deno_error", "deno_native_certs", "rustls", "rustls-pemfile", @@ -2403,11 +2495,12 @@ dependencies = [ [[package]] name = "deno_url" -version = "0.184.0" +version = "0.186.0" dependencies = [ "deno_bench_util", "deno_console", "deno_core", + "deno_error", "deno_webidl", "thiserror 2.0.3", "urlpattern", @@ -2415,7 +2508,7 @@ dependencies = [ [[package]] name = "deno_web" -version = "0.215.0" +version = "0.217.0" dependencies = [ "async-trait", "base64-simd 0.8.0", @@ -2423,6 +2516,7 @@ dependencies = [ "deno_bench_util", "deno_console", "deno_core", + "deno_error", "deno_permissions", "deno_url", "deno_webidl", @@ -2437,9 +2531,10 @@ dependencies = [ [[package]] name = "deno_webgpu" -version = "0.151.0" +version = "0.153.0" dependencies = [ "deno_core", + "deno_error", "raw-window-handle", "serde", "thiserror 2.0.3", @@ -2450,7 +2545,7 @@ dependencies = [ [[package]] name = "deno_webidl" -version = "0.184.0" +version = "0.186.0" dependencies = [ "deno_bench_util", "deno_core", @@ -2458,10 +2553,11 @@ dependencies = [ [[package]] name = "deno_websocket" -version = "0.189.0" +version = "0.191.0" dependencies = [ "bytes", "deno_core", + "deno_error", "deno_net", "deno_permissions", "deno_tls", @@ -2480,9 +2576,10 @@ dependencies = [ [[package]] name = "deno_webstorage" -version = "0.179.0" +version = "0.181.0" dependencies = [ "deno_core", + "deno_error", "deno_web", "rusqlite", "thiserror 2.0.3", @@ -2500,13 +2597,13 @@ dependencies = [ [[package]] name = "denokv_proto" -version = "0.8.4" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7ba1f99ed11a9c11e868a8521b1f71a7e1aba785d7f42ea9ecbdc01146c89ec" +checksum = "d5b77de4d3b9215e14624d4f4eb16cb38c0810e3f5860ba3b3fc47d0537f9a4d" dependencies = [ - "anyhow", "async-trait", "chrono", + "deno_error", "futures", "num-bigint", "prost", @@ -2516,15 +2613,15 @@ dependencies = [ [[package]] name = "denokv_remote" -version = "0.8.4" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08ed833073189e8f6d03155fe3b05a024e75e29d8a28a4c2e9ec3b5c925e727b" +checksum = "c6497c28eec268ed99f1e8664f0842935f02d1508529c67d94c57ca5d893d743" dependencies = [ - "anyhow", "async-stream", "async-trait", "bytes", "chrono", + "deno_error", "denokv_proto", "futures", "http 1.1.0", @@ -2533,6 +2630,7 @@ dependencies = [ "rand", "serde", "serde_json", + "thiserror 2.0.3", "tokio", "tokio-util", "url", @@ -2541,14 +2639,14 @@ dependencies = [ [[package]] name = "denokv_sqlite" -version = "0.8.4" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b790f01d1302d53a0c3cbd27de88a06b3abd64ec8ab8673924e490541c7c713" +checksum = "dc0f21a450a35eb85760761401fddf9bfff9840127be07a6ca5c31863127913d" dependencies = [ - "anyhow", "async-stream", "async-trait", "chrono", + "deno_error", "denokv_proto", "futures", "hex", @@ -2557,7 +2655,7 @@ dependencies = [ "rand", "rusqlite", "serde_json", - "thiserror 1.0.64", + "thiserror 2.0.3", "tokio", "tokio-stream", "uuid", @@ -3515,6 +3613,19 @@ dependencies = [ "slab", ] +[[package]] +name = "generator" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd" +dependencies = [ + "cfg-if", + "libc", + "log", + "rustversion", + "windows 0.58.0", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -3590,8 +3701,8 @@ dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.6", + "regex-syntax 0.8.3", ] [[package]] @@ -4320,16 +4431,18 @@ dependencies = [ [[package]] name = "import_map" -version = "0.20.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "351a787decc56f38d65d16d32687265045d6d6a4531b4a0e1b649def3590354e" +checksum = "1215d4d92511fbbdaea50e750e91f2429598ef817f02b579158e92803b52c00a" dependencies = [ + "boxed_error", + "deno_error", "indexmap 2.3.0", "log", "percent-encoding", "serde", "serde_json", - "thiserror 1.0.64", + "thiserror 2.0.3", "url", ] @@ -4521,12 +4634,12 @@ dependencies = [ [[package]] name = "junction" -version = "0.2.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be39922b087cecaba4e2d5592dedfc8bda5d4a5a1231f143337cca207950b61d" +checksum = "72bbdfd737a243da3dfc1f99ee8d6e166480f17ab4ac84d7c34aacd73fc7bd16" dependencies = [ "scopeguard", - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -4779,6 +4892,19 @@ dependencies = [ "serde", ] +[[package]] +name = "loom" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + [[package]] name = "lsp-types" version = "0.97.0" @@ -4833,6 +4959,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "matchit" version = "0.7.3" @@ -4945,21 +5080,20 @@ dependencies = [ [[package]] name = "moka" -version = "0.12.7" +version = "0.12.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e0d88686dc561d743b40de8269b26eaf0dc58781bde087b0984646602021d08" +checksum = "a9321642ca94a4282428e6ea4af8cc2ca4eac48ac7a6a4ea8f33f76d0ce70926" dependencies = [ "crossbeam-channel", "crossbeam-epoch", "crossbeam-utils", - "once_cell", + "loom", "parking_lot", - "quanta", + "portable-atomic", "rustc_version 0.4.0", "smallvec", "tagptr", "thiserror 1.0.64", - "triomphe", "uuid", ] @@ -5014,7 +5148,7 @@ dependencies = [ [[package]] name = "napi_sym" -version = "0.114.0" +version = "0.116.0" dependencies = [ "quote", "serde", @@ -5069,14 +5203,15 @@ dependencies = [ [[package]] name = "node_resolver" -version = "0.22.0" +version = "0.24.0" dependencies = [ "anyhow", "async-trait", "boxed_error", + "deno_error", "deno_media_type", "deno_package_json", - "deno_path_util 0.3.0", + "deno_path_util", "futures", "lazy-regex", "once_cell", @@ -5137,6 +5272,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-bigint" version = "0.4.4" @@ -5394,6 +5539,12 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4030760ffd992bef45b0ae3f10ce1aba99e33464c90d14dd7c039884963ddc7a" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "p224" version = "0.13.2" @@ -5728,6 +5879,12 @@ dependencies = [ "universal-hash", ] +[[package]] +name = "portable-atomic" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" + [[package]] name = "powerfmt" version = "0.2.0" @@ -5945,21 +6102,6 @@ dependencies = [ "unicase", ] -[[package]] -name = "quanta" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5" -dependencies = [ - "crossbeam-utils", - "libc", - "once_cell", - "raw-cpuid", - "wasi", - "web-sys", - "winapi", -] - [[package]] name = "quick-error" version = "1.2.3" @@ -6129,15 +6271,6 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8a99fddc9f0ba0a85884b8d14e3592853e787d581ca1816c91349b10e4eeab" -[[package]] -name = "raw-cpuid" -version = "11.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0" -dependencies = [ - "bitflags 2.6.0", -] - [[package]] name = "raw-window-handle" version = "0.6.1" @@ -6212,8 +6345,17 @@ checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.6", + "regex-syntax 0.8.3", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", ] [[package]] @@ -6224,9 +6366,15 @@ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.8.3", ] +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.8.3" @@ -6801,14 +6949,15 @@ dependencies = [ [[package]] name = "serde_v8" -version = "0.236.0" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e23b3abce64010612f88f4ff689a959736f99eb3dc0dbf1c7903434b8bd8cda5" +checksum = "3caa6d882827148e5d9052d9d8d6d1c9d6ad426ed00cab46cafb8c07a0e7126a" dependencies = [ + "deno_error", "num-bigint", "serde", "smallvec", - "thiserror 1.0.64", + "thiserror 2.0.3", "v8", ] @@ -6860,6 +7009,15 @@ dependencies = [ "keccak", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shell-escape" version = "0.1.5" @@ -7682,9 +7840,9 @@ dependencies = [ [[package]] name = "sys_traits" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6683465f4e1d8fd75069cbc36c646258c05b7d8d6676bcb5d71968b99b7d5ae2" +checksum = "5b46ac05dfbe9fd3a9703eff20e17f5b31e7b6a54daf27a421dcd56c7a27ecdd" dependencies = [ "filetime", "getrandom", @@ -8191,6 +8349,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", ] [[package]] @@ -8422,9 +8610,9 @@ dependencies = [ [[package]] name = "v8" -version = "130.0.2" +version = "130.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ee0be58935708fa4d7efb970c6cf9f2d9511d24ee24246481a65b6ee167348d" +checksum = "a511192602f7b435b0a241c1947aa743eb7717f20a9195f4b5e8ed1952e01db1" dependencies = [ "bindgen", "bitflags 2.6.0", @@ -8434,7 +8622,7 @@ dependencies = [ "miniz_oxide", "once_cell", "paste", - "which 6.0.1", + "which", ] [[package]] @@ -8452,6 +8640,12 @@ dependencies = [ "wtf8", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "value-trait" version = "0.10.0" @@ -8616,11 +8810,12 @@ dependencies = [ [[package]] name = "wasm_dep_analyzer" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f270206a91783fd90625c8bb0d8fbd459d0b1d1bf209b656f713f01ae7c04b8" +checksum = "2eeee3bdea6257cc36d756fa745a70f9d393571e47d69e0ed97581676a5369ca" dependencies = [ - "thiserror 1.0.64", + "deno_error", + "thiserror 2.0.3", ] [[package]] @@ -8744,18 +8939,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - [[package]] name = "which" version = "6.0.1" @@ -8792,7 +8975,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b2b1bf557d947847a30eb73f79aa6cdb3eaf3ce02f5e9599438f77896a62b3c" dependencies = [ "thiserror 1.0.64", - "windows", + "windows 0.52.0", ] [[package]] @@ -8832,7 +9015,17 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ - "windows-core", + "windows-core 0.52.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core 0.58.0", "windows-targets 0.52.6", ] @@ -8845,6 +9038,60 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index bfd7437441..42c2970e05 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,11 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [workspace] resolver = "2" members = [ "bench_util", "cli", + "cli/lib", "ext/broadcast_channel", "ext/cache", "ext/canvas", @@ -48,55 +49,58 @@ repository = "https://github.com/denoland/deno" [workspace.dependencies] deno_ast = { version = "=0.44.0", features = ["transpiling"] } -deno_core = { version = "0.327.0" } +deno_core = { version = "0.330.0" } -deno_bench_util = { version = "0.178.0", path = "./bench_util" } -deno_config = { version = "=0.42.0", features = ["workspace", "sync"] } +deno_bench_util = { version = "0.180.0", path = "./bench_util" } +deno_config = { version = "=0.45.0", features = ["workspace", "sync"] } deno_lockfile = "=0.24.0" -deno_media_type = { version = "0.2.0", features = ["module_specifier"] } -deno_npm = "=0.27.0" +deno_media_type = { version = "0.2.3", features = ["module_specifier"] } +deno_npm = "=0.27.2" deno_path_util = "=0.3.0" -deno_permissions = { version = "0.43.0", path = "./runtime/permissions" } -deno_runtime = { version = "0.192.0", path = "./runtime" } +deno_permissions = { version = "0.45.0", path = "./runtime/permissions" } +deno_runtime = { version = "0.194.0", path = "./runtime" } deno_semver = "=0.7.1" deno_terminal = "0.2.0" -napi_sym = { version = "0.114.0", path = "./ext/napi/sym" } +napi_sym = { version = "0.116.0", path = "./ext/napi/sym" } test_util = { package = "test_server", path = "./tests/util/server" } -denokv_proto = "0.8.4" -denokv_remote = "0.8.4" +denokv_proto = "0.9.0" +denokv_remote = "0.9.0" # denokv_sqlite brings in bundled sqlite if we don't disable the default features -denokv_sqlite = { default-features = false, version = "0.8.4" } +denokv_sqlite = { default-features = false, version = "0.9.0" } # exts -deno_broadcast_channel = { version = "0.178.0", path = "./ext/broadcast_channel" } -deno_cache = { version = "0.116.0", path = "./ext/cache" } -deno_canvas = { version = "0.53.0", path = "./ext/canvas" } -deno_console = { version = "0.184.0", path = "./ext/console" } -deno_cron = { version = "0.64.0", path = "./ext/cron" } -deno_crypto = { version = "0.198.0", path = "./ext/crypto" } -deno_fetch = { version = "0.208.0", path = "./ext/fetch" } -deno_ffi = { version = "0.171.0", path = "./ext/ffi" } -deno_fs = { version = "0.94.0", path = "./ext/fs" } -deno_http = { version = "0.182.0", path = "./ext/http" } -deno_io = { version = "0.94.0", path = "./ext/io" } -deno_kv = { version = "0.92.0", path = "./ext/kv" } -deno_napi = { version = "0.115.0", path = "./ext/napi" } -deno_net = { version = "0.176.0", path = "./ext/net" } -deno_node = { version = "0.122.0", path = "./ext/node" } -deno_telemetry = { version = "0.6.0", path = "./ext/telemetry" } -deno_tls = { version = "0.171.0", path = "./ext/tls" } -deno_url = { version = "0.184.0", path = "./ext/url" } -deno_web = { version = "0.215.0", path = "./ext/web" } -deno_webgpu = { version = "0.151.0", path = "./ext/webgpu" } -deno_webidl = { version = "0.184.0", path = "./ext/webidl" } -deno_websocket = { version = "0.189.0", path = "./ext/websocket" } -deno_webstorage = { version = "0.179.0", path = "./ext/webstorage" } +deno_broadcast_channel = { version = "0.180.0", path = "./ext/broadcast_channel" } +deno_cache = { version = "0.118.0", path = "./ext/cache" } +deno_canvas = { version = "0.55.0", path = "./ext/canvas" } +deno_console = { version = "0.186.0", path = "./ext/console" } +deno_cron = { version = "0.66.0", path = "./ext/cron" } +deno_crypto = { version = "0.200.0", path = "./ext/crypto" } +deno_fetch = { version = "0.210.0", path = "./ext/fetch" } +deno_ffi = { version = "0.173.0", path = "./ext/ffi" } +deno_fs = { version = "0.96.0", path = "./ext/fs" } +deno_http = { version = "0.184.0", path = "./ext/http" } +deno_io = { version = "0.96.0", path = "./ext/io" } +deno_kv = { version = "0.94.0", path = "./ext/kv" } +deno_napi = { version = "0.117.0", path = "./ext/napi" } +deno_net = { version = "0.178.0", path = "./ext/net" } +deno_node = { version = "0.124.0", path = "./ext/node" } +deno_os = { version = "0.3.0", path = "./ext/os" } +deno_process = { version = "0.1.0", path = "./ext/process" } +deno_telemetry = { version = "0.8.0", path = "./ext/telemetry" } +deno_tls = { version = "0.173.0", path = "./ext/tls" } +deno_url = { version = "0.186.0", path = "./ext/url" } +deno_web = { version = "0.217.0", path = "./ext/web" } +deno_webgpu = { version = "0.153.0", path = "./ext/webgpu" } +deno_webidl = { version = "0.186.0", path = "./ext/webidl" } +deno_websocket = { version = "0.191.0", path = "./ext/websocket" } +deno_webstorage = { version = "0.181.0", path = "./ext/webstorage" } -# resolvers -deno_npm_cache = { version = "0.3.0", path = "./resolvers/npm_cache" } -deno_resolver = { version = "0.15.0", path = "./resolvers/deno" } -node_resolver = { version = "0.22.0", path = "./resolvers/node" } +# workspace libraries +deno_lib = { version = "0.2.0", path = "./cli/lib" } +deno_npm_cache = { version = "0.5.0", path = "./resolvers/npm_cache" } +deno_resolver = { version = "0.17.0", path = "./resolvers/deno" } +node_resolver = { version = "0.24.0", path = "./resolvers/node" } aes = "=0.8.3" anyhow = "1.0.57" @@ -119,7 +123,7 @@ dashmap = "5.5.3" data-encoding = "2.3.3" data-url = "=0.3.1" deno_cache_dir = "=0.16.0" -deno_error = "=0.5.2" +deno_error = "=0.5.3" deno_package_json = { version = "0.4.0", default-features = false } deno_unsync = "0.4.2" dlopen2 = "0.6.1" @@ -193,7 +197,7 @@ slab = "0.4" smallvec = "1.8" socket2 = { version = "0.5.3", features = ["all"] } spki = "0.7.2" -sys_traits = "=0.1.4" +sys_traits = "=0.1.7" tar = "=0.4.40" tempfile = "3.4.0" termcolor = "1.1.3" @@ -212,7 +216,7 @@ url = { version = "2.5", features = ["serde", "expose_internals"] } uuid = { version = "1.3.0", features = ["v4"] } webpki-root-certs = "0.26.5" webpki-roots = "0.26" -which = "4.2.5" +which = "6" yoke = { version = "0.7.4", features = ["derive"] } zeromq = { version = "=0.4.1", default-features = false, features = ["tcp-transport", "tokio-runtime"] } zstd = "=0.12.4" @@ -240,7 +244,7 @@ syn = { version = "2", features = ["full", "extra-traits"] } nix = "=0.27.1" # windows deps -junction = "=0.2.0" +junction = "=1.2.0" winapi = "=0.3.9" windows-sys = { version = "0.59.0", features = ["Win32_Foundation", "Win32_Media", "Win32_Storage_FileSystem", "Win32_System_IO", "Win32_System_WindowsProgramming", "Wdk", "Wdk_System", "Wdk_System_SystemInformation", "Win32_Security", "Win32_System_Pipes", "Wdk_Storage_FileSystem", "Win32_System_Registry", "Win32_System_Kernel", "Win32_System_Threading", "Win32_UI", "Win32_UI_Shell"] } winres = "=0.1.12" diff --git a/LICENSE.md b/LICENSE.md index 56753af367..406ae09364 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ MIT License -Copyright 2018-2024 the Deno authors +Copyright 2018-2025 the Deno authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/Releases.md b/Releases.md index aaae202a37..1fc6ebd1df 100644 --- a/Releases.md +++ b/Releases.md @@ -6,6 +6,111 @@ https://github.com/denoland/deno/releases We also have one-line install commands at: https://github.com/denoland/deno_install +### 2.1.6 / 2025.01.16 + +- fix(check/lsp): correctly resolve compilerOptions.types (#27686) +- fix(check/lsp): fix bugs with tsc type resolution, allow npm packages to + augment `ImportMeta` (#27690) +- fix(compile): store embedded fs case sensitivity (#27653) +- fix(compile/windows): better handling of deno_dir on different drive letter + than code (#27654) +- fix(ext/console): change Temporal color (#27684) +- fix(ext/node): add `writev` method to `FileHandle` (#27563) +- fix(ext/node): add chown method to FileHandle class (#27638) +- fix(ext/node): apply `@npmcli/agent` workaround to `npm-check-updates` + (#27639) +- fix(ext/node): fix playwright http client (#27662) +- fix(ext/node): show bare-node-builtin hint when using an import map (#27632) +- fix(ext/node): use primordials in `ext/node/polyfills/_fs_common.ts` (#27589) +- fix(lsp): handle pathless untitled URIs (#27637) +- fix(lsp/check): don't resolve unknown media types to a `.js` extension + (#27631) +- fix(node): Prevent node:child_process from always inheriting the parent + environment (#27343) (#27340) +- fix(node/fs): add utimes method to the FileHandle class (#27582) +- fix(outdated): Use `latest` tag even when it's the same as the current version + (#27699) +- fix(outdated): retain strict semver specifier when updating (#27701) + +### 2.1.5 / 2025.01.09 + +- feat(unstable): implement QUIC (#21942) +- feat(unstable): add JS linting plugin infrastructure (#27416) +- feat(unstable): add OTEL MeterProvider (#27240) +- feat(unstable): no config npm:@opentelemetry/api integration (#27541) +- feat(unstable): replace SpanExporter with TracerProvider (#27473) +- feat(unstable): support selectors in JS lint plugins (#27452) +- fix(check): line-break between diagnostic message chain entries (#27543) +- fix(check): move module not found errors to typescript diagnostics (#27533) +- fix(compile): analyze modules in directory specified in --include (#27296) +- fix(compile): be more deterministic when compiling the same code in different + directories (#27395) +- fix(compile): display embedded file sizes and total (#27360) +- fix(compile): output contents of embedded file system (#27302) +- fix(ext/fetch): better error message when body resource is unavailable + (#27429) +- fix(ext/fetch): retry some http/2 errors (#27417) +- fix(ext/fs): do not throw for bigint ctime/mtime/atime (#27453) +- fix(ext/http): improve error message when underlying resource of request body + unavailable (#27463) +- fix(ext/net): update moka cache to avoid potential panic in `Deno.resolveDns` + on some laptops with Ryzen CPU (#27572) +- fix(ext/node): fix `fs.access`/`fs.promises.access` with `X_OK` mode parameter + on Windows (#27407) +- fix(ext/node): fix `os.cpus()` on Linux (#27592) +- fix(ext/node): RangeError timingSafeEqual with different byteLength (#27470) +- fix(ext/node): add `truncate` method to the `FileHandle` class (#27389) +- fix(ext/node): add support of any length IV for aes-(128|256)-gcm ciphers + (#27476) +- fix(ext/node): convert brotli chunks with proper byte offset (#27455) +- fix(ext/node): do not exit worker thread when there is pending async op + (#27378) +- fix(ext/node): have `process` global available in Node context (#27562) +- fix(ext/node): make getCiphers return supported ciphers (#27466) +- fix(ext/node): sort list of built-in modules alphabetically (#27410) +- fix(ext/node): support createConnection option in node:http.request() (#25470) +- fix(ext/node): support private key export in JWK format (#27325) +- fix(ext/web): add `[[ErrorData]]` slot to `DOMException` (#27342) +- fix(ext/websocket): Fix close code without reason (#27578) +- fix(jsr): Wasm imports fail to load (#27594) +- fix(kv): improve backoff error message and inline documentation (#27537) +- fix(lint): fix single char selectors being ignored (#27576) +- fix(lockfile): include dependencies listed in external import map in lockfile + (#27337) +- fix(lsp): css preprocessor formatting (#27526) +- fix(lsp): don't skip dirs with enabled subdirs (#27580) +- fix(lsp): include "node:" prefix for node builtin auto-imports (#27404) +- fix(lsp): respect "typescript.suggestionActions.enabled" setting (#27373) +- fix(lsp): rewrite imports for 'Move to a new file' action (#27427) +- fix(lsp): sql and component file formatting (#27350) +- fix(lsp): use verbatim specifier for URL auto-imports (#27605) +- fix(no-slow-types): handle rest param with internal assignments (#27581) +- fix(node/fs): add a chmod method to the FileHandle class (#27522) +- fix(node): add missing `inspector/promises` (#27491) +- fix(node): handle cjs exports with escaped chars (#27438) +- fix(npm): deterministically output tags to initialized file (#27514) +- fix(npm): search node_modules folder for package matching npm specifier + (#27345) +- fix(outdated): ensure "Latest" version is greater than "Update" version + (#27390) +- fix(outdated): support updating dependencies in external import maps (#27339) +- fix(permissions): implicit `--allow-import` when using `--cached-only` + (#27530) +- fix(publish): infer literal types in const contexts (#27425) +- fix(task): properly handle task name wildcards with --recursive (#27396) +- fix(task): support tasks without commands (#27191) +- fix(unstable): don't error on non-existing attrs or type attr (#27456) +- fix: FastString v8_string() should error when cannot allocated (#27375) +- fix: deno_resolver crate without 'sync' feature (#27403) +- fix: incorrect memory info free/available bytes on mac (#27460) +- fix: upgrade deno_doc to 0.161.3 (#27377) +- perf(fs/windows): stat - only open file once (#27487) +- perf(node/fs/copy): reduce metadata lookups copying directory (#27495) +- perf: don't store duplicate info for ops in the snapshot (#27430) +- perf: remove now needless canonicalization getting closest package.json + (#27437) +- perf: upgrade to deno_semver 0.7 (#27426) + ### 2.1.4 / 2024.12.11 - feat(unstable): support caching npm dependencies only as they're needed diff --git a/bench_util/Cargo.toml b/bench_util/Cargo.toml index 014b74f264..e2f1204eb2 100644 --- a/bench_util/Cargo.toml +++ b/bench_util/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_bench_util" -version = "0.178.0" +version = "0.180.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/bench_util/README.md b/bench_util/README.md index 12474a86b6..30616a08fd 100644 --- a/bench_util/README.md +++ b/bench_util/README.md @@ -7,7 +7,6 @@ use deno_bench_util::bench_js_sync; use deno_bench_util::bench_or_profile; use deno_bench_util::bencher::benchmark_group; use deno_bench_util::bencher::Bencher; - use deno_core::Extension; #[op2] diff --git a/bench_util/benches/utf8.rs b/bench_util/benches/utf8.rs index 48af4dba7e..88afce86c3 100644 --- a/bench_util/benches/utf8.rs +++ b/bench_util/benches/utf8.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_bench_util::bench_js_sync_with; use deno_bench_util::bench_or_profile; diff --git a/bench_util/js_runtime.rs b/bench_util/js_runtime.rs index a97d8ae501..402c9a4b00 100644 --- a/bench_util/js_runtime.rs +++ b/bench_util/js_runtime.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use bencher::Bencher; use deno_core::v8; use deno_core::Extension; diff --git a/bench_util/lib.rs b/bench_util/lib.rs index 39183be7fc..22587a5f7e 100644 --- a/bench_util/lib.rs +++ b/bench_util/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. mod js_runtime; mod profiling; diff --git a/bench_util/profiling.rs b/bench_util/profiling.rs index 151a29e599..1d2bfb51d2 100644 --- a/bench_util/profiling.rs +++ b/bench_util/profiling.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use bencher::DynBenchFn; use bencher::StaticBenchFn; use bencher::TestDescAndFn; diff --git a/cli/Cargo.toml b/cli/Cargo.toml index d05c3fb3e3..d71047cc63 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno" -version = "2.1.4" +version = "2.1.6" authors.workspace = true default-run = "deno" edition.workspace = true @@ -62,6 +62,7 @@ serde_json.workspace = true zstd.workspace = true glibc_version = "0.1.2" flate2 = { workspace = true, features = ["default"] } +deno_error.workspace = true [target.'cfg(windows)'.build-dependencies] winapi.workspace = true @@ -72,9 +73,10 @@ deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "proposa deno_cache_dir.workspace = true deno_config.workspace = true deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] } -deno_doc = { version = "=0.161.3", features = ["rust", "comrak"] } +deno_doc = { version = "=0.164.0", features = ["rust", "comrak"] } deno_error.workspace = true -deno_graph = { version = "=0.86.6" } +deno_graph = { version = "=0.87.0" } +deno_lib.workspace = true deno_lint = { version = "=0.68.2", features = ["docs"] } deno_lockfile.workspace = true deno_npm.workspace = true @@ -124,7 +126,7 @@ http.workspace = true http-body.workspace = true http-body-util.workspace = true hyper-util.workspace = true -import_map = { version = "=0.20.1", features = ["ext"] } +import_map = { version = "=0.21.0", features = ["ext"] } indexmap.workspace = true jsonc-parser = { workspace = true, features = ["cst", "serde"] } jupyter_runtime = { package = "runtimelib", version = "=0.19.0", features = ["tokio-runtime"] } diff --git a/cli/args/deno_json.rs b/cli/args/deno_json.rs index 47dcbb91ea..c27b1d3924 100644 --- a/cli/args/deno_json.rs +++ b/cli/args/deno_json.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashSet; diff --git a/cli/args/flags.rs b/cli/args/flags.rs index 2b0b9a2908..fb64b4eeaa 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -1,6 +1,5 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use std::borrow::Cow; use std::collections::HashSet; use std::env; use std::ffi::OsString; @@ -34,7 +33,6 @@ use deno_core::url::Url; use deno_graph::GraphKind; use deno_path_util::normalize_path; use deno_path_util::url_to_file_path; -use deno_runtime::deno_permissions::PermissionsOptions; use deno_runtime::deno_permissions::SysDescriptor; use deno_telemetry::OtelConfig; use deno_telemetry::OtelConsoleConfig; @@ -43,11 +41,8 @@ use log::Level; use serde::Deserialize; use serde::Serialize; -use crate::args::resolve_no_prompt; -use crate::util::fs::canonicalize_path; - use super::flags_net; -use super::jsr_url; +use crate::util::fs::canonicalize_path; #[derive(Clone, Debug, Default, Eq, PartialEq)] pub enum ConfigFlag { @@ -693,97 +688,6 @@ impl PermissionFlags { || self.deny_write.is_some() || self.allow_import.is_some() } - - pub fn to_options(&self, cli_arg_urls: &[Cow]) -> PermissionsOptions { - fn handle_allow( - allow_all: bool, - value: Option, - ) -> Option { - if allow_all { - assert!(value.is_none()); - Some(T::default()) - } else { - value - } - } - - fn handle_imports( - cli_arg_urls: &[Cow], - imports: Option>, - ) -> Option> { - if imports.is_some() { - return imports; - } - - let builtin_allowed_import_hosts = [ - "jsr.io:443", - "deno.land:443", - "esm.sh:443", - "cdn.jsdelivr.net:443", - "raw.githubusercontent.com:443", - "gist.githubusercontent.com:443", - ]; - - let mut imports = - Vec::with_capacity(builtin_allowed_import_hosts.len() + 1); - imports - .extend(builtin_allowed_import_hosts.iter().map(|s| s.to_string())); - - // also add the JSR_URL env var - if let Some(jsr_host) = allow_import_host_from_url(jsr_url()) { - imports.push(jsr_host); - } - // include the cli arg urls - for url in cli_arg_urls { - if let Some(host) = allow_import_host_from_url(url) { - imports.push(host); - } - } - - Some(imports) - } - - PermissionsOptions { - allow_all: self.allow_all, - allow_env: handle_allow(self.allow_all, self.allow_env.clone()), - deny_env: self.deny_env.clone(), - allow_net: handle_allow(self.allow_all, self.allow_net.clone()), - deny_net: self.deny_net.clone(), - allow_ffi: handle_allow(self.allow_all, self.allow_ffi.clone()), - deny_ffi: self.deny_ffi.clone(), - allow_read: handle_allow(self.allow_all, self.allow_read.clone()), - deny_read: self.deny_read.clone(), - allow_run: handle_allow(self.allow_all, self.allow_run.clone()), - deny_run: self.deny_run.clone(), - allow_sys: handle_allow(self.allow_all, self.allow_sys.clone()), - deny_sys: self.deny_sys.clone(), - allow_write: handle_allow(self.allow_all, self.allow_write.clone()), - deny_write: self.deny_write.clone(), - allow_import: handle_imports( - cli_arg_urls, - handle_allow(self.allow_all, self.allow_import.clone()), - ), - prompt: !resolve_no_prompt(self), - } - } -} - -/// Gets the --allow-import host from the provided url -fn allow_import_host_from_url(url: &Url) -> Option { - let host = url.host()?; - if let Some(port) = url.port() { - Some(format!("{}:{}", host, port)) - } else { - use deno_core::url::Host::*; - match host { - Domain(domain) if domain == "jsr.io" && url.scheme() == "https" => None, - _ => match url.scheme() { - "https" => Some(format!("{}:443", host)), - "http" => Some(format!("{}:80", host)), - _ => None, - }, - } - } } fn join_paths(allowlist: &[String], d: &str) -> String { @@ -6059,9 +5963,10 @@ pub fn resolve_urls(urls: Vec) -> Vec { #[cfg(test)] mod tests { - use super::*; use pretty_assertions::assert_eq; + use super::*; + /// Creates vector of strings, Vec macro_rules! svec { ($($x:expr),* $(,)?) => (vec![$($x.to_string().into()),*]); @@ -11549,8 +11454,6 @@ mod tests { ..Default::default() } ); - // just make sure this doesn't panic - let _ = flags.permissions.to_options(&[]); } #[test] @@ -11626,29 +11529,6 @@ Usage: deno repl [OPTIONS] [-- [ARGS]...]\n" ) } - #[test] - fn test_allow_import_host_from_url() { - fn parse(text: &str) -> Option { - allow_import_host_from_url(&Url::parse(text).unwrap()) - } - - assert_eq!(parse("https://jsr.io"), None); - assert_eq!( - parse("http://127.0.0.1:4250"), - Some("127.0.0.1:4250".to_string()) - ); - assert_eq!(parse("http://jsr.io"), Some("jsr.io:80".to_string())); - assert_eq!( - parse("https://example.com"), - Some("example.com:443".to_string()) - ); - assert_eq!( - parse("http://example.com"), - Some("example.com:80".to_string()) - ); - assert_eq!(parse("file:///example.com"), None); - } - #[test] fn allow_all_conflicts_allow_perms() { let flags = [ diff --git a/cli/args/flags_net.rs b/cli/args/flags_net.rs index abfcf28382..c39e377e10 100644 --- a/cli/args/flags_net.rs +++ b/cli/args/flags_net.rs @@ -1,9 +1,10 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::net::IpAddr; +use std::str::FromStr; use deno_core::url::Url; use deno_runtime::deno_permissions::NetDescriptor; -use std::net::IpAddr; -use std::str::FromStr; #[derive(Debug, PartialEq, Eq)] pub struct ParsePortError(String); diff --git a/cli/args/import_map.rs b/cli/args/import_map.rs index d6434ed46a..ff7e42ef20 100644 --- a/cli/args/import_map.rs +++ b/cli/args/import_map.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::error::AnyError; use deno_core::serde_json; diff --git a/cli/args/lockfile.rs b/cli/args/lockfile.rs index 7d5fe57bc3..976992aac8 100644 --- a/cli/args/lockfile.rs +++ b/cli/args/lockfile.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashSet; use std::path::PathBuf; @@ -10,6 +10,8 @@ use deno_core::error::AnyError; use deno_core::parking_lot::Mutex; use deno_core::parking_lot::MutexGuard; use deno_core::serde_json; +use deno_error::JsErrorBox; +use deno_lockfile::Lockfile; use deno_lockfile::WorkspaceMemberConfig; use deno_package_json::PackageJsonDepValue; use deno_path_util::fs::atomic_write_file_with_retries; @@ -17,15 +19,12 @@ use deno_runtime::deno_node::PackageJson; use deno_semver::jsr::JsrDepPackageReq; use crate::args::deno_json::import_map_deps; +use crate::args::DenoSubcommand; +use crate::args::InstallFlags; use crate::cache; use crate::sys::CliSys; use crate::Flags; -use crate::args::DenoSubcommand; -use crate::args::InstallFlags; - -use deno_lockfile::Lockfile; - #[derive(Debug)] pub struct CliLockfileReadFromPathOptions { pub file_path: PathBuf, @@ -61,6 +60,14 @@ impl<'a, T> std::ops::DerefMut for Guard<'a, T> { } } +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[error("Failed writing lockfile")] +#[class(inherit)] +struct AtomicWriteFileWithRetriesError { + #[source] + source: std::io::Error, +} + impl CliLockfile { /// Get the inner deno_lockfile::Lockfile. pub fn lock(&self) -> Guard { @@ -80,7 +87,7 @@ impl CliLockfile { self.lockfile.lock().overwrite } - pub fn write_if_changed(&self) -> Result<(), AnyError> { + pub fn write_if_changed(&self) -> Result<(), JsErrorBox> { if self.skip_write { return Ok(()); } @@ -98,7 +105,9 @@ impl CliLockfile { &bytes, cache::CACHE_PERM, ) - .context("Failed writing lockfile.")?; + .map_err(|source| { + JsErrorBox::from_err(AtomicWriteFileWithRetriesError { source }) + })?; lockfile.has_content_changed = false; Ok(()) } @@ -257,7 +266,7 @@ impl CliLockfile { }) } - pub fn error_if_changed(&self) -> Result<(), AnyError> { + pub fn error_if_changed(&self) -> Result<(), JsErrorBox> { if !self.frozen { return Ok(()); } @@ -269,9 +278,7 @@ impl CliLockfile { let diff = crate::util::diff::diff(&contents, &new_contents); // has an extra newline at the end let diff = diff.trim_end(); - Err(deno_core::anyhow::anyhow!( - "The lockfile is out of date. Run `deno install --frozen=false`, or rerun with `--frozen=false` to update it.\nchanges:\n{diff}" - )) + Err(JsErrorBox::generic(format!("The lockfile is out of date. Run `deno install --frozen=false`, or rerun with `--frozen=false` to update it.\nchanges:\n{diff}"))) } else { Ok(()) } diff --git a/cli/args/mod.rs b/cli/args/mod.rs index a059b07757..f77eedc594 100644 --- a/cli/args/mod.rs +++ b/cli/args/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. pub mod deno_json; mod flags; @@ -7,70 +7,6 @@ mod import_map; mod lockfile; mod package_json; -use deno_ast::MediaType; -use deno_ast::SourceMapOption; -use deno_cache_dir::file_fetcher::CacheSetting; -use deno_config::deno_json::NodeModulesDirMode; -use deno_config::workspace::CreateResolverOptions; -use deno_config::workspace::FolderConfigs; -use deno_config::workspace::PackageJsonDepResolution; -use deno_config::workspace::VendorEnablement; -use deno_config::workspace::Workspace; -use deno_config::workspace::WorkspaceDirectory; -use deno_config::workspace::WorkspaceDirectoryEmptyOptions; -use deno_config::workspace::WorkspaceDiscoverOptions; -use deno_config::workspace::WorkspaceDiscoverStart; -use deno_config::workspace::WorkspaceLintConfig; -use deno_config::workspace::WorkspaceResolver; -use deno_core::resolve_url_or_path; -use deno_graph::GraphKind; -use deno_lint::linter::LintConfig as DenoLintConfig; -use deno_npm::npm_rc::NpmRc; -use deno_npm::npm_rc::ResolvedNpmRc; -use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot; -use deno_npm::NpmSystemInfo; -use deno_path_util::normalize_path; -use deno_semver::npm::NpmPackageReqReference; -use deno_semver::StackString; -use deno_telemetry::OtelConfig; -use deno_telemetry::OtelRuntimeConfig; -use import_map::resolve_import_map_value_from_specifier; - -pub use deno_config::deno_json::BenchConfig; -pub use deno_config::deno_json::ConfigFile; -pub use deno_config::deno_json::FmtOptionsConfig; -pub use deno_config::deno_json::LintRulesConfig; -pub use deno_config::deno_json::ProseWrap; -pub use deno_config::deno_json::TsConfig; -pub use deno_config::deno_json::TsConfigForEmit; -pub use deno_config::deno_json::TsConfigType; -pub use deno_config::deno_json::TsTypeLib; -pub use deno_config::glob::FilePatterns; -pub use deno_json::check_warn_tsconfig; -pub use flags::*; -pub use lockfile::CliLockfile; -pub use lockfile::CliLockfileReadFromPathOptions; -pub use package_json::NpmInstallDepsProvider; -pub use package_json::PackageJsonDepValueParseWithLocationError; - -use deno_ast::ModuleSpecifier; -use deno_core::anyhow::bail; -use deno_core::anyhow::Context; -use deno_core::error::AnyError; -use deno_core::serde_json; -use deno_core::url::Url; -use deno_runtime::deno_permissions::PermissionsOptions; -use deno_runtime::deno_tls::deno_native_certs::load_native_certs; -use deno_runtime::deno_tls::rustls; -use deno_runtime::deno_tls::rustls::RootCertStore; -use deno_runtime::deno_tls::rustls_pemfile; -use deno_runtime::deno_tls::webpki_roots; -use deno_runtime::inspector_server::InspectorServer; -use deno_terminal::colors; -use dotenvy::from_filename; -use once_cell::sync::Lazy; -use serde::Deserialize; -use serde::Serialize; use std::borrow::Cow; use std::collections::HashMap; use std::env; @@ -83,19 +19,84 @@ use std::num::NonZeroUsize; use std::path::Path; use std::path::PathBuf; use std::sync::Arc; + +use deno_ast::MediaType; +use deno_ast::ModuleSpecifier; +use deno_ast::SourceMapOption; +use deno_cache_dir::file_fetcher::CacheSetting; +pub use deno_config::deno_json::BenchConfig; +pub use deno_config::deno_json::ConfigFile; +use deno_config::deno_json::ConfigFileError; +use deno_config::deno_json::FmtConfig; +pub use deno_config::deno_json::FmtOptionsConfig; +use deno_config::deno_json::LintConfig; +pub use deno_config::deno_json::LintRulesConfig; +use deno_config::deno_json::NodeModulesDirMode; +pub use deno_config::deno_json::ProseWrap; +use deno_config::deno_json::TestConfig; +pub use deno_config::deno_json::TsConfig; +pub use deno_config::deno_json::TsConfigForEmit; +pub use deno_config::deno_json::TsConfigType; +pub use deno_config::deno_json::TsTypeLib; +pub use deno_config::glob::FilePatterns; +use deno_config::workspace::CreateResolverOptions; +use deno_config::workspace::FolderConfigs; +use deno_config::workspace::PackageJsonDepResolution; +use deno_config::workspace::VendorEnablement; +use deno_config::workspace::Workspace; +use deno_config::workspace::WorkspaceDirectory; +use deno_config::workspace::WorkspaceDirectoryEmptyOptions; +use deno_config::workspace::WorkspaceDiscoverOptions; +use deno_config::workspace::WorkspaceDiscoverStart; +use deno_config::workspace::WorkspaceLintConfig; +use deno_config::workspace::WorkspaceResolver; +use deno_core::anyhow::bail; +use deno_core::anyhow::Context; +use deno_core::error::AnyError; +use deno_core::resolve_url_or_path; +use deno_core::serde_json; +use deno_core::url::Url; +use deno_graph::GraphKind; +pub use deno_json::check_warn_tsconfig; +use deno_lib::cache::DenoDirProvider; +use deno_lib::env::has_flag_env_var; +use deno_lib::worker::StorageKeyResolver; +use deno_lint::linter::LintConfig as DenoLintConfig; +use deno_npm::npm_rc::NpmRc; +use deno_npm::npm_rc::ResolvedNpmRc; +use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot; +use deno_npm::NpmSystemInfo; +use deno_path_util::normalize_path; +use deno_runtime::deno_permissions::PermissionsOptions; +use deno_runtime::deno_tls::deno_native_certs::load_native_certs; +use deno_runtime::deno_tls::rustls; +use deno_runtime::deno_tls::rustls::RootCertStore; +use deno_runtime::deno_tls::rustls_pemfile; +use deno_runtime::deno_tls::webpki_roots; +use deno_runtime::inspector_server::InspectorServer; +use deno_semver::npm::NpmPackageReqReference; +use deno_semver::StackString; +use deno_telemetry::OtelConfig; +use deno_telemetry::OtelRuntimeConfig; +use deno_terminal::colors; +use dotenvy::from_filename; +pub use flags::*; +use import_map::resolve_import_map_value_from_specifier; +pub use lockfile::CliLockfile; +pub use lockfile::CliLockfileReadFromPathOptions; +use once_cell::sync::Lazy; +pub use package_json::NpmInstallDepsProvider; +pub use package_json::PackageJsonDepValueParseWithLocationError; +use serde::Deserialize; +use serde::Serialize; use sys_traits::EnvHomeDir; use thiserror::Error; -use crate::cache::DenoDirProvider; use crate::file_fetcher::CliFileFetcher; use crate::sys::CliSys; use crate::util::fs::canonicalize_path_maybe_not_exists; use crate::version; -use deno_config::deno_json::FmtConfig; -use deno_config::deno_json::LintConfig; -use deno_config::deno_json::TestConfig; - pub fn npm_registry_url() -> &'static Url { static NPM_REGISTRY_DEFAULT_URL: Lazy = Lazy::new(|| { let env_var_name = "NPM_CONFIG_REGISTRY"; @@ -606,7 +607,8 @@ pub fn create_default_npmrc() -> Arc { }) } -#[derive(Error, Debug, Clone)] +#[derive(Error, Debug, Clone, deno_error::JsError)] +#[class(generic)] pub enum RootCertStoreLoadError { #[error( "Unknown certificate store \"{0}\" specified (allowed: \"system,mozilla\")" @@ -717,7 +719,7 @@ pub enum NpmProcessStateKind { } static NPM_PROCESS_STATE: Lazy> = Lazy::new(|| { - use deno_runtime::ops::process::NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME; + use deno_runtime::deno_process::NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME; let fd = std::env::var(NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME).ok()?; std::env::remove_var(NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME); let fd = fd.parse::().ok()?; @@ -768,7 +770,7 @@ pub struct CliOptions { maybe_external_import_map: Option<(PathBuf, serde_json::Value)>, overrides: CliOptionOverrides, pub start_dir: Arc, - pub deno_dir_provider: Arc, + pub deno_dir_provider: Arc>, } impl CliOptions { @@ -841,8 +843,6 @@ impl CliOptions { } else { &[] }; - let config_parse_options = - deno_config::deno_json::ConfigParseOptions::default(); let discover_pkg_json = flags.config_flag != ConfigFlag::Disabled && !flags.no_npm && !has_flag_env_var("DENO_NO_PACKAGE_JSON"); @@ -853,7 +853,6 @@ impl CliOptions { deno_json_cache: None, pkg_json_cache: Some(&node_resolver::PackageJsonThreadLocalCache), workspace_cache: None, - config_parse_options, additional_config_file_names, discover_pkg_json, maybe_vendor_override, @@ -1102,11 +1101,11 @@ impl CliOptions { } }; Ok(self.workspace().create_resolver( + &CliSys::default(), CreateResolverOptions { pkg_json_dep_resolution, specified_import_map: cli_arg_specified_import_map, }, - |path| Ok(std::fs::read_to_string(path)?), )?) } @@ -1230,6 +1229,16 @@ impl CliOptions { } } + pub fn resolve_storage_key_resolver(&self) -> StorageKeyResolver { + if let Some(location) = &self.flags.location { + StorageKeyResolver::from_flag(location) + } else if let Some(deno_json) = self.start_dir.maybe_deno_json() { + StorageKeyResolver::from_config_file_url(&deno_json.specifier) + } else { + StorageKeyResolver::new_use_main_module() + } + } + // If the main module should be treated as being in an npm package. // This is triggered via a secret environment variable which is used // for functionality like child_process.fork. Users should NOT depend @@ -1248,11 +1257,14 @@ impl CliOptions { pub fn node_modules_dir( &self, - ) -> Result, AnyError> { + ) -> Result< + Option, + deno_config::deno_json::NodeModulesDirParseError, + > { if let Some(flag) = self.flags.node_modules_dir { return Ok(Some(flag)); } - self.workspace().node_modules_dir().map_err(Into::into) + self.workspace().node_modules_dir() } pub fn vendor_dir_path(&self) -> Option<&PathBuf> { @@ -1262,7 +1274,7 @@ impl CliOptions { pub fn resolve_ts_config_for_emit( &self, config_type: TsConfigType, - ) -> Result { + ) -> Result { self.workspace().resolve_ts_config_for_emit(config_type) } @@ -1291,7 +1303,7 @@ impl CliOptions { pub fn to_compiler_option_types( &self, - ) -> Result, AnyError> { + ) -> Result, serde_json::Error> { self .workspace() .to_compiler_option_types() @@ -1528,20 +1540,100 @@ impl CliOptions { self.flags.no_npm } - pub fn permission_flags(&self) -> &PermissionFlags { - &self.flags.permissions - } - pub fn permissions_options(&self) -> PermissionsOptions { - fn files_to_urls(files: &[String]) -> Vec> { - files - .iter() - .filter_map(|f| Url::parse(f).ok().map(Cow::Owned)) - .collect() + // bury this in here to ensure people use cli_options.permissions_options() + fn flags_to_options(flags: &PermissionFlags) -> PermissionsOptions { + fn handle_allow( + allow_all: bool, + value: Option, + ) -> Option { + if allow_all { + assert!(value.is_none()); + Some(T::default()) + } else { + value + } + } + + PermissionsOptions { + allow_all: flags.allow_all, + allow_env: handle_allow(flags.allow_all, flags.allow_env.clone()), + deny_env: flags.deny_env.clone(), + allow_net: handle_allow(flags.allow_all, flags.allow_net.clone()), + deny_net: flags.deny_net.clone(), + allow_ffi: handle_allow(flags.allow_all, flags.allow_ffi.clone()), + deny_ffi: flags.deny_ffi.clone(), + allow_read: handle_allow(flags.allow_all, flags.allow_read.clone()), + deny_read: flags.deny_read.clone(), + allow_run: handle_allow(flags.allow_all, flags.allow_run.clone()), + deny_run: flags.deny_run.clone(), + allow_sys: handle_allow(flags.allow_all, flags.allow_sys.clone()), + deny_sys: flags.deny_sys.clone(), + allow_write: handle_allow(flags.allow_all, flags.allow_write.clone()), + deny_write: flags.deny_write.clone(), + allow_import: handle_allow(flags.allow_all, flags.allow_import.clone()), + prompt: !resolve_no_prompt(flags), + } } - // get a list of urls to imply for --allow-import - let cli_arg_urls = self + let mut permissions_options = flags_to_options(&self.flags.permissions); + self.augment_import_permissions(&mut permissions_options); + permissions_options + } + + fn augment_import_permissions(&self, options: &mut PermissionsOptions) { + // do not add if the user specified --allow-all or --allow-import + if !options.allow_all && options.allow_import.is_none() { + options.allow_import = Some(self.implicit_allow_import()); + } + } + + fn implicit_allow_import(&self) -> Vec { + // allow importing from anywhere when using cached only + if self.cache_setting() == CacheSetting::Only { + vec![] // allow all imports + } else { + // implicitly allow some trusted hosts and the CLI arg urls + let cli_arg_urls = self.get_cli_arg_urls(); + let builtin_allowed_import_hosts = [ + "jsr.io:443", + "deno.land:443", + "esm.sh:443", + "cdn.jsdelivr.net:443", + "raw.githubusercontent.com:443", + "gist.githubusercontent.com:443", + ]; + let mut imports = Vec::with_capacity( + builtin_allowed_import_hosts.len() + cli_arg_urls.len() + 1, + ); + imports + .extend(builtin_allowed_import_hosts.iter().map(|s| s.to_string())); + // also add the JSR_URL env var + if let Some(jsr_host) = allow_import_host_from_url(jsr_url()) { + if jsr_host != "jsr.io:443" { + imports.push(jsr_host); + } + } + // include the cli arg urls + for url in cli_arg_urls { + if let Some(host) = allow_import_host_from_url(&url) { + imports.push(host); + } + } + imports + } + } + + fn get_cli_arg_urls(&self) -> Vec> { + fn files_to_urls(files: &[String]) -> Vec> { + files.iter().filter_map(|f| file_to_url(f)).collect() + } + + fn file_to_url(file: &str) -> Option> { + Url::parse(file).ok().map(Cow::Owned) + } + + self .resolve_main_module() .ok() .map(|url| vec![Cow::Borrowed(url)]) @@ -1553,18 +1645,18 @@ impl CliOptions { Some(files_to_urls(&check_flags.files)) } DenoSubcommand::Install(InstallFlags::Global(flags)) => { - Url::parse(&flags.module_url) - .ok() - .map(|url| vec![Cow::Owned(url)]) + file_to_url(&flags.module_url).map(|url| vec![url]) } DenoSubcommand::Doc(DocFlags { source_files: DocSourceFileFlag::Paths(paths), .. }) => Some(files_to_urls(paths)), + DenoSubcommand::Info(InfoFlags { + file: Some(file), .. + }) => file_to_url(file).map(|url| vec![url]), _ => None, }) - .unwrap_or_default(); - self.flags.permissions.to_options(&cli_arg_urls) + .unwrap_or_default() } pub fn reload_flag(&self) -> bool { @@ -1791,7 +1883,7 @@ fn resolve_node_modules_folder( cwd: &Path, flags: &Flags, workspace: &Workspace, - deno_dir_provider: &Arc, + deno_dir_provider: &Arc>, ) -> Result, AnyError> { fn resolve_from_root(root_folder: &FolderConfigs, cwd: &Path) -> PathBuf { root_folder @@ -1895,63 +1987,11 @@ fn resolve_import_map_specifier( } } -pub struct StorageKeyResolver(Option>); - -impl StorageKeyResolver { - pub fn from_options(options: &CliOptions) -> Self { - Self(if let Some(location) = &options.flags.location { - // if a location is set, then the ascii serialization of the location is - // used, unless the origin is opaque, and then no storage origin is set, as - // we can't expect the origin to be reproducible - let storage_origin = location.origin(); - if storage_origin.is_tuple() { - Some(Some(storage_origin.ascii_serialization())) - } else { - Some(None) - } - } else { - // otherwise we will use the path to the config file or None to - // fall back to using the main module's path - options - .start_dir - .maybe_deno_json() - .map(|config_file| Some(config_file.specifier.to_string())) - }) - } - - /// Creates a storage key resolver that will always resolve to being empty. - pub fn empty() -> Self { - Self(Some(None)) - } - - /// Resolves the storage key to use based on the current flags, config, or main module. - pub fn resolve_storage_key( - &self, - main_module: &ModuleSpecifier, - ) -> Option { - // use the stored value or fall back to using the path of the main module. - if let Some(maybe_value) = &self.0 { - maybe_value.clone() - } else { - Some(main_module.to_string()) - } - } -} - /// Resolves the no_prompt value based on the cli flags and environment. pub fn resolve_no_prompt(flags: &PermissionFlags) -> bool { flags.no_prompt || has_flag_env_var("DENO_NO_PROMPT") } -pub fn has_trace_permissions_enabled() -> bool { - has_flag_env_var("DENO_TRACE_PERMISSIONS") -} - -pub fn has_flag_env_var(name: &str) -> bool { - let value = env::var(name); - matches!(value.as_ref().map(|s| s.as_str()), Ok("1")) -} - pub fn npm_pkg_req_ref_to_binary_command( req_ref: &NpmPackageReqReference, ) -> String { @@ -2000,6 +2040,20 @@ fn load_env_variables_from_env_file(filename: Option<&Vec>) { } } +/// Gets the --allow-import host from the provided url +fn allow_import_host_from_url(url: &Url) -> Option { + let host = url.host()?; + if let Some(port) = url.port() { + Some(format!("{}:{}", host, port)) + } else { + match url.scheme() { + "https" => Some(format!("{}:443", host)), + "http" => Some(format!("{}:80", host)), + _ => None, + } + } +} + #[derive(Debug, Clone, Copy)] pub enum NpmCachingStrategy { Eager, @@ -2007,7 +2061,7 @@ pub enum NpmCachingStrategy { Manual, } -pub(crate) fn otel_runtime_config() -> OtelRuntimeConfig { +pub fn otel_runtime_config() -> OtelRuntimeConfig { OtelRuntimeConfig { runtime_name: Cow::Borrowed("deno"), runtime_version: Cow::Borrowed(crate::version::DENO_VERSION_INFO.deno), @@ -2028,12 +2082,7 @@ mod test { let cwd = &std::env::current_dir().unwrap(); let config_specifier = ModuleSpecifier::parse("file:///deno/deno.jsonc").unwrap(); - let config_file = ConfigFile::new( - config_text, - config_specifier, - &deno_config::deno_json::ConfigParseOptions::default(), - ) - .unwrap(); + let config_file = ConfigFile::new(config_text, config_specifier).unwrap(); let actual = resolve_import_map_specifier( Some("import-map.json"), Some(&config_file), @@ -2052,12 +2101,7 @@ mod test { let config_text = r#"{}"#; let config_specifier = ModuleSpecifier::parse("file:///deno/deno.jsonc").unwrap(); - let config_file = ConfigFile::new( - config_text, - config_specifier, - &deno_config::deno_json::ConfigParseOptions::default(), - ) - .unwrap(); + let config_file = ConfigFile::new(config_text, config_specifier).unwrap(); let actual = resolve_import_map_specifier( None, Some(&config_file), @@ -2076,27 +2120,6 @@ mod test { assert_eq!(actual, None); } - #[test] - fn storage_key_resolver_test() { - let resolver = StorageKeyResolver(None); - let specifier = ModuleSpecifier::parse("file:///a.ts").unwrap(); - assert_eq!( - resolver.resolve_storage_key(&specifier), - Some(specifier.to_string()) - ); - let resolver = StorageKeyResolver(Some(None)); - assert_eq!(resolver.resolve_storage_key(&specifier), None); - let resolver = StorageKeyResolver(Some(Some("value".to_string()))); - assert_eq!( - resolver.resolve_storage_key(&specifier), - Some("value".to_string()) - ); - - // test empty - let resolver = StorageKeyResolver::empty(); - assert_eq!(resolver.resolve_storage_key(&specifier), None); - } - #[test] fn jsr_urls() { let reg_url = jsr_url(); @@ -2104,4 +2127,26 @@ mod test { let reg_api_url = jsr_api_url(); assert!(reg_api_url.as_str().ends_with('/')); } + + #[test] + fn test_allow_import_host_from_url() { + fn parse(text: &str) -> Option { + allow_import_host_from_url(&Url::parse(text).unwrap()) + } + + assert_eq!( + parse("http://127.0.0.1:4250"), + Some("127.0.0.1:4250".to_string()) + ); + assert_eq!(parse("http://jsr.io"), Some("jsr.io:80".to_string())); + assert_eq!( + parse("https://example.com"), + Some("example.com:443".to_string()) + ); + assert_eq!( + parse("http://example.com"), + Some("example.com:80".to_string()) + ); + assert_eq!(parse("file:///example.com"), None); + } } diff --git a/cli/args/package_json.rs b/cli/args/package_json.rs index 50d1c04799..efa5d46966 100644 --- a/cli/args/package_json.rs +++ b/cli/args/package_json.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::path::PathBuf; use std::sync::Arc; diff --git a/cli/bench/cache_api.js b/cli/bench/cache_api.js index af55fc132e..4b092ab627 100644 --- a/cli/bench/cache_api.js +++ b/cli/bench/cache_api.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. const cacheName = "cache-v1"; const cache = await caches.open(cacheName); diff --git a/cli/bench/command.js b/cli/bench/command.js index 5b7c300d26..5916dcfee2 100644 --- a/cli/bench/command.js +++ b/cli/bench/command.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. Deno.bench("echo deno", async () => { await new Deno.Command("echo", { args: ["deno"] }).output(); diff --git a/cli/bench/console.js b/cli/bench/console.js index 1d336fbbde..c1704549c6 100644 --- a/cli/bench/console.js +++ b/cli/bench/console.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console diff --git a/cli/bench/deno_common.js b/cli/bench/deno_common.js index 3693333915..011a1244aa 100644 --- a/cli/bench/deno_common.js +++ b/cli/bench/deno_common.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // v8 builtin that's close to the upper bound non-NOPs Deno.bench("date_now", { n: 5e5 }, () => { diff --git a/cli/bench/encode_into.js b/cli/bench/encode_into.js index ab5e11b04d..57313ca04a 100644 --- a/cli/bench/encode_into.js +++ b/cli/bench/encode_into.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console no-process-globals let [total, count] = typeof Deno !== "undefined" diff --git a/cli/bench/fs/run.mjs b/cli/bench/fs/run.mjs index 94240f20d4..7f080daf6a 100644 --- a/cli/bench/fs/run.mjs +++ b/cli/bench/fs/run.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. let total = 5; let current = ""; diff --git a/cli/bench/fs/serve.jsx b/cli/bench/fs/serve.jsx index 51125235fe..8b3328617a 100644 --- a/cli/bench/fs/serve.jsx +++ b/cli/bench/fs/serve.jsx @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /** @jsx h */ import results from "./deno.json" assert { type: "json" }; diff --git a/cli/bench/getrandom.js b/cli/bench/getrandom.js index fe99bbcbdf..775d02fc75 100644 --- a/cli/bench/getrandom.js +++ b/cli/bench/getrandom.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console no-process-globals let [total, count] = typeof Deno !== "undefined" diff --git a/cli/bench/lsp.rs b/cli/bench/lsp.rs index 7baaffca7e..7a93dcae1e 100644 --- a/cli/bench/lsp.rs +++ b/cli/bench/lsp.rs @@ -1,14 +1,15 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::collections::HashMap; +use std::path::Path; +use std::str::FromStr; +use std::time::Duration; use deno_core::serde::Deserialize; use deno_core::serde_json; use deno_core::serde_json::json; use deno_core::serde_json::Value; use lsp_types::Uri; -use std::collections::HashMap; -use std::path::Path; -use std::str::FromStr; -use std::time::Duration; use test_util::lsp::LspClientBuilder; use test_util::PathRef; use tower_lsp::lsp_types as lsp; diff --git a/cli/bench/lsp_bench_standalone.rs b/cli/bench/lsp_bench_standalone.rs index 3c946cfbe3..45d8788256 100644 --- a/cli/bench/lsp_bench_standalone.rs +++ b/cli/bench/lsp_bench_standalone.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_bench_util::bencher::benchmark_group; use deno_bench_util::bencher::benchmark_main; diff --git a/cli/bench/main.rs b/cli/bench/main.rs index c3c42d2488..e7f71f8cfa 100644 --- a/cli/bench/main.rs +++ b/cli/bench/main.rs @@ -1,11 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. #![allow(clippy::print_stdout)] #![allow(clippy::print_stderr)] -use deno_core::error::AnyError; -use deno_core::serde_json; -use deno_core::serde_json::Value; use std::collections::HashMap; use std::convert::From; use std::env; @@ -15,6 +12,10 @@ use std::path::PathBuf; use std::process::Command; use std::process::Stdio; use std::time::SystemTime; + +use deno_core::error::AnyError; +use deno_core::serde_json; +use deno_core::serde_json::Value; use test_util::PathRef; mod lsp; diff --git a/cli/bench/napi/bench.js b/cli/bench/napi/bench.js index c12c7aacbc..f40611e7a8 100644 --- a/cli/bench/napi/bench.js +++ b/cli/bench/napi/bench.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { loadTestLibrary } from "../../../tests/napi/common.js"; diff --git a/cli/bench/napi/bench_node.mjs b/cli/bench/napi/bench_node.mjs index a772eeafa1..557c4daefd 100644 --- a/cli/bench/napi/bench_node.mjs +++ b/cli/bench/napi/bench_node.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { bench, run } from "mitata"; import { createRequire } from "module"; diff --git a/cli/bench/op_now.js b/cli/bench/op_now.js index 7c1427c809..26c4958fe0 100644 --- a/cli/bench/op_now.js +++ b/cli/bench/op_now.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console no-process-globals const queueMicrotask = globalThis.queueMicrotask || process.nextTick; diff --git a/cli/bench/secure_curves.js b/cli/bench/secure_curves.js index 912b75cccd..a3fb4ebc41 100644 --- a/cli/bench/secure_curves.js +++ b/cli/bench/secure_curves.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console no-process-globals let [total, count] = typeof Deno !== "undefined" diff --git a/cli/bench/stdio/stdio.c b/cli/bench/stdio/stdio.c index acce207995..15df422405 100644 --- a/cli/bench/stdio/stdio.c +++ b/cli/bench/stdio/stdio.c @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // From https://github.com/just-js/benchmarks/tree/main/01-stdio #include diff --git a/cli/bench/stdio/stdio.js b/cli/bench/stdio/stdio.js index 81bea835a6..1ca947809a 100644 --- a/cli/bench/stdio/stdio.js +++ b/cli/bench/stdio/stdio.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // // From https://github.com/just-js/benchmarks/tree/main/01-stdio diff --git a/cli/bench/tcp.js b/cli/bench/tcp.js index b9f05e3a7e..6681eeeb52 100644 --- a/cli/bench/tcp.js +++ b/cli/bench/tcp.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. const listener = Deno.listen({ port: 4500 }); const response = new TextEncoder().encode( diff --git a/cli/bench/tty.js b/cli/bench/tty.js index e494e76af7..c61541ffa6 100644 --- a/cli/bench/tty.js +++ b/cli/bench/tty.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console no-process-globals const queueMicrotask = globalThis.queueMicrotask || process.nextTick; diff --git a/cli/bench/url_parse.js b/cli/bench/url_parse.js index 9cb0045f64..80579d6f6b 100644 --- a/cli/bench/url_parse.js +++ b/cli/bench/url_parse.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console no-process-globals const queueMicrotask = globalThis.queueMicrotask || process.nextTick; diff --git a/cli/bench/webstorage.js b/cli/bench/webstorage.js index d19f024c63..d284378d60 100644 --- a/cli/bench/webstorage.js +++ b/cli/bench/webstorage.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console diff --git a/cli/bench/write_file.js b/cli/bench/write_file.js index 747503ce2a..c7200a6f5b 100644 --- a/cli/bench/write_file.js +++ b/cli/bench/write_file.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console no-process-globals const queueMicrotask = globalThis.queueMicrotask || process.nextTick; diff --git a/cli/build.rs b/cli/build.rs index 3d98661284..590fee795d 100644 --- a/cli/build.rs +++ b/cli/build.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::env; use std::path::PathBuf; @@ -8,17 +8,18 @@ use deno_runtime::*; mod shared; mod ts { - use super::*; - use deno_core::error::custom_error; - use deno_core::error::AnyError; - use deno_core::op2; - use deno_core::OpState; - use serde::Serialize; use std::collections::HashMap; use std::io::Write; use std::path::Path; use std::path::PathBuf; + use deno_core::op2; + use deno_core::OpState; + use deno_error::JsErrorBox; + use serde::Serialize; + + use super::*; + #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] struct BuildInfoResponse { @@ -51,7 +52,7 @@ mod ts { fn op_script_version( _state: &mut OpState, #[string] _arg: &str, - ) -> Result, AnyError> { + ) -> Result, JsErrorBox> { Ok(Some("1".to_string())) } @@ -70,7 +71,7 @@ mod ts { fn op_load( state: &mut OpState, #[string] load_specifier: &str, - ) -> Result { + ) -> Result { let op_crate_libs = state.borrow::>(); let path_dts = state.borrow::(); let re_asset = lazy_regex::regex!(r"asset:/{3}lib\.(\S+)\.d\.ts"); @@ -91,12 +92,15 @@ mod ts { // if it comes from an op crate, we were supplied with the path to the // file. let path = if let Some(op_crate_lib) = op_crate_libs.get(lib) { - PathBuf::from(op_crate_lib).canonicalize()? + PathBuf::from(op_crate_lib) + .canonicalize() + .map_err(JsErrorBox::from_err)? // otherwise we will generate the path ourself } else { path_dts.join(format!("lib.{lib}.d.ts")) }; - let data = std::fs::read_to_string(path)?; + let data = + std::fs::read_to_string(path).map_err(JsErrorBox::from_err)?; Ok(LoadResponse { data, version: "1".to_string(), @@ -104,13 +108,13 @@ mod ts { script_kind: 3, }) } else { - Err(custom_error( + Err(JsErrorBox::new( "InvalidSpecifier", format!("An invalid specifier was requested: {}", load_specifier), )) } } else { - Err(custom_error( + Err(JsErrorBox::new( "InvalidSpecifier", format!("An invalid specifier was requested: {}", load_specifier), )) diff --git a/cli/cache/cache_db.rs b/cli/cache/cache_db.rs index 329ed2d970..7fd66e9333 100644 --- a/cli/cache/cache_db.rs +++ b/cli/cache/cache_db.rs @@ -1,4 +1,9 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::io::IsTerminal; +use std::path::Path; +use std::path::PathBuf; +use std::sync::Arc; use deno_core::error::AnyError; use deno_core::parking_lot::Mutex; @@ -9,10 +14,6 @@ use deno_runtime::deno_webstorage::rusqlite::Connection; use deno_runtime::deno_webstorage::rusqlite::OptionalExtension; use deno_runtime::deno_webstorage::rusqlite::Params; use once_cell::sync::OnceCell; -use std::io::IsTerminal; -use std::path::Path; -use std::path::PathBuf; -use std::sync::Arc; use super::FastInsecureHasher; @@ -24,12 +25,12 @@ impl CacheDBHash { Self(hash) } - pub fn from_source(source: impl std::hash::Hash) -> Self { + pub fn from_hashable(hashable: impl std::hash::Hash) -> Self { Self::new( // always write in the deno version just in case // the clearing on deno version change doesn't work FastInsecureHasher::new_deno_versioned() - .write_hashable(source) + .write_hashable(hashable) .finish(), ) } diff --git a/cli/cache/caches.rs b/cli/cache/caches.rs index 54371cee48..dd4a974814 100644 --- a/cli/cache/caches.rs +++ b/cli/cache/caches.rs @@ -1,22 +1,23 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::path::PathBuf; use std::sync::Arc; +use deno_lib::cache::DenoDirProvider; use once_cell::sync::OnceCell; use super::cache_db::CacheDB; use super::cache_db::CacheDBConfiguration; use super::check::TYPE_CHECK_CACHE_DB; use super::code_cache::CODE_CACHE_DB; -use super::deno_dir::DenoDirProvider; use super::fast_check::FAST_CHECK_CACHE_DB; use super::incremental::INCREMENTAL_CACHE_DB; use super::module_info::MODULE_INFO_CACHE_DB; use super::node::NODE_ANALYSIS_CACHE_DB; +use crate::sys::CliSys; pub struct Caches { - dir_provider: Arc, + dir_provider: Arc>, fmt_incremental_cache_db: OnceCell, lint_incremental_cache_db: OnceCell, dep_analysis_db: OnceCell, @@ -27,7 +28,7 @@ pub struct Caches { } impl Caches { - pub fn new(dir: Arc) -> Self { + pub fn new(dir: Arc>) -> Self { Self { dir_provider: dir, fmt_incremental_cache_db: Default::default(), diff --git a/cli/cache/check.rs b/cli/cache/check.rs index ca4e938533..a886f9fe0f 100644 --- a/cli/cache/check.rs +++ b/cli/cache/check.rs @@ -1,12 +1,13 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use deno_ast::ModuleSpecifier; +use deno_core::error::AnyError; +use deno_runtime::deno_webstorage::rusqlite::params; use super::cache_db::CacheDB; use super::cache_db::CacheDBConfiguration; use super::cache_db::CacheDBHash; use super::cache_db::CacheFailure; -use deno_ast::ModuleSpecifier; -use deno_core::error::AnyError; -use deno_runtime::deno_webstorage::rusqlite::params; pub static TYPE_CHECK_CACHE_DB: CacheDBConfiguration = CacheDBConfiguration { table_initializer: concat!( diff --git a/cli/cache/code_cache.rs b/cli/cache/code_cache.rs index b1d9ae757b..27ec544b5f 100644 --- a/cli/cache/code_cache.rs +++ b/cli/cache/code_cache.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::sync::Arc; @@ -7,12 +7,11 @@ use deno_core::error::AnyError; use deno_runtime::code_cache; use deno_runtime::deno_webstorage::rusqlite::params; -use crate::worker::CliCodeCache; - use super::cache_db::CacheDB; use super::cache_db::CacheDBConfiguration; use super::cache_db::CacheDBHash; use super::cache_db::CacheFailure; +use crate::worker::CliCodeCache; pub static CODE_CACHE_DB: CacheDBConfiguration = CacheDBConfiguration { table_initializer: concat!( diff --git a/cli/cache/common.rs b/cli/cache/common.rs index 0a68e95159..da607a27f2 100644 --- a/cli/cache/common.rs +++ b/cli/cache/common.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::hash::Hasher; diff --git a/cli/cache/emit.rs b/cli/cache/emit.rs index b239cc93ba..e8a940b3be 100644 --- a/cli/cache/emit.rs +++ b/cli/cache/emit.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::path::PathBuf; @@ -6,19 +6,20 @@ use deno_ast::ModuleSpecifier; use deno_core::anyhow::anyhow; use deno_core::error::AnyError; use deno_core::unsync::sync::AtomicFlag; +use deno_lib::cache::DiskCache; -use super::DiskCache; +use crate::sys::CliSys; /// The cache that stores previously emitted files. #[derive(Debug)] pub struct EmitCache { - disk_cache: DiskCache, + disk_cache: DiskCache, emit_failed_flag: AtomicFlag, file_serializer: EmitFileSerializer, } impl EmitCache { - pub fn new(disk_cache: DiskCache) -> Self { + pub fn new(disk_cache: DiskCache) -> Self { Self { disk_cache, emit_failed_flag: Default::default(), @@ -159,9 +160,8 @@ impl EmitFileSerializer { mod test { use test_util::TempDir; - use crate::sys::CliSys; - use super::*; + use crate::sys::CliSys; #[test] pub fn emit_cache_general_use() { diff --git a/cli/cache/fast_check.rs b/cli/cache/fast_check.rs index 43be1b7186..323312d057 100644 --- a/cli/cache/fast_check.rs +++ b/cli/cache/fast_check.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::error::AnyError; use deno_graph::FastCheckCacheItem; diff --git a/cli/cache/incremental.rs b/cli/cache/incremental.rs index 2d31b4125e..f430c1266f 100644 --- a/cli/cache/incremental.rs +++ b/cli/cache/incremental.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashMap; use std::path::Path; @@ -34,12 +34,16 @@ pub static INCREMENTAL_CACHE_DB: CacheDBConfiguration = CacheDBConfiguration { pub struct IncrementalCache(IncrementalCacheInner); impl IncrementalCache { - pub fn new( + pub fn new( db: CacheDB, - state: &TState, + state_hash: CacheDBHash, initial_file_paths: &[PathBuf], ) -> Self { - IncrementalCache(IncrementalCacheInner::new(db, state, initial_file_paths)) + IncrementalCache(IncrementalCacheInner::new( + db, + state_hash, + initial_file_paths, + )) } pub fn is_file_same(&self, file_path: &Path, file_text: &str) -> bool { @@ -67,12 +71,11 @@ struct IncrementalCacheInner { } impl IncrementalCacheInner { - pub fn new( + pub fn new( db: CacheDB, - state: &TState, + state_hash: CacheDBHash, initial_file_paths: &[PathBuf], ) -> Self { - let state_hash = CacheDBHash::from_source(state); let sql_cache = SqlIncrementalCache::new(db, state_hash); Self::from_sql_incremental_cache(sql_cache, initial_file_paths) } @@ -112,13 +115,13 @@ impl IncrementalCacheInner { pub fn is_file_same(&self, file_path: &Path, file_text: &str) -> bool { match self.previous_hashes.get(file_path) { - Some(hash) => *hash == CacheDBHash::from_source(file_text), + Some(hash) => *hash == CacheDBHash::from_hashable(file_text), None => false, } } pub fn update_file(&self, file_path: &Path, file_text: &str) { - let hash = CacheDBHash::from_source(file_text); + let hash = CacheDBHash::from_hashable(file_text); if let Some(previous_hash) = self.previous_hashes.get(file_path) { if *previous_hash == hash { return; // do not bother updating the db file because nothing has changed @@ -262,7 +265,7 @@ mod test { let sql_cache = SqlIncrementalCache::new(conn, CacheDBHash::new(1)); let file_path = PathBuf::from("/mod.ts"); let file_text = "test"; - let file_hash = CacheDBHash::from_source(file_text); + let file_hash = CacheDBHash::from_hashable(file_text); sql_cache.set_source_hash(&file_path, file_hash).unwrap(); let cache = IncrementalCacheInner::from_sql_incremental_cache( sql_cache, diff --git a/cli/cache/mod.rs b/cli/cache/mod.rs index bc6f792667..e16f95e56f 100644 --- a/cli/cache/mod.rs +++ b/cli/cache/mod.rs @@ -1,4 +1,23 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::collections::HashMap; +use std::path::PathBuf; +use std::sync::Arc; + +use deno_ast::MediaType; +use deno_cache_dir::file_fetcher::CacheSetting; +use deno_cache_dir::file_fetcher::FetchNoFollowErrorKind; +use deno_cache_dir::file_fetcher::FileOrRedirect; +use deno_core::futures; +use deno_core::futures::FutureExt; +use deno_core::ModuleSpecifier; +use deno_graph::source::CacheInfo; +use deno_graph::source::LoadFuture; +use deno_graph::source::LoadResponse; +use deno_graph::source::Loader; +use deno_resolver::npm::DenoInNpmPackageChecker; +use deno_runtime::deno_permissions::PermissionsContainer; +use node_resolver::InNpmPackageChecker; use crate::args::jsr_url; use crate::file_fetcher::CliFetchNoFollowErrorKind; @@ -7,31 +26,11 @@ use crate::file_fetcher::FetchNoFollowOptions; use crate::file_fetcher::FetchPermissionsOptionRef; use crate::sys::CliSys; -use deno_ast::MediaType; -use deno_cache_dir::file_fetcher::CacheSetting; -use deno_cache_dir::file_fetcher::FetchNoFollowErrorKind; -use deno_cache_dir::file_fetcher::FileOrRedirect; -use deno_core::error::AnyError; -use deno_core::futures; -use deno_core::futures::FutureExt; -use deno_core::ModuleSpecifier; -use deno_graph::source::CacheInfo; -use deno_graph::source::LoadFuture; -use deno_graph::source::LoadResponse; -use deno_graph::source::Loader; -use deno_runtime::deno_permissions::PermissionsContainer; -use node_resolver::InNpmPackageChecker; -use std::collections::HashMap; -use std::path::PathBuf; -use std::sync::Arc; - mod cache_db; mod caches; mod check; mod code_cache; mod common; -mod deno_dir; -mod disk_cache; mod emit; mod fast_check; mod incremental; @@ -44,9 +43,8 @@ pub use caches::Caches; pub use check::TypeCheckCache; pub use code_cache::CodeCache; pub use common::FastInsecureHasher; -pub use deno_dir::DenoDir; -pub use deno_dir::DenoDirProvider; -pub use disk_cache::DiskCache; +/// Permissions used to save a file in the disk caches. +pub use deno_cache_dir::CACHE_PERM; pub use emit::EmitCache; pub use fast_check::FastCheckCache; pub use incremental::IncrementalCache; @@ -55,13 +53,11 @@ pub use node::NodeAnalysisCache; pub use parsed_source::LazyGraphSourceParser; pub use parsed_source::ParsedSourceCache; -/// Permissions used to save a file in the disk caches. -pub use deno_cache_dir::CACHE_PERM; - pub type GlobalHttpCache = deno_cache_dir::GlobalHttpCache; pub type LocalHttpCache = deno_cache_dir::LocalHttpCache; pub type LocalLspHttpCache = deno_cache_dir::LocalLspHttpCache; pub use deno_cache_dir::HttpCache; +use deno_error::JsErrorBox; pub struct FetchCacherOptions { pub file_header_overrides: HashMap>, @@ -76,7 +72,7 @@ pub struct FetchCacher { pub file_header_overrides: HashMap>, file_fetcher: Arc, global_http_cache: Arc, - in_npm_pkg_checker: Arc, + in_npm_pkg_checker: DenoInNpmPackageChecker, module_info_cache: Arc, permissions: PermissionsContainer, sys: CliSys, @@ -88,7 +84,7 @@ impl FetchCacher { pub fn new( file_fetcher: Arc, global_http_cache: Arc, - in_npm_pkg_checker: Arc, + in_npm_pkg_checker: DenoInNpmPackageChecker, module_info_cache: Arc, sys: CliSys, options: FetchCacherOptions, @@ -194,9 +190,9 @@ impl Loader for FetchCacher { LoaderCacheSetting::Use => None, LoaderCacheSetting::Reload => { if matches!(file_fetcher.cache_setting(), CacheSetting::Only) { - return Err(deno_core::anyhow::anyhow!( + return Err(deno_graph::source::LoadError::Other(Arc::new(JsErrorBox::generic( "Could not resolve version constraint using only cached data. Try running again without --cached-only" - )); + )))); } Some(CacheSetting::ReloadAll) } @@ -262,28 +258,27 @@ impl Loader for FetchCacher { FetchNoFollowErrorKind::CacheSave { .. } | FetchNoFollowErrorKind::UnsupportedScheme { .. } | FetchNoFollowErrorKind::RedirectHeaderParse { .. } | - FetchNoFollowErrorKind::InvalidHeader { .. } => Err(AnyError::from(err)), + FetchNoFollowErrorKind::InvalidHeader { .. } => Err(deno_graph::source::LoadError::Other(Arc::new(JsErrorBox::from_err(err)))), FetchNoFollowErrorKind::NotCached { .. } => { if options.cache_setting == LoaderCacheSetting::Only { Ok(None) } else { - Err(AnyError::from(err)) + Err(deno_graph::source::LoadError::Other(Arc::new(JsErrorBox::from_err(err)))) } }, FetchNoFollowErrorKind::ChecksumIntegrity(err) => { // convert to the equivalent deno_graph error so that it // enhances it if this is passed to deno_graph Err( - deno_graph::source::ChecksumIntegrityError { + deno_graph::source::LoadError::ChecksumIntegrity(deno_graph::source::ChecksumIntegrityError { actual: err.actual, expected: err.expected, - } - .into(), + }), ) } } }, - CliFetchNoFollowErrorKind::PermissionCheck(permission_check_error) => Err(AnyError::from(permission_check_error)), + CliFetchNoFollowErrorKind::PermissionCheck(permission_check_error) => Err(deno_graph::source::LoadError::Other(Arc::new(JsErrorBox::from_err(permission_check_error)))), } }) } @@ -298,7 +293,7 @@ impl Loader for FetchCacher { module_info: &deno_graph::ModuleInfo, ) { log::debug!("Caching module info for {}", specifier); - let source_hash = CacheDBHash::from_source(source); + let source_hash = CacheDBHash::from_hashable(source); let result = self.module_info_cache.set_module_info( specifier, media_type, diff --git a/cli/cache/module_info.rs b/cli/cache/module_info.rs index 469e2fafac..63f52c06f9 100644 --- a/cli/cache/module_info.rs +++ b/cli/cache/module_info.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::sync::Arc; @@ -194,7 +194,7 @@ impl<'a> ModuleInfoCacheModuleAnalyzer<'a> { source: &Arc, ) -> Result { // attempt to load from the cache - let source_hash = CacheDBHash::from_source(source); + let source_hash = CacheDBHash::from_hashable(source); if let Some(info) = self.load_cached_module_info(specifier, media_type, source_hash) { @@ -228,7 +228,7 @@ impl<'a> deno_graph::ModuleAnalyzer for ModuleInfoCacheModuleAnalyzer<'a> { media_type: MediaType, ) -> Result { // attempt to load from the cache - let source_hash = CacheDBHash::from_source(&source); + let source_hash = CacheDBHash::from_hashable(&source); if let Some(info) = self.load_cached_module_info(specifier, media_type, source_hash) { diff --git a/cli/cache/node.rs b/cli/cache/node.rs index e80342e5c0..89e372de43 100644 --- a/cli/cache/node.rs +++ b/cli/cache/node.rs @@ -1,15 +1,14 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::error::AnyError; use deno_core::serde_json; use deno_runtime::deno_webstorage::rusqlite::params; -use crate::node::CliCjsAnalysis; - use super::cache_db::CacheDB; use super::cache_db::CacheDBConfiguration; use super::cache_db::CacheFailure; use super::CacheDBHash; +use crate::node::CliCjsAnalysis; pub static NODE_ANALYSIS_CACHE_DB: CacheDBConfiguration = CacheDBConfiguration { diff --git a/cli/cache/parsed_source.rs b/cli/cache/parsed_source.rs index 4d031f8bf2..15207f4ba7 100644 --- a/cli/cache/parsed_source.rs +++ b/cli/cache/parsed_source.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashMap; use std::sync::Arc; diff --git a/cli/cdp.rs b/cli/cdp.rs index c5ff587dde..df82d58d9f 100644 --- a/cli/cdp.rs +++ b/cli/cdp.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// use deno_core::serde_json::Value; diff --git a/cli/emit.rs b/cli/emit.rs index 733a89d832..69ac8323bb 100644 --- a/cli/emit.rs +++ b/cli/emit.rs @@ -1,9 +1,6 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::cache::EmitCache; -use crate::cache::FastInsecureHasher; -use crate::cache::ParsedSourceCache; -use crate::resolver::CjsTracker; +use std::sync::Arc; use deno_ast::EmittedSourceText; use deno_ast::ModuleKind; @@ -14,18 +11,24 @@ use deno_ast::SourceRangedForSpanned; use deno_ast::TranspileModuleOptions; use deno_ast::TranspileResult; use deno_core::error::AnyError; +use deno_core::error::CoreError; use deno_core::futures::stream::FuturesUnordered; use deno_core::futures::FutureExt; use deno_core::futures::StreamExt; use deno_core::ModuleSpecifier; +use deno_error::JsErrorBox; use deno_graph::MediaType; use deno_graph::Module; use deno_graph::ModuleGraph; -use std::sync::Arc; + +use crate::cache::EmitCache; +use crate::cache::FastInsecureHasher; +use crate::cache::ParsedSourceCache; +use crate::resolver::CliCjsTracker; #[derive(Debug)] pub struct Emitter { - cjs_tracker: Arc, + cjs_tracker: Arc, emit_cache: Arc, parsed_source_cache: Arc, transpile_and_emit_options: @@ -36,7 +39,7 @@ pub struct Emitter { impl Emitter { pub fn new( - cjs_tracker: Arc, + cjs_tracker: Arc, emit_cache: Arc, parsed_source_cache: Arc, transpile_options: deno_ast::TranspileOptions, @@ -123,7 +126,7 @@ impl Emitter { let transpiled_source = deno_core::unsync::spawn_blocking({ let specifier = specifier.clone(); let source = source.clone(); - move || -> Result<_, AnyError> { + move || { EmitParsedSourceHelper::transpile( &parsed_source_cache, &specifier, @@ -154,7 +157,7 @@ impl Emitter { media_type: MediaType, module_kind: deno_ast::ModuleKind, source: &Arc, - ) -> Result { + ) -> Result { // Note: keep this in sync with the async version above let helper = EmitParsedSourceHelper(self); match helper.pre_emit_parsed_source(specifier, module_kind, source) { @@ -209,7 +212,7 @@ impl Emitter { pub async fn load_and_emit_for_hmr( &self, specifier: &ModuleSpecifier, - ) -> Result { + ) -> Result { let media_type = MediaType::from_specifier(specifier); let source_code = tokio::fs::read_to_string( ModuleSpecifier::to_file_path(specifier).unwrap(), @@ -224,17 +227,21 @@ impl Emitter { let source_arc: Arc = source_code.into(); let parsed_source = self .parsed_source_cache - .remove_or_parse_module(specifier, source_arc, media_type)?; + .remove_or_parse_module(specifier, source_arc, media_type) + .map_err(JsErrorBox::from_err)?; // HMR doesn't work with embedded source maps for some reason, so set // the option to not use them (though you should test this out because // this statement is probably wrong) let mut options = self.transpile_and_emit_options.1.clone(); options.source_map = SourceMapOption::None; - let is_cjs = self.cjs_tracker.is_cjs_with_known_is_script( - specifier, - media_type, - parsed_source.compute_is_script(), - )?; + let is_cjs = self + .cjs_tracker + .is_cjs_with_known_is_script( + specifier, + media_type, + parsed_source.compute_is_script(), + ) + .map_err(JsErrorBox::from_err)?; let transpiled_source = parsed_source .transpile( &self.transpile_and_emit_options.0, @@ -242,7 +249,8 @@ impl Emitter { module_kind: Some(ModuleKind::from_is_cjs(is_cjs)), }, &options, - )? + ) + .map_err(JsErrorBox::from_err)? .into_source(); Ok(transpiled_source.text) } @@ -281,6 +289,19 @@ enum PreEmitResult { NotCached { source_hash: u64 }, } +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum EmitParsedSourceHelperError { + #[class(inherit)] + #[error(transparent)] + ParseDiagnostic(#[from] deno_ast::ParseDiagnostic), + #[class(inherit)] + #[error(transparent)] + Transpile(#[from] deno_ast::TranspileError), + #[class(inherit)] + #[error(transparent)] + Other(#[from] JsErrorBox), +} + /// Helper to share code between async and sync emit_parsed_source methods. struct EmitParsedSourceHelper<'a>(&'a Emitter); @@ -310,7 +331,7 @@ impl<'a> EmitParsedSourceHelper<'a> { source: Arc, transpile_options: &deno_ast::TranspileOptions, emit_options: &deno_ast::EmitOptions, - ) -> Result { + ) -> Result { // nothing else needs the parsed source at this point, so remove from // the cache in order to not transpile owned let parsed_source = parsed_source_cache @@ -350,7 +371,7 @@ impl<'a> EmitParsedSourceHelper<'a> { // todo(dsherret): this is a temporary measure until we have swc erroring for this fn ensure_no_import_assertion( parsed_source: &deno_ast::ParsedSource, -) -> Result<(), AnyError> { +) -> Result<(), JsErrorBox> { fn has_import_assertion(text: &str) -> bool { // good enough text.contains(" assert ") && !text.contains(" with ") @@ -359,7 +380,7 @@ fn ensure_no_import_assertion( fn create_err( parsed_source: &deno_ast::ParsedSource, range: SourceRange, - ) -> AnyError { + ) -> JsErrorBox { let text_info = parsed_source.text_info_lazy(); let loc = text_info.line_and_column_display(range.start); let mut msg = "Import assertions are deprecated. Use `with` keyword, instead of 'assert' keyword.".to_string(); @@ -372,7 +393,7 @@ fn ensure_no_import_assertion( loc.line_number, loc.column_number, )); - deno_core::anyhow::anyhow!("{}", msg) + JsErrorBox::generic(msg) } let deno_ast::ProgramRef::Module(module) = parsed_source.program_ref() else { diff --git a/cli/errors.rs b/cli/errors.rs deleted file mode 100644 index 38dc8259e3..0000000000 --- a/cli/errors.rs +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. - -//! There are many types of errors in Deno: -//! - AnyError: a generic wrapper that can encapsulate any type of error. -//! - JsError: a container for the error message and stack trace for exceptions -//! thrown in JavaScript code. We use this to pretty-print stack traces. -//! - Diagnostic: these are errors that originate in TypeScript's compiler. -//! They're similar to JsError, in that they have line numbers. But -//! Diagnostics are compile-time type errors, whereas JsErrors are runtime -//! exceptions. - -use deno_ast::ParseDiagnostic; -use deno_core::error::AnyError; -use deno_graph::source::ResolveError; -use deno_graph::ModuleError; -use deno_graph::ModuleGraphError; -use deno_graph::ModuleLoadError; -use deno_graph::ResolutionError; -use import_map::ImportMapError; - -fn get_import_map_error_class(_: &ImportMapError) -> &'static str { - "URIError" -} - -fn get_diagnostic_class(_: &ParseDiagnostic) -> &'static str { - "SyntaxError" -} - -fn get_module_graph_error_class(err: &ModuleGraphError) -> &'static str { - use deno_graph::JsrLoadError; - use deno_graph::NpmLoadError; - - match err { - ModuleGraphError::ResolutionError(err) - | ModuleGraphError::TypesResolutionError(err) => { - get_resolution_error_class(err) - } - ModuleGraphError::ModuleError(err) => match err { - ModuleError::InvalidTypeAssertion { .. } => "SyntaxError", - ModuleError::ParseErr(_, diagnostic) => get_diagnostic_class(diagnostic), - ModuleError::WasmParseErr(..) => "SyntaxError", - ModuleError::UnsupportedMediaType { .. } - | ModuleError::UnsupportedImportAttributeType { .. } => "TypeError", - ModuleError::Missing(_, _) | ModuleError::MissingDynamic(_, _) => { - "NotFound" - } - ModuleError::LoadingErr(_, _, err) => match err { - ModuleLoadError::Loader(err) => get_error_class_name(err.as_ref()), - ModuleLoadError::HttpsChecksumIntegrity(_) - | ModuleLoadError::TooManyRedirects => "Error", - ModuleLoadError::NodeUnknownBuiltinModule(_) => "NotFound", - ModuleLoadError::Decode(_) => "TypeError", - ModuleLoadError::Npm(err) => match err { - NpmLoadError::NotSupportedEnvironment - | NpmLoadError::PackageReqResolution(_) - | NpmLoadError::RegistryInfo(_) => "Error", - NpmLoadError::PackageReqReferenceParse(_) => "TypeError", - }, - ModuleLoadError::Jsr(err) => match err { - JsrLoadError::UnsupportedManifestChecksum - | JsrLoadError::PackageFormat(_) => "TypeError", - JsrLoadError::ContentLoadExternalSpecifier - | JsrLoadError::ContentLoad(_) - | JsrLoadError::ContentChecksumIntegrity(_) - | JsrLoadError::PackageManifestLoad(_, _) - | JsrLoadError::PackageVersionManifestChecksumIntegrity(..) - | JsrLoadError::PackageVersionManifestLoad(_, _) - | JsrLoadError::RedirectInPackage(_) => "Error", - JsrLoadError::PackageNotFound(_) - | JsrLoadError::PackageReqNotFound(_) - | JsrLoadError::PackageVersionNotFound(_) - | JsrLoadError::UnknownExport { .. } => "NotFound", - }, - }, - }, - } -} - -fn get_resolution_error_class(err: &ResolutionError) -> &'static str { - match err { - ResolutionError::ResolverError { error, .. } => { - use ResolveError::*; - match error.as_ref() { - Specifier(_) => "TypeError", - Other(e) => get_error_class_name(e), - } - } - _ => "TypeError", - } -} - -fn get_try_from_int_error_class(_: &std::num::TryFromIntError) -> &'static str { - "TypeError" -} - -pub fn get_error_class_name(e: &AnyError) -> &'static str { - deno_runtime::errors::get_error_class_name(e) - .or_else(|| { - e.downcast_ref::() - .map(get_import_map_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_diagnostic_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_module_graph_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_resolution_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_try_from_int_error_class) - }) - .unwrap_or("Error") -} diff --git a/cli/factory.rs b/cli/factory.rs index e33b95d235..bfe6d05570 100644 --- a/cli/factory.rs +++ b/cli/factory.rs @@ -1,4 +1,45 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::future::Future; +use std::path::PathBuf; +use std::sync::Arc; + +use deno_cache_dir::npm::NpmCacheDir; +use deno_config::workspace::PackageJsonDepResolution; +use deno_config::workspace::WorkspaceResolver; +use deno_core::error::AnyError; +use deno_core::futures::FutureExt; +use deno_core::FeatureChecker; +use deno_error::JsErrorBox; +use deno_lib::cache::DenoDir; +use deno_lib::cache::DenoDirProvider; +use deno_lib::npm::NpmRegistryReadPermissionChecker; +use deno_lib::npm::NpmRegistryReadPermissionCheckerMode; +use deno_lib::worker::LibMainWorkerFactory; +use deno_lib::worker::LibMainWorkerOptions; +use deno_npm_cache::NpmCacheSetting; +use deno_resolver::cjs::IsCjsResolutionMode; +use deno_resolver::npm::managed::ManagedInNpmPkgCheckerCreateOptions; +use deno_resolver::npm::managed::NpmResolutionCell; +use deno_resolver::npm::CreateInNpmPkgCheckerOptions; +use deno_resolver::npm::DenoInNpmPackageChecker; +use deno_resolver::npm::NpmReqResolverOptions; +use deno_resolver::sloppy_imports::SloppyImportsCachedFs; +use deno_resolver::DenoResolverOptions; +use deno_resolver::NodeAndNpmReqResolver; +use deno_runtime::deno_fs; +use deno_runtime::deno_fs::RealFs; +use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker; +use deno_runtime::deno_permissions::Permissions; +use deno_runtime::deno_permissions::PermissionsContainer; +use deno_runtime::deno_tls::rustls::RootCertStore; +use deno_runtime::deno_tls::RootCertStoreProvider; +use deno_runtime::deno_web::BlobStore; +use deno_runtime::inspector_server::InspectorServer; +use deno_runtime::permissions::RuntimePermissionDescriptorParser; +use log::warn; +use node_resolver::analyze::NodeCodeTranslator; +use once_cell::sync::OnceCell; use crate::args::check_warn_tsconfig; use crate::args::get_root_cert_store; @@ -7,12 +48,9 @@ use crate::args::CliOptions; use crate::args::DenoSubcommand; use crate::args::Flags; use crate::args::NpmInstallDepsProvider; -use crate::args::StorageKeyResolver; use crate::args::TsConfigType; use crate::cache::Caches; use crate::cache::CodeCache; -use crate::cache::DenoDir; -use crate::cache::DenoDirProvider; use crate::cache::EmitCache; use crate::cache::GlobalHttpCache; use crate::cache::HttpCache; @@ -33,23 +71,27 @@ use crate::node::CliCjsCodeAnalyzer; use crate::node::CliNodeCodeTranslator; use crate::node::CliNodeResolver; use crate::node::CliPackageJsonResolver; -use crate::npm::create_cli_npm_resolver; -use crate::npm::create_in_npm_pkg_checker; +use crate::npm::create_npm_process_state_provider; +use crate::npm::installer::NpmInstaller; +use crate::npm::installer::NpmResolutionInstaller; use crate::npm::CliByonmNpmResolverCreateOptions; -use crate::npm::CliManagedInNpmPkgCheckerCreateOptions; use crate::npm::CliManagedNpmResolverCreateOptions; +use crate::npm::CliNpmCache; +use crate::npm::CliNpmCacheHttpClient; +use crate::npm::CliNpmRegistryInfoProvider; use crate::npm::CliNpmResolver; use crate::npm::CliNpmResolverCreateOptions; use crate::npm::CliNpmResolverManagedSnapshotOption; -use crate::npm::CreateInNpmPkgCheckerOptions; -use crate::resolver::CjsTracker; +use crate::npm::CliNpmTarballCache; +use crate::npm::NpmResolutionInitializer; +use crate::resolver::CliCjsTracker; use crate::resolver::CliDenoResolver; +use crate::resolver::CliNpmGraphResolver; use crate::resolver::CliNpmReqResolver; use crate::resolver::CliResolver; -use crate::resolver::CliResolverOptions; use crate::resolver::CliSloppyImportsResolver; +use crate::resolver::FoundPackageJsonDepFlag; use crate::resolver::NpmModuleLoader; -use crate::resolver::SloppyImportsCachedFs; use crate::standalone::binary::DenoCompileBinaryWriter; use crate::sys::CliSys; use crate::tools::check::TypeChecker; @@ -63,35 +105,6 @@ use crate::util::progress_bar::ProgressBar; use crate::util::progress_bar::ProgressBarStyle; use crate::worker::CliMainWorkerFactory; use crate::worker::CliMainWorkerOptions; -use std::path::PathBuf; - -use deno_cache_dir::npm::NpmCacheDir; -use deno_config::workspace::PackageJsonDepResolution; -use deno_config::workspace::WorkspaceResolver; -use deno_core::error::AnyError; -use deno_core::futures::FutureExt; -use deno_core::FeatureChecker; - -use deno_resolver::cjs::IsCjsResolutionMode; -use deno_resolver::npm::NpmReqResolverOptions; -use deno_resolver::DenoResolverOptions; -use deno_resolver::NodeAndNpmReqResolver; -use deno_runtime::deno_fs; -use deno_runtime::deno_fs::RealFs; -use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker; -use deno_runtime::deno_permissions::Permissions; -use deno_runtime::deno_permissions::PermissionsContainer; -use deno_runtime::deno_tls::rustls::RootCertStore; -use deno_runtime::deno_tls::RootCertStoreProvider; -use deno_runtime::deno_web::BlobStore; -use deno_runtime::inspector_server::InspectorServer; -use deno_runtime::permissions::RuntimePermissionDescriptorParser; -use log::warn; -use node_resolver::analyze::NodeCodeTranslator; -use node_resolver::InNpmPackageChecker; -use once_cell::sync::OnceCell; -use std::future::Future; -use std::sync::Arc; struct CliRootCertStoreProvider { cell: OnceCell, @@ -116,7 +129,7 @@ impl CliRootCertStoreProvider { } impl RootCertStoreProvider for CliRootCertStoreProvider { - fn get_or_try_init(&self) -> Result<&RootCertStore, AnyError> { + fn get_or_try_init(&self) -> Result<&RootCertStore, JsErrorBox> { self .cell .get_or_try_init(|| { @@ -126,7 +139,7 @@ impl RootCertStoreProvider for CliRootCertStoreProvider { self.maybe_ca_data.clone(), ) }) - .map_err(|e| e.into()) + .map_err(JsErrorBox::from_err) } } @@ -178,7 +191,7 @@ impl Deferred { struct CliFactoryServices { blob_store: Deferred>, caches: Deferred>, - cjs_tracker: Deferred>, + cjs_tracker: Deferred>, cli_options: Deferred>, code_cache: Deferred>, deno_resolver: Deferred>, @@ -186,11 +199,12 @@ struct CliFactoryServices { emitter: Deferred>, feature_checker: Deferred>, file_fetcher: Deferred>, + found_pkg_json_dep_flag: Arc, fs: Deferred>, global_http_cache: Deferred>, http_cache: Deferred>, http_client_provider: Deferred>, - in_npm_pkg_checker: Deferred>, + in_npm_pkg_checker: Deferred, main_graph_container: Deferred>, maybe_file_watcher_reporter: Deferred>, maybe_inspector_server: Deferred>>, @@ -200,9 +214,18 @@ struct CliFactoryServices { module_load_preparer: Deferred>, node_code_translator: Deferred>, node_resolver: Deferred>, + npm_cache: Deferred>, npm_cache_dir: Deferred>, + npm_cache_http_client: Deferred>, + npm_graph_resolver: Deferred>, + npm_installer: Deferred>, + npm_registry_info_provider: Deferred>, npm_req_resolver: Deferred>, - npm_resolver: Deferred>, + npm_resolution: Arc, + npm_resolution_initializer: Deferred>, + npm_resolution_installer: Deferred>, + npm_resolver: Deferred, + npm_tarball_cache: Deferred>, parsed_source_cache: Deferred>, permission_desc_parser: Deferred>>, @@ -260,11 +283,13 @@ impl CliFactory { }) } - pub fn deno_dir_provider(&self) -> Result<&Arc, AnyError> { + pub fn deno_dir_provider( + &self, + ) -> Result<&Arc>, AnyError> { Ok(&self.cli_options()?.deno_dir_provider) } - pub fn deno_dir(&self) -> Result<&DenoDir, AnyError> { + pub fn deno_dir(&self) -> Result<&DenoDir, AnyError> { Ok(self.deno_dir_provider()?.get_or_create()?) } @@ -377,14 +402,14 @@ impl CliFactory { pub fn in_npm_pkg_checker( &self, - ) -> Result<&Arc, AnyError> { + ) -> Result<&DenoInNpmPackageChecker, AnyError> { self.services.in_npm_pkg_checker.get_or_try_init(|| { let cli_options = self.cli_options()?; let options = if cli_options.use_byonm() { CreateInNpmPkgCheckerOptions::Byonm } else { CreateInNpmPkgCheckerOptions::Managed( - CliManagedInNpmPkgCheckerCreateOptions { + ManagedInNpmPkgCheckerCreateOptions { root_cache_dir_url: self.npm_cache_dir()?.root_dir_url(), maybe_node_modules_path: cli_options .node_modules_dir_path() @@ -392,7 +417,19 @@ impl CliFactory { }, ) }; - Ok(create_in_npm_pkg_checker(options)) + Ok(DenoInNpmPackageChecker::new(options)) + }) + } + + pub fn npm_cache(&self) -> Result<&Arc, AnyError> { + self.services.npm_cache.get_or_try_init(|| { + let cli_options = self.cli_options()?; + Ok(Arc::new(CliNpmCache::new( + self.npm_cache_dir()?.clone(), + self.sys(), + NpmCacheSetting::from_cache_setting(&cli_options.cache_setting()), + cli_options.npmrc().clone(), + ))) }) } @@ -408,16 +445,131 @@ impl CliFactory { }) } - pub async fn npm_resolver( + pub fn npm_cache_http_client(&self) -> &Arc { + self.services.npm_cache_http_client.get_or_init(|| { + Arc::new(CliNpmCacheHttpClient::new( + self.http_client_provider().clone(), + self.text_only_progress_bar().clone(), + )) + }) + } + + pub fn npm_graph_resolver( &self, - ) -> Result<&Arc, AnyError> { + ) -> Result<&Arc, AnyError> { + self.services.npm_graph_resolver.get_or_try_init(|| { + let cli_options = self.cli_options()?; + Ok(Arc::new(CliNpmGraphResolver::new( + self.npm_installer_if_managed()?.cloned(), + self.services.found_pkg_json_dep_flag.clone(), + cli_options.unstable_bare_node_builtins(), + cli_options.default_npm_caching_strategy(), + ))) + }) + } + + pub fn npm_installer_if_managed( + &self, + ) -> Result>, AnyError> { + let options = self.cli_options()?; + if options.use_byonm() || options.no_npm() { + Ok(None) + } else { + Ok(Some(self.npm_installer()?)) + } + } + + pub fn npm_installer(&self) -> Result<&Arc, AnyError> { + self.services.npm_installer.get_or_try_init(|| { + let cli_options = self.cli_options()?; + Ok(Arc::new(NpmInstaller::new( + self.npm_cache()?.clone(), + Arc::new(NpmInstallDepsProvider::from_workspace( + cli_options.workspace(), + )), + self.npm_resolution().clone(), + self.npm_resolution_initializer()?.clone(), + self.npm_resolution_installer()?.clone(), + self.text_only_progress_bar(), + self.sys(), + self.npm_tarball_cache()?.clone(), + cli_options.maybe_lockfile().cloned(), + cli_options.node_modules_dir_path().cloned(), + cli_options.lifecycle_scripts_config(), + cli_options.npm_system_info(), + ))) + }) + } + + pub fn npm_registry_info_provider( + &self, + ) -> Result<&Arc, AnyError> { + self + .services + .npm_registry_info_provider + .get_or_try_init(|| { + let cli_options = self.cli_options()?; + Ok(Arc::new(CliNpmRegistryInfoProvider::new( + self.npm_cache()?.clone(), + self.npm_cache_http_client().clone(), + cli_options.npmrc().clone(), + ))) + }) + } + + pub fn npm_resolution(&self) -> &Arc { + &self.services.npm_resolution + } + + pub fn npm_resolution_initializer( + &self, + ) -> Result<&Arc, AnyError> { + self + .services + .npm_resolution_initializer + .get_or_try_init(|| { + let cli_options = self.cli_options()?; + Ok(Arc::new(NpmResolutionInitializer::new( + self.npm_registry_info_provider()?.clone(), + self.npm_resolution().clone(), + match cli_options.resolve_npm_resolution_snapshot()? { + Some(snapshot) => { + CliNpmResolverManagedSnapshotOption::Specified(Some(snapshot)) + } + None => match cli_options.maybe_lockfile() { + Some(lockfile) => { + CliNpmResolverManagedSnapshotOption::ResolveFromLockfile( + lockfile.clone(), + ) + } + None => CliNpmResolverManagedSnapshotOption::Specified(None), + }, + }, + ))) + }) + } + + pub fn npm_resolution_installer( + &self, + ) -> Result<&Arc, AnyError> { + self.services.npm_resolution_installer.get_or_try_init(|| { + let cli_options = self.cli_options()?; + Ok(Arc::new(NpmResolutionInstaller::new( + self.npm_registry_info_provider()?.clone(), + self.npm_resolution().clone(), + cli_options.maybe_lockfile().cloned(), + ))) + }) + } + + pub async fn npm_resolver(&self) -> Result<&CliNpmResolver, AnyError> { self .services .npm_resolver .get_or_try_init_async( async { let cli_options = self.cli_options()?; - create_cli_npm_resolver(if cli_options.use_byonm() { + Ok(CliNpmResolver::new(if cli_options.use_byonm() { CliNpmResolverCreateOptions::Byonm( CliByonmNpmResolverCreateOptions { sys: self.sys(), @@ -436,52 +588,43 @@ impl CliFactory { }, ) } else { + self + .npm_resolution_initializer()? + .ensure_initialized() + .await?; CliNpmResolverCreateOptions::Managed( CliManagedNpmResolverCreateOptions { - http_client_provider: self.http_client_provider().clone(), - npm_install_deps_provider: Arc::new( - NpmInstallDepsProvider::from_workspace( - cli_options.workspace(), - ), - ), sys: self.sys(), - snapshot: match cli_options.resolve_npm_resolution_snapshot()? { - Some(snapshot) => { - CliNpmResolverManagedSnapshotOption::Specified(Some( - snapshot, - )) - } - None => match cli_options.maybe_lockfile() { - Some(lockfile) => { - CliNpmResolverManagedSnapshotOption::ResolveFromLockfile( - lockfile.clone(), - ) - } - None => { - CliNpmResolverManagedSnapshotOption::Specified(None) - } - }, - }, - maybe_lockfile: cli_options.maybe_lockfile().cloned(), + npm_resolution: self.npm_resolution().clone(), npm_cache_dir: self.npm_cache_dir()?.clone(), - cache_setting: cli_options.cache_setting(), - text_only_progress_bar: self.text_only_progress_bar().clone(), maybe_node_modules_path: cli_options .node_modules_dir_path() .cloned(), npm_system_info: cli_options.npm_system_info(), npmrc: cli_options.npmrc().clone(), - lifecycle_scripts: cli_options.lifecycle_scripts_config(), }, ) - }) - .await + })) } .boxed_local(), ) .await } + pub fn npm_tarball_cache( + &self, + ) -> Result<&Arc, AnyError> { + self.services.npm_tarball_cache.get_or_try_init(|| { + let cli_options = self.cli_options()?; + Ok(Arc::new(CliNpmTarballCache::new( + self.npm_cache()?.clone(), + self.npm_cache_http_client().clone(), + self.sys(), + cli_options.npmrc().clone(), + ))) + }) + } + pub fn sloppy_imports_resolver( &self, ) -> Result>, AnyError> { @@ -569,17 +712,10 @@ impl CliFactory { .resolver .get_or_try_init_async( async { - let cli_options = self.cli_options()?; - Ok(Arc::new(CliResolver::new(CliResolverOptions { - npm_resolver: if cli_options.no_npm() { - None - } else { - Some(self.npm_resolver().await?.clone()) - }, - bare_node_builtins_enabled: cli_options - .unstable_bare_node_builtins(), - deno_resolver: self.deno_resolver().await?.clone(), - }))) + Ok(Arc::new(CliResolver::new( + self.deno_resolver().await?.clone(), + self.services.found_pkg_json_dep_flag.clone(), + ))) } .boxed_local(), ) @@ -661,13 +797,10 @@ impl CliFactory { Ok(Arc::new(CliNodeResolver::new( self.in_npm_pkg_checker()?.clone(), RealIsBuiltInNodeModuleChecker, - self - .npm_resolver() - .await? - .clone() - .into_npm_pkg_folder_resolver(), + self.npm_resolver().await?.clone(), self.pkg_json_resolver().clone(), self.sys(), + node_resolver::ConditionsFromResolutionMode::default(), ))) } .boxed_local(), @@ -697,11 +830,7 @@ impl CliFactory { cjs_esm_analyzer, self.in_npm_pkg_checker()?.clone(), node_resolver, - self - .npm_resolver() - .await? - .clone() - .into_npm_pkg_folder_resolver(), + self.npm_resolver().await?.clone(), self.pkg_json_resolver().clone(), self.sys(), ))) @@ -718,11 +847,10 @@ impl CliFactory { .get_or_try_init_async(async { let npm_resolver = self.npm_resolver().await?; Ok(Arc::new(CliNpmReqResolver::new(NpmReqResolverOptions { - byonm_resolver: (npm_resolver.clone()).into_maybe_byonm(), sys: self.sys(), in_npm_pkg_checker: self.in_npm_pkg_checker()?.clone(), node_resolver: self.node_resolver().await?.clone(), - npm_req_resolver: npm_resolver.clone().into_npm_req_resolver(), + npm_resolver: npm_resolver.clone(), }))) }) .await @@ -750,7 +878,9 @@ impl CliFactory { cli_options.clone(), self.module_graph_builder().await?.clone(), self.node_resolver().await?.clone(), + self.npm_installer_if_managed()?.cloned(), self.npm_resolver().await?.clone(), + self.sys(), ))) }) .await @@ -774,6 +904,8 @@ impl CliFactory { cli_options.maybe_lockfile().cloned(), self.maybe_file_watcher_reporter().clone(), self.module_info_cache()?.clone(), + self.npm_graph_resolver()?.clone(), + self.npm_installer_if_managed()?.cloned(), self.npm_resolver().await?.clone(), self.parsed_source_cache().clone(), self.resolver().await?.clone(), @@ -794,7 +926,7 @@ impl CliFactory { let cli_options = self.cli_options()?; Ok(Arc::new(ModuleGraphCreator::new( cli_options.clone(), - self.npm_resolver().await?.clone(), + self.npm_installer_if_managed()?.cloned(), self.module_graph_builder().await?.clone(), self.type_checker().await?.clone(), ))) @@ -849,10 +981,10 @@ impl CliFactory { .await } - pub fn cjs_tracker(&self) -> Result<&Arc, AnyError> { + pub fn cjs_tracker(&self) -> Result<&Arc, AnyError> { self.services.cjs_tracker.get_or_try_init(|| { let options = self.cli_options()?; - Ok(Arc::new(CjsTracker::new( + Ok(Arc::new(CliCjsTracker::new( self.in_npm_pkg_checker()?.clone(), self.pkg_json_resolver().clone(), if options.is_node_main() || options.unstable_detect_cjs() { @@ -901,7 +1033,7 @@ impl CliFactory { self.emitter()?, self.file_fetcher()?, self.http_client_provider(), - self.npm_resolver().await?.as_ref(), + self.npm_resolver().await?, self.workspace_resolver().await?.as_ref(), cli_options.npm_system_info(), )) @@ -941,8 +1073,48 @@ impl CliFactory { let cjs_tracker = self.cjs_tracker()?.clone(); let pkg_json_resolver = self.pkg_json_resolver().clone(); let npm_req_resolver = self.npm_req_resolver().await?; + let npm_registry_permission_checker = { + let mode = if cli_options.use_byonm() { + NpmRegistryReadPermissionCheckerMode::Byonm + } else if let Some(node_modules_dir) = cli_options.node_modules_dir_path() + { + NpmRegistryReadPermissionCheckerMode::Local(node_modules_dir.clone()) + } else { + NpmRegistryReadPermissionCheckerMode::Global( + self.npm_cache_dir()?.root_dir().to_path_buf(), + ) + }; + Arc::new(NpmRegistryReadPermissionChecker::new(self.sys(), mode)) + }; - Ok(CliMainWorkerFactory::new( + let module_loader_factory = CliModuleLoaderFactory::new( + cli_options, + cjs_tracker, + if cli_options.code_cache_enabled() { + Some(self.code_cache()?.clone()) + } else { + None + }, + self.emitter()?.clone(), + in_npm_pkg_checker.clone(), + self.main_module_graph_container().await?.clone(), + self.module_load_preparer().await?.clone(), + node_code_translator.clone(), + node_resolver.clone(), + NpmModuleLoader::new( + self.cjs_tracker()?.clone(), + fs.clone(), + node_code_translator.clone(), + ), + npm_registry_permission_checker, + npm_req_resolver.clone(), + cli_npm_resolver.clone(), + self.parsed_source_cache().clone(), + self.resolver().await?.clone(), + self.sys(), + ); + + let lib_main_worker_factory = LibMainWorkerFactory::new( self.blob_store().clone(), if cli_options.code_cache_enabled() { Some(self.code_cache()?.clone()) @@ -951,48 +1123,70 @@ impl CliFactory { }, self.feature_checker()?.clone(), fs.clone(), - maybe_file_watcher_communicator, self.maybe_inspector_server()?.clone(), - cli_options.maybe_lockfile().cloned(), - Box::new(CliModuleLoaderFactory::new( - cli_options, - cjs_tracker, - if cli_options.code_cache_enabled() { - Some(self.code_cache()?.clone()) - } else { - None - }, - self.emitter()?.clone(), - in_npm_pkg_checker.clone(), - self.main_module_graph_container().await?.clone(), - self.module_load_preparer().await?.clone(), - node_code_translator.clone(), - node_resolver.clone(), - npm_req_resolver.clone(), - cli_npm_resolver.clone(), - NpmModuleLoader::new( - self.cjs_tracker()?.clone(), - fs.clone(), - node_code_translator.clone(), - ), - self.parsed_source_cache().clone(), - self.resolver().await?.clone(), - self.sys(), - )), + Box::new(module_loader_factory), node_resolver.clone(), - npm_resolver.clone(), + create_npm_process_state_provider(npm_resolver), pkg_json_resolver, self.root_cert_store_provider().clone(), - self.root_permissions_container()?.clone(), - StorageKeyResolver::from_options(cli_options), + cli_options.resolve_storage_key_resolver(), + self.sys(), + self.create_lib_main_worker_options()?, + ); + + Ok(CliMainWorkerFactory::new( + lib_main_worker_factory, + maybe_file_watcher_communicator, + cli_options.maybe_lockfile().cloned(), + node_resolver.clone(), + self.npm_installer_if_managed()?.cloned(), + npm_resolver.clone(), self.sys(), - cli_options.sub_command().clone(), self.create_cli_main_worker_options()?, - self.cli_options()?.otel_config(), - self.cli_options()?.default_npm_caching_strategy(), + self.root_permissions_container()?.clone(), )) } + fn create_lib_main_worker_options( + &self, + ) -> Result { + let cli_options = self.cli_options()?; + Ok(LibMainWorkerOptions { + argv: cli_options.argv().clone(), + // This optimization is only available for "run" subcommand + // because we need to register new ops for testing and jupyter + // integration. + skip_op_registration: cli_options.sub_command().is_run(), + log_level: cli_options.log_level().unwrap_or(log::Level::Info).into(), + enable_op_summary_metrics: cli_options.enable_op_summary_metrics(), + enable_testing_features: cli_options.enable_testing_features(), + has_node_modules_dir: cli_options.has_node_modules_dir(), + inspect_brk: cli_options.inspect_brk().is_some(), + inspect_wait: cli_options.inspect_wait().is_some(), + strace_ops: cli_options.strace_ops().clone(), + is_inspecting: cli_options.is_inspecting(), + location: cli_options.location_flag().clone(), + // if the user ran a binary command, we'll need to set process.argv[0] + // to be the name of the binary command instead of deno + argv0: cli_options + .take_binary_npm_command_name() + .or(std::env::args().next()), + node_debug: std::env::var("NODE_DEBUG").ok(), + origin_data_folder_path: Some(self.deno_dir()?.origin_data_folder_path()), + seed: cli_options.seed(), + unsafely_ignore_certificate_errors: cli_options + .unsafely_ignore_certificate_errors() + .clone(), + node_ipc: cli_options.node_ipc_fd(), + serve_port: cli_options.serve_port(), + serve_host: cli_options.serve_host(), + deno_version: crate::version::DENO_VERSION_INFO.deno, + deno_user_agent: crate::version::DENO_VERSION_INFO.user_agent, + otel_config: self.cli_options()?.otel_config(), + startup_snapshot: crate::js::deno_isolate_init(), + }) + } + fn create_cli_main_worker_options( &self, ) -> Result { @@ -1024,37 +1218,10 @@ impl CliFactory { }; Ok(CliMainWorkerOptions { - argv: cli_options.argv().clone(), - // This optimization is only available for "run" subcommand - // because we need to register new ops for testing and jupyter - // integration. - skip_op_registration: cli_options.sub_command().is_run(), - log_level: cli_options.log_level().unwrap_or(log::Level::Info).into(), - enable_op_summary_metrics: cli_options.enable_op_summary_metrics(), - enable_testing_features: cli_options.enable_testing_features(), - has_node_modules_dir: cli_options.has_node_modules_dir(), - hmr: cli_options.has_hmr(), - inspect_brk: cli_options.inspect_brk().is_some(), - inspect_wait: cli_options.inspect_wait().is_some(), - strace_ops: cli_options.strace_ops().clone(), - is_inspecting: cli_options.is_inspecting(), - location: cli_options.location_flag().clone(), - // if the user ran a binary command, we'll need to set process.argv[0] - // to be the name of the binary command instead of deno - argv0: cli_options - .take_binary_npm_command_name() - .or(std::env::args().next()), - node_debug: std::env::var("NODE_DEBUG").ok(), - origin_data_folder_path: Some(self.deno_dir()?.origin_data_folder_path()), - seed: cli_options.seed(), - unsafely_ignore_certificate_errors: cli_options - .unsafely_ignore_certificate_errors() - .clone(), + needs_test_modules: cli_options.sub_command().needs_test(), create_hmr_runner, create_coverage_collector, - node_ipc: cli_options.node_ipc_fd(), - serve_port: cli_options.serve_port(), - serve_host: cli_options.serve_host(), + default_npm_caching_strategy: cli_options.default_npm_caching_strategy(), }) } } diff --git a/cli/file_fetcher.rs b/cli/file_fetcher.rs index 7e8438d639..cfc26d7e69 100644 --- a/cli/file_fetcher.rs +++ b/cli/file_fetcher.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::collections::HashMap; @@ -498,10 +498,6 @@ fn validate_scheme(specifier: &Url) -> Result<(), UnsupportedSchemeError> { #[cfg(test)] mod tests { - use crate::cache::GlobalHttpCache; - use crate::http_util::HttpClientProvider; - - use super::*; use deno_cache_dir::file_fetcher::FetchNoFollowErrorKind; use deno_cache_dir::file_fetcher::HttpClient; use deno_core::resolve_url; @@ -509,6 +505,10 @@ mod tests { use deno_runtime::deno_web::InMemoryBlobPart; use test_util::TempDir; + use super::*; + use crate::cache::GlobalHttpCache; + use crate::http_util::HttpClientProvider; + fn setup( cache_setting: CacheSetting, maybe_temp_dir: Option, diff --git a/cli/graph_container.rs b/cli/graph_container.rs index c463d71a6a..1fe30b47ab 100644 --- a/cli/graph_container.rs +++ b/cli/graph_container.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::sync::Arc; diff --git a/cli/graph_util.rs b/cli/graph_util.rs index 68d48d9bbc..e57fcf8a94 100644 --- a/cli/graph_util.rs +++ b/cli/graph_util.rs @@ -1,18 +1,20 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashSet; use std::error::Error; -use std::ops::Deref; use std::path::PathBuf; use std::sync::Arc; +use deno_config::deno_json; use deno_config::deno_json::JsxImportSourceConfig; +use deno_config::deno_json::NodeModulesDirMode; use deno_config::workspace::JsrPackageConfig; -use deno_core::anyhow::bail; -use deno_core::error::custom_error; use deno_core::error::AnyError; use deno_core::parking_lot::Mutex; +use deno_core::serde_json; use deno_core::ModuleSpecifier; +use deno_error::JsErrorBox; +use deno_error::JsErrorClass; use deno_graph::source::Loader; use deno_graph::source::LoaderChecksum; use deno_graph::source::ResolutionKind; @@ -28,14 +30,14 @@ use deno_graph::ResolutionError; use deno_graph::SpecifierError; use deno_graph::WorkspaceFastCheckOption; use deno_path_util::url_to_file_path; +use deno_resolver::npm::DenoInNpmPackageChecker; +use deno_resolver::sloppy_imports::SloppyImportsCachedFs; use deno_resolver::sloppy_imports::SloppyImportsResolutionKind; use deno_runtime::deno_node; use deno_runtime::deno_permissions::PermissionsContainer; use deno_semver::jsr::JsrDepPackageReq; use deno_semver::package::PackageNv; use deno_semver::SmallStackString; -use import_map::ImportMapError; -use node_resolver::InNpmPackageChecker; use crate::args::config_to_deno_graph_workspace_member; use crate::args::jsr_url; @@ -49,15 +51,17 @@ use crate::cache::GlobalHttpCache; use crate::cache::ModuleInfoCache; use crate::cache::ParsedSourceCache; use crate::colors; -use crate::errors::get_error_class_name; use crate::file_fetcher::CliFileFetcher; +use crate::npm::installer::NpmInstaller; +use crate::npm::installer::PackageCaching; use crate::npm::CliNpmResolver; -use crate::resolver::CjsTracker; +use crate::resolver::CliCjsTracker; +use crate::resolver::CliNpmGraphResolver; use crate::resolver::CliResolver; use crate::resolver::CliSloppyImportsResolver; -use crate::resolver::SloppyImportsCachedFs; use crate::sys::CliSys; use crate::tools::check; +use crate::tools::check::CheckError; use crate::tools::check::TypeChecker; use crate::util::file_watcher::WatcherCommunicator; use crate::util::fs::canonicalize_path; @@ -84,7 +88,7 @@ pub fn graph_valid( sys: &CliSys, roots: &[ModuleSpecifier], options: GraphValidOptions, -) -> Result<(), AnyError> { +) -> Result<(), JsErrorBox> { if options.exit_integrity_errors { graph_exit_integrity_errors(graph); } @@ -103,9 +107,9 @@ pub fn graph_valid( } else { // finally surface the npm resolution result if let Err(err) = &graph.npm_dep_graph_result { - return Err(custom_error( - get_error_class_name(err), - format_deno_graph_error(err.as_ref().deref()), + return Err(JsErrorBox::new( + err.get_class(), + format_deno_graph_error(err), )); } Ok(()) @@ -144,7 +148,7 @@ pub fn graph_walk_errors<'a>( sys: &'a CliSys, roots: &'a [ModuleSpecifier], options: GraphWalkErrorsOptions, -) -> impl Iterator + 'a { +) -> impl Iterator + 'a { graph .walk( roots.iter(), @@ -164,29 +168,15 @@ pub fn graph_walk_errors<'a>( roots.contains(error.specifier()) } }; - let mut message = match &error { - ModuleGraphError::ResolutionError(resolution_error) => { - enhanced_resolution_error_message(resolution_error) - } - ModuleGraphError::TypesResolutionError(resolution_error) => { - format!( - "Failed resolving types. {}", - enhanced_resolution_error_message(resolution_error) - ) - } - ModuleGraphError::ModuleError(error) => { - enhanced_integrity_error_message(error) - .or_else(|| enhanced_sloppy_imports_error_message(sys, error)) - .unwrap_or_else(|| format_deno_graph_error(error)) - } - }; - - if let Some(range) = error.maybe_range() { - if !is_root && !range.specifier.as_str().contains("/$deno$eval") { - message.push_str("\n at "); - message.push_str(&format_range_with_colors(range)); - } - } + let message = enhance_graph_error( + sys, + &error, + if is_root { + EnhanceGraphErrorMode::HideRange + } else { + EnhanceGraphErrorMode::ShowRange + }, + ); if graph.graph_kind() == GraphKind::TypesOnly && matches!( @@ -198,10 +188,61 @@ pub fn graph_walk_errors<'a>( return None; } - Some(custom_error(get_error_class_name(&error.into()), message)) + if graph.graph_kind().include_types() + && (message.contains(RUN_WITH_SLOPPY_IMPORTS_MSG) + || matches!( + error, + ModuleGraphError::ModuleError(ModuleError::Missing(..)) + )) + { + // ignore and let typescript surface this as a diagnostic instead + log::debug!("Ignoring: {}", message); + return None; + } + + Some(JsErrorBox::new(error.get_class(), message)) }) } +#[derive(Debug, PartialEq, Eq)] +pub enum EnhanceGraphErrorMode { + ShowRange, + HideRange, +} + +pub fn enhance_graph_error( + sys: &CliSys, + error: &ModuleGraphError, + mode: EnhanceGraphErrorMode, +) -> String { + let mut message = match &error { + ModuleGraphError::ResolutionError(resolution_error) => { + enhanced_resolution_error_message(resolution_error) + } + ModuleGraphError::TypesResolutionError(resolution_error) => { + format!( + "Failed resolving types. {}", + enhanced_resolution_error_message(resolution_error) + ) + } + ModuleGraphError::ModuleError(error) => { + enhanced_integrity_error_message(error) + .or_else(|| enhanced_sloppy_imports_error_message(sys, error)) + .unwrap_or_else(|| format_deno_graph_error(error)) + } + }; + + if let Some(range) = error.maybe_range() { + if mode == EnhanceGraphErrorMode::ShowRange + && !range.specifier.as_str().contains("/$deno$eval") + { + message.push_str("\n at "); + message.push_str(&format_range_with_colors(range)); + } + } + message +} + pub fn graph_exit_integrity_errors(graph: &ModuleGraph) { for error in graph.module_errors() { exit_for_integrity_error(error); @@ -226,7 +267,7 @@ pub struct CreateGraphOptions<'a> { pub struct ModuleGraphCreator { options: Arc, - npm_resolver: Arc, + npm_installer: Option>, module_graph_builder: Arc, type_checker: Arc, } @@ -234,13 +275,13 @@ pub struct ModuleGraphCreator { impl ModuleGraphCreator { pub fn new( options: Arc, - npm_resolver: Arc, + npm_installer: Option>, module_graph_builder: Arc, type_checker: Arc, ) -> Self { Self { options, - npm_resolver, + npm_installer, module_graph_builder, type_checker, } @@ -363,9 +404,9 @@ impl ModuleGraphCreator { .build_graph_with_npm_resolution(&mut graph, options) .await?; - if let Some(npm_resolver) = self.npm_resolver.as_managed() { + if let Some(npm_installer) = &self.npm_installer { if graph.has_node_specifier && self.options.type_check_mode().is_true() { - npm_resolver.inject_synthetic_types_node_package().await?; + npm_installer.inject_synthetic_types_node_package().await?; } } @@ -399,14 +440,14 @@ impl ModuleGraphCreator { } } - pub fn graph_valid(&self, graph: &ModuleGraph) -> Result<(), AnyError> { + pub fn graph_valid(&self, graph: &ModuleGraph) -> Result<(), JsErrorBox> { self.module_graph_builder.graph_valid(graph) } async fn type_check_graph( &self, graph: ModuleGraph, - ) -> Result, AnyError> { + ) -> Result, CheckError> { self .type_checker .check( @@ -429,17 +470,40 @@ pub struct BuildFastCheckGraphOptions<'a> { pub workspace_fast_check: deno_graph::WorkspaceFastCheckOption<'a>, } +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum BuildGraphWithNpmResolutionError { + #[class(inherit)] + #[error(transparent)] + SerdeJson(#[from] serde_json::Error), + #[class(inherit)] + #[error(transparent)] + ToMaybeJsxImportSourceConfig( + #[from] deno_json::ToMaybeJsxImportSourceConfigError, + ), + #[class(inherit)] + #[error(transparent)] + NodeModulesDirParse(#[from] deno_json::NodeModulesDirParseError), + #[class(inherit)] + #[error(transparent)] + Other(#[from] JsErrorBox), + #[class(generic)] + #[error("Resolving npm specifier entrypoints this way is currently not supported with \"nodeModules\": \"manual\". In the meantime, try with --node-modules-dir=auto instead")] + UnsupportedNpmSpecifierEntrypointResolutionWay, +} + pub struct ModuleGraphBuilder { caches: Arc, - cjs_tracker: Arc, + cjs_tracker: Arc, cli_options: Arc, file_fetcher: Arc, global_http_cache: Arc, - in_npm_pkg_checker: Arc, + in_npm_pkg_checker: DenoInNpmPackageChecker, lockfile: Option>, maybe_file_watcher_reporter: Option, module_info_cache: Arc, - npm_resolver: Arc, + npm_graph_resolver: Arc, + npm_installer: Option>, + npm_resolver: CliNpmResolver, parsed_source_cache: Arc, resolver: Arc, root_permissions_container: PermissionsContainer, @@ -450,15 +514,17 @@ impl ModuleGraphBuilder { #[allow(clippy::too_many_arguments)] pub fn new( caches: Arc, - cjs_tracker: Arc, + cjs_tracker: Arc, cli_options: Arc, file_fetcher: Arc, global_http_cache: Arc, - in_npm_pkg_checker: Arc, + in_npm_pkg_checker: DenoInNpmPackageChecker, lockfile: Option>, maybe_file_watcher_reporter: Option, module_info_cache: Arc, - npm_resolver: Arc, + npm_graph_resolver: Arc, + npm_installer: Option>, + npm_resolver: CliNpmResolver, parsed_source_cache: Arc, resolver: Arc, root_permissions_container: PermissionsContainer, @@ -474,6 +540,8 @@ impl ModuleGraphBuilder { lockfile, maybe_file_watcher_reporter, module_info_cache, + npm_graph_resolver, + npm_installer, npm_resolver, parsed_source_cache, resolver, @@ -486,7 +554,7 @@ impl ModuleGraphBuilder { &self, graph: &mut ModuleGraph, options: CreateGraphOptions<'a>, - ) -> Result<(), AnyError> { + ) -> Result<(), BuildGraphWithNpmResolutionError> { enum MutLoaderRef<'a> { Borrowed(&'a mut dyn Loader), Owned(cache::FetchCacher), @@ -572,10 +640,7 @@ impl ModuleGraphBuilder { Some(loader) => MutLoaderRef::Borrowed(loader), None => MutLoaderRef::Owned(self.create_graph_loader()), }; - let cli_resolver = &self.resolver; let graph_resolver = self.create_graph_resolver()?; - let graph_npm_resolver = - cli_resolver.create_graph_npm_resolver(options.npm_caching); let maybe_file_watcher_reporter = self .maybe_file_watcher_reporter .as_ref() @@ -596,7 +661,7 @@ impl ModuleGraphBuilder { executor: Default::default(), file_system: &self.sys, jsr_url_provider: &CliJsrUrlProvider, - npm_resolver: Some(&graph_npm_resolver), + npm_resolver: Some(self.npm_graph_resolver.as_ref()), module_analyzer: &analyzer, reporter: maybe_file_watcher_reporter, resolver: Some(&graph_resolver), @@ -614,22 +679,21 @@ impl ModuleGraphBuilder { loader: &'a mut dyn deno_graph::source::Loader, options: deno_graph::BuildOptions<'a>, npm_caching: NpmCachingStrategy, - ) -> Result<(), AnyError> { + ) -> Result<(), BuildGraphWithNpmResolutionError> { // ensure an "npm install" is done if the user has explicitly // opted into using a node_modules directory if self .cli_options .node_modules_dir()? - .map(|m| m.uses_node_modules_dir()) + .map(|m| m == NodeModulesDirMode::Auto) .unwrap_or(false) { - if let Some(npm_resolver) = self.npm_resolver.as_managed() { - let already_done = - npm_resolver.ensure_top_level_package_json_install().await?; + if let Some(npm_installer) = &self.npm_installer { + let already_done = npm_installer + .ensure_top_level_package_json_install() + .await?; if !already_done && matches!(npm_caching, NpmCachingStrategy::Eager) { - npm_resolver - .cache_packages(crate::npm::PackageCaching::All) - .await?; + npm_installer.cache_packages(PackageCaching::All).await?; } } } @@ -648,10 +712,9 @@ impl ModuleGraphBuilder { let initial_package_deps_len = graph.packages.package_deps_sum(); let initial_package_mappings_len = graph.packages.mappings().len(); - if roots.iter().any(|r| r.scheme() == "npm") - && self.npm_resolver.as_byonm().is_some() + if roots.iter().any(|r| r.scheme() == "npm") && self.npm_resolver.is_byonm() { - bail!("Resolving npm specifier entrypoints this way is currently not supported with \"nodeModules\": \"manual\". In the meantime, try with --node-modules-dir=auto instead"); + return Err(BuildGraphWithNpmResolutionError::UnsupportedNpmSpecifierEntrypointResolutionWay); } graph.build(roots, loader, options).await; @@ -702,7 +765,7 @@ impl ModuleGraphBuilder { &self, graph: &mut ModuleGraph, options: BuildFastCheckGraphOptions, - ) -> Result<(), AnyError> { + ) -> Result<(), deno_json::ToMaybeJsxImportSourceConfigError> { if !graph.graph_kind().include_types() { return Ok(()); } @@ -717,11 +780,7 @@ impl ModuleGraphBuilder { None }; let parser = self.parsed_source_cache.as_capturing_parser(); - let cli_resolver = &self.resolver; let graph_resolver = self.create_graph_resolver()?; - let graph_npm_resolver = cli_resolver.create_graph_npm_resolver( - self.cli_options.default_npm_caching_strategy(), - ); graph.build_fast_check_type_graph( deno_graph::BuildFastCheckTypeGraphOptions { @@ -730,7 +789,7 @@ impl ModuleGraphBuilder { fast_check_dts: false, jsr_url_provider: &CliJsrUrlProvider, resolver: Some(&graph_resolver), - npm_resolver: Some(&graph_npm_resolver), + npm_resolver: Some(self.npm_graph_resolver.as_ref()), workspace_fast_check: options.workspace_fast_check, }, ); @@ -766,7 +825,7 @@ impl ModuleGraphBuilder { /// Check if `roots` and their deps are available. Returns `Ok(())` if /// so. Returns `Err(_)` if there is a known module graph or resolution /// error statically reachable from `roots` and not a dynamic import. - pub fn graph_valid(&self, graph: &ModuleGraph) -> Result<(), AnyError> { + pub fn graph_valid(&self, graph: &ModuleGraph) -> Result<(), JsErrorBox> { self.graph_roots_valid( graph, &graph.roots.iter().cloned().collect::>(), @@ -777,7 +836,7 @@ impl ModuleGraphBuilder { &self, graph: &ModuleGraph, roots: &[ModuleSpecifier], - ) -> Result<(), AnyError> { + ) -> Result<(), JsErrorBox> { graph_valid( graph, &self.sys, @@ -794,7 +853,10 @@ impl ModuleGraphBuilder { ) } - fn create_graph_resolver(&self) -> Result { + fn create_graph_resolver( + &self, + ) -> Result + { let jsx_import_source_config = self .cli_options .workspace() @@ -835,6 +897,9 @@ pub fn enhanced_resolution_error_message(error: &ResolutionError) -> String { message } +static RUN_WITH_SLOPPY_IMPORTS_MSG: &str = + "or run with --unstable-sloppy-imports"; + fn enhanced_sloppy_imports_error_message( sys: &CliSys, error: &ModuleError, @@ -842,11 +907,9 @@ fn enhanced_sloppy_imports_error_message( match error { ModuleError::LoadingErr(specifier, _, ModuleLoadError::Loader(_)) // ex. "Is a directory" error | ModuleError::Missing(specifier, _) => { - let additional_message = CliSloppyImportsResolver::new(SloppyImportsCachedFs::new(sys.clone())) - .resolve(specifier, SloppyImportsResolutionKind::Execution)? - .as_suggestion_message(); + let additional_message = maybe_additional_sloppy_imports_message(sys, specifier)?; Some(format!( - "{} {} or run with --unstable-sloppy-imports", + "{} {}", error, additional_message, )) @@ -855,6 +918,19 @@ fn enhanced_sloppy_imports_error_message( } } +pub fn maybe_additional_sloppy_imports_message( + sys: &CliSys, + specifier: &ModuleSpecifier, +) -> Option { + Some(format!( + "{} {}", + CliSloppyImportsResolver::new(SloppyImportsCachedFs::new(sys.clone())) + .resolve(specifier, SloppyImportsResolutionKind::Execution)? + .as_suggestion_message(), + RUN_WITH_SLOPPY_IMPORTS_MSG + )) +} + fn enhanced_integrity_error_message(err: &ModuleError) -> Option { match err { ModuleError::LoadingErr( @@ -948,9 +1024,11 @@ fn get_resolution_error_bare_specifier( { Some(specifier.as_str()) } else if let ResolutionError::ResolverError { error, .. } = error { - if let ResolveError::Other(error) = (*error).as_ref() { - if let Some(ImportMapError::UnmappedBareSpecifier(specifier, _)) = - error.downcast_ref::() + if let ResolveError::ImportMap(error) = (*error).as_ref() { + if let import_map::ImportMapErrorKind::UnmappedBareSpecifier( + specifier, + _, + ) = error.as_kind() { Some(specifier.as_str()) } else { @@ -987,11 +1065,12 @@ fn get_import_prefix_missing_error(error: &ResolutionError) -> Option<&str> { ResolveError::Other(other_error) => { if let Some(SpecifierError::ImportPrefixMissing { specifier, .. - }) = other_error.downcast_ref::() + }) = other_error.as_any().downcast_ref::() { maybe_specifier = Some(specifier); } } + ResolveError::ImportMap(_) => {} } } } @@ -1146,7 +1225,7 @@ fn format_deno_graph_error(err: &dyn Error) -> String { #[derive(Debug)] struct CliGraphResolver<'a> { - cjs_tracker: &'a CjsTracker, + cjs_tracker: &'a CliCjsTracker, resolver: &'a CliResolver, jsx_import_source_config: Option, } @@ -1242,7 +1321,7 @@ mod test { let specifier = ModuleSpecifier::parse("file:///file.ts").unwrap(); let err = import_map.resolve(input, &specifier).err().unwrap(); let err = ResolutionError::ResolverError { - error: Arc::new(ResolveError::Other(err.into())), + error: Arc::new(ResolveError::ImportMap(err)), specifier: input.to_string(), range: Range { specifier, diff --git a/cli/http_util.rs b/cli/http_util.rs index b24dd7bc0c..5e63ab0a4a 100644 --- a/cli/http_util.rs +++ b/cli/http_util.rs @@ -1,17 +1,19 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::util::progress_bar::UpdateGuard; -use crate::version; +use std::collections::HashMap; +use std::sync::Arc; +use std::thread::ThreadId; use boxed_error::Boxed; use deno_cache_dir::file_fetcher::RedirectHeaderParseError; -use deno_core::error::custom_error; use deno_core::error::AnyError; use deno_core::futures::StreamExt; use deno_core::parking_lot::Mutex; use deno_core::serde; use deno_core::serde_json; use deno_core::url::Url; +use deno_error::JsError; +use deno_error::JsErrorBox; use deno_runtime::deno_fetch; use deno_runtime::deno_fetch::create_http_client; use deno_runtime::deno_fetch::CreateHttpClientOptions; @@ -23,12 +25,11 @@ use http::header::CONTENT_LENGTH; use http::HeaderMap; use http::StatusCode; use http_body_util::BodyExt; - -use std::collections::HashMap; -use std::sync::Arc; -use std::thread::ThreadId; use thiserror::Error; +use crate::util::progress_bar::UpdateGuard; +use crate::version; + #[derive(Debug, Error)] pub enum SendError { #[error(transparent)] @@ -69,7 +70,7 @@ impl HttpClientProvider { } } - pub fn get_or_create(&self) -> Result { + pub fn get_or_create(&self) -> Result { use std::collections::hash_map::Entry; let thread_id = std::thread::current().id(); let mut clients = self.clients_by_thread_id.lock(); @@ -86,7 +87,8 @@ impl HttpClientProvider { }, ..self.options.clone() }, - )?; + ) + .map_err(JsErrorBox::from_err)?; entry.insert(client.clone()); Ok(HttpClient::new(client)) } @@ -94,34 +96,49 @@ impl HttpClientProvider { } } -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] +#[class(type)] #[error("Bad response: {:?}{}", .status_code, .response_text.as_ref().map(|s| format!("\n\n{}", s)).unwrap_or_else(String::new))] pub struct BadResponseError { pub status_code: StatusCode, pub response_text: Option, } -#[derive(Debug, Boxed)] +#[derive(Debug, Boxed, JsError)] pub struct DownloadError(pub Box); -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] pub enum DownloadErrorKind { + #[class(inherit)] #[error(transparent)] - Fetch(AnyError), + Fetch(deno_fetch::ClientSendError), + #[class(inherit)] #[error(transparent)] UrlParse(#[from] deno_core::url::ParseError), + #[class(generic)] #[error(transparent)] HttpParse(#[from] http::Error), + #[class(inherit)] #[error(transparent)] Json(#[from] serde_json::Error), + #[class(generic)] #[error(transparent)] ToStr(#[from] http::header::ToStrError), + #[class(inherit)] #[error(transparent)] RedirectHeaderParse(RedirectHeaderParseError), + #[class(type)] #[error("Too many redirects.")] TooManyRedirects, + #[class(inherit)] #[error(transparent)] BadResponse(#[from] BadResponseError), + #[class("Http")] + #[error("Not Found.")] + NotFound, + #[class(inherit)] + #[error(transparent)] + Other(JsErrorBox), } #[derive(Debug)] @@ -208,11 +225,11 @@ impl HttpClient { Ok(String::from_utf8(bytes)?) } - pub async fn download(&self, url: Url) -> Result, AnyError> { + pub async fn download(&self, url: Url) -> Result, DownloadError> { let maybe_bytes = self.download_inner(url, None, None).await?; match maybe_bytes { Some(bytes) => Ok(bytes), - None => Err(custom_error("Http", "Not found.")), + None => Err(DownloadErrorKind::NotFound.into_box()), } } @@ -276,7 +293,7 @@ impl HttpClient { get_response_body_with_progress(response, progress_guard) .await .map(|(_, body)| Some(body)) - .map_err(|err| DownloadErrorKind::Fetch(err).into_box()) + .map_err(|err| DownloadErrorKind::Other(err).into_box()) } async fn get_redirected_response( @@ -293,7 +310,7 @@ impl HttpClient { .clone() .send(req) .await - .map_err(|e| DownloadErrorKind::Fetch(e.into()).into_box())?; + .map_err(|e| DownloadErrorKind::Fetch(e).into_box())?; let status = response.status(); if status.is_redirection() { for _ in 0..5 { @@ -313,7 +330,7 @@ impl HttpClient { .clone() .send(req) .await - .map_err(|e| DownloadErrorKind::Fetch(e.into()).into_box())?; + .map_err(|e| DownloadErrorKind::Fetch(e).into_box())?; let status = new_response.status(); if status.is_redirection() { response = new_response; @@ -332,7 +349,7 @@ impl HttpClient { pub async fn get_response_body_with_progress( response: http::Response, progress_guard: Option<&UpdateGuard>, -) -> Result<(HeaderMap, Vec), AnyError> { +) -> Result<(HeaderMap, Vec), JsErrorBox> { use http_body::Body as _; if let Some(progress_guard) = progress_guard { let mut total_size = response.body().size_hint().exact(); diff --git a/cli/integration_tests_runner.rs b/cli/integration_tests_runner.rs index 12e83a0194..7342e62fa0 100644 --- a/cli/integration_tests_runner.rs +++ b/cli/integration_tests_runner.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. pub fn main() { let mut args = vec!["cargo", "test", "-p", "cli_tests", "--features", "run"]; diff --git a/cli/js.rs b/cli/js.rs index 2c93f004ca..5337c53f76 100644 --- a/cli/js.rs +++ b/cli/js.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use log::debug; diff --git a/cli/js/40_bench.js b/cli/js/40_bench.js index b07df3993c..fb0e86463d 100644 --- a/cli/js/40_bench.js +++ b/cli/js/40_bench.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file import { core, primordials } from "ext:core/mod.js"; @@ -8,7 +8,7 @@ import { restorePermissions, } from "ext:cli/40_test_common.js"; import { Console } from "ext:deno_console/01_console.js"; -import { setExitHandler } from "ext:runtime/30_os.js"; +import { setExitHandler } from "ext:deno_os/30_os.js"; const { op_register_bench, op_bench_get_origin, diff --git a/cli/js/40_jupyter.js b/cli/js/40_jupyter.js index 198b6a3502..f392af1d43 100644 --- a/cli/js/40_jupyter.js +++ b/cli/js/40_jupyter.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file /* diff --git a/cli/js/40_lint.js b/cli/js/40_lint.js index d29dc3e850..9f85f0871d 100644 --- a/cli/js/40_lint.js +++ b/cli/js/40_lint.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check @@ -8,10 +8,27 @@ import { splitSelectors, } from "ext:cli/40_lint_selector.js"; import { core, internals } from "ext:core/mod.js"; + const { op_lint_create_serialized_ast, } = core.ops; +// Keep these in sync with Rust +const AST_IDX_INVALID = 0; +const AST_GROUP_TYPE = 1; +/// +/// +/// +/// +/// +const NODE_SIZE = 1 + 4 + 4 + 4 + 4; +const PROP_OFFSET = 1; +const CHILD_OFFSET = 1 + 4; +const NEXT_OFFSET = 1 + 4 + 4; +const PARENT_OFFSET = 1 + 4 + 4 + 4; +// Span size in buffer: u32 + u32 +const SPAN_SIZE = 4 + 4; + // Keep in sync with Rust // These types are expected to be present on every node. Note that this // isn't set in stone. We could revise this at a future point. @@ -34,12 +51,21 @@ const PropFlags = { * the string table that was included in the message. */ String: 2, + /** + * A numnber field. Numbers are represented as strings internally. + */ + Number: 3, /** This value is either 0 = false, or 1 = true */ - Bool: 3, + Bool: 4, /** No value, it's null */ - Null: 4, + Null: 5, /** No value, it's undefined */ - Undefined: 5, + Undefined: 6, + /** An object */ + Obj: 7, + Regex: 8, + BigInt: 9, + Array: 10, }; /** @typedef {import("./40_lint_types.d.ts").AstContext} AstContext */ @@ -51,6 +77,7 @@ const PropFlags = { /** @typedef {import("./40_lint_types.d.ts").LintPlugin} LintPlugin */ /** @typedef {import("./40_lint_types.d.ts").TransformFn} TransformFn */ /** @typedef {import("./40_lint_types.d.ts").MatchContext} MatchContext */ +/** @typedef {import("./40_lint_types.d.ts").Node} Node */ /** @type {LintState} */ const state = { @@ -100,17 +127,17 @@ export function installPlugin(plugin) { /** * @param {AstContext} ctx - * @param {number} offset - * @returns + * @param {number} idx + * @returns {FacadeNode | null} */ -function getNode(ctx, offset) { - if (offset === 0) return null; - const cached = ctx.nodes.get(offset); - if (cached !== undefined) return cached; +function getNode(ctx, idx) { + if (idx === AST_IDX_INVALID) return null; + const cached = ctx.nodes.get(idx); + if (cached !== undefined) return /** @type {*} */ (cached); - const node = new Node(ctx, offset); - ctx.nodes.set(offset, /** @type {*} */ (cached)); - return node; + const node = new FacadeNode(ctx, idx); + ctx.nodes.set(idx, /** @type {*} */ (node)); + return /** @type {*} */ (node); } /** @@ -122,31 +149,22 @@ function getNode(ctx, offset) { * @returns {number} */ function findPropOffset(buf, offset, search) { - // type + parentId + SpanLo + SpanHi - offset += 1 + 4 + 4 + 4; - - const propCount = buf[offset]; + const count = buf[offset]; offset += 1; - for (let i = 0; i < propCount; i++) { + for (let i = 0; i < count; i++) { const maybe = offset; const prop = buf[offset++]; const kind = buf[offset++]; if (prop === search) return maybe; - if (kind === PropFlags.Ref) { - offset += 4; - } else if (kind === PropFlags.RefArr) { + if (kind === PropFlags.Obj) { const len = readU32(buf, offset); - offset += 4 + (len * 4); - } else if (kind === PropFlags.String) { offset += 4; - } else if (kind === PropFlags.Bool) { - offset++; - } else if (kind === PropFlags.Null || kind === PropFlags.Undefined) { - // No value + // prop + kind + value + offset += len * (1 + 1 + 4); } else { - offset++; + offset += 4; } } @@ -154,23 +172,23 @@ function findPropOffset(buf, offset, search) { } const INTERNAL_CTX = Symbol("ctx"); -const INTERNAL_OFFSET = Symbol("offset"); +const INTERNAL_IDX = Symbol("offset"); // This class is a facade for all materialized nodes. Instead of creating a // unique class per AST node, we have one class with getters for every // possible node property. This allows us to lazily materialize child node // only when they are needed. -class Node { +class FacadeNode { [INTERNAL_CTX]; - [INTERNAL_OFFSET]; + [INTERNAL_IDX]; /** * @param {AstContext} ctx - * @param {number} offset + * @param {number} idx */ - constructor(ctx, offset) { + constructor(ctx, idx) { this[INTERNAL_CTX] = ctx; - this[INTERNAL_OFFSET] = offset; + this[INTERNAL_IDX] = idx; } /** @@ -186,12 +204,12 @@ class Node { * @returns {string} */ [Symbol.for("Deno.customInspect")](_, options) { - const json = toJsValue(this[INTERNAL_CTX], this[INTERNAL_OFFSET]); + const json = nodeToJson(this[INTERNAL_CTX], this[INTERNAL_IDX]); return Deno.inspect(json, options); } [Symbol.for("Deno.lint.toJsValue")]() { - return toJsValue(this[INTERNAL_CTX], this[INTERNAL_OFFSET]); + return nodeToJson(this[INTERNAL_CTX], this[INTERNAL_IDX]); } } @@ -212,125 +230,243 @@ function setNodeGetters(ctx) { const name = getString(ctx.strTable, id); - Object.defineProperty(Node.prototype, name, { + Object.defineProperty(FacadeNode.prototype, name, { get() { - return readValue(this[INTERNAL_CTX], this[INTERNAL_OFFSET], i); + return readValue( + this[INTERNAL_CTX], + this[INTERNAL_IDX], + i, + getNode, + ); }, }); } } /** - * Serialize a node recursively to plain JSON * @param {AstContext} ctx - * @param {number} offset - * @returns {*} + * @param {number} idx */ -function toJsValue(ctx, offset) { - const { buf } = ctx; - +function nodeToJson(ctx, idx) { /** @type {Record} */ const node = { - type: readValue(ctx, offset, AST_PROP_TYPE), - range: readValue(ctx, offset, AST_PROP_RANGE), + type: readValue(ctx, idx, AST_PROP_TYPE, nodeToJson), + range: readValue(ctx, idx, AST_PROP_RANGE, nodeToJson), }; - // type + parentId + SpanLo + SpanHi - offset += 1 + 4 + 4 + 4; + const { buf } = ctx; + let offset = readPropOffset(ctx, idx); const count = buf[offset++]; - for (let i = 0; i < count; i++) { - const prop = buf[offset++]; - const kind = buf[offset++]; - const name = getString(ctx.strTable, ctx.strByProp[prop]); - if (kind === PropFlags.Ref) { - const v = readU32(buf, offset); - offset += 4; - node[name] = v === 0 ? null : toJsValue(ctx, v); - } else if (kind === PropFlags.RefArr) { - const len = readU32(buf, offset); - offset += 4; - const nodes = new Array(len); - for (let i = 0; i < len; i++) { - const v = readU32(buf, offset); - if (v === 0) continue; - nodes[i] = toJsValue(ctx, v); - offset += 4; - } - node[name] = nodes; - } else if (kind === PropFlags.Bool) { - const v = buf[offset++]; - node[name] = v === 1; - } else if (kind === PropFlags.String) { - const v = readU32(buf, offset); - offset += 4; - node[name] = getString(ctx.strTable, v); - } else if (kind === PropFlags.Null) { - node[name] = null; - } else if (kind === PropFlags.Undefined) { - node[name] = undefined; - } + for (let i = 0; i < count; i++) { + const prop = buf[offset]; + const _kind = buf[offset + 1]; + + const name = getString(ctx.strTable, ctx.strByProp[prop]); + node[name] = readProperty(ctx, offset, nodeToJson); + + // prop + type + value + offset += 1 + 1 + 4; } return node; } /** - * Read a specific property from a node + * @param {AstContext["buf"]} buf + * @param {number} idx + * @returns {number} + */ +function readType(buf, idx) { + return buf[idx * NODE_SIZE]; +} + +/** + * @param {AstContext} ctx + * @param {number} idx + * @returns {Node["range"]} + */ +function readSpan(ctx, idx) { + let offset = ctx.spansOffset + (idx * SPAN_SIZE); + const start = readU32(ctx.buf, offset); + offset += 4; + const end = readU32(ctx.buf, offset); + + return [start, end]; +} + +/** + * @param {AstContext["buf"]} buf + * @param {number} idx + * @returns {number} + */ +function readRawPropOffset(buf, idx) { + const offset = (idx * NODE_SIZE) + PROP_OFFSET; + return readU32(buf, offset); +} + +/** + * @param {AstContext} ctx + * @param {number} idx + * @returns {number} + */ +function readPropOffset(ctx, idx) { + return readRawPropOffset(ctx.buf, idx) + ctx.propsOffset; +} + +/** + * @param {AstContext["buf"]} buf + * @param {number} idx + * @returns {number} + */ +function readChild(buf, idx) { + const offset = (idx * NODE_SIZE) + CHILD_OFFSET; + return readU32(buf, offset); +} +/** + * @param {AstContext["buf"]} buf + * @param {number} idx + * @returns {number} + */ +function readNext(buf, idx) { + const offset = (idx * NODE_SIZE) + NEXT_OFFSET; + return readU32(buf, offset); +} + +/** + * @param {AstContext["buf"]} buf + * @param {number} idx + * @returns {number} + */ +function readParent(buf, idx) { + const offset = (idx * NODE_SIZE) + PARENT_OFFSET; + return readU32(buf, offset); +} + +/** + * @param {AstContext["strTable"]} strTable + * @param {number} strId + * @returns {RegExp} + */ +function readRegex(strTable, strId) { + const raw = getString(strTable, strId); + const idx = raw.lastIndexOf("/"); + const pattern = raw.slice(1, idx); + const flags = idx < raw.length - 1 ? raw.slice(idx + 1) : undefined; + + return new RegExp(pattern, flags); +} + +/** * @param {AstContext} ctx * @param {number} offset - * @param {number} search - * @returns {*} + * @param {(ctx: AstContext, idx: number) => any} parseNode + * @returns {Record} */ -function readValue(ctx, offset, search) { - const { buf } = ctx; - const type = buf[offset]; +function readObject(ctx, offset, parseNode) { + const { buf, strTable, strByProp } = ctx; - if (search === AST_PROP_TYPE) { - return getString(ctx.strTable, ctx.strByType[type]); - } else if (search === AST_PROP_RANGE) { - const start = readU32(buf, offset + 1 + 4); - const end = readU32(buf, offset + 1 + 4 + 4); - return [start, end]; - } else if (search === AST_PROP_PARENT) { - const pos = readU32(buf, offset + 1); - return getNode(ctx, pos); + /** @type {Record} */ + const obj = {}; + + const count = readU32(buf, offset); + offset += 4; + + for (let i = 0; i < count; i++) { + const prop = buf[offset]; + const name = getString(strTable, strByProp[prop]); + obj[name] = readProperty(ctx, offset, parseNode); + // name + kind + value + offset += 1 + 1 + 4; } - offset = findPropOffset(ctx.buf, offset, search); - if (offset === -1) return undefined; + return obj; +} - const kind = buf[offset + 1]; - offset += 2; +/** + * @param {AstContext} ctx + * @param {number} offset + * @param {(ctx: AstContext, idx: number) => any} parseNode + * @returns {any} + */ +function readProperty(ctx, offset, parseNode) { + const { buf } = ctx; + + // skip over name + const _name = buf[offset++]; + const kind = buf[offset++]; if (kind === PropFlags.Ref) { const value = readU32(buf, offset); - return getNode(ctx, value); + return parseNode(ctx, value); } else if (kind === PropFlags.RefArr) { - const len = readU32(buf, offset); - offset += 4; + const groupId = readU32(buf, offset); - const nodes = new Array(len); - for (let i = 0; i < len; i++) { - nodes[i] = getNode(ctx, readU32(buf, offset)); - offset += 4; + const nodes = []; + let next = readChild(buf, groupId); + while (next > AST_IDX_INVALID) { + nodes.push(parseNode(ctx, next)); + next = readNext(buf, next); } + return nodes; } else if (kind === PropFlags.Bool) { - return buf[offset] === 1; + const v = readU32(buf, offset); + return v === 1; } else if (kind === PropFlags.String) { const v = readU32(buf, offset); return getString(ctx.strTable, v); + } else if (kind === PropFlags.Number) { + const v = readU32(buf, offset); + return Number(getString(ctx.strTable, v)); + } else if (kind === PropFlags.BigInt) { + const v = readU32(buf, offset); + return BigInt(getString(ctx.strTable, v)); + } else if (kind === PropFlags.Regex) { + const v = readU32(buf, offset); + return readRegex(ctx.strTable, v); } else if (kind === PropFlags.Null) { return null; } else if (kind === PropFlags.Undefined) { return undefined; + } else if (kind === PropFlags.Obj) { + const objOffset = readU32(buf, offset) + ctx.propsOffset; + return readObject(ctx, objOffset, parseNode); } throw new Error(`Unknown prop kind: ${kind}`); } +/** + * Read a specific property from a node + * @param {AstContext} ctx + * @param {number} idx + * @param {number} search + * @param {(ctx: AstContext, idx: number) => any} parseNode + * @returns {*} + */ +function readValue(ctx, idx, search, parseNode) { + const { buf } = ctx; + + if (search === AST_PROP_TYPE) { + const type = readType(buf, idx); + return getString(ctx.strTable, ctx.strByType[type]); + } else if (search === AST_PROP_RANGE) { + return readSpan(ctx, idx); + } else if (search === AST_PROP_PARENT) { + const parent = readParent(buf, idx); + return getNode(ctx, parent); + } + + const propOffset = readPropOffset(ctx, idx); + + const offset = findPropOffset(ctx.buf, propOffset, search); + if (offset === -1) return undefined; + + return readProperty(ctx, offset, parseNode); +} + const DECODER = new TextDecoder(); /** @@ -359,322 +495,149 @@ function getString(strTable, id) { return name; } -/** - * @param {AstContext["buf"]} buf - * @param {number} child - * @returns {null | [number, number]} - */ -function findChildOffset(buf, child) { - let offset = readU32(buf, child + 1); - - // type + parentId + SpanLo + SpanHi - offset += 1 + 4 + 4 + 4; - - const propCount = buf[offset++]; - for (let i = 0; i < propCount; i++) { - const _prop = buf[offset++]; - const kind = buf[offset++]; - - switch (kind) { - case PropFlags.Ref: { - const start = offset; - const value = readU32(buf, offset); - offset += 4; - if (value === child) { - return [start, -1]; - } - break; - } - case PropFlags.RefArr: { - const start = offset; - - const len = readU32(buf, offset); - offset += 4; - - for (let j = 0; j < len; j++) { - const value = readU32(buf, offset); - offset += 4; - if (value === child) { - return [start, j]; - } - } - - break; - } - case PropFlags.String: - offset += 4; - break; - case PropFlags.Bool: - offset++; - break; - case PropFlags.Null: - case PropFlags.Undefined: - break; - } - } - - return null; -} - /** @implements {MatchContext} */ class MatchCtx { /** - * @param {AstContext["buf"]} buf - * @param {AstContext["strTable"]} strTable - * @param {AstContext["strByType"]} strByType + * @param {AstContext} ctx */ - constructor(buf, strTable, strByType) { - this.buf = buf; - this.strTable = strTable; - this.strByType = strByType; + constructor(ctx) { + this.ctx = ctx; } /** - * @param {number} offset - * @returns {number} - */ - getParent(offset) { - return readU32(this.buf, offset + 1); - } - - /** - * @param {number} offset - * @returns {number} - */ - getType(offset) { - return this.buf[offset]; - } - - /** - * @param {number} offset - * @param {number[]} propIds * @param {number} idx + * @returns {number} + */ + getParent(idx) { + return readParent(this.ctx.buf, idx); + } + + /** + * @param {number} idx + * @returns {number} + */ + getType(idx) { + return readType(this.ctx.buf, idx); + } + + /** + * @param {number} idx - Node idx + * @param {number[]} propIds + * @param {number} propIdx * @returns {unknown} */ - getAttrPathValue(offset, propIds, idx) { - const { buf } = this; + getAttrPathValue(idx, propIds, propIdx) { + if (idx === 0) throw -1; - const propId = propIds[idx]; + const { buf, strTable, strByType } = this.ctx; + + const propId = propIds[propIdx]; switch (propId) { case AST_PROP_TYPE: { - const type = this.getType(offset); - return getString(this.strTable, this.strByType[type]); + const type = readType(buf, idx); + return getString(strTable, strByType[type]); } case AST_PROP_PARENT: case AST_PROP_RANGE: - throw new Error(`Not supported`); + throw -1; } + let offset = readPropOffset(this.ctx, idx); + offset = findPropOffset(buf, offset, propId); - if (offset === -1) return undefined; + if (offset === -1) throw -1; const _prop = buf[offset++]; const kind = buf[offset++]; if (kind === PropFlags.Ref) { const value = readU32(buf, offset); // Checks need to end with a value, not a node - if (idx === propIds.length - 1) return undefined; - return this.getAttrPathValue(value, propIds, idx + 1); + if (propIdx === propIds.length - 1) throw -1; + return this.getAttrPathValue(value, propIds, propIdx + 1); } else if (kind === PropFlags.RefArr) { - const count = readU32(buf, offset); + const arrIdx = readU32(buf, offset); offset += 4; - if (idx < propIds.length - 1 && propIds[idx + 1] === AST_PROP_LENGTH) { + let count = 0; + let child = readChild(buf, arrIdx); + while (child > AST_IDX_INVALID) { + count++; + child = readNext(buf, child); + } + + if ( + propIdx < propIds.length - 1 && propIds[propIdx + 1] === AST_PROP_LENGTH + ) { return count; } // TODO(@marvinhagemeister): Allow traversing into array children? + throw -1; + } else if (kind === PropFlags.Obj) { + // TODO(@marvinhagemeister) } // Cannot traverse into primitives further - if (idx < propIds.length - 1) return undefined; + if (propIdx < propIds.length - 1) throw -1; if (kind === PropFlags.String) { const s = readU32(buf, offset); - return getString(this.strTable, s); + return getString(strTable, s); + } else if (kind === PropFlags.Number) { + const s = readU32(buf, offset); + return Number(getString(strTable, s)); + } else if (kind === PropFlags.Regex) { + const v = readU32(buf, offset); + return readRegex(strTable, v); } else if (kind === PropFlags.Bool) { - return buf[offset] === 1; + return readU32(buf, offset) === 1; } else if (kind === PropFlags.Null) { return null; } else if (kind === PropFlags.Undefined) { return undefined; } - return undefined; + throw -1; } /** - * @param {number} offset - * @param {number[]} propIds * @param {number} idx - * @returns {boolean} - */ - hasAttrPath(offset, propIds, idx) { - const { buf } = this; - - const propId = propIds[idx]; - // If propId is 0 then the property doesn't exist in the AST - if (propId === 0) return false; - - switch (propId) { - case AST_PROP_TYPE: - case AST_PROP_PARENT: - case AST_PROP_RANGE: - return true; - } - - offset = findPropOffset(buf, offset, propId); - if (offset === -1) return false; - if (idx === propIds.length - 1) return true; - - const _prop = buf[offset++]; - const kind = buf[offset++]; - if (kind === PropFlags.Ref) { - const value = readU32(buf, offset); - return this.hasAttrPath(value, propIds, idx + 1); - } else if (kind === PropFlags.RefArr) { - const _count = readU32(buf, offset); - offset += 4; - - if (idx < propIds.length - 1 && propIds[idx + 1] === AST_PROP_LENGTH) { - return true; - } - - // TODO(@marvinhagemeister): Allow traversing into array children? - } - - // Primitives cannot be traversed further. This means we - // didn't found the attribute. - if (idx < propIds.length - 1) return false; - - return true; - } - - /** - * @param {number} offset * @returns {number} */ - getFirstChild(offset) { - const { buf } = this; - - // type + parentId + SpanLo + SpanHi - offset += 1 + 4 + 4 + 4; - - const count = buf[offset++]; - for (let i = 0; i < count; i++) { - const _prop = buf[offset++]; - const kind = buf[offset++]; - - switch (kind) { - case PropFlags.Ref: { - const v = readU32(buf, offset); - offset += 4; - return v; - } - case PropFlags.RefArr: { - const len = readU32(buf, offset); - offset += 4; - for (let j = 0; j < len; j++) { - const v = readU32(buf, offset); - offset += 4; - return v; - } - - return len; - } - - case PropFlags.String: - offset += 4; - break; - case PropFlags.Bool: - offset++; - break; - case PropFlags.Null: - case PropFlags.Undefined: - break; - } - } - - return -1; + getFirstChild(idx) { + const siblings = this.getSiblings(idx); + return siblings[0] ?? -1; } /** - * @param {number} offset + * @param {number} idx * @returns {number} */ - getLastChild(offset) { - const { buf } = this; - - // type + parentId + SpanLo + SpanHi - offset += 1 + 4 + 4 + 4; - - let last = -1; - - const count = buf[offset++]; - for (let i = 0; i < count; i++) { - const _prop = buf[offset++]; - const kind = buf[offset++]; - - switch (kind) { - case PropFlags.Ref: { - const v = readU32(buf, offset); - offset += 4; - last = v; - break; - } - case PropFlags.RefArr: { - const len = readU32(buf, offset); - offset += 4; - for (let j = 0; j < len; j++) { - const v = readU32(buf, offset); - last = v; - offset += 4; - } - - break; - } - - case PropFlags.String: - offset += 4; - break; - case PropFlags.Bool: - offset++; - break; - case PropFlags.Null: - case PropFlags.Undefined: - break; - } - } - - return last; + getLastChild(idx) { + const siblings = this.getSiblings(idx); + return siblings.at(-1) ?? -1; } /** - * @param {number} id + * @param {number} idx * @returns {number[]} */ - getSiblings(id) { - const { buf } = this; + getSiblings(idx) { + const { buf } = this.ctx; + const parent = readParent(buf, idx); - const result = findChildOffset(buf, id); - // Happens for program nodes - if (result === null) return []; - - if (result[1] === -1) { - return [id]; + // Only RefArrays have siblings + const parentType = readType(buf, parent); + if (parentType !== AST_GROUP_TYPE) { + return []; } - let offset = result[0]; - const count = readU32(buf, offset); - offset += 4; - - /** @type {number[]} */ const out = []; - for (let i = 0; i < count; i++) { - const v = readU32(buf, offset); - offset += 4; - out.push(v); + let child = readChild(buf, parent); + while (child > AST_IDX_INVALID) { + out.push(child); + child = readNext(buf, child); } return out; @@ -683,7 +646,7 @@ class MatchCtx { /** * @param {Uint8Array} buf - * @param {AstContext} buf + * @returns {AstContext} */ function createAstContext(buf) { /** @type {Map} */ @@ -691,6 +654,8 @@ function createAstContext(buf) { // The buffer has a few offsets at the end which allows us to easily // jump to the relevant sections of the message. + const propsOffset = readU32(buf, buf.length - 24); + const spansOffset = readU32(buf, buf.length - 20); const typeMapOffset = readU32(buf, buf.length - 16); const propMapOffset = readU32(buf, buf.length - 12); const strTableOffset = readU32(buf, buf.length - 8); @@ -702,9 +667,7 @@ function createAstContext(buf) { const stringCount = readU32(buf, offset); offset += 4; - // TODO(@marvinhagemeister): We could lazily decode the strings on an as needed basis. - // Not sure if this matters much in practice though. - let id = 0; + let strId = 0; for (let i = 0; i < stringCount; i++) { const len = readU32(buf, offset); offset += 4; @@ -712,8 +675,8 @@ function createAstContext(buf) { const strBytes = buf.slice(offset, offset + len); offset += len; const s = DECODER.decode(strBytes); - strTable.set(id, s); - id++; + strTable.set(strId, s); + strId++; } if (strTable.size !== stringCount) { @@ -755,14 +718,17 @@ function createAstContext(buf) { buf, strTable, rootOffset, + spansOffset, + propsOffset, nodes: new Map(), strTableOffset, strByProp, strByType, typeByStr, propByStr, - matcher: new MatchCtx(buf, strTable, strByType), + matcher: /** @type {*} */ (null), }; + ctx.matcher = new MatchCtx(ctx); setNodeGetters(ctx); @@ -903,76 +869,53 @@ export function runPluginsForFile(fileName, serializedAst) { /** * @param {AstContext} ctx * @param {CompiledVisitor[]} visitors - * @param {number} offset + * @param {number} idx */ -function traverse(ctx, visitors, offset) { - // The 0 offset is used to denote an empty/placeholder node - if (offset === 0) return; - - const originalOffset = offset; +function traverse(ctx, visitors, idx) { + if (idx === AST_IDX_INVALID) return; const { buf } = ctx; + const nodeType = readType(ctx.buf, idx); /** @type {VisitorFn[] | null} */ let exits = null; - for (let i = 0; i < visitors.length; i++) { - const v = visitors[i]; - - if (v.matcher(ctx.matcher, offset)) { - if (v.info.exit !== NOOP) { - if (exits === null) { - exits = [v.info.exit]; - } else { - exits.push(v.info.exit); + // Only visit if it's an actual node + if (nodeType !== AST_GROUP_TYPE) { + // Loop over visitors and check if any selector matches + for (let i = 0; i < visitors.length; i++) { + const v = visitors[i]; + if (v.matcher(ctx.matcher, idx)) { + if (v.info.exit !== NOOP) { + if (exits === null) { + exits = [v.info.exit]; + } else { + exits.push(v.info.exit); + } } - } - if (v.info.enter !== NOOP) { - const node = /** @type {*} */ (getNode(ctx, offset)); - v.info.enter(node); + if (v.info.enter !== NOOP) { + const node = /** @type {*} */ (getNode(ctx, idx)); + v.info.enter(node); + } } } } - // Search for node references in the properties of the current node. All - // other properties can be ignored. try { - // type + parentId + SpanLo + SpanHi - offset += 1 + 4 + 4 + 4; + const childIdx = readChild(buf, idx); + if (childIdx > AST_IDX_INVALID) { + traverse(ctx, visitors, childIdx); + } - const propCount = buf[offset]; - offset += 1; - - for (let i = 0; i < propCount; i++) { - const kind = buf[offset + 1]; - offset += 2; // propId + propFlags - - if (kind === PropFlags.Ref) { - const next = readU32(buf, offset); - offset += 4; - traverse(ctx, visitors, next); - } else if (kind === PropFlags.RefArr) { - const len = readU32(buf, offset); - offset += 4; - - for (let j = 0; j < len; j++) { - const child = readU32(buf, offset); - offset += 4; - traverse(ctx, visitors, child); - } - } else if (kind === PropFlags.String) { - offset += 4; - } else if (kind === PropFlags.Bool) { - offset += 1; - } else if (kind === PropFlags.Null || kind === PropFlags.Undefined) { - // No value - } + const nextIdx = readNext(buf, idx); + if (nextIdx > AST_IDX_INVALID) { + traverse(ctx, visitors, nextIdx); } } finally { if (exits !== null) { for (let i = 0; i < exits.length; i++) { - const node = /** @type {*} */ (getNode(ctx, originalOffset)); + const node = /** @type {*} */ (getNode(ctx, idx)); exits[i](node); } } @@ -1009,38 +952,46 @@ function _dump(ctx) { // deno-lint-ignore no-console console.log(); - let offset = 0; + // @ts-ignore dump fn + // deno-lint-ignore no-console + console.log(); - while (offset < strTableOffset) { - const type = buf[offset]; - const name = getString(ctx.strTable, ctx.strByType[type]); + let idx = 0; + while (idx < (strTableOffset / NODE_SIZE)) { + const type = readType(buf, idx); + const child = readChild(buf, idx); + const next = readNext(buf, idx); + const parent = readParent(buf, idx); + const range = readSpan(ctx, idx); + + const name = type === AST_IDX_INVALID + ? "" + : type === AST_GROUP_TYPE + ? "" + : getString(ctx.strTable, ctx.strByType[type]); // @ts-ignore dump fn // deno-lint-ignore no-console - console.log(`${name}, offset: ${offset}, type: ${type}`); - offset += 1; + console.log(`${name}, idx: ${idx}, type: ${type}`); - const parent = readU32(buf, offset); - offset += 4; // @ts-ignore dump fn // deno-lint-ignore no-console - console.log(` parent: ${parent}`); - - const start = readU32(buf, offset); - offset += 4; - const end = readU32(buf, offset); - offset += 4; + console.log(` child: ${child}, next: ${next}, parent: ${parent}`); // @ts-ignore dump fn // deno-lint-ignore no-console - console.log(` range: ${start} -> ${end}`); + console.log(` range: ${range[0]}, ${range[1]}`); - const count = buf[offset++]; + const rawOffset = readRawPropOffset(ctx.buf, idx); + let propOffset = readPropOffset(ctx, idx); + const count = buf[propOffset++]; // @ts-ignore dump fn // deno-lint-ignore no-console - console.log(` prop count: ${count}`); + console.log( + ` prop count: ${count}, prop offset: ${propOffset} raw offset: ${rawOffset}`, + ); for (let i = 0; i < count; i++) { - const prop = buf[offset++]; - const kind = buf[offset++]; + const prop = buf[propOffset++]; + const kind = buf[propOffset++]; const name = getString(ctx.strTable, ctx.strByProp[prop]); let kindName = "unknown"; @@ -1051,40 +1002,36 @@ function _dump(ctx) { } } + const v = readU32(buf, propOffset); + propOffset += 4; + if (kind === PropFlags.Ref) { - const v = readU32(buf, offset); - offset += 4; // @ts-ignore dump fn // deno-lint-ignore no-console console.log(` ${name}: ${v} (${kindName}, ${prop})`); } else if (kind === PropFlags.RefArr) { - const len = readU32(buf, offset); - offset += 4; // @ts-ignore dump fn // deno-lint-ignore no-console - console.log(` ${name}: Array(${len}) (${kindName}, ${prop})`); - - for (let j = 0; j < len; j++) { - const v = readU32(buf, offset); - offset += 4; - // @ts-ignore dump fn - // deno-lint-ignore no-console - console.log(` - ${v} (${prop})`); - } + console.log(` ${name}: RefArray: ${v}, (${kindName}, ${prop})`); } else if (kind === PropFlags.Bool) { - const v = buf[offset]; - offset += 1; // @ts-ignore dump fn // deno-lint-ignore no-console console.log(` ${name}: ${v} (${kindName}, ${prop})`); } else if (kind === PropFlags.String) { - const v = readU32(buf, offset); - offset += 4; + const raw = getString(ctx.strTable, v); // @ts-ignore dump fn // deno-lint-ignore no-console - console.log( - ` ${name}: ${getString(ctx.strTable, v)} (${kindName}, ${prop})`, - ); + console.log(` ${name}: ${raw} (${kindName}, ${prop})`); + } else if (kind === PropFlags.Number) { + const raw = getString(ctx.strTable, v); + // @ts-ignore dump fn + // deno-lint-ignore no-console + console.log(` ${name}: ${raw} (${kindName}, ${prop})`); + } else if (kind === PropFlags.Regex) { + const raw = getString(ctx.strTable, v); + // @ts-ignore dump fn + // deno-lint-ignore no-console + console.log(` ${name}: ${raw} (${kindName}, ${prop})`); } else if (kind === PropFlags.Null) { // @ts-ignore dump fn // deno-lint-ignore no-console @@ -1093,8 +1040,27 @@ function _dump(ctx) { // @ts-ignore dump fn // deno-lint-ignore no-console console.log(` ${name}: undefined (${kindName}, ${prop})`); + } else if (kind === PropFlags.BigInt) { + const raw = getString(ctx.strTable, v); + // @ts-ignore dump fn + // deno-lint-ignore no-console + console.log(` ${name}: ${raw} (${kindName}, ${prop})`); + } else if (kind === PropFlags.Obj) { + let offset = v + ctx.propsOffset; + const count = readU32(ctx.buf, offset); + offset += 4; + + // @ts-ignore dump fn + // deno-lint-ignore no-console + console.log( + ` ${name}: Object (${count}) (${kindName}, ${prop}), raw offset ${v}`, + ); + + // TODO(@marvinhagemeister): Show object } } + + idx++; } } @@ -1107,9 +1073,10 @@ function _dump(ctx) { */ function runLintPlugin(plugin, fileName, sourceText) { installPlugin(plugin); - const serializedAst = op_lint_create_serialized_ast(fileName, sourceText); try { + const serializedAst = op_lint_create_serialized_ast(fileName, sourceText); + runPluginsForFile(fileName, serializedAst); } finally { // During testing we don't want to keep plugins around diff --git a/cli/js/40_lint_selector.js b/cli/js/40_lint_selector.js index b78f7a5d0e..362130076a 100644 --- a/cli/js/40_lint_selector.js +++ b/cli/js/40_lint_selector.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check @@ -406,8 +406,9 @@ export function splitSelectors(input) { } } - if (last < input.length - 1) { - out.push(input.slice(last).trim()); + const remaining = input.slice(last).trim(); + if (remaining.length > 0) { + out.push(remaining); } return out; @@ -743,8 +744,7 @@ export function compileSelector(selector) { fn = matchNthChild(node, fn); break; case PSEUDO_HAS: - // FIXME - // fn = matchIs(part, fn); + // TODO(@marvinhagemeister) throw new Error("TODO: :has"); case PSEUDO_NOT: fn = matchNot(node.selectors, fn); @@ -766,8 +766,7 @@ export function compileSelector(selector) { */ function matchFirstChild(next) { return (ctx, id) => { - const parent = ctx.getParent(id); - const first = ctx.getFirstChild(parent); + const first = ctx.getFirstChild(id); return first === id && next(ctx, first); }; } @@ -778,8 +777,7 @@ function matchFirstChild(next) { */ function matchLastChild(next) { return (ctx, id) => { - const parent = ctx.getParent(id); - const last = ctx.getLastChild(parent); + const last = ctx.getLastChild(id); return last === id && next(ctx, id); }; } @@ -954,7 +952,9 @@ function matchElem(part, next) { else if (part.elem === 0) return false; const type = ctx.getType(id); - if (type > 0 && type === part.elem) return next(ctx, id); + if (type > 0 && type === part.elem) { + return next(ctx, id); + } return false; }; @@ -967,7 +967,16 @@ function matchElem(part, next) { */ function matchAttrExists(attr, next) { return (ctx, id) => { - return ctx.hasAttrPath(id, attr.prop, 0) ? next(ctx, id) : false; + try { + ctx.getAttrPathValue(id, attr.prop, 0); + return next(ctx, id); + } catch (err) { + if (err === -1) { + return false; + } + + throw err; + } }; } @@ -978,9 +987,15 @@ function matchAttrExists(attr, next) { */ function matchAttrBin(attr, next) { return (ctx, id) => { - if (!ctx.hasAttrPath(id, attr.prop, 0)) return false; - const value = ctx.getAttrPathValue(id, attr.prop, 0); - if (!matchAttrValue(attr, value)) return false; + try { + const value = ctx.getAttrPathValue(id, attr.prop, 0); + if (!matchAttrValue(attr, value)) return false; + } catch (err) { + if (err === -1) { + return false; + } + throw err; + } return next(ctx, id); }; } diff --git a/cli/js/40_lint_types.d.ts b/cli/js/40_lint_types.d.ts index 7b06e36098..f07d16581e 100644 --- a/cli/js/40_lint_types.d.ts +++ b/cli/js/40_lint_types.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. export interface NodeFacade { type: string; @@ -12,6 +12,8 @@ export interface AstContext { strTableOffset: number; rootOffset: number; nodes: Map; + spansOffset: number; + propsOffset: number; strByType: number[]; strByProp: number[]; typeByStr: Map; @@ -19,6 +21,12 @@ export interface AstContext { matcher: MatchContext; } +export interface Node { + range: Range; +} + +export type Range = [number, number]; + // TODO(@marvinhagemeister) Remove once we land "official" types export interface RuleContext { id: string; @@ -121,7 +129,6 @@ export interface MatchContext { getSiblings(id: number): number[]; getParent(id: number): number; getType(id: number): number; - hasAttrPath(id: number, propIds: number[], idx: number): boolean; getAttrPathValue(id: number, propIds: number[], idx: number): unknown; } diff --git a/cli/js/40_test.js b/cli/js/40_test.js index ea526a17d4..3dbb7ec340 100644 --- a/cli/js/40_test.js +++ b/cli/js/40_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, primordials } from "ext:core/mod.js"; import { escapeName, withPermissions } from "ext:cli/40_test_common.js"; @@ -26,7 +26,7 @@ const { TypeError, } = primordials; -import { setExitHandler } from "ext:runtime/30_os.js"; +import { setExitHandler } from "ext:deno_os/30_os.js"; // Capture `Deno` global so that users deleting or mangling it, won't // have impact on our sanitizers. diff --git a/cli/js/40_test_common.js b/cli/js/40_test_common.js index 7711148f1e..6b7828cd2d 100644 --- a/cli/js/40_test_common.js +++ b/cli/js/40_test_common.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, primordials } from "ext:core/mod.js"; import { serializePermissions } from "ext:runtime/10_permissions.js"; const ops = core.ops; diff --git a/cli/jsr.rs b/cli/jsr.rs index acfbb1c8e2..34a2ec04e4 100644 --- a/cli/jsr.rs +++ b/cli/jsr.rs @@ -1,14 +1,16 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::sync::Arc; -use crate::args::jsr_url; -use crate::file_fetcher::CliFileFetcher; use dashmap::DashMap; use deno_core::serde_json; use deno_graph::packages::JsrPackageInfo; use deno_graph::packages::JsrPackageVersionInfo; use deno_semver::package::PackageNv; use deno_semver::package::PackageReq; -use std::sync::Arc; + +use crate::args::jsr_url; +use crate::file_fetcher::CliFileFetcher; /// This is similar to a subset of `JsrCacheResolver` which fetches rather than /// just reads the cache. Keep in sync! diff --git a/cli/lib/Cargo.toml b/cli/lib/Cargo.toml new file mode 100644 index 0000000000..67caf6e944 --- /dev/null +++ b/cli/lib/Cargo.toml @@ -0,0 +1,37 @@ +# Copyright 2018-2025 the Deno authors. MIT license. + +[package] +name = "deno_lib" +version = "0.2.0" +authors.workspace = true +edition.workspace = true +license.workspace = true +readme = "README.md" +repository.workspace = true +description = "Shared code between the Deno CLI and denort" + +[lib] +path = "lib.rs" + +[dependencies] +deno_cache_dir.workspace = true +deno_error.workspace = true +deno_fs = { workspace = true, features = ["sync_fs"] } +deno_node = { workspace = true, features = ["sync_fs"] } +deno_path_util.workspace = true +deno_resolver = { workspace = true, features = ["sync"] } +deno_runtime.workspace = true +deno_terminal.workspace = true +faster-hex.workspace = true +log.workspace = true +node_resolver = { workspace = true, features = ["sync"] } +parking_lot.workspace = true +ring.workspace = true +serde = { workspace = true, features = ["derive"] } +sys_traits = { workspace = true, features = ["getrandom"] } +thiserror.workspace = true +tokio.workspace = true +url.workspace = true + +[dev-dependencies] +test_util.workspace = true diff --git a/cli/lib/README.md b/cli/lib/README.md new file mode 100644 index 0000000000..bc6d7b57d0 --- /dev/null +++ b/cli/lib/README.md @@ -0,0 +1,4 @@ +# deno_lib + +This crate contains the shared code between the Deno CLI and denort. It is +highly unstable. diff --git a/cli/cache/deno_dir.rs b/cli/lib/cache/deno_dir.rs similarity index 89% rename from cli/cache/deno_dir.rs rename to cli/lib/cache/deno_dir.rs index 90a3add54e..00bc83ff9b 100644 --- a/cli/cache/deno_dir.rs +++ b/cli/lib/cache/deno_dir.rs @@ -1,25 +1,23 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. - -use deno_cache_dir::DenoDirResolutionError; -use once_cell::sync::OnceCell; - -use crate::sys::CliSys; - -use super::DiskCache; +// Copyright 2018-2025 the Deno authors. MIT license. use std::env; use std::path::PathBuf; +use deno_cache_dir::DenoDirResolutionError; + +use super::DiskCache; +use crate::sys::DenoLibSys; + /// Lazily creates the deno dir which might be useful in scenarios /// where functionality wants to continue if the DENO_DIR can't be created. -pub struct DenoDirProvider { - sys: CliSys, +pub struct DenoDirProvider { + sys: TSys, maybe_custom_root: Option, - deno_dir: OnceCell>, + deno_dir: std::sync::OnceLock, DenoDirResolutionError>>, } -impl DenoDirProvider { - pub fn new(sys: CliSys, maybe_custom_root: Option) -> Self { +impl DenoDirProvider { + pub fn new(sys: TSys, maybe_custom_root: Option) -> Self { Self { sys, maybe_custom_root, @@ -27,7 +25,9 @@ impl DenoDirProvider { } } - pub fn get_or_create(&self) -> Result<&DenoDir, DenoDirResolutionError> { + pub fn get_or_create( + &self, + ) -> Result<&DenoDir, DenoDirResolutionError> { self .deno_dir .get_or_init(|| { @@ -50,16 +50,16 @@ impl DenoDirProvider { /// `DenoDir` serves as coordinator for multiple `DiskCache`s containing them /// in single directory that can be controlled with `$DENO_DIR` env variable. #[derive(Debug, Clone)] -pub struct DenoDir { +pub struct DenoDir { /// Example: /Users/rld/.deno/ pub root: PathBuf, /// Used by TsCompiler to cache compiler output. - pub gen_cache: DiskCache, + pub gen_cache: DiskCache, } -impl DenoDir { +impl DenoDir { pub fn new( - sys: CliSys, + sys: TSys, maybe_custom_root: Option, ) -> Result { let root = deno_cache_dir::resolve_deno_dir( diff --git a/cli/cache/disk_cache.rs b/cli/lib/cache/disk_cache.rs similarity index 92% rename from cli/cache/disk_cache.rs rename to cli/lib/cache/disk_cache.rs index c96a3943c0..2c735a34b2 100644 --- a/cli/cache/disk_cache.rs +++ b/cli/lib/cache/disk_cache.rs @@ -1,13 +1,5 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::sys::CliSys; - -use super::CACHE_PERM; - -use deno_cache_dir::url_to_filename; -use deno_core::url::Host; -use deno_core::url::Url; -use deno_path_util::fs::atomic_write_file_with_retries; use std::ffi::OsStr; use std::fs; use std::path::Component; @@ -16,15 +8,23 @@ use std::path::PathBuf; use std::path::Prefix; use std::str; +use deno_cache_dir::url_to_filename; +use deno_cache_dir::CACHE_PERM; +use deno_path_util::fs::atomic_write_file_with_retries; +use url::Host; +use url::Url; + +use crate::sys::DenoLibSys; + #[derive(Debug, Clone)] -pub struct DiskCache { - sys: CliSys, +pub struct DiskCache { + sys: TSys, pub location: PathBuf, } -impl DiskCache { +impl DiskCache { /// `location` must be an absolute path. - pub fn new(sys: CliSys, location: &Path) -> Self { + pub fn new(sys: TSys, location: &Path) -> Self { assert!(location.is_absolute()); Self { sys, @@ -130,14 +130,18 @@ impl DiskCache { #[cfg(test)] mod tests { - use super::*; + // ok, testing + #[allow(clippy::disallowed_types)] + use sys_traits::impls::RealSys; use test_util::TempDir; + use super::*; + #[test] fn test_set_get_cache_file() { let temp_dir = TempDir::new(); let sub_dir = temp_dir.path().join("sub_dir"); - let cache = DiskCache::new(CliSys::default(), &sub_dir.to_path_buf()); + let cache = DiskCache::new(RealSys, &sub_dir.to_path_buf()); let path = PathBuf::from("foo/bar.txt"); cache.set(&path, b"hello").unwrap(); assert_eq!(cache.get(&path).unwrap(), b"hello"); @@ -151,7 +155,7 @@ mod tests { PathBuf::from("/deno_dir/") }; - let cache = DiskCache::new(CliSys::default(), &cache_location); + let cache = DiskCache::new(RealSys, &cache_location); let mut test_cases = vec![ ( @@ -207,7 +211,7 @@ mod tests { } else { "/foo" }; - let cache = DiskCache::new(CliSys::default(), &PathBuf::from(p)); + let cache = DiskCache::new(RealSys, &PathBuf::from(p)); let mut test_cases = vec![ ( @@ -255,7 +259,7 @@ mod tests { PathBuf::from("/deno_dir/") }; - let cache = DiskCache::new(CliSys::default(), &cache_location); + let cache = DiskCache::new(RealSys, &cache_location); let mut test_cases = vec!["unknown://localhost/test.ts"]; diff --git a/cli/lib/cache/mod.rs b/cli/lib/cache/mod.rs new file mode 100644 index 0000000000..c4395df3e1 --- /dev/null +++ b/cli/lib/cache/mod.rs @@ -0,0 +1,8 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +pub use deno_dir::DenoDir; +pub use deno_dir::DenoDirProvider; +pub use disk_cache::DiskCache; + +mod deno_dir; +mod disk_cache; diff --git a/cli/lib/env.rs b/cli/lib/env.rs new file mode 100644 index 0000000000..9c6001478b --- /dev/null +++ b/cli/lib/env.rs @@ -0,0 +1,10 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +pub fn has_trace_permissions_enabled() -> bool { + has_flag_env_var("DENO_TRACE_PERMISSIONS") +} + +pub fn has_flag_env_var(name: &str) -> bool { + let value = std::env::var(name); + matches!(value.as_ref().map(|s| s.as_str()), Ok("1")) +} diff --git a/cli/lib/lib.rs b/cli/lib/lib.rs new file mode 100644 index 0000000000..5453bddaee --- /dev/null +++ b/cli/lib/lib.rs @@ -0,0 +1,9 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +pub mod cache; +pub mod env; +pub mod npm; +pub mod standalone; +pub mod sys; +pub mod util; +pub mod worker; diff --git a/cli/lib/npm/mod.rs b/cli/lib/npm/mod.rs new file mode 100644 index 0000000000..e7d4d8d9d1 --- /dev/null +++ b/cli/lib/npm/mod.rs @@ -0,0 +1,6 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +mod permission_checker; + +pub use permission_checker::NpmRegistryReadPermissionChecker; +pub use permission_checker::NpmRegistryReadPermissionCheckerMode; diff --git a/cli/lib/npm/permission_checker.rs b/cli/lib/npm/permission_checker.rs new file mode 100644 index 0000000000..ebed1270f3 --- /dev/null +++ b/cli/lib/npm/permission_checker.rs @@ -0,0 +1,120 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::borrow::Cow; +use std::collections::HashMap; +use std::io::ErrorKind; +use std::path::Path; +use std::path::PathBuf; + +use deno_error::JsErrorBox; +use deno_runtime::deno_node::NodePermissions; +use parking_lot::Mutex; + +use crate::sys::DenoLibSys; + +#[derive(Debug)] +pub enum NpmRegistryReadPermissionCheckerMode { + Byonm, + Global(PathBuf), + Local(PathBuf), +} + +#[derive(Debug)] +pub struct NpmRegistryReadPermissionChecker { + sys: TSys, + cache: Mutex>, + mode: NpmRegistryReadPermissionCheckerMode, +} + +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(inherit)] +#[error("failed canonicalizing '{path}'")] +struct EnsureRegistryReadPermissionError { + path: PathBuf, + #[source] + #[inherit] + source: std::io::Error, +} + +impl NpmRegistryReadPermissionChecker { + pub fn new(sys: TSys, mode: NpmRegistryReadPermissionCheckerMode) -> Self { + Self { + sys, + cache: Default::default(), + mode, + } + } + + #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] + pub fn ensure_read_permission<'a>( + &self, + permissions: &mut dyn NodePermissions, + path: &'a Path, + ) -> Result, JsErrorBox> { + if permissions.query_read_all() { + return Ok(Cow::Borrowed(path)); // skip permissions checks below + } + + match &self.mode { + NpmRegistryReadPermissionCheckerMode::Byonm => { + if path.components().any(|c| c.as_os_str() == "node_modules") { + Ok(Cow::Borrowed(path)) + } else { + permissions + .check_read_path(path) + .map_err(JsErrorBox::from_err) + } + } + NpmRegistryReadPermissionCheckerMode::Global(registry_path) + | NpmRegistryReadPermissionCheckerMode::Local(registry_path) => { + // allow reading if it's in the node_modules + let is_path_in_node_modules = path.starts_with(registry_path) + && path + .components() + .all(|c| !matches!(c, std::path::Component::ParentDir)); + + if is_path_in_node_modules { + let mut cache = self.cache.lock(); + let mut canonicalize = + |path: &Path| -> Result, JsErrorBox> { + match cache.get(path) { + Some(canon) => Ok(Some(canon.clone())), + None => match self.sys.fs_canonicalize(path) { + Ok(canon) => { + cache.insert(path.to_path_buf(), canon.clone()); + Ok(Some(canon)) + } + Err(e) => { + if e.kind() == ErrorKind::NotFound { + return Ok(None); + } + Err(JsErrorBox::from_err( + EnsureRegistryReadPermissionError { + path: path.to_path_buf(), + source: e, + }, + )) + } + }, + } + }; + if let Some(registry_path_canon) = canonicalize(registry_path)? { + if let Some(path_canon) = canonicalize(path)? { + if path_canon.starts_with(registry_path_canon) { + return Ok(Cow::Owned(path_canon)); + } + } else if path.starts_with(registry_path_canon) + || path.starts_with(registry_path) + { + return Ok(Cow::Borrowed(path)); + } + } + } + + permissions + .check_read_path(path) + .map_err(JsErrorBox::from_err) + } + } + } +} diff --git a/cli/lib/standalone/mod.rs b/cli/lib/standalone/mod.rs new file mode 100644 index 0000000000..6e173a457a --- /dev/null +++ b/cli/lib/standalone/mod.rs @@ -0,0 +1,3 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +pub mod virtual_fs; diff --git a/cli/lib/standalone/virtual_fs.rs b/cli/lib/standalone/virtual_fs.rs new file mode 100644 index 0000000000..5fc17f27b7 --- /dev/null +++ b/cli/lib/standalone/virtual_fs.rs @@ -0,0 +1,296 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::cmp::Ordering; +use std::path::Path; +use std::path::PathBuf; + +use serde::Deserialize; +use serde::Serialize; + +#[derive(Debug, Copy, Clone)] +pub enum VfsFileSubDataKind { + /// Raw bytes of the file. + Raw, + /// Bytes to use for module loading. For example, for TypeScript + /// files this will be the transpiled JavaScript source. + ModuleGraph, +} + +#[derive(Debug, PartialEq, Eq)] +pub enum WindowsSystemRootablePath { + /// The root of the system above any drive letters. + WindowSystemRoot, + Path(PathBuf), +} + +impl WindowsSystemRootablePath { + pub fn join(&self, name_component: &str) -> PathBuf { + // this method doesn't handle multiple components + debug_assert!( + !name_component.contains('\\'), + "Invalid component: {}", + name_component + ); + debug_assert!( + !name_component.contains('/'), + "Invalid component: {}", + name_component + ); + + match self { + WindowsSystemRootablePath::WindowSystemRoot => { + // windows drive letter + PathBuf::from(&format!("{}\\", name_component)) + } + WindowsSystemRootablePath::Path(path) => path.join(name_component), + } + } +} + +#[derive(Debug, Copy, Clone, Serialize, Deserialize)] +pub enum FileSystemCaseSensitivity { + #[serde(rename = "s")] + Sensitive, + #[serde(rename = "i")] + Insensitive, +} +#[derive(Debug, Default, Serialize, Deserialize)] +pub struct VirtualDirectoryEntries(Vec); + +impl VirtualDirectoryEntries { + pub fn new(mut entries: Vec) -> Self { + // needs to be sorted by name + entries.sort_by(|a, b| a.name().cmp(b.name())); + Self(entries) + } + + pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, VfsEntry> { + self.0.iter_mut() + } + + pub fn iter(&self) -> std::slice::Iter<'_, VfsEntry> { + self.0.iter() + } + + pub fn take_inner(&mut self) -> Vec { + std::mem::take(&mut self.0) + } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + pub fn len(&self) -> usize { + self.0.len() + } + + pub fn get_by_name( + &self, + name: &str, + case_sensitivity: FileSystemCaseSensitivity, + ) -> Option<&VfsEntry> { + self + .binary_search(name, case_sensitivity) + .ok() + .map(|index| &self.0[index]) + } + + pub fn get_mut_by_name( + &mut self, + name: &str, + case_sensitivity: FileSystemCaseSensitivity, + ) -> Option<&mut VfsEntry> { + self + .binary_search(name, case_sensitivity) + .ok() + .map(|index| &mut self.0[index]) + } + + pub fn get_mut_by_index(&mut self, index: usize) -> Option<&mut VfsEntry> { + self.0.get_mut(index) + } + + pub fn binary_search( + &self, + name: &str, + case_sensitivity: FileSystemCaseSensitivity, + ) -> Result { + match case_sensitivity { + FileSystemCaseSensitivity::Sensitive => { + self.0.binary_search_by(|e| e.name().cmp(name)) + } + FileSystemCaseSensitivity::Insensitive => self.0.binary_search_by(|e| { + e.name() + .chars() + .zip(name.chars()) + .map(|(a, b)| a.to_ascii_lowercase().cmp(&b.to_ascii_lowercase())) + .find(|&ord| ord != Ordering::Equal) + .unwrap_or_else(|| e.name().len().cmp(&name.len())) + }), + } + } + + pub fn insert( + &mut self, + entry: VfsEntry, + case_sensitivity: FileSystemCaseSensitivity, + ) -> usize { + match self.binary_search(entry.name(), case_sensitivity) { + Ok(index) => { + self.0[index] = entry; + index + } + Err(insert_index) => { + self.0.insert(insert_index, entry); + insert_index + } + } + } + + pub fn insert_or_modify( + &mut self, + name: &str, + case_sensitivity: FileSystemCaseSensitivity, + on_insert: impl FnOnce() -> VfsEntry, + on_modify: impl FnOnce(&mut VfsEntry), + ) -> usize { + match self.binary_search(name, case_sensitivity) { + Ok(index) => { + on_modify(&mut self.0[index]); + index + } + Err(insert_index) => { + self.0.insert(insert_index, on_insert()); + insert_index + } + } + } + + pub fn remove(&mut self, index: usize) -> VfsEntry { + self.0.remove(index) + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct VirtualDirectory { + #[serde(rename = "n")] + pub name: String, + // should be sorted by name + #[serde(rename = "e")] + pub entries: VirtualDirectoryEntries, +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +pub struct OffsetWithLength { + #[serde(rename = "o")] + pub offset: u64, + #[serde(rename = "l")] + pub len: u64, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct VirtualFile { + #[serde(rename = "n")] + pub name: String, + #[serde(rename = "o")] + pub offset: OffsetWithLength, + /// Offset file to use for module loading when it differs from the + /// raw file. Often this will be the same offset as above for data + /// such as JavaScript files, but for TypeScript files the `offset` + /// will be the original raw bytes when included as an asset and this + /// offset will be to the transpiled JavaScript source. + #[serde(rename = "m")] + pub module_graph_offset: OffsetWithLength, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct VirtualSymlinkParts(Vec); + +impl VirtualSymlinkParts { + pub fn from_path(path: &Path) -> Self { + Self( + path + .components() + .filter(|c| !matches!(c, std::path::Component::RootDir)) + .map(|c| c.as_os_str().to_string_lossy().to_string()) + .collect(), + ) + } + + pub fn take_parts(&mut self) -> Vec { + std::mem::take(&mut self.0) + } + + pub fn parts(&self) -> &[String] { + &self.0 + } + + pub fn set_parts(&mut self, parts: Vec) { + self.0 = parts; + } + + pub fn display(&self) -> String { + self.0.join("/") + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct VirtualSymlink { + #[serde(rename = "n")] + pub name: String, + #[serde(rename = "p")] + pub dest_parts: VirtualSymlinkParts, +} + +impl VirtualSymlink { + pub fn resolve_dest_from_root(&self, root: &Path) -> PathBuf { + let mut dest = root.to_path_buf(); + for part in &self.dest_parts.0 { + dest.push(part); + } + dest + } +} + +#[derive(Debug, Copy, Clone)] +pub enum VfsEntryRef<'a> { + Dir(&'a VirtualDirectory), + File(&'a VirtualFile), + Symlink(&'a VirtualSymlink), +} + +impl VfsEntryRef<'_> { + pub fn name(&self) -> &str { + match self { + Self::Dir(dir) => &dir.name, + Self::File(file) => &file.name, + Self::Symlink(symlink) => &symlink.name, + } + } +} + +// todo(dsherret): we should store this more efficiently in the binary +#[derive(Debug, Serialize, Deserialize)] +pub enum VfsEntry { + Dir(VirtualDirectory), + File(VirtualFile), + Symlink(VirtualSymlink), +} + +impl VfsEntry { + pub fn name(&self) -> &str { + match self { + Self::Dir(dir) => &dir.name, + Self::File(file) => &file.name, + Self::Symlink(symlink) => &symlink.name, + } + } + + pub fn as_ref(&self) -> VfsEntryRef { + match self { + VfsEntry::Dir(dir) => VfsEntryRef::Dir(dir), + VfsEntry::File(file) => VfsEntryRef::File(file), + VfsEntry::Symlink(symlink) => VfsEntryRef::Symlink(symlink), + } + } +} diff --git a/cli/lib/sys.rs b/cli/lib/sys.rs new file mode 100644 index 0000000000..f5ca48b41c --- /dev/null +++ b/cli/lib/sys.rs @@ -0,0 +1,37 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +use deno_node::ExtNodeSys; +use sys_traits::FsCanonicalize; +use sys_traits::FsCreateDirAll; +use sys_traits::FsMetadata; +use sys_traits::FsOpen; +use sys_traits::FsRead; +use sys_traits::FsReadDir; +use sys_traits::FsRemoveFile; +use sys_traits::FsRename; +use sys_traits::SystemRandom; +use sys_traits::ThreadSleep; + +pub trait DenoLibSys: + FsCanonicalize + + FsCreateDirAll + + FsReadDir + + FsMetadata + + FsOpen + + FsRemoveFile + + FsRename + + FsRead + + ThreadSleep + + SystemRandom + + ExtNodeSys + + Clone + + Send + + Sync + + std::fmt::Debug + + 'static +{ +} + +// ok, implementation +#[allow(clippy::disallowed_types)] +impl DenoLibSys for sys_traits::impls::RealSys {} diff --git a/cli/util/checksum.rs b/cli/lib/util/checksum.rs similarity index 87% rename from cli/util/checksum.rs rename to cli/lib/util/checksum.rs index c9c55ec2b4..b15380abd7 100644 --- a/cli/util/checksum.rs +++ b/cli/lib/util/checksum.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use ring::digest::Context; use ring::digest::SHA256; diff --git a/cli/lib/util/mod.rs b/cli/lib/util/mod.rs new file mode 100644 index 0000000000..8371440750 --- /dev/null +++ b/cli/lib/util/mod.rs @@ -0,0 +1,3 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +pub mod checksum; diff --git a/cli/lib/worker.rs b/cli/lib/worker.rs new file mode 100644 index 0000000000..180d3eef8c --- /dev/null +++ b/cli/lib/worker.rs @@ -0,0 +1,581 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::path::PathBuf; +use std::rc::Rc; +use std::sync::Arc; + +use deno_core::error::JsError; +use deno_node::NodeRequireLoaderRc; +use deno_resolver::npm::DenoInNpmPackageChecker; +use deno_resolver::npm::NpmResolver; +use deno_runtime::colors; +use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel; +use deno_runtime::deno_core; +use deno_runtime::deno_core::error::CoreError; +use deno_runtime::deno_core::v8; +use deno_runtime::deno_core::CompiledWasmModuleStore; +use deno_runtime::deno_core::Extension; +use deno_runtime::deno_core::FeatureChecker; +use deno_runtime::deno_core::JsRuntime; +use deno_runtime::deno_core::LocalInspectorSession; +use deno_runtime::deno_core::ModuleLoader; +use deno_runtime::deno_core::SharedArrayBufferStore; +use deno_runtime::deno_fs; +use deno_runtime::deno_node::NodeExtInitServices; +use deno_runtime::deno_node::NodeRequireLoader; +use deno_runtime::deno_node::NodeResolver; +use deno_runtime::deno_permissions::PermissionsContainer; +use deno_runtime::deno_process::NpmProcessStateProviderRc; +use deno_runtime::deno_telemetry::OtelConfig; +use deno_runtime::deno_tls::RootCertStoreProvider; +use deno_runtime::deno_web::BlobStore; +use deno_runtime::fmt_errors::format_js_error; +use deno_runtime::inspector_server::InspectorServer; +use deno_runtime::ops::worker_host::CreateWebWorkerCb; +use deno_runtime::web_worker::WebWorker; +use deno_runtime::web_worker::WebWorkerOptions; +use deno_runtime::web_worker::WebWorkerServiceOptions; +use deno_runtime::worker::MainWorker; +use deno_runtime::worker::WorkerOptions; +use deno_runtime::worker::WorkerServiceOptions; +use deno_runtime::BootstrapOptions; +use deno_runtime::WorkerExecutionMode; +use deno_runtime::WorkerLogLevel; +use deno_runtime::UNSTABLE_GRANULAR_FLAGS; +use url::Url; + +use crate::env::has_trace_permissions_enabled; +use crate::sys::DenoLibSys; +use crate::util::checksum; + +pub struct CreateModuleLoaderResult { + pub module_loader: Rc, + pub node_require_loader: Rc, +} + +pub trait ModuleLoaderFactory: Send + Sync { + fn create_for_main( + &self, + root_permissions: PermissionsContainer, + ) -> CreateModuleLoaderResult; + + fn create_for_worker( + &self, + parent_permissions: PermissionsContainer, + permissions: PermissionsContainer, + ) -> CreateModuleLoaderResult; +} + +enum StorageKeyResolverStrategy { + Specified(Option), + UseMainModule, +} + +pub struct StorageKeyResolver(StorageKeyResolverStrategy); + +impl StorageKeyResolver { + pub fn from_flag(location: &Url) -> Self { + // if a location is set, then the ascii serialization of the location is + // used, unless the origin is opaque, and then no storage origin is set, as + // we can't expect the origin to be reproducible + let storage_origin = location.origin(); + Self(StorageKeyResolverStrategy::Specified( + if storage_origin.is_tuple() { + Some(storage_origin.ascii_serialization()) + } else { + None + }, + )) + } + + pub fn from_config_file_url(url: &Url) -> Self { + Self(StorageKeyResolverStrategy::Specified(Some(url.to_string()))) + } + + pub fn new_use_main_module() -> Self { + Self(StorageKeyResolverStrategy::UseMainModule) + } + + /// Creates a storage key resolver that will always resolve to being empty. + pub fn empty() -> Self { + Self(StorageKeyResolverStrategy::Specified(None)) + } + + /// Resolves the storage key to use based on the current flags, config, or main module. + pub fn resolve_storage_key(&self, main_module: &Url) -> Option { + // use the stored value or fall back to using the path of the main module. + match &self.0 { + StorageKeyResolverStrategy::Specified(value) => value.clone(), + StorageKeyResolverStrategy::UseMainModule => { + Some(main_module.to_string()) + } + } + } +} + +// TODO(bartlomieju): this should be moved to some other place, added to avoid string +// duplication between worker setups and `deno info` output. +pub fn get_cache_storage_dir() -> PathBuf { + // Note: we currently use temp_dir() to avoid managing storage size. + std::env::temp_dir().join("deno_cache") +} + +/// By default V8 uses 1.4Gb heap limit which is meant for browser tabs. +/// Instead probe for the total memory on the system and use it instead +/// as a default. +pub fn create_isolate_create_params() -> Option { + let maybe_mem_info = deno_runtime::deno_os::sys_info::mem_info(); + maybe_mem_info.map(|mem_info| { + v8::CreateParams::default() + .heap_limits_from_system_memory(mem_info.total, 0) + }) +} + +pub struct LibMainWorkerOptions { + pub argv: Vec, + pub deno_version: &'static str, + pub deno_user_agent: &'static str, + pub log_level: WorkerLogLevel, + pub enable_op_summary_metrics: bool, + pub enable_testing_features: bool, + pub has_node_modules_dir: bool, + pub inspect_brk: bool, + pub inspect_wait: bool, + pub strace_ops: Option>, + pub is_inspecting: bool, + pub location: Option, + pub argv0: Option, + pub node_debug: Option, + pub otel_config: OtelConfig, + pub origin_data_folder_path: Option, + pub seed: Option, + pub unsafely_ignore_certificate_errors: Option>, + pub skip_op_registration: bool, + pub node_ipc: Option, + pub startup_snapshot: Option<&'static [u8]>, + pub serve_port: Option, + pub serve_host: Option, +} + +struct LibWorkerFactorySharedState { + blob_store: Arc, + broadcast_channel: InMemoryBroadcastChannel, + code_cache: Option>, + compiled_wasm_module_store: CompiledWasmModuleStore, + feature_checker: Arc, + fs: Arc, + maybe_inspector_server: Option>, + module_loader_factory: Box, + node_resolver: + Arc, TSys>>, + npm_process_state_provider: NpmProcessStateProviderRc, + pkg_json_resolver: Arc>, + root_cert_store_provider: Arc, + shared_array_buffer_store: SharedArrayBufferStore, + storage_key_resolver: StorageKeyResolver, + sys: TSys, + options: LibMainWorkerOptions, +} + +impl LibWorkerFactorySharedState { + fn resolve_unstable_features( + &self, + feature_checker: &FeatureChecker, + ) -> Vec { + let mut unstable_features = + Vec::with_capacity(UNSTABLE_GRANULAR_FLAGS.len()); + for granular_flag in UNSTABLE_GRANULAR_FLAGS { + if feature_checker.check(granular_flag.name) { + unstable_features.push(granular_flag.id); + } + } + unstable_features + } + + fn create_node_init_services( + &self, + node_require_loader: NodeRequireLoaderRc, + ) -> NodeExtInitServices, TSys> { + NodeExtInitServices { + node_require_loader, + node_resolver: self.node_resolver.clone(), + pkg_json_resolver: self.pkg_json_resolver.clone(), + sys: self.sys.clone(), + } + } + + fn create_web_worker_callback( + self: &Arc, + stdio: deno_runtime::deno_io::Stdio, + ) -> Arc { + let shared = self.clone(); + Arc::new(move |args| { + let maybe_inspector_server = shared.maybe_inspector_server.clone(); + + let CreateModuleLoaderResult { + module_loader, + node_require_loader, + } = shared.module_loader_factory.create_for_worker( + args.parent_permissions.clone(), + args.permissions.clone(), + ); + let create_web_worker_cb = + shared.create_web_worker_callback(stdio.clone()); + + let maybe_storage_key = shared + .storage_key_resolver + .resolve_storage_key(&args.main_module); + let cache_storage_dir = maybe_storage_key.map(|key| { + // TODO(@satyarohith): storage quota management + get_cache_storage_dir().join(checksum::gen(&[key.as_bytes()])) + }); + + // TODO(bartlomieju): this is cruft, update FeatureChecker to spit out + // list of enabled features. + let feature_checker = shared.feature_checker.clone(); + let unstable_features = + shared.resolve_unstable_features(feature_checker.as_ref()); + + let services = WebWorkerServiceOptions { + root_cert_store_provider: Some(shared.root_cert_store_provider.clone()), + module_loader, + fs: shared.fs.clone(), + node_services: Some( + shared.create_node_init_services(node_require_loader), + ), + blob_store: shared.blob_store.clone(), + broadcast_channel: shared.broadcast_channel.clone(), + shared_array_buffer_store: Some( + shared.shared_array_buffer_store.clone(), + ), + compiled_wasm_module_store: Some( + shared.compiled_wasm_module_store.clone(), + ), + maybe_inspector_server, + feature_checker, + npm_process_state_provider: Some( + shared.npm_process_state_provider.clone(), + ), + permissions: args.permissions, + }; + let options = WebWorkerOptions { + name: args.name, + main_module: args.main_module.clone(), + worker_id: args.worker_id, + bootstrap: BootstrapOptions { + deno_version: shared.options.deno_version.to_string(), + args: shared.options.argv.clone(), + cpu_count: std::thread::available_parallelism() + .map(|p| p.get()) + .unwrap_or(1), + log_level: shared.options.log_level, + enable_op_summary_metrics: shared.options.enable_op_summary_metrics, + enable_testing_features: shared.options.enable_testing_features, + locale: deno_core::v8::icu::get_language_tag(), + location: Some(args.main_module), + no_color: !colors::use_color(), + color_level: colors::get_color_level(), + is_stdout_tty: deno_terminal::is_stdout_tty(), + is_stderr_tty: deno_terminal::is_stderr_tty(), + unstable_features, + user_agent: shared.options.deno_user_agent.to_string(), + inspect: shared.options.is_inspecting, + has_node_modules_dir: shared.options.has_node_modules_dir, + argv0: shared.options.argv0.clone(), + node_debug: shared.options.node_debug.clone(), + node_ipc_fd: None, + mode: WorkerExecutionMode::Worker, + serve_port: shared.options.serve_port, + serve_host: shared.options.serve_host.clone(), + otel_config: shared.options.otel_config.clone(), + close_on_idle: args.close_on_idle, + }, + extensions: vec![], + startup_snapshot: shared.options.startup_snapshot, + create_params: create_isolate_create_params(), + unsafely_ignore_certificate_errors: shared + .options + .unsafely_ignore_certificate_errors + .clone(), + seed: shared.options.seed, + create_web_worker_cb, + format_js_error_fn: Some(Arc::new(format_js_error)), + worker_type: args.worker_type, + stdio: stdio.clone(), + cache_storage_dir, + strace_ops: shared.options.strace_ops.clone(), + close_on_idle: args.close_on_idle, + maybe_worker_metadata: args.maybe_worker_metadata, + enable_stack_trace_arg_in_ops: has_trace_permissions_enabled(), + }; + + WebWorker::bootstrap_from_options(services, options) + }) + } +} + +pub struct LibMainWorkerFactory { + shared: Arc>, +} + +impl LibMainWorkerFactory { + #[allow(clippy::too_many_arguments)] + pub fn new( + blob_store: Arc, + code_cache: Option>, + feature_checker: Arc, + fs: Arc, + maybe_inspector_server: Option>, + module_loader_factory: Box, + node_resolver: Arc< + NodeResolver, TSys>, + >, + npm_process_state_provider: NpmProcessStateProviderRc, + pkg_json_resolver: Arc>, + root_cert_store_provider: Arc, + storage_key_resolver: StorageKeyResolver, + sys: TSys, + options: LibMainWorkerOptions, + ) -> Self { + Self { + shared: Arc::new(LibWorkerFactorySharedState { + blob_store, + broadcast_channel: Default::default(), + code_cache, + compiled_wasm_module_store: Default::default(), + feature_checker, + fs, + maybe_inspector_server, + module_loader_factory, + node_resolver, + npm_process_state_provider, + pkg_json_resolver, + root_cert_store_provider, + shared_array_buffer_store: Default::default(), + storage_key_resolver, + sys, + options, + }), + } + } + + pub fn create_custom_worker( + &self, + mode: WorkerExecutionMode, + main_module: Url, + permissions: PermissionsContainer, + custom_extensions: Vec, + stdio: deno_runtime::deno_io::Stdio, + ) -> Result { + let shared = &self.shared; + let CreateModuleLoaderResult { + module_loader, + node_require_loader, + } = shared + .module_loader_factory + .create_for_main(permissions.clone()); + + // TODO(bartlomieju): this is cruft, update FeatureChecker to spit out + // list of enabled features. + let feature_checker = shared.feature_checker.clone(); + let unstable_features = + shared.resolve_unstable_features(feature_checker.as_ref()); + let maybe_storage_key = shared + .storage_key_resolver + .resolve_storage_key(&main_module); + let origin_storage_dir = maybe_storage_key.as_ref().map(|key| { + shared + .options + .origin_data_folder_path + .as_ref() + .unwrap() // must be set if storage key resolver returns a value + .join(checksum::gen(&[key.as_bytes()])) + }); + let cache_storage_dir = maybe_storage_key.map(|key| { + // TODO(@satyarohith): storage quota management + get_cache_storage_dir().join(checksum::gen(&[key.as_bytes()])) + }); + + let services = WorkerServiceOptions { + root_cert_store_provider: Some(shared.root_cert_store_provider.clone()), + module_loader, + fs: shared.fs.clone(), + node_services: Some( + shared.create_node_init_services(node_require_loader), + ), + npm_process_state_provider: Some( + shared.npm_process_state_provider.clone(), + ), + blob_store: shared.blob_store.clone(), + broadcast_channel: shared.broadcast_channel.clone(), + fetch_dns_resolver: Default::default(), + shared_array_buffer_store: Some(shared.shared_array_buffer_store.clone()), + compiled_wasm_module_store: Some( + shared.compiled_wasm_module_store.clone(), + ), + feature_checker, + permissions, + v8_code_cache: shared.code_cache.clone(), + }; + + let options = WorkerOptions { + bootstrap: BootstrapOptions { + deno_version: shared.options.deno_version.to_string(), + args: shared.options.argv.clone(), + cpu_count: std::thread::available_parallelism() + .map(|p| p.get()) + .unwrap_or(1), + log_level: shared.options.log_level, + enable_op_summary_metrics: shared.options.enable_op_summary_metrics, + enable_testing_features: shared.options.enable_testing_features, + locale: deno_core::v8::icu::get_language_tag(), + location: shared.options.location.clone(), + no_color: !colors::use_color(), + is_stdout_tty: deno_terminal::is_stdout_tty(), + is_stderr_tty: deno_terminal::is_stderr_tty(), + color_level: colors::get_color_level(), + unstable_features, + user_agent: shared.options.deno_user_agent.to_string(), + inspect: shared.options.is_inspecting, + has_node_modules_dir: shared.options.has_node_modules_dir, + argv0: shared.options.argv0.clone(), + node_debug: shared.options.node_debug.clone(), + node_ipc_fd: shared.options.node_ipc, + mode, + serve_port: shared.options.serve_port, + serve_host: shared.options.serve_host.clone(), + otel_config: shared.options.otel_config.clone(), + close_on_idle: true, + }, + extensions: custom_extensions, + startup_snapshot: shared.options.startup_snapshot, + create_params: create_isolate_create_params(), + unsafely_ignore_certificate_errors: shared + .options + .unsafely_ignore_certificate_errors + .clone(), + seed: shared.options.seed, + format_js_error_fn: Some(Arc::new(format_js_error)), + create_web_worker_cb: shared.create_web_worker_callback(stdio.clone()), + maybe_inspector_server: shared.maybe_inspector_server.clone(), + should_break_on_first_statement: shared.options.inspect_brk, + should_wait_for_inspector_session: shared.options.inspect_wait, + strace_ops: shared.options.strace_ops.clone(), + cache_storage_dir, + origin_storage_dir, + stdio, + skip_op_registration: shared.options.skip_op_registration, + enable_stack_trace_arg_in_ops: has_trace_permissions_enabled(), + }; + + let worker = + MainWorker::bootstrap_from_options(&main_module, services, options); + + Ok(LibMainWorker { + main_module, + worker, + }) + } +} + +pub struct LibMainWorker { + main_module: Url, + worker: MainWorker, +} + +impl LibMainWorker { + pub fn into_main_worker(self) -> MainWorker { + self.worker + } + + pub fn main_module(&self) -> &Url { + &self.main_module + } + + pub fn js_runtime(&mut self) -> &mut JsRuntime { + &mut self.worker.js_runtime + } + + #[inline] + pub fn create_inspector_session(&mut self) -> LocalInspectorSession { + self.worker.create_inspector_session() + } + + #[inline] + pub fn dispatch_load_event(&mut self) -> Result<(), JsError> { + self.worker.dispatch_load_event() + } + + #[inline] + pub fn dispatch_beforeunload_event(&mut self) -> Result { + self.worker.dispatch_beforeunload_event() + } + + #[inline] + pub fn dispatch_process_beforeexit_event(&mut self) -> Result { + self.worker.dispatch_process_beforeexit_event() + } + + #[inline] + pub fn dispatch_unload_event(&mut self) -> Result<(), JsError> { + self.worker.dispatch_unload_event() + } + + #[inline] + pub fn dispatch_process_exit_event(&mut self) -> Result<(), JsError> { + self.worker.dispatch_process_exit_event() + } + + pub async fn execute_main_module(&mut self) -> Result<(), CoreError> { + let id = self.worker.preload_main_module(&self.main_module).await?; + self.worker.evaluate_module(id).await + } + + pub async fn execute_side_module(&mut self) -> Result<(), CoreError> { + let id = self.worker.preload_side_module(&self.main_module).await?; + self.worker.evaluate_module(id).await + } + + #[inline] + pub async fn run_event_loop( + &mut self, + wait_for_inspector: bool, + ) -> Result<(), CoreError> { + self.worker.run_event_loop(wait_for_inspector).await + } + + #[inline] + pub fn exit_code(&self) -> i32 { + self.worker.exit_code() + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn storage_key_resolver_test() { + let resolver = + StorageKeyResolver(StorageKeyResolverStrategy::UseMainModule); + let specifier = Url::parse("file:///a.ts").unwrap(); + assert_eq!( + resolver.resolve_storage_key(&specifier), + Some(specifier.to_string()) + ); + let resolver = + StorageKeyResolver(StorageKeyResolverStrategy::Specified(None)); + assert_eq!(resolver.resolve_storage_key(&specifier), None); + let resolver = StorageKeyResolver(StorageKeyResolverStrategy::Specified( + Some("value".to_string()), + )); + assert_eq!( + resolver.resolve_storage_key(&specifier), + Some("value".to_string()) + ); + + // test empty + let resolver = StorageKeyResolver::empty(); + assert_eq!(resolver.resolve_storage_key(&specifier), None); + } +} diff --git a/cli/lsp/analysis.rs b/cli/lsp/analysis.rs index 8fb3454bc8..f8f382f594 100644 --- a/cli/lsp/analysis.rs +++ b/cli/lsp/analysis.rs @@ -1,33 +1,25 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use super::diagnostics::DenoDiagnostic; -use super::diagnostics::DiagnosticSource; -use super::documents::Document; -use super::documents::Documents; -use super::language_server; -use super::resolver::LspResolver; -use super::tsc; -use super::urls::url_to_uri; - -use crate::args::jsr_url; -use crate::lsp::logging::lsp_warn; -use crate::lsp::search::PackageSearchApi; -use crate::tools::lint::CliLinter; -use crate::util::path::relative_specifier; -use deno_config::workspace::MappedResolution; -use deno_lint::diagnostic::LintDiagnosticRange; +use std::borrow::Cow; +use std::cmp::Ordering; +use std::collections::HashMap; +use std::collections::HashSet; +use std::path::Path; use deno_ast::SourceRange; use deno_ast::SourceRangedForSpanned; use deno_ast::SourceTextInfo; -use deno_core::error::custom_error; +use deno_config::workspace::MappedResolution; use deno_core::error::AnyError; use deno_core::serde::Deserialize; use deno_core::serde::Serialize; use deno_core::serde_json; use deno_core::serde_json::json; use deno_core::ModuleSpecifier; +use deno_error::JsErrorBox; +use deno_lint::diagnostic::LintDiagnosticRange; use deno_path_util::url_to_file_path; +use deno_resolver::npm::managed::NpmResolutionCell; use deno_runtime::deno_node::PathClean; use deno_semver::jsr::JsrPackageNvReference; use deno_semver::jsr::JsrPackageReqReference; @@ -40,20 +32,30 @@ use deno_semver::SmallStackString; use deno_semver::StackString; use deno_semver::Version; use import_map::ImportMap; +use node_resolver::InNpmPackageChecker; use node_resolver::NodeResolutionKind; use node_resolver::ResolutionMode; use once_cell::sync::Lazy; use regex::Regex; -use std::borrow::Cow; -use std::cmp::Ordering; -use std::collections::HashMap; -use std::collections::HashSet; -use std::path::Path; use text_lines::LineAndColumnIndex; use tower_lsp::lsp_types as lsp; use tower_lsp::lsp_types::Position; use tower_lsp::lsp_types::Range; +use super::diagnostics::DenoDiagnostic; +use super::diagnostics::DiagnosticSource; +use super::documents::Document; +use super::documents::Documents; +use super::language_server; +use super::resolver::LspResolver; +use super::tsc; +use super::urls::url_to_uri; +use crate::args::jsr_url; +use crate::lsp::logging::lsp_warn; +use crate::lsp::search::PackageSearchApi; +use crate::tools::lint::CliLinter; +use crate::util::path::relative_specifier; + /// Diagnostic error codes which actually are the same, and so when grouping /// fixes we treat them the same. static FIX_ALL_ERROR_CODES: Lazy> = @@ -365,7 +367,9 @@ impl<'a> TsResponseImportMapper<'a> { if let Ok(Some(pkg_id)) = npm_resolver.resolve_pkg_id_from_specifier(specifier) { - let pkg_reqs = npm_resolver.resolve_pkg_reqs_from_pkg_id(&pkg_id); + let pkg_reqs = npm_resolver + .resolution() + .resolve_pkg_reqs_from_pkg_id(&pkg_id); // check if any pkg reqs match what is found in an import map if !pkg_reqs.is_empty() { let sub_path = npm_resolver @@ -1070,10 +1074,13 @@ impl CodeActionCollection { // we wrap tsc, we can't handle the asynchronous response, so it is // actually easier to return errors if we ever encounter one of these, // which we really wouldn't expect from the Deno lsp. - return Err(custom_error( - "UnsupportedFix", - "The action returned from TypeScript is unsupported.", - )); + return Err( + JsErrorBox::new( + "UnsupportedFix", + "The action returned from TypeScript is unsupported.", + ) + .into(), + ); } let Some(action) = fix_ts_import_action(specifier, resolution_mode, action, language_server) @@ -1292,6 +1299,19 @@ impl CodeActionCollection { range: &lsp::Range, language_server: &language_server::Inner, ) -> Option { + fn top_package_req_for_name( + resolution: &NpmResolutionCell, + name: &str, + ) -> Option { + let package_reqs = resolution.package_reqs(); + let mut entries = package_reqs + .into_iter() + .filter(|(_, nv)| nv.name == name) + .collect::>(); + entries.sort_by(|a, b| a.1.version.cmp(&b.1.version)); + Some(entries.pop()?.0) + } + let (dep_key, dependency, _) = document.get_maybe_dependency(&range.end)?; if dependency.maybe_deno_types_specifier.is_some() { @@ -1379,9 +1399,10 @@ impl CodeActionCollection { .and_then(|versions| versions.first().cloned())?; let types_specifier_text = if let Some(npm_resolver) = managed_npm_resolver { - let mut specifier_text = if let Some(req) = - npm_resolver.top_package_req_for_name(&types_package_name) - { + let mut specifier_text = if let Some(req) = top_package_req_for_name( + npm_resolver.resolution(), + &types_package_name, + ) { format!("npm:{req}") } else { format!("npm:{}@^{}", &types_package_name, types_package_version) diff --git a/cli/lsp/cache.rs b/cli/lsp/cache.rs index 24a55d495c..a65bbd5efe 100644 --- a/cli/lsp/cache.rs +++ b/cli/lsp/cache.rs @@ -1,6 +1,16 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::collections::BTreeMap; +use std::fs; +use std::path::Path; +use std::sync::Arc; +use std::time::SystemTime; + +use deno_core::url::Url; +use deno_core::ModuleSpecifier; +use deno_lib::cache::DenoDir; +use deno_path_util::url_to_file_path; -use crate::cache::DenoDir; use crate::cache::GlobalHttpCache; use crate::cache::HttpCache; use crate::cache::LocalLspHttpCache; @@ -9,15 +19,6 @@ use crate::lsp::logging::lsp_log; use crate::lsp::logging::lsp_warn; use crate::sys::CliSys; -use deno_core::url::Url; -use deno_core::ModuleSpecifier; -use deno_path_util::url_to_file_path; -use std::collections::BTreeMap; -use std::fs; -use std::path::Path; -use std::sync::Arc; -use std::time::SystemTime; - pub fn calculate_fs_version( cache: &LspCache, specifier: &ModuleSpecifier, @@ -69,7 +70,7 @@ fn calculate_fs_version_in_cache( #[derive(Debug, Clone)] pub struct LspCache { - deno_dir: DenoDir, + deno_dir: DenoDir, global: Arc, vendors_by_scope: BTreeMap>>, } @@ -120,7 +121,7 @@ impl LspCache { .collect(); } - pub fn deno_dir(&self) -> &DenoDir { + pub fn deno_dir(&self) -> &DenoDir { &self.deno_dir } diff --git a/cli/lsp/capabilities.rs b/cli/lsp/capabilities.rs index 5cdb1224d8..4c81edeea2 100644 --- a/cli/lsp/capabilities.rs +++ b/cli/lsp/capabilities.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. //! //! Provides information about what capabilities that are supported by the diff --git a/cli/lsp/client.rs b/cli/lsp/client.rs index 65865d5b32..85ea1bb4e5 100644 --- a/cli/lsp/client.rs +++ b/cli/lsp/client.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::sync::Arc; @@ -12,12 +12,11 @@ use lsp_types::Uri; use tower_lsp::lsp_types as lsp; use tower_lsp::lsp_types::ConfigurationItem; -use crate::lsp::repl::get_repl_workspace_settings; - use super::config::WorkspaceSettings; use super::config::SETTINGS_SECTION; use super::lsp_custom; use super::testing::lsp_custom as testing_lsp_custom; +use crate::lsp::repl::get_repl_workspace_settings; #[derive(Debug)] pub enum TestingNotification { diff --git a/cli/lsp/code_lens.rs b/cli/lsp/code_lens.rs index a57ca3ac9f..bb72d0db77 100644 --- a/cli/lsp/code_lens.rs +++ b/cli/lsp/code_lens.rs @@ -1,13 +1,9 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::lsp::logging::lsp_warn; - -use super::analysis::source_range_to_lsp_range; -use super::config::CodeLensSettings; -use super::language_server; -use super::text::LineIndex; -use super::tsc; -use super::tsc::NavigationTree; +use std::cell::RefCell; +use std::collections::HashSet; +use std::rc::Rc; +use std::sync::Arc; use deno_ast::swc::ast; use deno_ast::swc::visit::Visit; @@ -25,13 +21,17 @@ use deno_core::ModuleSpecifier; use lazy_regex::lazy_regex; use once_cell::sync::Lazy; use regex::Regex; -use std::cell::RefCell; -use std::collections::HashSet; -use std::rc::Rc; -use std::sync::Arc; use tower_lsp::jsonrpc::Error as LspError; use tower_lsp::lsp_types as lsp; +use super::analysis::source_range_to_lsp_range; +use super::config::CodeLensSettings; +use super::language_server; +use super::text::LineIndex; +use super::tsc; +use super::tsc::NavigationTree; +use crate::lsp::logging::lsp_warn; + static ABSTRACT_MODIFIER: Lazy = lazy_regex!(r"\babstract\b"); static EXPORT_MODIFIER: Lazy = lazy_regex!(r"\bexport\b"); diff --git a/cli/lsp/completions.rs b/cli/lsp/completions.rs index 31f0b066ed..7309d984b4 100644 --- a/cli/lsp/completions.rs +++ b/cli/lsp/completions.rs @@ -1,4 +1,26 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use deno_ast::LineAndColumnIndex; +use deno_ast::SourceTextInfo; +use deno_core::resolve_path; +use deno_core::resolve_url; +use deno_core::serde::Deserialize; +use deno_core::serde::Serialize; +use deno_core::serde_json::json; +use deno_core::url::Position; +use deno_core::ModuleSpecifier; +use deno_path_util::url_to_file_path; +use deno_runtime::deno_node::SUPPORTED_BUILTIN_NODE_MODULES; +use deno_semver::jsr::JsrPackageReqReference; +use deno_semver::package::PackageNv; +use import_map::ImportMap; +use indexmap::IndexSet; +use lsp_types::CompletionList; +use node_resolver::NodeResolutionKind; +use node_resolver::ResolutionMode; +use once_cell::sync::Lazy; +use regex::Regex; +use tower_lsp::lsp_types as lsp; use super::client::Client; use super::config::Config; @@ -12,33 +34,10 @@ use super::registries::ModuleRegistry; use super::resolver::LspResolver; use super::search::PackageSearchApi; use super::tsc; - use crate::graph_util::to_node_resolution_mode; use crate::jsr::JsrFetchResolver; use crate::util::path::is_importable_ext; use crate::util::path::relative_specifier; -use deno_runtime::deno_node::SUPPORTED_BUILTIN_NODE_MODULES; - -use deno_ast::LineAndColumnIndex; -use deno_ast::SourceTextInfo; -use deno_core::resolve_path; -use deno_core::resolve_url; -use deno_core::serde::Deserialize; -use deno_core::serde::Serialize; -use deno_core::serde_json::json; -use deno_core::url::Position; -use deno_core::ModuleSpecifier; -use deno_path_util::url_to_file_path; -use deno_semver::jsr::JsrPackageReqReference; -use deno_semver::package::PackageNv; -use import_map::ImportMap; -use indexmap::IndexSet; -use lsp_types::CompletionList; -use node_resolver::NodeResolutionKind; -use node_resolver::ResolutionMode; -use once_cell::sync::Lazy; -use regex::Regex; -use tower_lsp::lsp_types as lsp; static FILE_PROTO_RE: Lazy = lazy_regex::lazy_regex!(r#"^file:/{2}(?:/[A-Za-z]:)?"#); @@ -822,16 +821,18 @@ fn get_workspace_completions( #[cfg(test)] mod tests { + use std::collections::HashMap; + + use deno_core::resolve_url; + use pretty_assertions::assert_eq; + use test_util::TempDir; + use super::*; use crate::cache::HttpCache; use crate::lsp::cache::LspCache; use crate::lsp::documents::Documents; use crate::lsp::documents::LanguageId; use crate::lsp::search::tests::TestPackageSearchApi; - use deno_core::resolve_url; - use pretty_assertions::assert_eq; - use std::collections::HashMap; - use test_util::TempDir; fn setup( open_sources: &[(&str, &str, i32, LanguageId)], diff --git a/cli/lsp/config.rs b/cli/lsp/config.rs index ff4c2978d5..98c4498a1a 100644 --- a/cli/lsp/config.rs +++ b/cli/lsp/config.rs @@ -1,4 +1,13 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::collections::BTreeMap; +use std::collections::BTreeSet; +use std::collections::HashMap; +use std::ops::Deref; +use std::ops::DerefMut; +use std::path::Path; +use std::path::PathBuf; +use std::sync::Arc; use deno_ast::MediaType; use deno_config::deno_json::DenoJsonCache; @@ -32,28 +41,21 @@ use deno_core::serde_json::json; use deno_core::serde_json::Value; use deno_core::url::Url; use deno_core::ModuleSpecifier; +use deno_lib::env::has_flag_env_var; use deno_lint::linter::LintConfig as DenoLintConfig; use deno_npm::npm_rc::ResolvedNpmRc; use deno_package_json::PackageJsonCache; use deno_path_util::url_to_file_path; +use deno_resolver::sloppy_imports::SloppyImportsCachedFs; use deno_runtime::deno_node::PackageJson; use indexmap::IndexSet; use lsp_types::ClientCapabilities; -use std::collections::BTreeMap; -use std::collections::BTreeSet; -use std::collections::HashMap; -use std::ops::Deref; -use std::ops::DerefMut; -use std::path::Path; -use std::path::PathBuf; -use std::sync::Arc; use tower_lsp::lsp_types as lsp; use super::logging::lsp_log; use super::lsp_custom; use super::urls::url_to_uri; use crate::args::discover_npmrc_from_workspace; -use crate::args::has_flag_env_var; use crate::args::CliLockfile; use crate::args::CliLockfileReadFromPathOptions; use crate::args::ConfigFile; @@ -63,7 +65,6 @@ use crate::cache::FastInsecureHasher; use crate::file_fetcher::CliFileFetcher; use crate::lsp::logging::lsp_warn; use crate::resolver::CliSloppyImportsResolver; -use crate::resolver::SloppyImportsCachedFs; use crate::sys::CliSys; use crate::tools::lint::CliLinter; use crate::tools::lint::CliLinterOptions; @@ -852,7 +853,8 @@ impl Settings { Some(false) } else if let Some(enable_paths) = &enable_paths { for enable_path in enable_paths { - if path.starts_with(enable_path) { + // Also enable if the checked path is a dir containing an enabled path. + if path.starts_with(enable_path) || enable_path.starts_with(&path) { return Some(true); } } @@ -1244,7 +1246,6 @@ impl ConfigData { pkg_json_cache: Some(pkg_json_cache), workspace_cache: Some(workspace_cache), discover_pkg_json: !has_flag_env_var("DENO_NO_PACKAGE_JSON"), - config_parse_options: Default::default(), maybe_vendor_override: None, }, ) @@ -1569,11 +1570,11 @@ impl ConfigData { let resolver = member_dir .workspace .create_resolver( + &CliSys::default(), CreateResolverOptions { pkg_json_dep_resolution, specified_import_map, }, - |path| Ok(std::fs::read_to_string(path)?), ) .inspect_err(|err| { lsp_warn!( @@ -2075,7 +2076,6 @@ impl deno_config::workspace::WorkspaceCache for WorkspaceMemCache { #[cfg(test)] mod tests { - use deno_config::deno_json::ConfigParseOptions; use deno_core::resolve_url; use deno_core::serde_json; use deno_core::serde_json::json; @@ -2349,12 +2349,7 @@ mod tests { config .tree .inject_config_file( - ConfigFile::new( - "{}", - root_uri.join("deno.json").unwrap(), - &ConfigParseOptions::default(), - ) - .unwrap(), + ConfigFile::new("{}", root_uri.join("deno.json").unwrap()).unwrap(), ) .await; assert!(config.specifier_enabled(&root_uri)); @@ -2410,7 +2405,6 @@ mod tests { }) .to_string(), root_uri.join("deno.json").unwrap(), - &ConfigParseOptions::default(), ) .unwrap(), ) @@ -2436,7 +2430,6 @@ mod tests { }) .to_string(), root_uri.join("deno.json").unwrap(), - &ConfigParseOptions::default(), ) .unwrap(), ) @@ -2454,7 +2447,6 @@ mod tests { }) .to_string(), root_uri.join("deno.json").unwrap(), - &ConfigParseOptions::default(), ) .unwrap(), ) diff --git a/cli/lsp/diagnostics.rs b/cli/lsp/diagnostics.rs index af6fdf53a4..3e3e31de28 100644 --- a/cli/lsp/diagnostics.rs +++ b/cli/lsp/diagnostics.rs @@ -1,32 +1,11 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use super::analysis; -use super::client::Client; -use super::config::Config; -use super::documents; -use super::documents::Document; -use super::documents::Documents; -use super::documents::DocumentsFilter; -use super::language_server; -use super::language_server::StateSnapshot; -use super::performance::Performance; -use super::tsc; -use super::tsc::TsServer; -use super::urls::uri_parse_unencoded; -use super::urls::url_to_uri; -use super::urls::LspUrlMap; - -use crate::graph_util; -use crate::graph_util::enhanced_resolution_error_message; -use crate::lsp::lsp_custom::DiagnosticBatchNotificationParams; -use crate::resolver::CliSloppyImportsResolver; -use crate::resolver::SloppyImportsCachedFs; -use crate::sys::CliSys; -use crate::tools::lint::CliLinter; -use crate::tools::lint::CliLinterOptions; -use crate::tools::lint::LintRuleProvider; -use crate::tsc::DiagnosticCategory; -use crate::util::path::to_percent_decoded_str; +use std::collections::HashMap; +use std::collections::HashSet; +use std::path::PathBuf; +use std::sync::atomic::AtomicUsize; +use std::sync::Arc; +use std::thread; use deno_ast::MediaType; use deno_config::deno_json::LintConfig; @@ -47,6 +26,7 @@ use deno_graph::Resolution; use deno_graph::ResolutionError; use deno_graph::SpecifierError; use deno_lint::linter::LintConfig as DenoLintConfig; +use deno_resolver::sloppy_imports::SloppyImportsCachedFs; use deno_resolver::sloppy_imports::SloppyImportsResolution; use deno_resolver::sloppy_imports::SloppyImportsResolutionKind; use deno_runtime::deno_node; @@ -55,20 +35,40 @@ use deno_semver::jsr::JsrPackageReqReference; use deno_semver::npm::NpmPackageReqReference; use deno_semver::package::PackageReq; use import_map::ImportMap; -use import_map::ImportMapError; +use import_map::ImportMapErrorKind; use log::error; -use std::collections::HashMap; -use std::collections::HashSet; -use std::path::PathBuf; -use std::sync::atomic::AtomicUsize; -use std::sync::Arc; -use std::thread; use tokio::sync::mpsc; use tokio::sync::Mutex; use tokio::time::Duration; use tokio_util::sync::CancellationToken; use tower_lsp::lsp_types as lsp; +use super::analysis; +use super::client::Client; +use super::config::Config; +use super::documents; +use super::documents::Document; +use super::documents::Documents; +use super::documents::DocumentsFilter; +use super::language_server; +use super::language_server::StateSnapshot; +use super::performance::Performance; +use super::tsc; +use super::tsc::TsServer; +use super::urls::uri_parse_unencoded; +use super::urls::url_to_uri; +use super::urls::LspUrlMap; +use crate::graph_util; +use crate::graph_util::enhanced_resolution_error_message; +use crate::lsp::lsp_custom::DiagnosticBatchNotificationParams; +use crate::resolver::CliSloppyImportsResolver; +use crate::sys::CliSys; +use crate::tools::lint::CliLinter; +use crate::tools::lint::CliLinterOptions; +use crate::tools::lint::LintRuleProvider; +use crate::tsc::DiagnosticCategory; +use crate::util::path::to_percent_decoded_str; + #[derive(Debug)] pub struct DiagnosticServerUpdateMessage { pub snapshot: Arc, @@ -265,7 +265,7 @@ impl TsDiagnosticsStore { } pub fn should_send_diagnostic_batch_index_notifications() -> bool { - crate::args::has_flag_env_var( + deno_lib::env::has_flag_env_var( "DENO_DONT_USE_INTERNAL_LSP_DIAGNOSTIC_SYNC_FLAG", ) } @@ -1297,8 +1297,8 @@ impl DenoDiagnostic { let mut message; message = enhanced_resolution_error_message(err); if let deno_graph::ResolutionError::ResolverError {error, ..} = err{ - if let ResolveError::Other(resolve_error, ..) = (*error).as_ref() { - if let Some(ImportMapError::UnmappedBareSpecifier(specifier, _)) = resolve_error.downcast_ref::() { + if let ResolveError::ImportMap(importmap) = (*error).as_ref() { + if let ImportMapErrorKind::UnmappedBareSpecifier(specifier, _) = &**importmap { if specifier.chars().next().unwrap_or('\0') == '@'{ let hint = format!("\nHint: Use [deno add {}] to add the dependency.", specifier); message.push_str(hint.as_str()); @@ -1646,6 +1646,12 @@ fn generate_deno_diagnostics( #[cfg(test)] mod tests { + use std::sync::Arc; + + use deno_config::deno_json::ConfigFile; + use pretty_assertions::assert_eq; + use test_util::TempDir; + use super::*; use crate::lsp::cache::LspCache; use crate::lsp::config::Config; @@ -1656,11 +1662,6 @@ mod tests { use crate::lsp::language_server::StateSnapshot; use crate::lsp::resolver::LspResolver; - use deno_config::deno_json::ConfigFile; - use pretty_assertions::assert_eq; - use std::sync::Arc; - use test_util::TempDir; - fn mock_config() -> Config { let root_url = resolve_url("file:///").unwrap(); let root_uri = url_to_uri(&root_url).unwrap(); @@ -1694,12 +1695,7 @@ mod tests { let mut config = Config::new_with_roots([root_uri.clone()]); if let Some((relative_path, json_string)) = maybe_import_map { let base_url = root_uri.join(relative_path).unwrap(); - let config_file = ConfigFile::new( - json_string, - base_url, - &deno_config::deno_json::ConfigParseOptions::default(), - ) - .unwrap(); + let config_file = ConfigFile::new(json_string, base_url).unwrap(); config.tree.inject_config_file(config_file).await; } let resolver = diff --git a/cli/lsp/documents.rs b/cli/lsp/documents.rs index d15cfe5a6c..6a7a08b5a1 100644 --- a/cli/lsp/documents.rs +++ b/cli/lsp/documents.rs @@ -1,41 +1,5 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use super::cache::calculate_fs_version; -use super::cache::LspCache; -use super::config::Config; -use super::resolver::LspResolver; -use super::resolver::ScopeDepInfo; -use super::resolver::SingleReferrerGraphResolver; -use super::testing::TestCollector; -use super::testing::TestModule; -use super::text::LineIndex; -use super::tsc; -use super::tsc::AssetDocument; - -use crate::graph_util::CliJsrUrlProvider; - -use dashmap::DashMap; -use deno_ast::swc::visit::VisitWith; -use deno_ast::MediaType; -use deno_ast::ParsedSource; -use deno_ast::SourceTextInfo; -use deno_core::error::custom_error; -use deno_core::error::AnyError; -use deno_core::futures::future; -use deno_core::futures::future::Shared; -use deno_core::futures::FutureExt; -use deno_core::parking_lot::Mutex; -use deno_core::ModuleSpecifier; -use deno_graph::Resolution; -use deno_path_util::url_to_file_path; -use deno_runtime::deno_node; -use deno_semver::jsr::JsrPackageReqReference; -use deno_semver::npm::NpmPackageReqReference; -use deno_semver::package::PackageReq; -use indexmap::IndexMap; -use indexmap::IndexSet; -use node_resolver::NodeResolutionKind; -use node_resolver::ResolutionMode; use std::borrow::Cow; use std::collections::BTreeMap; use std::collections::HashMap; @@ -48,8 +12,44 @@ use std::str::FromStr; use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering; use std::sync::Arc; + +use dashmap::DashMap; +use deno_ast::swc::visit::VisitWith; +use deno_ast::MediaType; +use deno_ast::ParsedSource; +use deno_ast::SourceTextInfo; +use deno_core::error::AnyError; +use deno_core::futures::future; +use deno_core::futures::future::Shared; +use deno_core::futures::FutureExt; +use deno_core::parking_lot::Mutex; +use deno_core::ModuleSpecifier; +use deno_error::JsErrorBox; +use deno_graph::Resolution; +use deno_path_util::url_to_file_path; +use deno_runtime::deno_node; +use deno_semver::jsr::JsrPackageReqReference; +use deno_semver::npm::NpmPackageReqReference; +use deno_semver::package::PackageReq; +use indexmap::IndexMap; +use indexmap::IndexSet; +use node_resolver::NodeResolutionKind; +use node_resolver::ResolutionMode; use tower_lsp::lsp_types as lsp; +use super::cache::calculate_fs_version; +use super::cache::LspCache; +use super::config::Config; +use super::resolver::LspResolver; +use super::resolver::ScopeDepInfo; +use super::resolver::SingleReferrerGraphResolver; +use super::testing::TestCollector; +use super::testing::TestModule; +use super::text::LineIndex; +use super::tsc; +use super::tsc::AssetDocument; +use crate::graph_util::CliJsrUrlProvider; + pub const DOCUMENT_SCHEMES: [&str; 5] = ["data", "blob", "file", "http", "https"]; @@ -64,6 +64,9 @@ pub enum LanguageId { Markdown, Html, Css, + Scss, + Sass, + Less, Yaml, Sql, Svelte, @@ -86,6 +89,9 @@ impl LanguageId { LanguageId::Markdown => Some("md"), LanguageId::Html => Some("html"), LanguageId::Css => Some("css"), + LanguageId::Scss => Some("scss"), + LanguageId::Sass => Some("sass"), + LanguageId::Less => Some("less"), LanguageId::Yaml => Some("yaml"), LanguageId::Sql => Some("sql"), LanguageId::Svelte => Some("svelte"), @@ -107,6 +113,9 @@ impl LanguageId { LanguageId::Markdown => Some("text/markdown"), LanguageId::Html => Some("text/html"), LanguageId::Css => Some("text/css"), + LanguageId::Scss => None, + LanguageId::Sass => None, + LanguageId::Less => None, LanguageId::Yaml => Some("application/yaml"), LanguageId::Sql => None, LanguageId::Svelte => None, @@ -140,6 +149,9 @@ impl FromStr for LanguageId { "markdown" => Ok(Self::Markdown), "html" => Ok(Self::Html), "css" => Ok(Self::Css), + "scss" => Ok(Self::Scss), + "sass" => Ok(Self::Sass), + "less" => Ok(Self::Less), "yaml" => Ok(Self::Yaml), "sql" => Ok(Self::Sql), "svelte" => Ok(Self::Svelte), @@ -468,7 +480,7 @@ impl Document { let is_cjs_resolver = resolver.as_is_cjs_resolver(self.file_referrer.as_ref()); let npm_resolver = - resolver.create_graph_npm_resolver(self.file_referrer.as_ref()); + resolver.as_graph_npm_resolver(self.file_referrer.as_ref()); let config_data = resolver.as_config_data(self.file_referrer.as_ref()); let jsx_import_source_config = config_data.and_then(|d| d.maybe_jsx_import_source_config()); @@ -491,7 +503,7 @@ impl Document { s, &CliJsrUrlProvider, Some(&resolver), - Some(&npm_resolver), + Some(npm_resolver.as_ref()), ), ) }) @@ -501,7 +513,7 @@ impl Document { Arc::new(d.with_new_resolver( &CliJsrUrlProvider, Some(&resolver), - Some(&npm_resolver), + Some(npm_resolver.as_ref()), )) }); is_script = self.is_script; @@ -1069,7 +1081,7 @@ impl Documents { .or_else(|| self.file_system_docs.remove_document(specifier)) .map(Ok) .unwrap_or_else(|| { - Err(custom_error( + Err(JsErrorBox::new( "NotFound", format!("The specifier \"{specifier}\" was not found."), )) @@ -1690,7 +1702,7 @@ fn analyze_module( ) -> (ModuleResult, ResolutionMode) { match parsed_source_result { Ok(parsed_source) => { - let npm_resolver = resolver.create_graph_npm_resolver(file_referrer); + let npm_resolver = resolver.as_graph_npm_resolver(file_referrer); let cli_resolver = resolver.as_cli_resolver(file_referrer); let is_cjs_resolver = resolver.as_is_cjs_resolver(file_referrer); let config_data = resolver.as_config_data(file_referrer); @@ -1719,7 +1731,7 @@ fn analyze_module( file_system: &deno_graph::source::NullFileSystem, jsr_url_provider: &CliJsrUrlProvider, maybe_resolver: Some(&resolver), - maybe_npm_resolver: Some(&npm_resolver), + maybe_npm_resolver: Some(npm_resolver.as_ref()), }, )), module_resolution_mode, @@ -1754,16 +1766,15 @@ fn bytes_to_content( #[cfg(test)] mod tests { - use super::*; - use crate::lsp::cache::LspCache; - use deno_config::deno_json::ConfigFile; - use deno_config::deno_json::ConfigParseOptions; use deno_core::serde_json; use deno_core::serde_json::json; use pretty_assertions::assert_eq; use test_util::TempDir; + use super::*; + use crate::lsp::cache::LspCache; + async fn setup() -> (Documents, LspCache, TempDir) { let temp_dir = TempDir::new(); temp_dir.create_dir_all(".deno_dir"); @@ -1912,7 +1923,6 @@ console.log(b, "hello deno"); }) .to_string(), config.root_uri().unwrap().join("deno.json").unwrap(), - &ConfigParseOptions::default(), ) .unwrap(), ) @@ -1956,7 +1966,6 @@ console.log(b, "hello deno"); }) .to_string(), config.root_uri().unwrap().join("deno.json").unwrap(), - &ConfigParseOptions::default(), ) .unwrap(), ) diff --git a/cli/lsp/jsr.rs b/cli/lsp/jsr.rs index fc30de2ae0..1bcd6f3930 100644 --- a/cli/lsp/jsr.rs +++ b/cli/lsp/jsr.rs @@ -1,11 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::collections::HashMap; +use std::sync::Arc; -use crate::args::jsr_api_url; -use crate::args::jsr_url; -use crate::file_fetcher::CliFileFetcher; -use crate::file_fetcher::TextDecodedFile; -use crate::jsr::partial_jsr_package_version_info_from_slice; -use crate::jsr::JsrFetchResolver; use dashmap::DashMap; use deno_cache_dir::HttpCache; use deno_core::anyhow::anyhow; @@ -21,11 +18,15 @@ use deno_semver::package::PackageReq; use deno_semver::StackString; use deno_semver::Version; use serde::Deserialize; -use std::collections::HashMap; -use std::sync::Arc; use super::config::ConfigData; use super::search::PackageSearchApi; +use crate::args::jsr_api_url; +use crate::args::jsr_url; +use crate::file_fetcher::CliFileFetcher; +use crate::file_fetcher::TextDecodedFile; +use crate::jsr::partial_jsr_package_version_info_from_slice; +use crate::jsr::JsrFetchResolver; /// Keep in sync with `JsrFetchResolver`! #[derive(Debug)] diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index 9ab1d9786c..c2fddc08bd 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -1,4 +1,15 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::collections::BTreeMap; +use std::collections::BTreeSet; +use std::collections::HashMap; +use std::collections::HashSet; +use std::collections::VecDeque; +use std::env; +use std::fmt::Write as _; +use std::path::PathBuf; +use std::str::FromStr; +use std::sync::Arc; use deno_ast::MediaType; use deno_cache_dir::file_fetcher::CacheSetting; @@ -16,6 +27,7 @@ use deno_core::url::Url; use deno_core::ModuleSpecifier; use deno_graph::GraphKind; use deno_graph::Resolution; +use deno_lib::env::has_flag_env_var; use deno_path_util::url_to_file_path; use deno_runtime::deno_tls::rustls::RootCertStore; use deno_runtime::deno_tls::RootCertStoreProvider; @@ -27,16 +39,6 @@ use node_resolver::NodeResolutionKind; use node_resolver::ResolutionMode; use serde::Deserialize; use serde_json::from_value; -use std::collections::BTreeMap; -use std::collections::BTreeSet; -use std::collections::HashMap; -use std::collections::HashSet; -use std::collections::VecDeque; -use std::env; -use std::fmt::Write as _; -use std::path::PathBuf; -use std::str::FromStr; -use std::sync::Arc; use tokio::sync::mpsc::unbounded_channel; use tokio::sync::mpsc::UnboundedReceiver; use tokio::sync::mpsc::UnboundedSender; @@ -94,7 +96,6 @@ use super::urls::uri_to_url; use super::urls::url_to_uri; use crate::args::create_default_npmrc; use crate::args::get_root_cert_store; -use crate::args::has_flag_env_var; use crate::args::CaData; use crate::args::CliOptions; use crate::args::Flags; @@ -121,7 +122,7 @@ use crate::util::sync::AsyncFlag; struct LspRootCertStoreProvider(RootCertStore); impl RootCertStoreProvider for LspRootCertStoreProvider { - fn get_or_try_init(&self) -> Result<&RootCertStore, AnyError> { + fn get_or_try_init(&self) -> Result<&RootCertStore, deno_error::JsErrorBox> { Ok(&self.0) } } @@ -1418,18 +1419,16 @@ impl Inner { // the file path is only used to determine what formatter should // be used to format the file, so give the filepath an extension // that matches what the user selected as the language - let file_path = document + let ext = document .maybe_language_id() - .and_then(|id| id.as_extension()) - .map(|ext| file_path.with_extension(ext)) - .unwrap_or(file_path); + .and_then(|id| id.as_extension().map(|s| s.to_string())); // it's not a js/ts file, so attempt to format its contents format_file( &file_path, document.content(), &fmt_options, &unstable_options, - None, + ext, ) } }; @@ -3622,8 +3621,6 @@ impl Inner { deno_json_cache: None, pkg_json_cache: None, workspace_cache: None, - config_parse_options: - deno_config::deno_json::ConfigParseOptions::default(), additional_config_file_names: &[], discover_pkg_json: !has_flag_env_var("DENO_NO_PACKAGE_JSON"), maybe_vendor_override: if force_global_cache { @@ -3963,10 +3960,11 @@ impl Inner { #[cfg(test)] mod tests { - use super::*; use pretty_assertions::assert_eq; use test_util::TempDir; + use super::*; + #[test] fn test_walk_workspace() { let temp_dir = TempDir::new(); @@ -4003,12 +4001,14 @@ mod tests { temp_dir.write("root1/target/main.ts", ""); // no, because there is a Cargo.toml in the root directory temp_dir.create_dir_all("root2/folder"); + temp_dir.create_dir_all("root2/folder2/inner_folder"); temp_dir.create_dir_all("root2/sub_folder"); temp_dir.create_dir_all("root2/root2.1"); temp_dir.write("root2/file1.ts", ""); // yes, enabled temp_dir.write("root2/file2.ts", ""); // no, not enabled temp_dir.write("root2/folder/main.ts", ""); // yes, enabled temp_dir.write("root2/folder/other.ts", ""); // no, disabled + temp_dir.write("root2/folder2/inner_folder/main.ts", ""); // yes, enabled (regression test for https://github.com/denoland/vscode_deno/issues/1239) temp_dir.write("root2/sub_folder/a.js", ""); // no, not enabled temp_dir.write("root2/sub_folder/b.ts", ""); // no, not enabled temp_dir.write("root2/sub_folder/c.js", ""); // no, not enabled @@ -4049,6 +4049,7 @@ mod tests { enable_paths: Some(vec![ "file1.ts".to_string(), "folder".to_string(), + "folder2/inner_folder".to_string(), ]), disable_paths: vec!["folder/other.ts".to_string()], ..Default::default() @@ -4099,6 +4100,10 @@ mod tests { temp_dir.url().join("root1/folder/mod.ts").unwrap(), temp_dir.url().join("root2/folder/main.ts").unwrap(), temp_dir.url().join("root2/root2.1/main.ts").unwrap(), + temp_dir + .url() + .join("root2/folder2/inner_folder/main.ts") + .unwrap(), ]) ); } diff --git a/cli/lsp/logging.rs b/cli/lsp/logging.rs index 2b85d77ec1..efb49b2d48 100644 --- a/cli/lsp/logging.rs +++ b/cli/lsp/logging.rs @@ -1,8 +1,5 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use chrono::DateTime; -use chrono::Utc; -use deno_core::parking_lot::Mutex; use std::fs; use std::io::prelude::*; use std::path::Path; @@ -12,6 +9,10 @@ use std::sync::atomic::Ordering; use std::thread; use std::time::SystemTime; +use chrono::DateTime; +use chrono::Utc; +use deno_core::parking_lot::Mutex; + static LSP_DEBUG_FLAG: AtomicBool = AtomicBool::new(false); static LSP_LOG_LEVEL: AtomicUsize = AtomicUsize::new(log::Level::Info as usize); static LSP_WARN_LEVEL: AtomicUsize = diff --git a/cli/lsp/lsp_custom.rs b/cli/lsp/lsp_custom.rs index 8df4ba1d07..050fcf3184 100644 --- a/cli/lsp/lsp_custom.rs +++ b/cli/lsp/lsp_custom.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::serde::Deserialize; use deno_core::serde::Serialize; diff --git a/cli/lsp/mod.rs b/cli/lsp/mod.rs index afb949f68d..6b5d17798b 100644 --- a/cli/lsp/mod.rs +++ b/cli/lsp/mod.rs @@ -1,16 +1,15 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::error::AnyError; use deno_core::unsync::spawn; +pub use repl::ReplCompletionItem; +pub use repl::ReplLanguageServer; use tower_lsp::LspService; use tower_lsp::Server; +use self::diagnostics::should_send_diagnostic_batch_index_notifications; use crate::lsp::language_server::LanguageServer; use crate::util::sync::AsyncFlag; -pub use repl::ReplCompletionItem; -pub use repl::ReplLanguageServer; - -use self::diagnostics::should_send_diagnostic_batch_index_notifications; mod analysis; mod cache; diff --git a/cli/lsp/npm.rs b/cli/lsp/npm.rs index 18c7e2fccf..d53c8cb2ab 100644 --- a/cli/lsp/npm.rs +++ b/cli/lsp/npm.rs @@ -1,4 +1,6 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::sync::Arc; use dashmap::DashMap; use deno_core::anyhow::anyhow; @@ -8,15 +10,13 @@ use deno_npm::npm_rc::NpmRc; use deno_semver::package::PackageNv; use deno_semver::Version; use serde::Deserialize; -use std::sync::Arc; +use super::search::PackageSearchApi; use crate::args::npm_registry_url; use crate::file_fetcher::CliFileFetcher; use crate::file_fetcher::TextDecodedFile; use crate::npm::NpmFetchResolver; -use super::search::PackageSearchApi; - #[derive(Debug)] pub struct CliNpmSearchApi { file_fetcher: Arc, diff --git a/cli/lsp/parent_process_checker.rs b/cli/lsp/parent_process_checker.rs index b8a42cd1a4..b8ab60922b 100644 --- a/cli/lsp/parent_process_checker.rs +++ b/cli/lsp/parent_process_checker.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::time::Duration; @@ -52,10 +52,12 @@ fn is_process_active(process_id: u32) -> bool { #[cfg(test)] mod test { - use super::is_process_active; use std::process::Command; + use test_util::deno_exe_path; + use super::is_process_active; + #[test] fn process_active() { // launch a long running process diff --git a/cli/lsp/path_to_regex.rs b/cli/lsp/path_to_regex.rs index 88d8a2ec68..65322da6d0 100644 --- a/cli/lsp/path_to_regex.rs +++ b/cli/lsp/path_to_regex.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // The logic of this module is heavily influenced by path-to-regexp at: // https://github.com/pillarjs/path-to-regexp/ which is licensed as follows: @@ -26,15 +26,16 @@ // THE SOFTWARE. // +use std::collections::HashMap; +use std::fmt; +use std::fmt::Write as _; +use std::iter::Peekable; + use deno_core::anyhow::anyhow; use deno_core::error::AnyError; use fancy_regex::Regex as FancyRegex; use once_cell::sync::Lazy; use regex::Regex; -use std::collections::HashMap; -use std::fmt; -use std::fmt::Write as _; -use std::iter::Peekable; static ESCAPE_STRING_RE: Lazy = lazy_regex::lazy_regex!(r"([.+*?=^!:${}()\[\]|/\\])"); diff --git a/cli/lsp/performance.rs b/cli/lsp/performance.rs index b3dc53b283..8d836c7adf 100644 --- a/cli/lsp/performance.rs +++ b/cli/lsp/performance.rs @@ -1,9 +1,5 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use deno_core::parking_lot::Mutex; -use deno_core::serde::Deserialize; -use deno_core::serde::Serialize; -use deno_core::serde_json::json; use std::cmp; use std::collections::HashMap; use std::collections::VecDeque; @@ -12,6 +8,11 @@ use std::sync::Arc; use std::time::Duration; use std::time::Instant; +use deno_core::parking_lot::Mutex; +use deno_core::serde::Deserialize; +use deno_core::serde::Serialize; +use deno_core::serde_json::json; + use super::logging::lsp_debug; #[derive(Debug, Deserialize, Serialize, PartialEq, Eq)] diff --git a/cli/lsp/refactor.rs b/cli/lsp/refactor.rs index 82751d3b12..e1abd963a2 100644 --- a/cli/lsp/refactor.rs +++ b/cli/lsp/refactor.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // The logic of this module is heavily influenced by // https://github.com/microsoft/vscode/blob/main/extensions/typescript-language-features/src/languageFeatures/refactor.ts diff --git a/cli/lsp/registries.rs b/cli/lsp/registries.rs index c8dd7fa1a7..f8c38d97ea 100644 --- a/cli/lsp/registries.rs +++ b/cli/lsp/registries.rs @@ -1,25 +1,9 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use super::completions::IMPORT_COMMIT_CHARS; -use super::logging::lsp_log; -use super::path_to_regex::parse; -use super::path_to_regex::string_to_regex; -use super::path_to_regex::Compiler; -use super::path_to_regex::Key; -use super::path_to_regex::MatchResult; -use super::path_to_regex::Matcher; -use super::path_to_regex::StringOrNumber; -use super::path_to_regex::StringOrVec; -use super::path_to_regex::Token; - -use crate::cache::GlobalHttpCache; -use crate::cache::HttpCache; -use crate::file_fetcher::CliFileFetcher; -use crate::file_fetcher::FetchOptions; -use crate::file_fetcher::FetchPermissionsOptionRef; -use crate::file_fetcher::TextDecodedFile; -use crate::http_util::HttpClientProvider; -use crate::sys::CliSys; +use std::borrow::Cow; +use std::collections::HashMap; +use std::path::PathBuf; +use std::sync::Arc; use deno_cache_dir::file_fetcher::CacheSetting; use deno_core::anyhow::anyhow; @@ -35,12 +19,28 @@ use deno_core::ModuleSpecifier; use deno_graph::Dependency; use log::error; use once_cell::sync::Lazy; -use std::borrow::Cow; -use std::collections::HashMap; -use std::path::PathBuf; -use std::sync::Arc; use tower_lsp::lsp_types as lsp; +use super::completions::IMPORT_COMMIT_CHARS; +use super::logging::lsp_log; +use super::path_to_regex::parse; +use super::path_to_regex::string_to_regex; +use super::path_to_regex::Compiler; +use super::path_to_regex::Key; +use super::path_to_regex::MatchResult; +use super::path_to_regex::Matcher; +use super::path_to_regex::StringOrNumber; +use super::path_to_regex::StringOrVec; +use super::path_to_regex::Token; +use crate::cache::GlobalHttpCache; +use crate::cache::HttpCache; +use crate::file_fetcher::CliFileFetcher; +use crate::file_fetcher::FetchOptions; +use crate::file_fetcher::FetchPermissionsOptionRef; +use crate::file_fetcher::TextDecodedFile; +use crate::http_util::HttpClientProvider; +use crate::sys::CliSys; + const CONFIG_PATH: &str = "/.well-known/deno-import-intellisense.json"; const COMPONENT: &percent_encoding::AsciiSet = &percent_encoding::CONTROLS .add(b' ') @@ -1128,9 +1128,10 @@ FetchPermissionsOptionRef::AllowAll, #[cfg(test)] mod tests { - use super::*; use test_util::TempDir; + use super::*; + #[test] fn test_validate_registry_configuration() { assert!(validate_config(&RegistryConfigurationJson { diff --git a/cli/lsp/repl.rs b/cli/lsp/repl.rs index b4aaa8cd0d..a30427312d 100644 --- a/cli/lsp/repl.rs +++ b/cli/lsp/repl.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashMap; diff --git a/cli/lsp/resolver.rs b/cli/lsp/resolver.rs index 2dec5266f4..1b393ad22b 100644 --- a/cli/lsp/resolver.rs +++ b/cli/lsp/resolver.rs @@ -1,8 +1,14 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::borrow::Cow; +use std::collections::BTreeMap; +use std::collections::BTreeSet; +use std::collections::HashMap; +use std::collections::HashSet; +use std::sync::Arc; use dashmap::DashMap; use deno_ast::MediaType; -use deno_cache_dir::file_fetcher::CacheSetting; use deno_cache_dir::npm::NpmCacheDir; use deno_cache_dir::HttpCache; use deno_config::deno_json::JsxImportSourceConfig; @@ -14,8 +20,13 @@ use deno_graph::GraphImport; use deno_graph::ModuleSpecifier; use deno_graph::Range; use deno_npm::NpmSystemInfo; +use deno_npm_cache::TarballCache; use deno_path_util::url_to_file_path; use deno_resolver::cjs::IsCjsResolutionMode; +use deno_resolver::npm::managed::ManagedInNpmPkgCheckerCreateOptions; +use deno_resolver::npm::managed::NpmResolutionCell; +use deno_resolver::npm::CreateInNpmPkgCheckerOptions; +use deno_resolver::npm::DenoInNpmPackageChecker; use deno_resolver::npm::NpmReqResolverOptions; use deno_resolver::DenoResolverOptions; use deno_resolver::NodeAndNpmReqResolver; @@ -25,20 +36,15 @@ use deno_semver::npm::NpmPackageReqReference; use deno_semver::package::PackageNv; use deno_semver::package::PackageReq; use indexmap::IndexMap; -use node_resolver::InNpmPackageChecker; use node_resolver::NodeResolutionKind; use node_resolver::ResolutionMode; -use std::borrow::Cow; -use std::collections::BTreeMap; -use std::collections::BTreeSet; -use std::collections::HashMap; -use std::collections::HashSet; -use std::sync::Arc; use super::cache::LspCache; use super::jsr::JsrCacheResolver; use crate::args::create_default_npmrc; use crate::args::CliLockfile; +use crate::args::LifecycleScriptsConfig; +use crate::args::NpmCachingStrategy; use crate::args::NpmInstallDepsProvider; use crate::factory::Deferred; use crate::graph_util::to_node_resolution_kind; @@ -50,21 +56,24 @@ use crate::lsp::config::ConfigData; use crate::lsp::logging::lsp_warn; use crate::node::CliNodeResolver; use crate::node::CliPackageJsonResolver; -use crate::npm::create_cli_npm_resolver_for_lsp; +use crate::npm::installer::NpmInstaller; +use crate::npm::installer::NpmResolutionInstaller; use crate::npm::CliByonmNpmResolverCreateOptions; -use crate::npm::CliManagedInNpmPkgCheckerCreateOptions; +use crate::npm::CliManagedNpmResolver; use crate::npm::CliManagedNpmResolverCreateOptions; +use crate::npm::CliNpmCache; +use crate::npm::CliNpmCacheHttpClient; +use crate::npm::CliNpmRegistryInfoProvider; use crate::npm::CliNpmResolver; use crate::npm::CliNpmResolverCreateOptions; use crate::npm::CliNpmResolverManagedSnapshotOption; -use crate::npm::CreateInNpmPkgCheckerOptions; -use crate::npm::ManagedCliNpmResolver; +use crate::npm::NpmResolutionInitializer; use crate::resolver::CliDenoResolver; +use crate::resolver::CliIsCjsResolver; +use crate::resolver::CliNpmGraphResolver; use crate::resolver::CliNpmReqResolver; use crate::resolver::CliResolver; -use crate::resolver::CliResolverOptions; -use crate::resolver::IsCjsResolver; -use crate::resolver::WorkerCliNpmGraphResolver; +use crate::resolver::FoundPackageJsonDepFlag; use crate::sys::CliSys; use crate::tsc::into_specifier_and_media_type; use crate::util::progress_bar::ProgressBar; @@ -73,10 +82,13 @@ use crate::util::progress_bar::ProgressBarStyle; #[derive(Debug, Clone)] struct LspScopeResolver { resolver: Arc, - in_npm_pkg_checker: Arc, - is_cjs_resolver: Arc, + in_npm_pkg_checker: DenoInNpmPackageChecker, + is_cjs_resolver: Arc, jsr_resolver: Option>, - npm_resolver: Option>, + npm_graph_resolver: Arc, + npm_installer: Option>, + npm_resolution: Arc, + npm_resolver: Option, node_resolver: Option>, npm_pkg_req_resolver: Option>, pkg_json_resolver: Arc, @@ -95,8 +107,11 @@ impl Default for LspScopeResolver { in_npm_pkg_checker: factory.in_npm_pkg_checker().clone(), is_cjs_resolver: factory.is_cjs_resolver().clone(), jsr_resolver: None, + npm_graph_resolver: factory.npm_graph_resolver().clone(), + npm_installer: None, npm_resolver: None, node_resolver: None, + npm_resolution: factory.services.npm_resolution.clone(), npm_pkg_req_resolver: None, pkg_json_resolver: factory.pkg_json_resolver().clone(), redirect_resolver: None, @@ -120,6 +135,7 @@ impl LspScopeResolver { } let in_npm_pkg_checker = factory.in_npm_pkg_checker().clone(); let npm_resolver = factory.npm_resolver().cloned(); + let npm_installer = factory.npm_installer().cloned(); let node_resolver = factory.node_resolver().cloned(); let npm_pkg_req_resolver = factory.npm_pkg_req_resolver().cloned(); let cli_resolver = factory.cli_resolver().clone(); @@ -132,8 +148,7 @@ impl LspScopeResolver { cache.for_specifier(config_data.map(|d| d.scope.as_ref())), config_data.and_then(|d| d.lockfile.clone()), ))); - let npm_graph_resolver = cli_resolver - .create_graph_npm_resolver(crate::graph_util::NpmCachingStrategy::Eager); + let npm_graph_resolver = factory.npm_graph_resolver(); let maybe_jsx_import_source_config = config_data.and_then(|d| d.maybe_jsx_import_source_config()); let graph_imports = config_data @@ -155,7 +170,7 @@ impl LspScopeResolver { imports, &CliJsrUrlProvider, Some(&resolver), - Some(&npm_graph_resolver), + Some(npm_graph_resolver.as_ref()), ); (referrer, graph_import) }) @@ -206,8 +221,11 @@ impl LspScopeResolver { in_npm_pkg_checker, is_cjs_resolver: factory.is_cjs_resolver().clone(), jsr_resolver, + npm_graph_resolver: factory.npm_graph_resolver().clone(), npm_pkg_req_resolver, npm_resolver, + npm_installer, + npm_resolution: factory.services.npm_resolution.clone(), node_resolver, pkg_json_resolver, redirect_resolver, @@ -219,18 +237,68 @@ impl LspScopeResolver { } fn snapshot(&self) -> Arc { + // create a copy of the resolution and then re-initialize the npm resolver from that + // todo(dsherret): this is pretty terrible... we should improve this. It should + // be possible to just change the npm_resolution on the new factory then access + // another method to create a new npm resolver let mut factory = ResolverFactory::new(self.config_data.as_ref()); - let npm_resolver = - self.npm_resolver.as_ref().map(|r| r.clone_snapshotted()); + factory + .services + .npm_resolution + .set_snapshot(self.npm_resolution.snapshot()); + let npm_resolver = self.npm_resolver.as_ref(); if let Some(npm_resolver) = &npm_resolver { - factory.set_npm_resolver(npm_resolver.clone()); + factory.set_npm_resolver(CliNpmResolver::new::( + match npm_resolver { + CliNpmResolver::Byonm(byonm_npm_resolver) => { + CliNpmResolverCreateOptions::Byonm( + CliByonmNpmResolverCreateOptions { + root_node_modules_dir: byonm_npm_resolver + .root_node_modules_path() + .map(|p| p.to_path_buf()), + sys: CliSys::default(), + pkg_json_resolver: self.pkg_json_resolver.clone(), + }, + ) + } + CliNpmResolver::Managed(managed_npm_resolver) => { + CliNpmResolverCreateOptions::Managed({ + let npmrc = self + .config_data + .as_ref() + .and_then(|d| d.npmrc.clone()) + .unwrap_or_else(create_default_npmrc); + let npm_cache_dir = Arc::new(NpmCacheDir::new( + &CliSys::default(), + managed_npm_resolver.global_cache_root_path().to_path_buf(), + npmrc.get_all_known_registries_urls(), + )); + CliManagedNpmResolverCreateOptions { + sys: CliSys::default(), + npm_cache_dir, + maybe_node_modules_path: managed_npm_resolver + .root_node_modules_path() + .map(|p| p.to_path_buf()), + npmrc, + npm_resolution: factory.services.npm_resolution.clone(), + npm_system_info: NpmSystemInfo::default(), + } + }) + } + }, + )); } + Arc::new(Self { resolver: factory.cli_resolver().clone(), in_npm_pkg_checker: factory.in_npm_pkg_checker().clone(), is_cjs_resolver: factory.is_cjs_resolver().clone(), jsr_resolver: self.jsr_resolver.clone(), + npm_graph_resolver: factory.npm_graph_resolver().clone(), + // npm installer isn't necessary for a snapshot + npm_installer: None, npm_pkg_req_resolver: factory.npm_pkg_req_resolver().cloned(), + npm_resolution: factory.services.npm_resolution.clone(), npm_resolver: factory.npm_resolver().cloned(), node_resolver: factory.node_resolver().cloned(), redirect_resolver: self.redirect_resolver.clone(), @@ -317,14 +385,12 @@ impl LspResolver { if let Some(dep_info) = dep_info { *resolver.dep_info.lock() = dep_info.clone(); } - if let Some(npm_resolver) = resolver.npm_resolver.as_ref() { - if let Some(npm_resolver) = npm_resolver.as_managed() { - let reqs = dep_info - .map(|i| i.npm_reqs.iter().cloned().collect::>()) - .unwrap_or_default(); - if let Err(err) = npm_resolver.set_package_reqs(&reqs).await { - lsp_warn!("Could not set npm package requirements: {:#}", err); - } + if let Some(npm_installer) = resolver.npm_installer.as_ref() { + let reqs = dep_info + .map(|i| i.npm_reqs.iter().cloned().collect::>()) + .unwrap_or_default(); + if let Err(err) = npm_installer.set_package_reqs(&reqs).await { + lsp_warn!("Could not set npm package requirements: {:#}", err); } } } @@ -338,20 +404,18 @@ impl LspResolver { resolver.resolver.as_ref() } - pub fn create_graph_npm_resolver( + pub fn as_graph_npm_resolver( &self, file_referrer: Option<&ModuleSpecifier>, - ) -> WorkerCliNpmGraphResolver { + ) -> &Arc { let resolver = self.get_scope_resolver(file_referrer); - resolver - .resolver - .create_graph_npm_resolver(crate::graph_util::NpmCachingStrategy::Eager) + &resolver.npm_graph_resolver } pub fn as_is_cjs_resolver( &self, file_referrer: Option<&ModuleSpecifier>, - ) -> &IsCjsResolver { + ) -> &CliIsCjsResolver { let resolver = self.get_scope_resolver(file_referrer); resolver.is_cjs_resolver.as_ref() } @@ -367,7 +431,7 @@ impl LspResolver { pub fn in_npm_pkg_checker( &self, file_referrer: Option<&ModuleSpecifier>, - ) -> &Arc { + ) -> &DenoInNpmPackageChecker { let resolver = self.get_scope_resolver(file_referrer); &resolver.in_npm_pkg_checker } @@ -375,7 +439,7 @@ impl LspResolver { pub fn maybe_managed_npm_resolver( &self, file_referrer: Option<&ModuleSpecifier>, - ) -> Option<&ManagedCliNpmResolver> { + ) -> Option<&CliManagedNpmResolver> { let resolver = self.get_scope_resolver(file_referrer); resolver.npm_resolver.as_ref().and_then(|r| r.as_managed()) } @@ -589,11 +653,15 @@ pub struct ScopeDepInfo { #[derive(Default)] struct ResolverFactoryServices { cli_resolver: Deferred>, - in_npm_pkg_checker: Deferred>, - is_cjs_resolver: Deferred>, + found_pkg_json_dep_flag: Arc, + in_npm_pkg_checker: Deferred, + is_cjs_resolver: Deferred>, node_resolver: Deferred>>, + npm_graph_resolver: Deferred>, + npm_installer: Option>, npm_pkg_req_resolver: Deferred>>, - npm_resolver: Option>, + npm_resolver: Option, + npm_resolution: Arc, } struct ResolverFactory<'a> { @@ -615,6 +683,10 @@ impl<'a> ResolverFactory<'a> { } } + // todo(dsherret): probably this method could be removed in the future + // and instead just `npm_resolution_initializer.ensure_initialized()` could + // be called. The reason this exists is because creating the npm resolvers + // used to be async. async fn init_npm_resolver( &mut self, http_client_provider: &Arc, @@ -644,11 +716,30 @@ impl<'a> ResolverFactory<'a> { cache.deno_dir().npm_folder_path(), npmrc.get_all_known_registries_urls(), )); - CliNpmResolverCreateOptions::Managed(CliManagedNpmResolverCreateOptions { - http_client_provider: http_client_provider.clone(), - // only used for top level install, so we can ignore this - npm_install_deps_provider: Arc::new(NpmInstallDepsProvider::empty()), - snapshot: match self.config_data.and_then(|d| d.lockfile.as_ref()) { + let npm_cache = Arc::new(CliNpmCache::new( + npm_cache_dir.clone(), + sys.clone(), + // Use an "only" cache setting in order to make the + // user do an explicit "cache" command and prevent + // the cache from being filled with lots of packages while + // the user is typing. + deno_npm_cache::NpmCacheSetting::Only, + npmrc.clone(), + )); + let pb = ProgressBar::new(ProgressBarStyle::TextOnly); + let npm_client = Arc::new(CliNpmCacheHttpClient::new( + http_client_provider.clone(), + pb.clone(), + )); + let registry_info_provider = Arc::new(CliNpmRegistryInfoProvider::new( + npm_cache.clone(), + npm_client.clone(), + npmrc.clone(), + )); + let npm_resolution_initializer = Arc::new(NpmResolutionInitializer::new( + registry_info_provider.clone(), + self.services.npm_resolution.clone(), + match self.config_data.and_then(|d| d.lockfile.as_ref()) { Some(lockfile) => { CliNpmResolverManagedSnapshotOption::ResolveFromLockfile( lockfile.clone(), @@ -656,33 +747,69 @@ impl<'a> ResolverFactory<'a> { } None => CliNpmResolverManagedSnapshotOption::Specified(None), }, + )); + // Don't provide the lockfile. We don't want these resolvers + // updating it. Only the cache request should update the lockfile. + let maybe_lockfile: Option> = None; + let maybe_node_modules_path = + self.config_data.and_then(|d| d.node_modules_dir.clone()); + let tarball_cache = Arc::new(TarballCache::new( + npm_cache.clone(), + npm_client.clone(), + sys.clone(), + npmrc.clone(), + )); + let npm_resolution_installer = Arc::new(NpmResolutionInstaller::new( + registry_info_provider, + self.services.npm_resolution.clone(), + maybe_lockfile.clone(), + )); + let npm_installer = Arc::new(NpmInstaller::new( + npm_cache.clone(), + Arc::new(NpmInstallDepsProvider::empty()), + self.services.npm_resolution.clone(), + npm_resolution_initializer.clone(), + npm_resolution_installer, + &pb, + sys.clone(), + tarball_cache.clone(), + maybe_lockfile, + maybe_node_modules_path.clone(), + LifecycleScriptsConfig::default(), + NpmSystemInfo::default(), + )); + self.set_npm_installer(npm_installer); + // spawn due to the lsp's `Send` requirement + deno_core::unsync::spawn(async move { + if let Err(err) = npm_resolution_initializer.ensure_initialized().await + { + log::warn!("failed to initialize npm resolution: {}", err); + } + }) + .await + .unwrap(); + + CliNpmResolverCreateOptions::Managed(CliManagedNpmResolverCreateOptions { sys: CliSys::default(), npm_cache_dir, - // Use an "only" cache setting in order to make the - // user do an explicit "cache" command and prevent - // the cache from being filled with lots of packages while - // the user is typing. - cache_setting: CacheSetting::Only, - text_only_progress_bar: ProgressBar::new(ProgressBarStyle::TextOnly), - // Don't provide the lockfile. We don't want these resolvers - // updating it. Only the cache request should update the lockfile. - maybe_lockfile: None, - maybe_node_modules_path: self - .config_data - .and_then(|d| d.node_modules_dir.clone()), + maybe_node_modules_path, npmrc, + npm_resolution: self.services.npm_resolution.clone(), npm_system_info: NpmSystemInfo::default(), - lifecycle_scripts: Default::default(), }) }; - self.set_npm_resolver(create_cli_npm_resolver_for_lsp(options).await); + self.set_npm_resolver(CliNpmResolver::new(options)); } - pub fn set_npm_resolver(&mut self, npm_resolver: Arc) { + pub fn set_npm_installer(&mut self, npm_installer: Arc) { + self.services.npm_installer = Some(npm_installer); + } + + pub fn set_npm_resolver(&mut self, npm_resolver: CliNpmResolver) { self.services.npm_resolver = Some(npm_resolver); } - pub fn npm_resolver(&self) -> Option<&Arc> { + pub fn npm_resolver(&self) -> Option<&CliNpmResolver> { self.services.npm_resolver.as_ref() } @@ -719,13 +846,27 @@ impl<'a> ResolverFactory<'a> { is_byonm: self.config_data.map(|d| d.byonm).unwrap_or(false), maybe_vendor_dir: self.config_data.and_then(|d| d.vendor_dir.as_ref()), })); - Arc::new(CliResolver::new(CliResolverOptions { + Arc::new(CliResolver::new( deno_resolver, - npm_resolver: self.npm_resolver().cloned(), - bare_node_builtins_enabled: self + self.services.found_pkg_json_dep_flag.clone(), + )) + }) + } + + pub fn npm_installer(&self) -> Option<&Arc> { + self.services.npm_installer.as_ref() + } + + pub fn npm_graph_resolver(&self) -> &Arc { + self.services.npm_graph_resolver.get_or_init(|| { + Arc::new(CliNpmGraphResolver::new( + None, + self.services.found_pkg_json_dep_flag.clone(), + self .config_data .is_some_and(|d| d.unstable.contains("bare-node-builtins")), - })) + NpmCachingStrategy::Eager, + )) }) } @@ -733,29 +874,27 @@ impl<'a> ResolverFactory<'a> { &self.pkg_json_resolver } - pub fn in_npm_pkg_checker(&self) -> &Arc { + pub fn in_npm_pkg_checker(&self) -> &DenoInNpmPackageChecker { self.services.in_npm_pkg_checker.get_or_init(|| { - crate::npm::create_in_npm_pkg_checker( - match self.services.npm_resolver.as_ref().map(|r| r.as_inner()) { - Some(crate::npm::InnerCliNpmResolverRef::Byonm(_)) | None => { - CreateInNpmPkgCheckerOptions::Byonm - } - Some(crate::npm::InnerCliNpmResolverRef::Managed(m)) => { - CreateInNpmPkgCheckerOptions::Managed( - CliManagedInNpmPkgCheckerCreateOptions { - root_cache_dir_url: m.global_cache_root_url(), - maybe_node_modules_path: m.maybe_node_modules_path(), - }, - ) - } - }, - ) + DenoInNpmPackageChecker::new(match &self.services.npm_resolver { + Some(CliNpmResolver::Byonm(_)) | None => { + CreateInNpmPkgCheckerOptions::Byonm + } + Some(CliNpmResolver::Managed(m)) => { + CreateInNpmPkgCheckerOptions::Managed( + ManagedInNpmPkgCheckerCreateOptions { + root_cache_dir_url: m.global_cache_root_url(), + maybe_node_modules_path: m.root_node_modules_path(), + }, + ) + } + }) }) } - pub fn is_cjs_resolver(&self) -> &Arc { + pub fn is_cjs_resolver(&self) -> &Arc { self.services.is_cjs_resolver.get_or_init(|| { - Arc::new(IsCjsResolver::new( + Arc::new(CliIsCjsResolver::new( self.in_npm_pkg_checker().clone(), self.pkg_json_resolver().clone(), if self @@ -779,9 +918,10 @@ impl<'a> ResolverFactory<'a> { Some(Arc::new(CliNodeResolver::new( self.in_npm_pkg_checker().clone(), RealIsBuiltInNodeModuleChecker, - npm_resolver.clone().into_npm_pkg_folder_resolver(), + npm_resolver.clone(), self.pkg_json_resolver.clone(), self.sys.clone(), + node_resolver::ConditionsFromResolutionMode::default(), ))) }) .as_ref() @@ -795,10 +935,9 @@ impl<'a> ResolverFactory<'a> { let node_resolver = self.node_resolver()?; let npm_resolver = self.npm_resolver()?; Some(Arc::new(CliNpmReqResolver::new(NpmReqResolverOptions { - byonm_resolver: (npm_resolver.clone()).into_maybe_byonm(), in_npm_pkg_checker: self.in_npm_pkg_checker().clone(), node_resolver: node_resolver.clone(), - npm_req_resolver: npm_resolver.clone().into_npm_req_resolver(), + npm_resolver: npm_resolver.clone(), sys: self.sys.clone(), }))) }) diff --git a/cli/lsp/search.rs b/cli/lsp/search.rs index c98acde6f1..281542742d 100644 --- a/cli/lsp/search.rs +++ b/cli/lsp/search.rs @@ -1,9 +1,10 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::sync::Arc; use deno_core::error::AnyError; use deno_semver::package::PackageNv; use deno_semver::Version; -use std::sync::Arc; #[async_trait::async_trait] pub trait PackageSearchApi { @@ -15,10 +16,12 @@ pub trait PackageSearchApi { #[cfg(test)] pub mod tests { - use super::*; - use deno_core::anyhow::anyhow; use std::collections::BTreeMap; + use deno_core::anyhow::anyhow; + + use super::*; + #[derive(Debug, Default)] pub struct TestPackageSearchApi { /// [(name -> [(version -> [export])])] diff --git a/cli/lsp/semantic_tokens.rs b/cli/lsp/semantic_tokens.rs index 0cf154d0ff..d2466f4c14 100644 --- a/cli/lsp/semantic_tokens.rs +++ b/cli/lsp/semantic_tokens.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // The logic of this module is heavily influenced by // https://github.com/microsoft/vscode/blob/main/extensions/typescript-language-features/src/languageFeatures/semanticTokens.ts @@ -7,6 +7,7 @@ use std::ops::Index; use std::ops::IndexMut; + use tower_lsp::lsp_types as lsp; use tower_lsp::lsp_types::SemanticToken; use tower_lsp::lsp_types::SemanticTokenModifier; diff --git a/cli/lsp/testing/collectors.rs b/cli/lsp/testing/collectors.rs index 2dd7ec0d96..8a36ca1f25 100644 --- a/cli/lsp/testing/collectors.rs +++ b/cli/lsp/testing/collectors.rs @@ -1,8 +1,7 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::lsp::analysis::source_range_to_lsp_range; - -use super::definitions::TestModule; +use std::collections::HashMap; +use std::collections::HashSet; use deno_ast::swc::ast; use deno_ast::swc::visit::Visit; @@ -11,10 +10,11 @@ use deno_ast::SourceRangedForSpanned; use deno_ast::SourceTextInfo; use deno_core::ModuleSpecifier; use lsp::Range; -use std::collections::HashMap; -use std::collections::HashSet; use tower_lsp::lsp_types as lsp; +use super::definitions::TestModule; +use crate::lsp::analysis::source_range_to_lsp_range; + /// Parse an arrow expression for any test steps and return them. fn visit_arrow( arrow_expr: &ast::ArrowExpr, @@ -626,12 +626,12 @@ impl Visit for TestCollector { #[cfg(test)] pub mod tests { - use crate::lsp::testing::definitions::TestDefinition; - - use super::*; use deno_core::resolve_url; use lsp::Position; + use super::*; + use crate::lsp::testing::definitions::TestDefinition; + pub fn new_range(l1: u32, c1: u32, l2: u32, c2: u32) -> Range { Range::new(Position::new(l1, c1), Position::new(l2, c2)) } diff --git a/cli/lsp/testing/definitions.rs b/cli/lsp/testing/definitions.rs index f23411852f..d6630c1844 100644 --- a/cli/lsp/testing/definitions.rs +++ b/cli/lsp/testing/definitions.rs @@ -1,21 +1,21 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::collections::HashMap; +use std::collections::HashSet; + +use deno_core::error::AnyError; +use deno_core::ModuleSpecifier; +use deno_lib::util::checksum; +use lsp::Range; +use tower_lsp::lsp_types as lsp; use super::lsp_custom; use super::lsp_custom::TestData; - use crate::lsp::client::TestingNotification; use crate::lsp::logging::lsp_warn; use crate::lsp::urls::url_to_uri; use crate::tools::test::TestDescription; use crate::tools::test::TestStepDescription; -use crate::util::checksum; - -use deno_core::error::AnyError; -use deno_core::ModuleSpecifier; -use lsp::Range; -use std::collections::HashMap; -use std::collections::HashSet; -use tower_lsp::lsp_types as lsp; #[derive(Debug, Clone, PartialEq)] pub struct TestDefinition { diff --git a/cli/lsp/testing/execution.rs b/cli/lsp/testing/execution.rs index 88fb496e4e..3d6d6f6b73 100644 --- a/cli/lsp/testing/execution.rs +++ b/cli/lsp/testing/execution.rs @@ -1,24 +1,12 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use super::definitions::TestDefinition; -use super::definitions::TestModule; -use super::lsp_custom; -use super::server::TestServerTests; - -use crate::args::flags_from_vec; -use crate::args::DenoSubcommand; -use crate::factory::CliFactory; -use crate::lsp::client::Client; -use crate::lsp::client::TestingNotification; -use crate::lsp::config; -use crate::lsp::logging::lsp_log; -use crate::lsp::urls::uri_parse_unencoded; -use crate::lsp::urls::uri_to_url; -use crate::lsp::urls::url_to_uri; -use crate::tools::test; -use crate::tools::test::create_test_event_channel; -use crate::tools::test::FailFastTracker; -use crate::tools::test::TestFailureFormatOptions; +use std::borrow::Cow; +use std::collections::HashMap; +use std::collections::HashSet; +use std::num::NonZeroUsize; +use std::sync::Arc; +use std::time::Duration; +use std::time::Instant; use deno_core::anyhow::anyhow; use deno_core::error::AnyError; @@ -34,16 +22,28 @@ use deno_runtime::deno_permissions::Permissions; use deno_runtime::deno_permissions::PermissionsContainer; use deno_runtime::tokio_util::create_and_run_current_thread; use indexmap::IndexMap; -use std::borrow::Cow; -use std::collections::HashMap; -use std::collections::HashSet; -use std::num::NonZeroUsize; -use std::sync::Arc; -use std::time::Duration; -use std::time::Instant; use tokio_util::sync::CancellationToken; use tower_lsp::lsp_types as lsp; +use super::definitions::TestDefinition; +use super::definitions::TestModule; +use super::lsp_custom; +use super::server::TestServerTests; +use crate::args::flags_from_vec; +use crate::args::DenoSubcommand; +use crate::factory::CliFactory; +use crate::lsp::client::Client; +use crate::lsp::client::TestingNotification; +use crate::lsp::config; +use crate::lsp::logging::lsp_log; +use crate::lsp::urls::uri_parse_unencoded; +use crate::lsp::urls::uri_to_url; +use crate::lsp::urls::url_to_uri; +use crate::tools::test; +use crate::tools::test::create_test_event_channel; +use crate::tools::test::FailFastTracker; +use crate::tools::test::TestFailureFormatOptions; + /// Logic to convert a test request into a set of test modules to be tested and /// any filters to be applied to those tests fn as_queue_and_filters( @@ -794,9 +794,10 @@ impl LspTestReporter { #[cfg(test)] mod tests { + use deno_core::serde_json::json; + use super::*; use crate::lsp::testing::collectors::tests::new_range; - use deno_core::serde_json::json; #[test] fn test_as_queue_and_filters() { diff --git a/cli/lsp/testing/lsp_custom.rs b/cli/lsp/testing/lsp_custom.rs index 84ac30de57..5ee6e84f52 100644 --- a/cli/lsp/testing/lsp_custom.rs +++ b/cli/lsp/testing/lsp_custom.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::serde::Deserialize; use deno_core::serde::Serialize; diff --git a/cli/lsp/testing/mod.rs b/cli/lsp/testing/mod.rs index d285481f06..1398ba1eca 100644 --- a/cli/lsp/testing/mod.rs +++ b/cli/lsp/testing/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. mod collectors; mod definitions; diff --git a/cli/lsp/testing/server.rs b/cli/lsp/testing/server.rs index c9c39d9ffc..e0570fcada 100644 --- a/cli/lsp/testing/server.rs +++ b/cli/lsp/testing/server.rs @@ -1,16 +1,9 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use super::definitions::TestModule; -use super::execution::TestRun; -use super::lsp_custom; - -use crate::lsp::client::Client; -use crate::lsp::client::TestingNotification; -use crate::lsp::config; -use crate::lsp::documents::DocumentsFilter; -use crate::lsp::language_server::StateSnapshot; -use crate::lsp::performance::Performance; -use crate::lsp::urls::url_to_uri; +use std::collections::HashMap; +use std::collections::HashSet; +use std::sync::Arc; +use std::thread; use deno_core::error::AnyError; use deno_core::parking_lot::Mutex; @@ -18,15 +11,22 @@ use deno_core::serde_json::json; use deno_core::serde_json::Value; use deno_core::ModuleSpecifier; use deno_runtime::tokio_util::create_basic_runtime; -use std::collections::HashMap; -use std::collections::HashSet; -use std::sync::Arc; -use std::thread; use tokio::sync::mpsc; use tower_lsp::jsonrpc::Error as LspError; use tower_lsp::jsonrpc::Result as LspResult; use tower_lsp::lsp_types as lsp; +use super::definitions::TestModule; +use super::execution::TestRun; +use super::lsp_custom; +use crate::lsp::client::Client; +use crate::lsp::client::TestingNotification; +use crate::lsp::config; +use crate::lsp::documents::DocumentsFilter; +use crate::lsp::language_server::StateSnapshot; +use crate::lsp::performance::Performance; +use crate::lsp::urls::url_to_uri; + fn as_delete_notification( url: &ModuleSpecifier, ) -> Result { diff --git a/cli/lsp/text.rs b/cli/lsp/text.rs index 88f27915bb..efb9a072a4 100644 --- a/cli/lsp/text.rs +++ b/cli/lsp/text.rs @@ -1,10 +1,11 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::collections::HashMap; -use deno_core::error::custom_error; use deno_core::error::AnyError; +use deno_error::JsErrorBox; use dissimilar::diff; use dissimilar::Chunk; -use std::collections::HashMap; use text_size::TextRange; use text_size::TextSize; use tower_lsp::jsonrpc; @@ -136,7 +137,7 @@ impl LineIndex { if let Some(line_offset) = self.utf8_offsets.get(position.line as usize) { Ok(line_offset + col) } else { - Err(custom_error("OutOfRange", "The position is out of range.")) + Err(JsErrorBox::new("OutOfRange", "The position is out of range.").into()) } } @@ -156,7 +157,7 @@ impl LineIndex { if let Some(line_offset) = self.utf16_offsets.get(position.line as usize) { Ok(line_offset + TextSize::from(position.character)) } else { - Err(custom_error("OutOfRange", "The position is out of range.")) + Err(JsErrorBox::new("OutOfRange", "The position is out of range.").into()) } } diff --git a/cli/lsp/tsc.rs b/cli/lsp/tsc.rs index f8b972511f..32352d9f26 100644 --- a/cli/lsp/tsc.rs +++ b/cli/lsp/tsc.rs @@ -1,52 +1,28 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use super::analysis::CodeActionData; -use super::code_lens; -use super::config; -use super::config::LspTsConfig; -use super::documents::AssetOrDocument; -use super::documents::Document; -use super::documents::DocumentsFilter; -use super::language_server; -use super::language_server::StateSnapshot; -use super::performance::Performance; -use super::performance::PerformanceMark; -use super::refactor::RefactorCodeActionData; -use super::refactor::ALL_KNOWN_REFACTOR_ACTION_KINDS; -use super::refactor::EXTRACT_CONSTANT; -use super::refactor::EXTRACT_INTERFACE; -use super::refactor::EXTRACT_TYPE; -use super::semantic_tokens; -use super::semantic_tokens::SemanticTokensBuilder; -use super::text::LineIndex; -use super::urls::uri_to_url; -use super::urls::url_to_uri; -use super::urls::INVALID_SPECIFIER; -use super::urls::INVALID_URI; - -use crate::args::jsr_url; -use crate::args::FmtOptionsConfig; -use crate::lsp::logging::lsp_warn; -use crate::tsc; -use crate::tsc::ResolveArgs; -use crate::tsc::MISSING_DEPENDENCY_SPECIFIER; -use crate::util::path::relative_specifier; -use crate::util::path::to_percent_decoded_str; -use crate::util::result::InfallibleResultExt; -use crate::util::v8::convert; -use crate::worker::create_isolate_create_params; -use deno_core::convert::Smi; -use deno_core::convert::ToV8; -use deno_core::error::StdAnyError; -use deno_core::futures::stream::FuturesOrdered; -use deno_core::futures::StreamExt; +use std::cell::RefCell; +use std::cmp; +use std::collections::BTreeMap; +use std::collections::HashMap; +use std::collections::HashSet; +use std::convert::Infallible; +use std::net::SocketAddr; +use std::ops::Range; +use std::path::Path; +use std::rc::Rc; +use std::sync::Arc; +use std::thread; use dashmap::DashMap; use deno_ast::MediaType; use deno_core::anyhow::anyhow; use deno_core::anyhow::Context as _; +use deno_core::convert::Smi; +use deno_core::convert::ToV8; use deno_core::error::AnyError; +use deno_core::futures::stream::FuturesOrdered; use deno_core::futures::FutureExt; +use deno_core::futures::StreamExt; use deno_core::op2; use deno_core::parking_lot::Mutex; use deno_core::resolve_url; @@ -63,6 +39,7 @@ use deno_core::ModuleSpecifier; use deno_core::OpState; use deno_core::PollEventLoopOptions; use deno_core::RuntimeOptions; +use deno_lib::worker::create_isolate_create_params; use deno_path_util::url_to_file_path; use deno_runtime::deno_node::SUPPORTED_BUILTIN_NODE_MODULES; use deno_runtime::inspector_server::InspectorServer; @@ -77,18 +54,6 @@ use regex::Captures; use regex::Regex; use serde_repr::Deserialize_repr; use serde_repr::Serialize_repr; -use std::cell::RefCell; -use std::cmp; -use std::collections::BTreeMap; -use std::collections::HashMap; -use std::collections::HashSet; -use std::convert::Infallible; -use std::net::SocketAddr; -use std::ops::Range; -use std::path::Path; -use std::rc::Rc; -use std::sync::Arc; -use std::thread; use text_size::TextRange; use text_size::TextSize; use tokio::sync::mpsc; @@ -99,6 +64,41 @@ use tower_lsp::jsonrpc::Error as LspError; use tower_lsp::jsonrpc::Result as LspResult; use tower_lsp::lsp_types as lsp; +use super::analysis::CodeActionData; +use super::code_lens; +use super::config; +use super::config::LspTsConfig; +use super::documents::AssetOrDocument; +use super::documents::Document; +use super::documents::DocumentsFilter; +use super::language_server; +use super::language_server::StateSnapshot; +use super::logging::lsp_log; +use super::performance::Performance; +use super::performance::PerformanceMark; +use super::refactor::RefactorCodeActionData; +use super::refactor::ALL_KNOWN_REFACTOR_ACTION_KINDS; +use super::refactor::EXTRACT_CONSTANT; +use super::refactor::EXTRACT_INTERFACE; +use super::refactor::EXTRACT_TYPE; +use super::semantic_tokens; +use super::semantic_tokens::SemanticTokensBuilder; +use super::text::LineIndex; +use super::urls::uri_to_url; +use super::urls::url_to_uri; +use super::urls::INVALID_SPECIFIER; +use super::urls::INVALID_URI; +use crate::args::jsr_url; +use crate::args::FmtOptionsConfig; +use crate::lsp::logging::lsp_warn; +use crate::tsc; +use crate::tsc::ResolveArgs; +use crate::tsc::MISSING_DEPENDENCY_SPECIFIER; +use crate::util::path::relative_specifier; +use crate::util::path::to_percent_decoded_str; +use crate::util::result::InfallibleResultExt; +use crate::util::v8::convert; + static BRACKET_ACCESSOR_RE: Lazy = lazy_regex!(r#"^\[['"](.+)[\['"]\]$"#); static CAPTION_RE: Lazy = @@ -3973,6 +3973,11 @@ impl CompletionEntry { if let Some(mut new_specifier) = import_mapper .check_specifier(&import_data.normalized, specifier) .or_else(|| relative_specifier(specifier, &import_data.normalized)) + .or_else(|| { + ModuleSpecifier::parse(&import_data.raw.module_specifier) + .is_ok() + .then(|| import_data.normalized.to_string()) + }) { if new_specifier.contains("/node_modules/") { return None; @@ -4331,15 +4336,17 @@ impl TscSpecifierMap { pub fn normalize>( &self, specifier: S, - ) -> Result { + ) -> Result { let original = specifier.as_ref(); if let Some(specifier) = self.normalized_specifiers.get(original) { return Ok(specifier.clone()); } - let specifier_str = original.replace(".d.ts.d.ts", ".d.ts"); + let specifier_str = original + .replace(".d.ts.d.ts", ".d.ts") + .replace("$node_modules", "node_modules"); let specifier = match ModuleSpecifier::parse(&specifier_str) { Ok(s) => s, - Err(err) => return Err(err.into()), + Err(err) => return Err(err), }; if specifier.as_str() != original { self @@ -4437,6 +4444,16 @@ fn op_is_node_file(state: &mut OpState, #[string] path: String) -> bool { r } +#[derive(Debug, thiserror::Error, deno_error::JsError)] +enum LoadError { + #[error("{0}")] + #[class(inherit)] + UrlParse(#[from] deno_core::url::ParseError), + #[error("{0}")] + #[class(inherit)] + SerdeV8(#[from] serde_v8::Error), +} + #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] struct LoadResponse { @@ -4451,7 +4468,7 @@ fn op_load<'s>( scope: &'s mut v8::HandleScope, state: &mut OpState, #[string] specifier: &str, -) -> Result, AnyError> { +) -> Result, LoadError> { let state = state.borrow_mut::(); let mark = state .performance @@ -4482,7 +4499,7 @@ fn op_load<'s>( fn op_release( state: &mut OpState, #[string] specifier: &str, -) -> Result<(), AnyError> { +) -> Result<(), deno_core::url::ParseError> { let state = state.borrow_mut::(); let mark = state .performance @@ -4495,11 +4512,12 @@ fn op_release( #[op2] #[serde] +#[allow(clippy::type_complexity)] fn op_resolve( state: &mut OpState, #[string] base: String, #[serde] specifiers: Vec<(bool, String)>, -) -> Result>, AnyError> { +) -> Result)>>, deno_core::url::ParseError> { op_resolve_inner(state, ResolveArgs { base, specifiers }) } @@ -4511,7 +4529,7 @@ struct TscRequestArray { } impl<'a> ToV8<'a> for TscRequestArray { - type Error = StdAnyError; + type Error = serde_v8::Error; fn to_v8( self, @@ -4526,9 +4544,7 @@ impl<'a> ToV8<'a> for TscRequestArray { .unwrap() .into(); let args = args.unwrap_or_else(|| v8::Array::new(scope, 0).into()); - let scope_url = serde_v8::to_v8(scope, self.scope) - .map_err(AnyError::from) - .map_err(StdAnyError::from)?; + let scope_url = serde_v8::to_v8(scope, self.scope)?; let change = self.change.to_v8(scope).unwrap_infallible(); @@ -4583,10 +4599,11 @@ async fn op_poll_requests( } #[inline] +#[allow(clippy::type_complexity)] fn op_resolve_inner( state: &mut OpState, args: ResolveArgs, -) -> Result>, AnyError> { +) -> Result)>>, deno_core::url::ParseError> { let state = state.borrow_mut::(); let mark = state.performance.mark_with_args("tsc.op.op_resolve", &args); let referrer = state.specifier_map.normalize(&args.base)?; @@ -4599,7 +4616,11 @@ fn op_resolve_inner( o.map(|(s, mt)| { ( state.specifier_map.denormalize(&s), - mt.as_ts_extension().to_string(), + if matches!(mt, MediaType::Unknown) { + None + } else { + Some(mt.as_ts_extension().to_string()) + }, ) }) }) @@ -4677,7 +4698,24 @@ fn op_script_names(state: &mut OpState) -> ScriptNames { .graph_imports_by_referrer(scope) { for specifier in specifiers { - script_names.insert(specifier.to_string()); + if let Ok(req_ref) = + deno_semver::npm::NpmPackageReqReference::from_specifier(specifier) + { + let Some((resolved, _)) = + state.state_snapshot.resolver.npm_to_file_url( + &req_ref, + scope, + ResolutionMode::Import, + Some(scope), + ) + else { + lsp_log!("failed to resolve {req_ref} to file URL"); + continue; + }; + script_names.insert(resolved.to_string()); + } else { + script_names.insert(specifier.to_string()); + } } } } @@ -4743,7 +4781,7 @@ fn op_script_names(state: &mut OpState) -> ScriptNames { fn op_script_version( state: &mut OpState, #[string] specifier: &str, -) -> Result, AnyError> { +) -> Result, deno_core::url::ParseError> { let state = state.borrow_mut::(); let mark = state.performance.mark("tsc.op.op_script_version"); let specifier = state.specifier_map.normalize(specifier)?; @@ -5398,7 +5436,8 @@ impl TscRequest { fn to_server_request<'s>( &self, scope: &mut v8::HandleScope<'s>, - ) -> Result<(&'static str, Option>), AnyError> { + ) -> Result<(&'static str, Option>), serde_v8::Error> + { let args = match self { TscRequest::GetDiagnostics(args) => { ("$getDiagnostics", Some(serde_v8::to_v8(scope, args)?)) @@ -5541,6 +5580,9 @@ impl TscRequest { #[cfg(test)] mod tests { + use pretty_assertions::assert_eq; + use test_util::TempDir; + use super::*; use crate::cache::HttpCache; use crate::lsp::cache::LspCache; @@ -5550,8 +5592,6 @@ mod tests { use crate::lsp::documents::LanguageId; use crate::lsp::resolver::LspResolver; use crate::lsp::text::LineIndex; - use pretty_assertions::assert_eq; - use test_util::TempDir; async fn setup( ts_config: Value, @@ -5569,7 +5609,6 @@ mod tests { }) .to_string(), temp_dir.url().join("deno.json").unwrap(), - &Default::default(), ) .unwrap(), ) @@ -6226,7 +6265,40 @@ mod tests { "kind": "keyword" } ], - "documentation": [] + "documentation": [ + { + "text": "Outputs a message to the console", + "kind": "text", + }, + ], + "tags": [ + { + "name": "param", + "text": [ + { + "text": "data", + "kind": "parameterName", + }, + { + "text": " ", + "kind": "space", + }, + { + "text": "Values to be printed to the console", + "kind": "text", + }, + ], + }, + { + "name": "example", + "text": [ + { + "text": "```ts\nconsole.log('Hello', 'World', 123);\n```", + "kind": "text", + }, + ], + }, + ] }) ); } @@ -6447,7 +6519,7 @@ mod tests { resolved, vec![Some(( temp_dir.url().join("b.ts").unwrap().to_string(), - MediaType::TypeScript.as_ts_extension().to_string() + Some(MediaType::TypeScript.as_ts_extension().to_string()) ))] ); } diff --git a/cli/lsp/urls.rs b/cli/lsp/urls.rs index 6c7da4f134..068e4ad4d5 100644 --- a/cli/lsp/urls.rs +++ b/cli/lsp/urls.rs @@ -1,4 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::collections::HashMap; +use std::str::FromStr; +use std::sync::Arc; use deno_ast::MediaType; use deno_core::error::AnyError; @@ -8,9 +12,6 @@ use deno_core::url::Url; use deno_core::ModuleSpecifier; use lsp_types::Uri; use once_cell::sync::Lazy; -use std::collections::HashMap; -use std::str::FromStr; -use std::sync::Arc; use super::cache::LspCache; use super::logging::lsp_warn; @@ -80,7 +81,7 @@ fn hash_data_specifier(specifier: &ModuleSpecifier) -> String { file_name_str.push('?'); file_name_str.push_str(query); } - crate::util::checksum::gen(&[file_name_str.as_bytes()]) + deno_lib::util::checksum::gen(&[file_name_str.as_bytes()]) } fn to_deno_uri(specifier: &Url) -> String { @@ -281,24 +282,26 @@ impl LspUrlMap { } } -/// Convert a e.g. `deno-notebook-cell:` specifier to a `file:` specifier. +/// Convert a e.g. `vscode-notebook-cell:` specifier to a `file:` specifier. /// ```rust /// assert_eq!( /// file_like_to_file_specifier( -/// &Url::parse("deno-notebook-cell:/path/to/file.ipynb#abc").unwrap(), +/// &Url::parse("vscode-notebook-cell:/path/to/file.ipynb#abc").unwrap(), /// ), -/// Some(Url::parse("file:///path/to/file.ipynb.ts?scheme=deno-notebook-cell#abc").unwrap()), +/// Some(Url::parse("file:///path/to/file.ipynb?scheme=untitled#abc").unwrap()), /// ); fn file_like_to_file_specifier(specifier: &Url) -> Option { - if matches!(specifier.scheme(), "untitled" | "deno-notebook-cell") { + if matches!( + specifier.scheme(), + "untitled" | "vscode-notebook-cell" | "deno-notebook-cell" + ) { if let Ok(mut s) = ModuleSpecifier::parse(&format!( - "file://{}", + "file:///{}", &specifier.as_str()[deno_core::url::quirks::internal_components(specifier) - .host_end as usize..], + .host_end as usize..].trim_start_matches('/'), )) { s.query_pairs_mut() .append_pair("scheme", specifier.scheme()); - s.set_path(&format!("{}.ts", s.path())); return Some(s); } } @@ -307,9 +310,10 @@ fn file_like_to_file_specifier(specifier: &Url) -> Option { #[cfg(test)] mod tests { - use super::*; use deno_core::resolve_url; + use super::*; + #[test] fn test_hash_data_specifier() { let fixture = resolve_url("data:application/typescript;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo=").unwrap(); @@ -430,11 +434,11 @@ mod tests { fn test_file_like_to_file_specifier() { assert_eq!( file_like_to_file_specifier( - &Url::parse("deno-notebook-cell:/path/to/file.ipynb#abc").unwrap(), + &Url::parse("vscode-notebook-cell:/path/to/file.ipynb#abc").unwrap(), ), Some( Url::parse( - "file:///path/to/file.ipynb.ts?scheme=deno-notebook-cell#abc" + "file:///path/to/file.ipynb?scheme=vscode-notebook-cell#abc" ) .unwrap() ), @@ -444,8 +448,7 @@ mod tests { &Url::parse("untitled:/path/to/file.ipynb#123").unwrap(), ), Some( - Url::parse("file:///path/to/file.ipynb.ts?scheme=untitled#123") - .unwrap() + Url::parse("file:///path/to/file.ipynb?scheme=untitled#123").unwrap() ), ); } diff --git a/cli/main.rs b/cli/main.rs index c3c7286e71..f97ea81e5d 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -1,10 +1,9 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. mod args; mod cache; mod cdp; mod emit; -mod errors; mod factory; mod file_fetcher; mod graph_container; @@ -28,31 +27,6 @@ mod util; mod version; mod worker; -use crate::args::flags_from_vec; -use crate::args::DenoSubcommand; -use crate::args::Flags; -use crate::util::display; -use crate::util::v8::get_v8_flags_from_env; -use crate::util::v8::init_v8_flags; - -use args::TaskFlags; -use deno_resolver::npm::ByonmResolvePkgFolderFromDenoReqError; -use deno_resolver::npm::ResolvePkgFolderFromDenoReqError; -use deno_runtime::WorkerExecutionMode; -pub use deno_runtime::UNSTABLE_GRANULAR_FLAGS; - -use deno_core::anyhow::Context; -use deno_core::error::AnyError; -use deno_core::error::JsError; -use deno_core::futures::FutureExt; -use deno_core::unsync::JoinHandle; -use deno_npm::resolution::SnapshotFromLockfileError; -use deno_runtime::fmt_errors::format_js_error; -use deno_runtime::tokio_util::create_and_run_current_thread_with_maybe_metrics; -use deno_terminal::colors; -use factory::CliFactory; -use standalone::MODULE_NOT_FOUND; -use standalone::UNSUPPORTED_SCHEME; use std::env; use std::future::Future; use std::io::IsTerminal; @@ -60,6 +34,31 @@ use std::ops::Deref; use std::path::PathBuf; use std::sync::Arc; +use args::TaskFlags; +use deno_core::anyhow::Context; +use deno_core::error::AnyError; +use deno_core::error::CoreError; +use deno_core::futures::FutureExt; +use deno_core::unsync::JoinHandle; +use deno_resolver::npm::ByonmResolvePkgFolderFromDenoReqError; +use deno_resolver::npm::ResolvePkgFolderFromDenoReqError; +use deno_runtime::fmt_errors::format_js_error; +use deno_runtime::tokio_util::create_and_run_current_thread_with_maybe_metrics; +use deno_runtime::WorkerExecutionMode; +pub use deno_runtime::UNSTABLE_GRANULAR_FLAGS; +use deno_terminal::colors; +use factory::CliFactory; +use standalone::MODULE_NOT_FOUND; +use standalone::UNSUPPORTED_SCHEME; + +use self::npm::ResolveSnapshotError; +use crate::args::flags_from_vec; +use crate::args::DenoSubcommand; +use crate::args::Flags; +use crate::util::display; +use crate::util::v8::get_v8_flags_from_env; +use crate::util::v8::init_v8_flags; + #[cfg(feature = "dhat-heap")] #[global_allocator] static ALLOC: dhat::Alloc = dhat::Alloc; @@ -202,7 +201,7 @@ async fn run_subcommand(flags: Arc) -> Result { match result { Ok(v) => Ok(v), Err(script_err) => { - if let Some(ResolvePkgFolderFromDenoReqError::Byonm(ByonmResolvePkgFolderFromDenoReqError::UnmatchedReq(_))) = script_err.downcast_ref::() { + if let Some(ResolvePkgFolderFromDenoReqError::Byonm(ByonmResolvePkgFolderFromDenoReqError::UnmatchedReq(_))) = util::result::any_and_jserrorbox_downcast_ref::(&script_err) { if flags.node_modules_dir.is_none() { let mut flags = flags.deref().clone(); let watch = match &flags.subcommand { @@ -373,13 +372,19 @@ fn exit_for_error(error: AnyError) -> ! { let mut error_string = format!("{error:?}"); let mut error_code = 1; - if let Some(e) = error.downcast_ref::() { - error_string = format_js_error(e); - } else if let Some(SnapshotFromLockfileError::IntegrityCheckFailed(e)) = - error.downcast_ref::() + if let Some(CoreError::Js(e)) = + util::result::any_and_jserrorbox_downcast_ref::(&error) { - error_string = e.to_string(); - error_code = 10; + error_string = format_js_error(e); + } else if let Some(e @ ResolveSnapshotError { .. }) = + util::result::any_and_jserrorbox_downcast_ref::( + &error, + ) + { + if let Some(e) = e.maybe_integrity_check_error() { + error_string = e.to_string(); + error_code = 10; + } } exit_with_message(&error_string, error_code); @@ -447,8 +452,9 @@ fn resolve_flags_and_init( } }; - deno_telemetry::init(crate::args::otel_runtime_config())?; - util::logger::init(flags.log_level, Some(flags.otel_config())); + let otel_config = flags.otel_config(); + deno_telemetry::init(crate::args::otel_runtime_config(), &otel_config)?; + util::logger::init(flags.log_level, Some(otel_config)); // TODO(bartlomieju): remove in Deno v2.5 and hard error then. if flags.unstable_config.legacy_flag_enabled { diff --git a/cli/mainrt.rs b/cli/mainrt.rs index 2b767ea89c..8eea3f85ed 100644 --- a/cli/mainrt.rs +++ b/cli/mainrt.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Allow unused code warnings because we share // code between the two bin targets. @@ -10,7 +10,6 @@ mod standalone; mod args; mod cache; mod emit; -mod errors; mod file_fetcher; mod http_util; mod js; @@ -24,8 +23,14 @@ mod util; mod version; mod worker; -use deno_core::error::generic_error; +use std::borrow::Cow; +use std::collections::HashMap; +use std::env; +use std::env::current_exe; +use std::sync::Arc; + use deno_core::error::AnyError; +use deno_core::error::CoreError; use deno_core::error::JsError; use deno_runtime::fmt_errors::format_js_error; use deno_runtime::tokio_util::create_and_run_current_thread_with_maybe_metrics; @@ -34,13 +39,8 @@ use deno_terminal::colors; use indexmap::IndexMap; use standalone::DenoCompileFileSystem; -use std::borrow::Cow; -use std::collections::HashMap; -use std::env; -use std::env::current_exe; -use std::sync::Arc; - use crate::args::Flags; +use crate::util::result::any_and_jserrorbox_downcast_ref; pub(crate) fn unstable_exit_cb(feature: &str, api_name: &str) { log::error!( @@ -65,8 +65,10 @@ fn unwrap_or_exit(result: Result) -> T { Err(error) => { let mut error_string = format!("{:?}", error); - if let Some(e) = error.downcast_ref::() { - error_string = format_js_error(e); + if let Some(CoreError::Js(js_error)) = + any_and_jserrorbox_downcast_ref::(&error) + { + error_string = format_js_error(js_error); } exit_with_message(&error_string, 1); @@ -89,7 +91,10 @@ fn main() { let future = async move { match standalone { Ok(Some(data)) => { - deno_telemetry::init(crate::args::otel_runtime_config())?; + deno_telemetry::init( + crate::args::otel_runtime_config(), + &data.metadata.otel_config, + )?; util::logger::init( data.metadata.log_level, Some(data.metadata.otel_config.clone()), diff --git a/cli/module_loader.rs b/cli/module_loader.rs index ea40dbe609..2b0ebca986 100644 --- a/cli/module_loader.rs +++ b/cli/module_loader.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::cell::RefCell; @@ -11,16 +11,12 @@ use std::sync::atomic::AtomicU16; use std::sync::atomic::Ordering; use std::sync::Arc; -use crate::node::CliNodeResolver; -use crate::sys::CliSys; use deno_ast::MediaType; use deno_ast::ModuleKind; use deno_core::anyhow::anyhow; -use deno_core::anyhow::bail; use deno_core::anyhow::Context; -use deno_core::error::custom_error; -use deno_core::error::generic_error; use deno_core::error::AnyError; +use deno_core::error::ModuleLoaderError; use deno_core::futures::future::FutureExt; use deno_core::futures::Future; use deno_core::parking_lot::Mutex; @@ -33,13 +29,20 @@ use deno_core::ModuleSpecifier; use deno_core::ModuleType; use deno_core::RequestedModuleType; use deno_core::SourceCodeCacheInfo; +use deno_error::JsErrorBox; +use deno_error::JsErrorClass; use deno_graph::GraphKind; use deno_graph::JsModule; use deno_graph::JsonModule; use deno_graph::Module; use deno_graph::ModuleGraph; +use deno_graph::ModuleGraphError; use deno_graph::Resolution; use deno_graph::WasmModule; +use deno_lib::npm::NpmRegistryReadPermissionChecker; +use deno_lib::worker::CreateModuleLoaderResult; +use deno_lib::worker::ModuleLoaderFactory; +use deno_resolver::npm::DenoInNpmPackageChecker; use deno_runtime::code_cache; use deno_runtime::deno_node::create_host_defined_options; use deno_runtime::deno_node::NodeRequireLoader; @@ -63,23 +66,41 @@ use crate::emit::Emitter; use crate::graph_container::MainModuleGraphContainer; use crate::graph_container::ModuleGraphContainer; use crate::graph_container::ModuleGraphUpdatePermit; +use crate::graph_util::enhance_graph_error; use crate::graph_util::CreateGraphOptions; +use crate::graph_util::EnhanceGraphErrorMode; use crate::graph_util::ModuleGraphBuilder; use crate::node::CliNodeCodeTranslator; +use crate::node::CliNodeResolver; use crate::npm::CliNpmResolver; -use crate::resolver::CjsTracker; +use crate::resolver::CliCjsTracker; use crate::resolver::CliNpmReqResolver; use crate::resolver::CliResolver; use crate::resolver::ModuleCodeStringSource; use crate::resolver::NotSupportedKindInNpmError; use crate::resolver::NpmModuleLoader; +use crate::sys::CliSys; use crate::tools::check; +use crate::tools::check::CheckError; use crate::tools::check::TypeChecker; use crate::util::progress_bar::ProgressBar; use crate::util::text_encoding::code_without_source_map; use crate::util::text_encoding::source_map_from_code; -use crate::worker::CreateModuleLoaderResult; -use crate::worker::ModuleLoaderFactory; + +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum PrepareModuleLoadError { + #[class(inherit)] + #[error(transparent)] + BuildGraphWithNpmResolution( + #[from] crate::graph_util::BuildGraphWithNpmResolutionError, + ), + #[class(inherit)] + #[error(transparent)] + Check(#[from] CheckError), + #[class(inherit)] + #[error(transparent)] + Other(#[from] JsErrorBox), +} pub struct ModuleLoadPreparer { options: Arc, @@ -120,7 +141,7 @@ impl ModuleLoadPreparer { lib: TsTypeLib, permissions: PermissionsContainer, ext_overwrite: Option<&String>, - ) -> Result<(), AnyError> { + ) -> Result<(), PrepareModuleLoadError> { log::debug!("Preparing module load."); let _pb_clear_guard = self.progress_bar.clear_guard(); @@ -201,7 +222,7 @@ impl ModuleLoadPreparer { &self, graph: &ModuleGraph, roots: &[ModuleSpecifier], - ) -> Result<(), AnyError> { + ) -> Result<(), JsErrorBox> { self.module_graph_builder.graph_roots_valid(graph, roots) } } @@ -213,17 +234,19 @@ struct SharedCliModuleLoaderState { initial_cwd: PathBuf, is_inspecting: bool, is_repl: bool, - cjs_tracker: Arc, + cjs_tracker: Arc, code_cache: Option>, emitter: Arc, - in_npm_pkg_checker: Arc, + in_npm_pkg_checker: DenoInNpmPackageChecker, main_module_graph_container: Arc, module_load_preparer: Arc, node_code_translator: Arc, node_resolver: Arc, - npm_req_resolver: Arc, - npm_resolver: Arc, npm_module_loader: NpmModuleLoader, + npm_registry_permission_checker: + Arc>, + npm_req_resolver: Arc, + npm_resolver: CliNpmResolver, parsed_source_cache: Arc, resolver: Arc, sys: CliSys, @@ -273,17 +296,20 @@ impl CliModuleLoaderFactory { #[allow(clippy::too_many_arguments)] pub fn new( options: &CliOptions, - cjs_tracker: Arc, + cjs_tracker: Arc, code_cache: Option>, emitter: Arc, - in_npm_pkg_checker: Arc, + in_npm_pkg_checker: DenoInNpmPackageChecker, main_module_graph_container: Arc, module_load_preparer: Arc, node_code_translator: Arc, node_resolver: Arc, - npm_req_resolver: Arc, - npm_resolver: Arc, npm_module_loader: NpmModuleLoader, + npm_registry_permission_checker: Arc< + NpmRegistryReadPermissionChecker, + >, + npm_req_resolver: Arc, + npm_resolver: CliNpmResolver, parsed_source_cache: Arc, resolver: Arc, sys: CliSys, @@ -307,9 +333,10 @@ impl CliModuleLoaderFactory { module_load_preparer, node_code_translator, node_resolver, + npm_module_loader, + npm_registry_permission_checker, npm_req_resolver, npm_resolver, - npm_module_loader, parsed_source_cache, resolver, sys, @@ -348,7 +375,10 @@ impl CliModuleLoaderFactory { sys: self.shared.sys.clone(), graph_container, in_npm_pkg_checker: self.shared.in_npm_pkg_checker.clone(), - npm_resolver: self.shared.npm_resolver.clone(), + npm_registry_permission_checker: self + .shared + .npm_registry_permission_checker + .clone(), }); CreateModuleLoaderResult { module_loader, @@ -412,7 +442,7 @@ impl specifier: &ModuleSpecifier, maybe_referrer: Option<&ModuleSpecifier>, requested_module_type: RequestedModuleType, - ) -> Result { + ) -> Result { let code_source = self.load_code_source(specifier, maybe_referrer).await?; let code = if self.shared.is_inspecting || code_source.media_type == MediaType::Wasm @@ -435,7 +465,7 @@ impl if module_type == ModuleType::Json && requested_module_type != RequestedModuleType::Json { - return Err(generic_error("Attempted to load JSON module without specifying \"type\": \"json\" attribute in the import statement.")); + return Err(JsErrorBox::generic("Attempted to load JSON module without specifying \"type\": \"json\" attribute in the import statement.").into()); } let code_cache = if module_type == ModuleType::JavaScript { @@ -496,7 +526,7 @@ impl fn resolve_referrer( &self, referrer: &str, - ) -> Result { + ) -> Result { let referrer = if referrer.is_empty() && self.shared.is_repl { // FIXME(bartlomieju): this is a hacky way to provide compatibility with REPL // and `Deno.core.evalContext` API. Ideally we should always have a referrer filled @@ -522,7 +552,7 @@ impl &self, raw_specifier: &str, referrer: &ModuleSpecifier, - ) -> Result { + ) -> Result { let graph = self.graph_container.graph(); let resolution = match graph.get(referrer) { Some(Module::Js(module)) => module @@ -536,19 +566,25 @@ impl let specifier = match resolution { Resolution::Ok(resolved) => Cow::Borrowed(&resolved.specifier), Resolution::Err(err) => { - return Err(custom_error( - "TypeError", - format!("{}\n", err.to_string_with_range()), - )); + return Err( + JsErrorBox::type_error(format!("{}\n", err.to_string_with_range())) + .into(), + ); } - Resolution::None => Cow::Owned(self.shared.resolver.resolve( - raw_specifier, - referrer, - deno_graph::Position::zeroed(), - // if we're here, that means it's resolving a dynamic import - ResolutionMode::Import, - NodeResolutionKind::Execution, - )?), + Resolution::None => Cow::Owned( + self + .shared + .resolver + .resolve( + raw_specifier, + referrer, + deno_graph::Position::zeroed(), + // if we're here, that means it's resolving a dynamic import + ResolutionMode::Import, + NodeResolutionKind::Execution, + ) + .map_err(JsErrorBox::from_err)?, + ), }; if self.shared.is_repl { @@ -563,7 +599,7 @@ impl ResolutionMode::Import, NodeResolutionKind::Execution, ) - .map_err(AnyError::from); + .map_err(|e| JsErrorBox::from_err(e).into()); } } @@ -574,7 +610,8 @@ impl .npm_resolver .as_managed() .unwrap() // byonm won't create a Module::Npm - .resolve_pkg_folder_from_deno_module(module.nv_reference.nv())?; + .resolve_pkg_folder_from_deno_module(module.nv_reference.nv()) + .map_err(JsErrorBox::from_err)?; self .shared .node_resolver @@ -690,13 +727,27 @@ impl &self, graph: &'graph ModuleGraph, specifier: &ModuleSpecifier, - ) -> Result>, AnyError> { + ) -> Result>, JsErrorBox> { if specifier.scheme() == "node" { // Node built-in modules should be handled internally. unreachable!("Deno bug. {} was misconfigured internally.", specifier); } - match graph.get(specifier) { + let maybe_module = match graph.try_get(specifier) { + Ok(module) => module, + Err(err) => { + return Err(JsErrorBox::new( + err.get_class(), + enhance_graph_error( + &self.shared.sys, + &ModuleGraphError::ModuleError(err.clone()), + EnhanceGraphErrorMode::ShowRange, + ), + )) + } + }; + + match maybe_module { Some(deno_graph::Module::Json(JsonModule { source, media_type, @@ -714,11 +765,12 @@ impl is_script, .. })) => { - if self.shared.cjs_tracker.is_cjs_with_known_is_script( - specifier, - *media_type, - *is_script, - )? { + if self + .shared + .cjs_tracker + .is_cjs_with_known_is_script(specifier, *media_type, *is_script) + .map_err(JsErrorBox::from_err)? + { return Ok(Some(CodeOrDeferredEmit::Cjs { specifier, media_type: *media_type, @@ -850,16 +902,16 @@ impl ModuleLoader specifier: &str, referrer: &str, _kind: deno_core::ResolutionKind, - ) -> Result { + ) -> Result { fn ensure_not_jsr_non_jsr_remote_import( specifier: &ModuleSpecifier, referrer: &ModuleSpecifier, - ) -> Result<(), AnyError> { + ) -> Result<(), JsErrorBox> { if referrer.as_str().starts_with(jsr_url().as_str()) && !specifier.as_str().starts_with(jsr_url().as_str()) && matches!(specifier.scheme(), "http" | "https") { - bail!("Importing {} blocked. JSR packages cannot import non-JSR remote modules for security reasons.", specifier); + return Err(JsErrorBox::generic(format!("Importing {} blocked. JSR packages cannot import non-JSR remote modules for security reasons.", specifier))); } Ok(()) } @@ -912,7 +964,7 @@ impl ModuleLoader specifier: &ModuleSpecifier, _maybe_referrer: Option, is_dynamic: bool, - ) -> Pin>>> { + ) -> Pin>>> { self.0.shared.in_flight_loads_tracker.increase(); if self.0.shared.in_npm_pkg_checker.in_npm_package(specifier) { return Box::pin(deno_core::futures::future::ready(Ok(()))); @@ -961,7 +1013,8 @@ impl ModuleLoader permissions, None, ) - .await?; + .await + .map_err(JsErrorBox::from_err)?; update_permit.commit(); Ok(()) } @@ -1090,12 +1143,13 @@ impl ModuleGraphUpdatePermit for WorkerModuleGraphUpdatePermit { #[derive(Debug)] struct CliNodeRequireLoader { - cjs_tracker: Arc, + cjs_tracker: Arc, emitter: Arc, sys: CliSys, graph_container: TGraphContainer, - in_npm_pkg_checker: Arc, - npm_resolver: Arc, + in_npm_pkg_checker: DenoInNpmPackageChecker, + npm_registry_permission_checker: + Arc>, } impl NodeRequireLoader @@ -1105,33 +1159,37 @@ impl NodeRequireLoader &self, permissions: &mut dyn deno_runtime::deno_node::NodePermissions, path: &'a Path, - ) -> Result, AnyError> { + ) -> Result, JsErrorBox> { if let Ok(url) = deno_path_util::url_from_file_path(path) { // allow reading if it's in the module graph if self.graph_container.graph().get(&url).is_some() { - return Ok(std::borrow::Cow::Borrowed(path)); + return Ok(Cow::Borrowed(path)); } } - self.npm_resolver.ensure_read_permission(permissions, path) + self + .npm_registry_permission_checker + .ensure_read_permission(permissions, path) + .map_err(JsErrorBox::from_err) } fn load_text_file_lossy( &self, path: &Path, - ) -> Result, AnyError> { + ) -> Result, JsErrorBox> { // todo(dsherret): use the preloaded module from the graph if available? let media_type = MediaType::from_path(path); - let text = self.sys.fs_read_to_string_lossy(path)?; + let text = self + .sys + .fs_read_to_string_lossy(path) + .map_err(JsErrorBox::from_err)?; if media_type.is_emittable() { - let specifier = deno_path_util::url_from_file_path(path)?; + let specifier = deno_path_util::url_from_file_path(path) + .map_err(JsErrorBox::from_err)?; if self.in_npm_pkg_checker.in_npm_package(&specifier) { - return Err( - NotSupportedKindInNpmError { - media_type, - specifier, - } - .into(), - ); + return Err(JsErrorBox::from_err(NotSupportedKindInNpmError { + media_type, + specifier, + })); } self .emitter @@ -1145,6 +1203,7 @@ impl NodeRequireLoader &text.into(), ) .map(Cow::Owned) + .map_err(JsErrorBox::from_err) } else { Ok(text) } @@ -1161,9 +1220,10 @@ impl NodeRequireLoader #[cfg(test)] mod tests { - use super::*; use deno_graph::ParsedSourceStore; + use super::*; + #[tokio::test] async fn test_inflight_module_loads_tracker() { let tracker = InFlightModuleLoadsTracker { diff --git a/cli/node.rs b/cli/node.rs index 4a87d26ee0..892e25914a 100644 --- a/cli/node.rs +++ b/cli/node.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::sync::Arc; @@ -7,6 +7,7 @@ use deno_ast::MediaType; use deno_ast::ModuleSpecifier; use deno_core::error::AnyError; use deno_graph::ParsedSourceStore; +use deno_resolver::npm::DenoInNpmPackageChecker; use deno_runtime::deno_fs; use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker; use node_resolver::analyze::CjsAnalysis as ExtNodeCjsAnalysis; @@ -19,15 +20,22 @@ use serde::Serialize; use crate::cache::CacheDBHash; use crate::cache::NodeAnalysisCache; use crate::cache::ParsedSourceCache; -use crate::resolver::CjsTracker; +use crate::npm::CliNpmResolver; +use crate::resolver::CliCjsTracker; use crate::sys::CliSys; pub type CliNodeCodeTranslator = NodeCodeTranslator< CliCjsCodeAnalyzer, + DenoInNpmPackageChecker, RealIsBuiltInNodeModuleChecker, + CliNpmResolver, + CliSys, +>; +pub type CliNodeResolver = deno_runtime::deno_node::NodeResolver< + DenoInNpmPackageChecker, + CliNpmResolver, CliSys, >; -pub type CliNodeResolver = deno_runtime::deno_node::NodeResolver; pub type CliPackageJsonResolver = node_resolver::PackageJsonResolver; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -43,7 +51,7 @@ pub enum CliCjsAnalysis { pub struct CliCjsCodeAnalyzer { cache: NodeAnalysisCache, - cjs_tracker: Arc, + cjs_tracker: Arc, fs: deno_fs::FileSystemRc, parsed_source_cache: Option>, } @@ -51,7 +59,7 @@ pub struct CliCjsCodeAnalyzer { impl CliCjsCodeAnalyzer { pub fn new( cache: NodeAnalysisCache, - cjs_tracker: Arc, + cjs_tracker: Arc, fs: deno_fs::FileSystemRc, parsed_source_cache: Option>, ) -> Self { @@ -68,7 +76,7 @@ impl CliCjsCodeAnalyzer { specifier: &ModuleSpecifier, source: &str, ) -> Result { - let source_hash = CacheDBHash::from_source(source); + let source_hash = CacheDBHash::from_hashable(source); if let Some(analysis) = self.cache.get_cjs_analysis(specifier.as_str(), source_hash) { diff --git a/cli/npm/byonm.rs b/cli/npm/byonm.rs index ca89a7399e..d52b222074 100644 --- a/cli/npm/byonm.rs +++ b/cli/npm/byonm.rs @@ -1,97 +1,32 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use std::borrow::Cow; -use std::path::Path; use std::sync::Arc; -use crate::sys::CliSys; -use deno_core::error::AnyError; use deno_core::serde_json; use deno_resolver::npm::ByonmNpmResolver; use deno_resolver::npm::ByonmNpmResolverCreateOptions; -use deno_resolver::npm::CliNpmReqResolver; -use deno_runtime::deno_node::NodePermissions; -use deno_runtime::ops::process::NpmProcessStateProvider; -use node_resolver::NpmPackageFolderResolver; +use deno_runtime::deno_process::NpmProcessStateProvider; use crate::args::NpmProcessState; use crate::args::NpmProcessStateKind; - -use super::CliNpmResolver; -use super::InnerCliNpmResolverRef; +use crate::sys::CliSys; pub type CliByonmNpmResolverCreateOptions = ByonmNpmResolverCreateOptions; pub type CliByonmNpmResolver = ByonmNpmResolver; -// todo(dsherret): the services hanging off `CliNpmResolver` doesn't seem ideal. We should probably decouple. #[derive(Debug)] -struct CliByonmWrapper(Arc); +pub struct CliByonmNpmProcessStateProvider(pub Arc); -impl NpmProcessStateProvider for CliByonmWrapper { +impl NpmProcessStateProvider for CliByonmNpmProcessStateProvider { fn get_npm_process_state(&self) -> String { serde_json::to_string(&NpmProcessState { kind: NpmProcessStateKind::Byonm, local_node_modules_path: self .0 - .root_node_modules_dir() + .root_node_modules_path() .map(|p| p.to_string_lossy().to_string()), }) .unwrap() } } - -impl CliNpmResolver for CliByonmNpmResolver { - fn into_npm_pkg_folder_resolver( - self: Arc, - ) -> Arc { - self - } - - fn into_npm_req_resolver(self: Arc) -> Arc { - self - } - - fn into_process_state_provider( - self: Arc, - ) -> Arc { - Arc::new(CliByonmWrapper(self)) - } - - fn into_maybe_byonm(self: Arc) -> Option> { - Some(self) - } - - fn clone_snapshotted(&self) -> Arc { - Arc::new(self.clone()) - } - - fn as_inner(&self) -> InnerCliNpmResolverRef { - InnerCliNpmResolverRef::Byonm(self) - } - - fn root_node_modules_path(&self) -> Option<&Path> { - self.root_node_modules_dir() - } - - fn ensure_read_permission<'a>( - &self, - permissions: &mut dyn NodePermissions, - path: &'a Path, - ) -> Result, AnyError> { - if !path - .components() - .any(|c| c.as_os_str().to_ascii_lowercase() == "node_modules") - { - permissions.check_read_path(path).map_err(Into::into) - } else { - Ok(Cow::Borrowed(path)) - } - } - - fn check_state_hash(&self) -> Option { - // it is very difficult to determine the check state hash for byonm - // so we just return None to signify check caching is not supported - None - } -} diff --git a/cli/npm/managed/resolvers/common/bin_entries.rs b/cli/npm/installer/common/bin_entries.rs similarity index 79% rename from cli/npm/managed/resolvers/common/bin_entries.rs rename to cli/npm/installer/common/bin_entries.rs index ca47b9a086..2f7bed285a 100644 --- a/cli/npm/managed/resolvers/common/bin_entries.rs +++ b/cli/npm/installer/common/bin_entries.rs @@ -1,16 +1,15 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::npm::managed::NpmResolutionPackage; -use deno_core::anyhow::Context; -use deno_core::error::AnyError; -use deno_npm::resolution::NpmResolutionSnapshot; -use deno_npm::NpmPackageId; use std::collections::HashMap; use std::collections::HashSet; use std::collections::VecDeque; use std::path::Path; use std::path::PathBuf; +use deno_npm::resolution::NpmResolutionSnapshot; +use deno_npm::NpmPackageId; +use deno_npm::NpmResolutionPackage; + #[derive(Default)] pub struct BinEntries<'a> { /// Packages that have colliding bin names @@ -48,6 +47,48 @@ pub fn warn_missing_entrypoint( ); } +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum BinEntriesError { + #[class(inherit)] + #[error("Creating '{path}'")] + Creating { + path: PathBuf, + #[source] + #[inherit] + source: std::io::Error, + }, + #[cfg(unix)] + #[class(inherit)] + #[error("Setting permissions on '{path}'")] + Permissions { + path: PathBuf, + #[source] + #[inherit] + source: std::io::Error, + }, + #[class(inherit)] + #[error("Can't set up '{name}' bin at {path}")] + SetUpBin { + name: String, + path: PathBuf, + #[source] + #[inherit] + source: Box, + }, + #[cfg(unix)] + #[class(inherit)] + #[error("Setting permissions on '{path}'")] + RemoveBinSymlink { + path: PathBuf, + #[source] + #[inherit] + source: std::io::Error, + }, + #[class(inherit)] + #[error(transparent)] + Io(#[from] std::io::Error), +} + impl<'a> BinEntries<'a> { pub fn new() -> Self { Self::default() @@ -90,15 +131,15 @@ impl<'a> BinEntries<'a> { mut already_seen: impl FnMut( &Path, &str, // bin script - ) -> Result<(), AnyError>, + ) -> Result<(), BinEntriesError>, mut new: impl FnMut( &NpmResolutionPackage, &Path, &str, // bin name &str, // bin script - ) -> Result<(), AnyError>, + ) -> Result<(), BinEntriesError>, mut filter: impl FnMut(&NpmResolutionPackage) -> bool, - ) -> Result<(), AnyError> { + ) -> Result<(), BinEntriesError> { if !self.collisions.is_empty() && !self.sorted { // walking the dependency tree to find out the depth of each package // is sort of expensive, so we only do it if there's a collision @@ -166,11 +207,14 @@ impl<'a> BinEntries<'a> { bin_node_modules_dir_path: &Path, filter: impl FnMut(&NpmResolutionPackage) -> bool, mut handler: impl FnMut(&EntrySetupOutcome<'_>), - ) -> Result<(), AnyError> { + ) -> Result<(), BinEntriesError> { if !self.entries.is_empty() && !bin_node_modules_dir_path.exists() { - std::fs::create_dir_all(bin_node_modules_dir_path).with_context( - || format!("Creating '{}'", bin_node_modules_dir_path.display()), - )?; + std::fs::create_dir_all(bin_node_modules_dir_path).map_err(|source| { + BinEntriesError::Creating { + path: bin_node_modules_dir_path.to_path_buf(), + source, + } + })?; } self.for_each_entry( @@ -207,7 +251,7 @@ impl<'a> BinEntries<'a> { snapshot: &NpmResolutionSnapshot, bin_node_modules_dir_path: &Path, handler: impl FnMut(&EntrySetupOutcome<'_>), - ) -> Result<(), AnyError> { + ) -> Result<(), BinEntriesError> { self.set_up_entries_filtered( snapshot, bin_node_modules_dir_path, @@ -224,7 +268,7 @@ impl<'a> BinEntries<'a> { bin_node_modules_dir_path: &Path, handler: impl FnMut(&EntrySetupOutcome<'_>), only: &HashSet<&NpmPackageId>, - ) -> Result<(), AnyError> { + ) -> Result<(), BinEntriesError> { self.set_up_entries_filtered( snapshot, bin_node_modules_dir_path, @@ -299,7 +343,7 @@ pub fn set_up_bin_entry<'a>( #[allow(unused_variables)] bin_script: &str, #[allow(unused_variables)] package_path: &'a Path, bin_node_modules_dir_path: &Path, -) -> Result, AnyError> { +) -> Result, BinEntriesError> { #[cfg(windows)] { set_up_bin_shim(package, bin_name, bin_node_modules_dir_path)?; @@ -322,14 +366,16 @@ fn set_up_bin_shim( package: &NpmResolutionPackage, bin_name: &str, bin_node_modules_dir_path: &Path, -) -> Result<(), AnyError> { +) -> Result<(), BinEntriesError> { use std::fs; let mut cmd_shim = bin_node_modules_dir_path.join(bin_name); cmd_shim.set_extension("cmd"); let shim = format!("@deno run -A npm:{}/{bin_name} %*", package.id.nv); - fs::write(&cmd_shim, shim).with_context(|| { - format!("Can't set up '{}' bin at {}", bin_name, cmd_shim.display()) + fs::write(&cmd_shim, shim).map_err(|err| BinEntriesError::SetUpBin { + name: bin_name.to_string(), + path: cmd_shim.clone(), + source: Box::new(err.into()), })?; Ok(()) @@ -338,7 +384,7 @@ fn set_up_bin_shim( #[cfg(unix)] /// Make the file at `path` executable if it exists. /// Returns `true` if the file exists, `false` otherwise. -fn make_executable_if_exists(path: &Path) -> Result { +fn make_executable_if_exists(path: &Path) -> Result { use std::io; use std::os::unix::fs::PermissionsExt; let mut perms = match std::fs::metadata(path) { @@ -353,8 +399,11 @@ fn make_executable_if_exists(path: &Path) -> Result { if perms.mode() & 0o111 == 0 { // if the original file is not executable, make it executable perms.set_mode(perms.mode() | 0o111); - std::fs::set_permissions(path, perms).with_context(|| { - format!("Setting permissions on '{}'", path.display()) + std::fs::set_permissions(path, perms).map_err(|source| { + BinEntriesError::Permissions { + path: path.to_path_buf(), + source, + } })?; } @@ -393,14 +442,18 @@ fn symlink_bin_entry<'a>( bin_script: &str, package_path: &'a Path, bin_node_modules_dir_path: &Path, -) -> Result, AnyError> { +) -> Result, BinEntriesError> { use std::io; use std::os::unix::fs::symlink; let link = bin_node_modules_dir_path.join(bin_name); let original = package_path.join(bin_script); - let found = make_executable_if_exists(&original).with_context(|| { - format!("Can't set up '{}' bin at {}", bin_name, original.display()) + let found = make_executable_if_exists(&original).map_err(|source| { + BinEntriesError::SetUpBin { + name: bin_name.to_string(), + path: original.to_path_buf(), + source: Box::new(source), + } })?; if !found { return Ok(EntrySetupOutcome::MissingEntrypoint { @@ -418,27 +471,25 @@ fn symlink_bin_entry<'a>( if let Err(err) = symlink(&original_relative, &link) { if err.kind() == io::ErrorKind::AlreadyExists { // remove and retry - std::fs::remove_file(&link).with_context(|| { - format!( - "Failed to remove existing bin symlink at {}", - link.display() - ) + std::fs::remove_file(&link).map_err(|source| { + BinEntriesError::RemoveBinSymlink { + path: link.clone(), + source, + } })?; - symlink(&original_relative, &link).with_context(|| { - format!( - "Can't set up '{}' bin at {}", - bin_name, - original_relative.display() - ) + symlink(&original_relative, &link).map_err(|source| { + BinEntriesError::SetUpBin { + name: bin_name.to_string(), + path: original_relative.to_path_buf(), + source: Box::new(source.into()), + } })?; return Ok(EntrySetupOutcome::Success); } - return Err(err).with_context(|| { - format!( - "Can't set up '{}' bin at {}", - bin_name, - original_relative.display() - ) + return Err(BinEntriesError::SetUpBin { + name: bin_name.to_string(), + path: original_relative.to_path_buf(), + source: Box::new(err.into()), }); } diff --git a/cli/npm/managed/resolvers/common/lifecycle_scripts.rs b/cli/npm/installer/common/lifecycle_scripts.rs similarity index 90% rename from cli/npm/managed/resolvers/common/lifecycle_scripts.rs rename to cli/npm/installer/common/lifecycle_scripts.rs index 958c4bcd19..3238b8d023 100644 --- a/cli/npm/managed/resolvers/common/lifecycle_scripts.rs +++ b/cli/npm/installer/common/lifecycle_scripts.rs @@ -1,24 +1,23 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::borrow::Cow; +use std::collections::HashSet; +use std::path::Path; +use std::path::PathBuf; +use std::rc::Rc; + +use deno_core::error::AnyError; +use deno_npm::resolution::NpmResolutionSnapshot; +use deno_npm::NpmResolutionPackage; +use deno_runtime::deno_io::FromRawIoHandle; +use deno_semver::package::PackageNv; +use deno_semver::Version; +use deno_task_shell::KillSignal; use super::bin_entries::BinEntries; use crate::args::LifecycleScriptsConfig; use crate::task_runner::TaskStdio; use crate::util::progress_bar::ProgressBar; -use deno_core::anyhow::Context; -use deno_npm::resolution::NpmResolutionSnapshot; -use deno_runtime::deno_io::FromRawIoHandle; -use deno_semver::package::PackageNv; -use deno_semver::Version; -use deno_task_shell::KillSignal; -use std::borrow::Cow; -use std::collections::HashSet; -use std::rc::Rc; - -use std::path::Path; -use std::path::PathBuf; - -use deno_core::error::AnyError; -use deno_npm::NpmResolutionPackage; pub trait LifecycleScriptsStrategy { fn can_run_scripts(&self) -> bool { @@ -29,7 +28,7 @@ pub trait LifecycleScriptsStrategy { fn warn_on_scripts_not_run( &self, packages: &[(&NpmResolutionPackage, PathBuf)], - ) -> Result<(), AnyError>; + ) -> Result<(), std::io::Error>; fn has_warned(&self, package: &NpmResolutionPackage) -> bool; @@ -38,7 +37,7 @@ pub trait LifecycleScriptsStrategy { fn did_run_scripts( &self, package: &NpmResolutionPackage, - ) -> Result<(), AnyError>; + ) -> Result<(), std::io::Error>; } pub struct LifecycleScripts<'a> { @@ -84,6 +83,27 @@ fn is_broken_default_install_script(script: &str, package_path: &Path) -> bool { script == "node-gyp rebuild" && !package_path.join("binding.gyp").exists() } +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum LifecycleScriptsError { + #[class(inherit)] + #[error(transparent)] + Io(#[from] std::io::Error), + #[class(inherit)] + #[error(transparent)] + BinEntries(#[from] super::bin_entries::BinEntriesError), + #[class(inherit)] + #[error( + "failed to create npm process state tempfile for running lifecycle scripts" + )] + CreateNpmProcessState(#[source] std::io::Error), + #[class(generic)] + #[error(transparent)] + Task(AnyError), + #[class(generic)] + #[error("failed to run scripts for packages: {}", .0.join(", "))] + RunScripts(Vec), +} + impl<'a> LifecycleScripts<'a> { pub fn can_run_scripts(&self, package_nv: &PackageNv) -> bool { if !self.strategy.can_run_scripts() { @@ -141,7 +161,7 @@ impl<'a> LifecycleScripts<'a> { } } - pub fn warn_not_run_scripts(&self) -> Result<(), AnyError> { + pub fn warn_not_run_scripts(&self) -> Result<(), std::io::Error> { if !self.packages_with_scripts_not_run.is_empty() { self .strategy @@ -156,7 +176,7 @@ impl<'a> LifecycleScripts<'a> { packages: &[NpmResolutionPackage], root_node_modules_dir_path: &Path, progress_bar: &ProgressBar, - ) -> Result<(), AnyError> { + ) -> Result<(), LifecycleScriptsError> { let kill_signal = KillSignal::default(); let _drop_signal = kill_signal.clone().drop_guard(); // we don't run with signals forwarded because once signals @@ -179,7 +199,7 @@ impl<'a> LifecycleScripts<'a> { root_node_modules_dir_path: &Path, progress_bar: &ProgressBar, kill_signal: KillSignal, - ) -> Result<(), AnyError> { + ) -> Result<(), LifecycleScriptsError> { self.warn_not_run_scripts()?; let get_package_path = |p: &NpmResolutionPackage| self.strategy.package_path(p); @@ -198,7 +218,7 @@ impl<'a> LifecycleScripts<'a> { snapshot, packages, get_package_path, - )?; + ); let init_cwd = &self.config.initial_cwd; let process_state = crate::npm::managed::npm_process_state( snapshot.as_valid_serialized(), @@ -220,14 +240,15 @@ impl<'a> LifecycleScripts<'a> { // However, if we concurrently run scripts in the future we will // have to have multiple temp files. let temp_file_fd = - deno_runtime::ops::process::npm_process_state_tempfile( + deno_runtime::deno_process::npm_process_state_tempfile( process_state.as_bytes(), - ).context("failed to create npm process state tempfile for running lifecycle scripts")?; + ) + .map_err(LifecycleScriptsError::CreateNpmProcessState)?; // SAFETY: fd/handle is valid let _temp_file = unsafe { std::fs::File::from_raw_io_handle(temp_file_fd) }; // make sure the file gets closed env_vars.insert( - deno_runtime::ops::process::NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME + deno_runtime::deno_process::NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME .to_string(), (temp_file_fd as usize).to_string(), ); @@ -240,7 +261,7 @@ impl<'a> LifecycleScripts<'a> { package, snapshot, get_package_path, - )?; + ); for script_name in ["preinstall", "install", "postinstall"] { if let Some(script) = package.scripts.get(script_name) { if script_name == "install" @@ -273,7 +294,8 @@ impl<'a> LifecycleScripts<'a> { kill_signal: kill_signal.clone(), }, ) - .await?; + .await + .map_err(LifecycleScriptsError::Task)?; let stdout = stdout.unwrap(); let stderr = stderr.unwrap(); if exit_code != 0 { @@ -322,14 +344,12 @@ impl<'a> LifecycleScripts<'a> { if failed_packages.is_empty() { Ok(()) } else { - Err(AnyError::msg(format!( - "failed to run scripts for packages: {}", + Err(LifecycleScriptsError::RunScripts( failed_packages .iter() .map(|p| p.to_string()) - .collect::>() - .join(", ") - ))) + .collect::>(), + )) } } } @@ -349,7 +369,7 @@ fn resolve_baseline_custom_commands<'a>( snapshot: &'a NpmResolutionSnapshot, packages: &'a [NpmResolutionPackage], get_package_path: impl Fn(&NpmResolutionPackage) -> PathBuf, -) -> Result { +) -> crate::task_runner::TaskCustomCommands { let mut custom_commands = crate::task_runner::TaskCustomCommands::new(); custom_commands .insert("npx".to_string(), Rc::new(crate::task_runner::NpxCommand)); @@ -390,7 +410,7 @@ fn resolve_custom_commands_from_packages< snapshot: &'a NpmResolutionSnapshot, packages: P, get_package_path: impl Fn(&'a NpmResolutionPackage) -> PathBuf, -) -> Result { +) -> crate::task_runner::TaskCustomCommands { for package in packages { let package_path = get_package_path(package); @@ -409,7 +429,7 @@ fn resolve_custom_commands_from_packages< ); } - Ok(commands) + commands } // resolves the custom commands from the dependencies of a package @@ -420,7 +440,7 @@ fn resolve_custom_commands_from_deps( package: &NpmResolutionPackage, snapshot: &NpmResolutionSnapshot, get_package_path: impl Fn(&NpmResolutionPackage) -> PathBuf, -) -> Result { +) -> crate::task_runner::TaskCustomCommands { let mut bin_entries = BinEntries::new(); resolve_custom_commands_from_packages( &mut bin_entries, diff --git a/cli/npm/installer/common/mod.rs b/cli/npm/installer/common/mod.rs new file mode 100644 index 0000000000..bd22a58f03 --- /dev/null +++ b/cli/npm/installer/common/mod.rs @@ -0,0 +1,18 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +use async_trait::async_trait; +use deno_error::JsErrorBox; + +use super::PackageCaching; + +pub mod bin_entries; +pub mod lifecycle_scripts; + +/// Part of the resolution that interacts with the file system. +#[async_trait(?Send)] +pub trait NpmPackageFsInstaller: std::fmt::Debug + Send + Sync { + async fn cache_packages<'a>( + &self, + caching: PackageCaching<'a>, + ) -> Result<(), JsErrorBox>; +} diff --git a/cli/npm/installer/global.rs b/cli/npm/installer/global.rs new file mode 100644 index 0000000000..a6b296c6d8 --- /dev/null +++ b/cli/npm/installer/global.rs @@ -0,0 +1,190 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::borrow::Cow; +use std::path::Path; +use std::path::PathBuf; +use std::sync::Arc; + +use async_trait::async_trait; +use deno_core::futures::stream::FuturesUnordered; +use deno_core::futures::StreamExt; +use deno_error::JsErrorBox; +use deno_npm::NpmResolutionPackage; +use deno_npm::NpmSystemInfo; +use deno_resolver::npm::managed::NpmResolutionCell; + +use super::common::lifecycle_scripts::LifecycleScriptsStrategy; +use super::common::NpmPackageFsInstaller; +use super::PackageCaching; +use crate::args::LifecycleScriptsConfig; +use crate::cache::FastInsecureHasher; +use crate::colors; +use crate::npm::CliNpmCache; +use crate::npm::CliNpmTarballCache; + +/// Resolves packages from the global npm cache. +#[derive(Debug)] +pub struct GlobalNpmPackageInstaller { + cache: Arc, + tarball_cache: Arc, + resolution: Arc, + lifecycle_scripts: LifecycleScriptsConfig, + system_info: NpmSystemInfo, +} + +impl GlobalNpmPackageInstaller { + pub fn new( + cache: Arc, + tarball_cache: Arc, + resolution: Arc, + lifecycle_scripts: LifecycleScriptsConfig, + system_info: NpmSystemInfo, + ) -> Self { + Self { + cache, + tarball_cache, + resolution, + lifecycle_scripts, + system_info, + } + } +} + +#[async_trait(?Send)] +impl NpmPackageFsInstaller for GlobalNpmPackageInstaller { + async fn cache_packages<'a>( + &self, + caching: PackageCaching<'a>, + ) -> Result<(), JsErrorBox> { + let package_partitions = match caching { + PackageCaching::All => self + .resolution + .all_system_packages_partitioned(&self.system_info), + PackageCaching::Only(reqs) => self + .resolution + .subset(&reqs) + .all_system_packages_partitioned(&self.system_info), + }; + cache_packages(&package_partitions.packages, &self.tarball_cache) + .await + .map_err(JsErrorBox::from_err)?; + + // create the copy package folders + for copy in package_partitions.copy_packages { + self + .cache + .ensure_copy_package(©.get_package_cache_folder_id()) + .map_err(JsErrorBox::from_err)?; + } + + let mut lifecycle_scripts = + super::common::lifecycle_scripts::LifecycleScripts::new( + &self.lifecycle_scripts, + GlobalLifecycleScripts::new(self, &self.lifecycle_scripts.root_dir), + ); + for package in &package_partitions.packages { + let package_folder = self.cache.package_folder_for_nv(&package.id.nv); + lifecycle_scripts.add(package, Cow::Borrowed(&package_folder)); + } + + lifecycle_scripts + .warn_not_run_scripts() + .map_err(JsErrorBox::from_err)?; + + Ok(()) + } +} + +async fn cache_packages( + packages: &[NpmResolutionPackage], + tarball_cache: &Arc, +) -> Result<(), deno_npm_cache::EnsurePackageError> { + let mut futures_unordered = FuturesUnordered::new(); + for package in packages { + futures_unordered.push(async move { + tarball_cache + .ensure_package(&package.id.nv, &package.dist) + .await + }); + } + while let Some(result) = futures_unordered.next().await { + // surface the first error + result?; + } + Ok(()) +} + +struct GlobalLifecycleScripts<'a> { + installer: &'a GlobalNpmPackageInstaller, + path_hash: u64, +} + +impl<'a> GlobalLifecycleScripts<'a> { + fn new(installer: &'a GlobalNpmPackageInstaller, root_dir: &Path) -> Self { + let mut hasher = FastInsecureHasher::new_without_deno_version(); + hasher.write(root_dir.to_string_lossy().as_bytes()); + let path_hash = hasher.finish(); + Self { + installer, + path_hash, + } + } + + fn warned_scripts_file(&self, package: &NpmResolutionPackage) -> PathBuf { + self + .package_path(package) + .join(format!(".scripts-warned-{}", self.path_hash)) + } +} + +impl<'a> super::common::lifecycle_scripts::LifecycleScriptsStrategy + for GlobalLifecycleScripts<'a> +{ + fn can_run_scripts(&self) -> bool { + false + } + fn package_path(&self, package: &NpmResolutionPackage) -> PathBuf { + self.installer.cache.package_folder_for_nv(&package.id.nv) + } + + fn warn_on_scripts_not_run( + &self, + packages: &[(&NpmResolutionPackage, PathBuf)], + ) -> std::result::Result<(), std::io::Error> { + log::warn!("{} The following packages contained npm lifecycle scripts ({}) that were not executed:", colors::yellow("Warning"), colors::gray("preinstall/install/postinstall")); + for (package, _) in packages { + log::warn!("┠─ {}", colors::gray(format!("npm:{}", package.id.nv))); + } + log::warn!("┃"); + log::warn!( + "┠─ {}", + colors::italic("This may cause the packages to not work correctly.") + ); + log::warn!("┠─ {}", colors::italic("Lifecycle scripts are only supported when using a `node_modules` directory.")); + log::warn!( + "┠─ {}", + colors::italic("Enable it in your deno config file:") + ); + log::warn!("┖─ {}", colors::bold("\"nodeModulesDir\": \"auto\"")); + + for (package, _) in packages { + std::fs::write(self.warned_scripts_file(package), "")?; + } + Ok(()) + } + + fn did_run_scripts( + &self, + _package: &NpmResolutionPackage, + ) -> Result<(), std::io::Error> { + Ok(()) + } + + fn has_warned(&self, package: &NpmResolutionPackage) -> bool { + self.warned_scripts_file(package).exists() + } + + fn has_run(&self, _package: &NpmResolutionPackage) -> bool { + false + } +} diff --git a/cli/npm/managed/resolvers/local.rs b/cli/npm/installer/local.rs similarity index 75% rename from cli/npm/managed/resolvers/local.rs rename to cli/npm/installer/local.rs index 5c93c228e8..87288c6c8e 100644 --- a/cli/npm/managed/resolvers/local.rs +++ b/cli/npm/installer/local.rs @@ -1,12 +1,12 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. //! Code for local node_modules resolution. -use std::borrow::Cow; use std::cell::RefCell; use std::cmp::Ordering; use std::collections::hash_map::Entry; use std::collections::BTreeMap; +use std::collections::BTreeSet; use std::collections::HashMap; use std::collections::HashSet; use std::fs; @@ -16,38 +16,28 @@ use std::rc::Rc; use std::sync::Arc; use async_trait::async_trait; -use deno_ast::ModuleSpecifier; -use deno_cache_dir::npm::mixed_case_package_name_decode; -use deno_core::anyhow::Context; -use deno_core::error::AnyError; use deno_core::futures::stream::FuturesUnordered; use deno_core::futures::StreamExt; use deno_core::parking_lot::Mutex; -use deno_core::url::Url; +use deno_error::JsErrorBox; use deno_npm::resolution::NpmResolutionSnapshot; -use deno_npm::NpmPackageCacheFolderId; -use deno_npm::NpmPackageId; use deno_npm::NpmResolutionPackage; use deno_npm::NpmSystemInfo; use deno_path_util::fs::atomic_write_file_with_retries; -use deno_path_util::fs::canonicalize_path_maybe_not_exists; -use deno_resolver::npm::normalize_pkg_name_for_node_modules_deno_folder; -use deno_runtime::deno_node::NodePermissions; +use deno_resolver::npm::get_package_folder_id_folder_name; +use deno_resolver::npm::managed::NpmResolutionCell; use deno_semver::package::PackageNv; use deno_semver::StackString; -use node_resolver::errors::PackageFolderResolveError; -use node_resolver::errors::PackageFolderResolveIoError; -use node_resolver::errors::PackageNotFoundError; -use node_resolver::errors::ReferrerNotFoundError; use serde::Deserialize; use serde::Serialize; -use sys_traits::FsMetadata; +use super::common::bin_entries; +use super::common::NpmPackageFsInstaller; +use super::PackageCaching; use crate::args::LifecycleScriptsConfig; use crate::args::NpmInstallDepsProvider; use crate::cache::CACHE_PERM; use crate::colors; -use crate::npm::managed::PackageCaching; use crate::npm::CliNpmCache; use crate::npm::CliNpmTarballCache; use crate::sys::CliSys; @@ -57,40 +47,33 @@ use crate::util::fs::LaxSingleProcessFsFlag; use crate::util::progress_bar::ProgressBar; use crate::util::progress_bar::ProgressMessagePrompt; -use super::super::resolution::NpmResolution; -use super::common::bin_entries; -use super::common::NpmPackageFsResolver; -use super::common::RegistryReadPermissionChecker; - /// Resolver that creates a local node_modules directory /// and resolves packages from it. #[derive(Debug)] -pub struct LocalNpmPackageResolver { +pub struct LocalNpmPackageInstaller { cache: Arc, npm_install_deps_provider: Arc, progress_bar: ProgressBar, - resolution: Arc, + resolution: Arc, sys: CliSys, tarball_cache: Arc, - root_node_modules_path: PathBuf, - root_node_modules_url: Url, - system_info: NpmSystemInfo, - registry_read_permission_checker: RegistryReadPermissionChecker, lifecycle_scripts: LifecycleScriptsConfig, + root_node_modules_path: PathBuf, + system_info: NpmSystemInfo, } -impl LocalNpmPackageResolver { +impl LocalNpmPackageInstaller { #[allow(clippy::too_many_arguments)] pub fn new( cache: Arc, npm_install_deps_provider: Arc, progress_bar: ProgressBar, - resolution: Arc, + resolution: Arc, sys: CliSys, tarball_cache: Arc, node_modules_folder: PathBuf, - system_info: NpmSystemInfo, lifecycle_scripts: LifecycleScriptsConfig, + system_info: NpmSystemInfo, ) -> Self { Self { cache, @@ -98,167 +81,20 @@ impl LocalNpmPackageResolver { progress_bar, resolution, tarball_cache, - registry_read_permission_checker: RegistryReadPermissionChecker::new( - sys.clone(), - node_modules_folder.clone(), - ), sys, - root_node_modules_url: Url::from_directory_path(&node_modules_folder) - .unwrap(), + lifecycle_scripts, root_node_modules_path: node_modules_folder, system_info, - lifecycle_scripts, } } - - fn resolve_package_root(&self, path: &Path) -> PathBuf { - let mut last_found = path; - loop { - let parent = last_found.parent().unwrap(); - if parent.file_name().unwrap() == "node_modules" { - return last_found.to_path_buf(); - } else { - last_found = parent; - } - } - } - - fn resolve_folder_for_specifier( - &self, - specifier: &ModuleSpecifier, - ) -> Result, std::io::Error> { - let Some(relative_url) = - self.root_node_modules_url.make_relative(specifier) - else { - return Ok(None); - }; - if relative_url.starts_with("../") { - return Ok(None); - } - // it's within the directory, so use it - let Some(path) = specifier.to_file_path().ok() else { - return Ok(None); - }; - // Canonicalize the path so it's not pointing to the symlinked directory - // in `node_modules` directory of the referrer. - canonicalize_path_maybe_not_exists(&self.sys, &path).map(Some) - } - - fn resolve_package_folder_from_specifier( - &self, - specifier: &ModuleSpecifier, - ) -> Result, AnyError> { - let Some(local_path) = self.resolve_folder_for_specifier(specifier)? else { - return Ok(None); - }; - let package_root_path = self.resolve_package_root(&local_path); - Ok(Some(package_root_path)) - } } #[async_trait(?Send)] -impl NpmPackageFsResolver for LocalNpmPackageResolver { - fn node_modules_path(&self) -> Option<&Path> { - Some(self.root_node_modules_path.as_ref()) - } - - fn maybe_package_folder(&self, id: &NpmPackageId) -> Option { - let cache_folder_id = self - .resolution - .resolve_pkg_cache_folder_id_from_pkg_id(id)?; - // package is stored at: - // node_modules/.deno//node_modules/ - Some( - self - .root_node_modules_path - .join(".deno") - .join(get_package_folder_id_folder_name(&cache_folder_id)) - .join("node_modules") - .join(&cache_folder_id.nv.name), - ) - } - - fn resolve_package_folder_from_package( - &self, - name: &str, - referrer: &ModuleSpecifier, - ) -> Result { - let maybe_local_path = self - .resolve_folder_for_specifier(referrer) - .map_err(|err| PackageFolderResolveIoError { - package_name: name.to_string(), - referrer: referrer.clone(), - source: err, - })?; - let Some(local_path) = maybe_local_path else { - return Err( - ReferrerNotFoundError { - referrer: referrer.clone(), - referrer_extra: None, - } - .into(), - ); - }; - let package_root_path = self.resolve_package_root(&local_path); - let mut current_folder = package_root_path.as_path(); - while let Some(parent_folder) = current_folder.parent() { - current_folder = parent_folder; - let node_modules_folder = if current_folder.ends_with("node_modules") { - Cow::Borrowed(current_folder) - } else { - Cow::Owned(current_folder.join("node_modules")) - }; - - let sub_dir = join_package_name(&node_modules_folder, name); - if self.sys.fs_is_dir_no_err(&sub_dir) { - return Ok(sub_dir); - } - - if current_folder == self.root_node_modules_path { - break; - } - } - - Err( - PackageNotFoundError { - package_name: name.to_string(), - referrer: referrer.clone(), - referrer_extra: None, - } - .into(), - ) - } - - fn resolve_package_cache_folder_id_from_specifier( - &self, - specifier: &ModuleSpecifier, - ) -> Result, AnyError> { - let Some(folder_path) = - self.resolve_package_folder_from_specifier(specifier)? - else { - return Ok(None); - }; - // ex. project/node_modules/.deno/preact@10.24.3/node_modules/preact/ - let Some(node_modules_ancestor) = folder_path - .ancestors() - .find(|ancestor| ancestor.ends_with("node_modules")) - else { - return Ok(None); - }; - let Some(folder_name) = - node_modules_ancestor.parent().and_then(|p| p.file_name()) - else { - return Ok(None); - }; - Ok(get_package_folder_id_from_folder_name( - &folder_name.to_string_lossy(), - )) - } - +impl NpmPackageFsInstaller for LocalNpmPackageInstaller { async fn cache_packages<'a>( &self, caching: PackageCaching<'a>, - ) -> Result<(), AnyError> { + ) -> Result<(), JsErrorBox> { let snapshot = match caching { PackageCaching::All => self.resolution.snapshot(), PackageCaching::Only(reqs) => self.resolution.subset(&reqs), @@ -270,20 +106,12 @@ impl NpmPackageFsResolver for LocalNpmPackageResolver { &self.progress_bar, &self.tarball_cache, &self.root_node_modules_path, + &self.sys, &self.system_info, &self.lifecycle_scripts, ) .await - } - - fn ensure_read_permission<'a>( - &self, - permissions: &mut dyn NodePermissions, - path: &'a Path, - ) -> Result, AnyError> { - self - .registry_read_permission_checker - .ensure_registry_read_permission(permissions, path) + .map_err(JsErrorBox::from_err) } } @@ -302,6 +130,38 @@ fn local_node_modules_package_contents_path( .join(&package.id.nv.name) } +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum SyncResolutionWithFsError { + #[class(inherit)] + #[error("Creating '{path}'")] + Creating { + path: PathBuf, + #[source] + #[inherit] + source: std::io::Error, + }, + #[class(inherit)] + #[error(transparent)] + CopyDirRecursive(#[from] crate::util::fs::CopyDirRecursiveError), + #[class(inherit)] + #[error(transparent)] + SymlinkPackageDir(#[from] SymlinkPackageDirError), + #[class(inherit)] + #[error(transparent)] + BinEntries(#[from] bin_entries::BinEntriesError), + #[class(inherit)] + #[error(transparent)] + LifecycleScripts( + #[from] super::common::lifecycle_scripts::LifecycleScriptsError, + ), + #[class(inherit)] + #[error(transparent)] + Io(#[from] std::io::Error), + #[class(inherit)] + #[error(transparent)] + Other(#[from] JsErrorBox), +} + /// Creates a pnpm style folder structure. #[allow(clippy::too_many_arguments)] async fn sync_resolution_with_fs( @@ -311,9 +171,10 @@ async fn sync_resolution_with_fs( progress_bar: &ProgressBar, tarball_cache: &Arc, root_node_modules_dir_path: &Path, + sys: &CliSys, system_info: &NpmSystemInfo, lifecycle_scripts: &LifecycleScriptsConfig, -) -> Result<(), AnyError> { +) -> Result<(), SyncResolutionWithFsError> { if snapshot.is_empty() && npm_install_deps_provider.workspace_pkgs().is_empty() { @@ -328,12 +189,18 @@ async fn sync_resolution_with_fs( let deno_local_registry_dir = root_node_modules_dir_path.join(".deno"); let deno_node_modules_dir = deno_local_registry_dir.join("node_modules"); - fs::create_dir_all(&deno_node_modules_dir).with_context(|| { - format!("Creating '{}'", deno_local_registry_dir.display()) + fs::create_dir_all(&deno_node_modules_dir).map_err(|source| { + SyncResolutionWithFsError::Creating { + path: deno_local_registry_dir.to_path_buf(), + source, + } })?; let bin_node_modules_dir_path = root_node_modules_dir_path.join(".bin"); - fs::create_dir_all(&bin_node_modules_dir_path).with_context(|| { - format!("Creating '{}'", bin_node_modules_dir_path.display()) + fs::create_dir_all(&bin_node_modules_dir_path).map_err(|source| { + SyncResolutionWithFsError::Creating { + path: deno_local_registry_dir.to_path_buf(), + source, + } })?; let single_process_lock = LaxSingleProcessFsFlag::lock( @@ -370,10 +237,10 @@ async fn sync_resolution_with_fs( ); let packages_with_deprecation_warnings = Arc::new(Mutex::new(Vec::new())); - let mut package_tags: HashMap<&PackageNv, Vec<&str>> = HashMap::new(); + let mut package_tags: HashMap<&PackageNv, BTreeSet<&str>> = HashMap::new(); for (package_req, package_nv) in snapshot.package_reqs() { if let Some(tag) = package_req.version_req.tag() { - package_tags.entry(package_nv).or_default().push(tag); + package_tags.entry(package_nv).or_default().insert(tag); } } @@ -393,7 +260,17 @@ async fn sync_resolution_with_fs( let folder_path = deno_local_registry_dir.join(&package_folder_name); let tags = package_tags .get(&package.id.nv) - .map(|tags| tags.join(",")) + .map(|tags| { + capacity_builder::StringBuilder::::build(|builder| { + for (i, tag) in tags.iter().enumerate() { + if i > 0 { + builder.append(',') + } + builder.append(*tag); + } + }) + .unwrap() + }) .unwrap_or_default(); enum PackageFolderState { UpToDate, @@ -427,7 +304,8 @@ async fn sync_resolution_with_fs( cache_futures.push(async move { tarball_cache .ensure_package(&package.id.nv, &package.dist) - .await?; + .await + .map_err(JsErrorBox::from_err)?; let pb_guard = progress_bar.update_with_prompt( ProgressMessagePrompt::Initialize, &package.id.nv.to_string(), @@ -439,15 +317,18 @@ async fn sync_resolution_with_fs( deno_core::unsync::spawn_blocking({ let package_path = package_path.clone(); + let sys = sys.clone(); move || { - clone_dir_recursive(&cache_folder, &package_path)?; + clone_dir_recursive(&sys, &cache_folder, &package_path)?; // write out a file that indicates this folder has been initialized fs::write(initialized_file, tags)?; - Ok::<_, AnyError>(()) + Ok::<_, SyncResolutionWithFsError>(()) } }) - .await??; + .await + .map_err(JsErrorBox::from_err)? + .map_err(JsErrorBox::from_err)?; if package.bin.is_some() { bin_entries_to_setup.borrow_mut().add(package, package_path); @@ -461,7 +342,7 @@ async fn sync_resolution_with_fs( // finally stop showing the progress bar drop(pb_guard); // explicit for clarity - Ok::<_, AnyError>(()) + Ok::<_, JsErrorBox>(()) }); } else if matches!(package_state, PackageFolderState::TagsOutdated) { fs::write(initialized_file, tags)?; @@ -497,7 +378,7 @@ async fn sync_resolution_with_fs( &package.id.nv.name, ); - clone_dir_recursive(&source_path, &package_path)?; + clone_dir_recursive(sys, &source_path, &package_path)?; // write out a file that indicates this folder has been initialized fs::write(initialized_file, "")?; } @@ -596,8 +477,11 @@ async fn sync_resolution_with_fs( // symlink the dep into the package's child node_modules folder let dest_node_modules = remote.base_dir.join("node_modules"); if !existing_child_node_modules_dirs.contains(&dest_node_modules) { - fs::create_dir_all(&dest_node_modules).with_context(|| { - format!("Creating '{}'", dest_node_modules.display()) + fs::create_dir_all(&dest_node_modules).map_err(|source| { + SyncResolutionWithFsError::Creating { + path: dest_node_modules.clone(), + source, + } })?; existing_child_node_modules_dirs.insert(dest_node_modules.clone()); } @@ -812,7 +696,7 @@ impl<'a> super::common::lifecycle_scripts::LifecycleScriptsStrategy fn did_run_scripts( &self, package: &NpmResolutionPackage, - ) -> std::result::Result<(), deno_core::anyhow::Error> { + ) -> std::result::Result<(), std::io::Error> { std::fs::write(self.ran_scripts_file(package), "")?; Ok(()) } @@ -820,7 +704,7 @@ impl<'a> super::common::lifecycle_scripts::LifecycleScriptsStrategy fn warn_on_scripts_not_run( &self, packages: &[(&NpmResolutionPackage, std::path::PathBuf)], - ) -> Result<(), AnyError> { + ) -> Result<(), std::io::Error> { if !packages.is_empty() { log::warn!("{} The following packages contained npm lifecycle scripts ({}) that were not executed:", colors::yellow("Warning"), colors::gray("preinstall/install/postinstall")); @@ -1003,52 +887,42 @@ impl SetupCache { } } -fn get_package_folder_id_folder_name( - folder_id: &NpmPackageCacheFolderId, -) -> String { - let copy_str = if folder_id.copy_index == 0 { - Cow::Borrowed("") - } else { - Cow::Owned(format!("_{}", folder_id.copy_index)) - }; - let nv = &folder_id.nv; - let name = normalize_pkg_name_for_node_modules_deno_folder(&nv.name); - format!("{}@{}{}", name, nv.version, copy_str) -} - -fn get_package_folder_id_from_folder_name( - folder_name: &str, -) -> Option { - let folder_name = folder_name.replace('+', "/"); - let (name, ending) = folder_name.rsplit_once('@')?; - let name: StackString = if let Some(encoded_name) = name.strip_prefix('_') { - StackString::from_string(mixed_case_package_name_decode(encoded_name)?) - } else { - name.into() - }; - let (raw_version, copy_index) = match ending.split_once('_') { - Some((raw_version, copy_index)) => { - let copy_index = copy_index.parse::().ok()?; - (raw_version, copy_index) - } - None => (ending, 0), - }; - let version = deno_semver::Version::parse_from_npm(raw_version).ok()?; - Some(NpmPackageCacheFolderId { - nv: PackageNv { name, version }, - copy_index, - }) +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum SymlinkPackageDirError { + #[class(inherit)] + #[error("Creating '{parent}'")] + Creating { + parent: PathBuf, + #[source] + #[inherit] + source: std::io::Error, + }, + #[class(inherit)] + #[error(transparent)] + Other(#[from] std::io::Error), + #[cfg(windows)] + #[class(inherit)] + #[error("Creating junction in node_modules folder")] + FailedCreatingJunction { + #[source] + #[inherit] + source: std::io::Error, + }, } fn symlink_package_dir( old_path: &Path, new_path: &Path, -) -> Result<(), AnyError> { +) -> Result<(), SymlinkPackageDirError> { let new_parent = new_path.parent().unwrap(); if new_parent.file_name().unwrap() != "node_modules" { // create the parent folder that will contain the symlink - fs::create_dir_all(new_parent) - .with_context(|| format!("Creating '{}'", new_parent.display()))?; + fs::create_dir_all(new_parent).map_err(|source| { + SymlinkPackageDirError::Creating { + parent: new_parent.to_path_buf(), + source, + } + })?; } // need to delete the previous symlink before creating a new one @@ -1064,7 +938,8 @@ fn symlink_package_dir( } #[cfg(not(windows))] { - symlink_dir(&old_path_relative, new_path).map_err(Into::into) + symlink_dir(&crate::sys::CliSys::default(), &old_path_relative, new_path) + .map_err(Into::into) } } @@ -1073,7 +948,7 @@ fn junction_or_symlink_dir( old_path_relative: &Path, old_path: &Path, new_path: &Path, -) -> Result<(), AnyError> { +) -> Result<(), SymlinkPackageDirError> { static USE_JUNCTIONS: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); @@ -1082,18 +957,21 @@ fn junction_or_symlink_dir( // needing to elevate privileges on Windows. // Note: junctions don't support relative paths, so we need to use the // absolute path here. - return junction::create(old_path, new_path) - .context("Failed creating junction in node_modules folder"); + return junction::create(old_path, new_path).map_err(|source| { + SymlinkPackageDirError::FailedCreatingJunction { source } + }); } - match symlink_dir(old_path_relative, new_path) { + match symlink_dir(&crate::sys::CliSys::default(), old_path_relative, new_path) + { Ok(()) => Ok(()), Err(symlink_err) if symlink_err.kind() == std::io::ErrorKind::PermissionDenied => { USE_JUNCTIONS.store(true, std::sync::atomic::Ordering::Relaxed); - junction::create(old_path, new_path) - .context("Failed creating junction in node_modules folder") + junction::create(old_path, new_path).map_err(|source| { + SymlinkPackageDirError::FailedCreatingJunction { source } + }) } Err(symlink_err) => { log::warn!( @@ -1101,8 +979,9 @@ fn junction_or_symlink_dir( colors::yellow("Warning") ); USE_JUNCTIONS.store(true, std::sync::atomic::Ordering::Relaxed); - junction::create(old_path, new_path) - .context("Failed creating junction in node_modules folder") + junction::create(old_path, new_path).map_err(|source| { + SymlinkPackageDirError::FailedCreatingJunction { source } + }) } } } @@ -1118,37 +997,10 @@ fn join_package_name(path: &Path, package_name: &str) -> PathBuf { #[cfg(test)] mod test { - use deno_npm::NpmPackageCacheFolderId; - use deno_semver::package::PackageNv; use test_util::TempDir; use super::*; - #[test] - fn test_get_package_folder_id_folder_name() { - let cases = vec![ - ( - NpmPackageCacheFolderId { - nv: PackageNv::from_str("@types/foo@1.2.3").unwrap(), - copy_index: 1, - }, - "@types+foo@1.2.3_1".to_string(), - ), - ( - NpmPackageCacheFolderId { - nv: PackageNv::from_str("JSON@3.2.1").unwrap(), - copy_index: 0, - }, - "_jjju6tq@3.2.1".to_string(), - ), - ]; - for (input, output) in cases { - assert_eq!(get_package_folder_id_folder_name(&input), output); - let folder_id = get_package_folder_id_from_folder_name(&output).unwrap(); - assert_eq!(folder_id, input); - } - } - #[test] fn test_setup_cache() { let temp_dir = TempDir::new(); diff --git a/cli/npm/installer/mod.rs b/cli/npm/installer/mod.rs new file mode 100644 index 0000000000..58b9cb1bc7 --- /dev/null +++ b/cli/npm/installer/mod.rs @@ -0,0 +1,283 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::borrow::Cow; +use std::path::PathBuf; +use std::sync::Arc; + +use deno_core::error::AnyError; +use deno_core::unsync::sync::AtomicFlag; +use deno_error::JsErrorBox; +use deno_npm::registry::NpmPackageInfo; +use deno_npm::registry::NpmRegistryPackageInfoLoadError; +use deno_npm::NpmSystemInfo; +use deno_resolver::npm::managed::NpmResolutionCell; +use deno_runtime::colors; +use deno_semver::package::PackageReq; + +pub use self::common::NpmPackageFsInstaller; +use self::global::GlobalNpmPackageInstaller; +use self::local::LocalNpmPackageInstaller; +pub use self::resolution::AddPkgReqsResult; +pub use self::resolution::NpmResolutionInstaller; +use super::NpmResolutionInitializer; +use crate::args::CliLockfile; +use crate::args::LifecycleScriptsConfig; +use crate::args::NpmInstallDepsProvider; +use crate::args::PackageJsonDepValueParseWithLocationError; +use crate::npm::CliNpmCache; +use crate::npm::CliNpmTarballCache; +use crate::sys::CliSys; +use crate::util::progress_bar::ProgressBar; + +mod common; +mod global; +mod local; +mod resolution; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum PackageCaching<'a> { + Only(Cow<'a, [PackageReq]>), + All, +} + +#[derive(Debug)] +pub struct NpmInstaller { + fs_installer: Arc, + npm_install_deps_provider: Arc, + npm_resolution_initializer: Arc, + npm_resolution_installer: Arc, + maybe_lockfile: Option>, + npm_resolution: Arc, + top_level_install_flag: AtomicFlag, +} + +impl NpmInstaller { + #[allow(clippy::too_many_arguments)] + pub fn new( + npm_cache: Arc, + npm_install_deps_provider: Arc, + npm_resolution: Arc, + npm_resolution_initializer: Arc, + npm_resolution_installer: Arc, + progress_bar: &ProgressBar, + sys: CliSys, + tarball_cache: Arc, + maybe_lockfile: Option>, + maybe_node_modules_path: Option, + lifecycle_scripts: LifecycleScriptsConfig, + system_info: NpmSystemInfo, + ) -> Self { + let fs_installer: Arc = + match maybe_node_modules_path { + Some(node_modules_folder) => Arc::new(LocalNpmPackageInstaller::new( + npm_cache, + npm_install_deps_provider.clone(), + progress_bar.clone(), + npm_resolution.clone(), + sys, + tarball_cache, + node_modules_folder, + lifecycle_scripts, + system_info, + )), + None => Arc::new(GlobalNpmPackageInstaller::new( + npm_cache, + tarball_cache, + npm_resolution.clone(), + lifecycle_scripts, + system_info, + )), + }; + Self { + fs_installer, + npm_install_deps_provider, + npm_resolution, + npm_resolution_initializer, + npm_resolution_installer, + maybe_lockfile, + top_level_install_flag: Default::default(), + } + } + + /// Adds package requirements to the resolver and ensures everything is setup. + /// This includes setting up the `node_modules` directory, if applicable. + pub async fn add_and_cache_package_reqs( + &self, + packages: &[PackageReq], + ) -> Result<(), JsErrorBox> { + self.npm_resolution_initializer.ensure_initialized().await?; + self + .add_package_reqs_raw( + packages, + Some(PackageCaching::Only(packages.into())), + ) + .await + .dependencies_result + } + + pub async fn add_package_reqs_no_cache( + &self, + packages: &[PackageReq], + ) -> Result<(), JsErrorBox> { + self.npm_resolution_initializer.ensure_initialized().await?; + self + .add_package_reqs_raw(packages, None) + .await + .dependencies_result + } + + pub async fn add_package_reqs( + &self, + packages: &[PackageReq], + caching: PackageCaching<'_>, + ) -> Result<(), JsErrorBox> { + self + .add_package_reqs_raw(packages, Some(caching)) + .await + .dependencies_result + } + + pub async fn add_package_reqs_raw<'a>( + &self, + packages: &[PackageReq], + caching: Option>, + ) -> AddPkgReqsResult { + if packages.is_empty() { + return AddPkgReqsResult { + dependencies_result: Ok(()), + results: vec![], + }; + } + + #[cfg(debug_assertions)] + self.npm_resolution_initializer.debug_assert_initialized(); + + let mut result = self + .npm_resolution_installer + .add_package_reqs(packages) + .await; + + if result.dependencies_result.is_ok() { + if let Some(lockfile) = self.maybe_lockfile.as_ref() { + result.dependencies_result = lockfile.error_if_changed(); + } + } + if result.dependencies_result.is_ok() { + if let Some(caching) = caching { + result.dependencies_result = self.cache_packages(caching).await; + } + } + + result + } + + /// Sets package requirements to the resolver, removing old requirements and adding new ones. + /// + /// This will retrieve and resolve package information, but not cache any package files. + pub async fn set_package_reqs( + &self, + packages: &[PackageReq], + ) -> Result<(), AnyError> { + self + .npm_resolution_installer + .set_package_reqs(packages) + .await + } + + pub async fn inject_synthetic_types_node_package( + &self, + ) -> Result<(), JsErrorBox> { + self.npm_resolution_initializer.ensure_initialized().await?; + let reqs = &[PackageReq::from_str("@types/node").unwrap()]; + // add and ensure this isn't added to the lockfile + self + .add_package_reqs(reqs, PackageCaching::Only(reqs.into())) + .await?; + + Ok(()) + } + + pub async fn cache_package_info( + &self, + package_name: &str, + ) -> Result, NpmRegistryPackageInfoLoadError> { + self + .npm_resolution_installer + .cache_package_info(package_name) + .await + } + + pub async fn cache_packages( + &self, + caching: PackageCaching<'_>, + ) -> Result<(), JsErrorBox> { + self.npm_resolution_initializer.ensure_initialized().await?; + self.fs_installer.cache_packages(caching).await + } + + pub fn ensure_no_pkg_json_dep_errors( + &self, + ) -> Result<(), Box> { + for err in self.npm_install_deps_provider.pkg_json_dep_errors() { + match err.source.as_kind() { + deno_package_json::PackageJsonDepValueParseErrorKind::VersionReq(_) => { + return Err(Box::new(err.clone())); + } + deno_package_json::PackageJsonDepValueParseErrorKind::Unsupported { + .. + } => { + // only warn for this one + log::warn!( + "{} {}\n at {}", + colors::yellow("Warning"), + err.source, + err.location, + ) + } + } + } + Ok(()) + } + + /// Ensures that the top level `package.json` dependencies are installed. + /// This may set up the `node_modules` directory. + /// + /// Returns `true` if the top level packages are already installed. A + /// return value of `false` means that new packages were added to the NPM resolution. + pub async fn ensure_top_level_package_json_install( + &self, + ) -> Result { + if !self.top_level_install_flag.raise() { + return Ok(true); // already did this + } + + self.npm_resolution_initializer.ensure_initialized().await?; + + let pkg_json_remote_pkgs = self.npm_install_deps_provider.remote_pkgs(); + if pkg_json_remote_pkgs.is_empty() { + return Ok(true); + } + + // check if something needs resolving before bothering to load all + // the package information (which is slow) + if pkg_json_remote_pkgs.iter().all(|pkg| { + self + .npm_resolution + .resolve_pkg_id_from_pkg_req(&pkg.req) + .is_ok() + }) { + log::debug!( + "All package.json deps resolvable. Skipping top level install." + ); + return Ok(true); // everything is already resolvable + } + + let pkg_reqs = pkg_json_remote_pkgs + .iter() + .map(|pkg| pkg.req.clone()) + .collect::>(); + self.add_package_reqs_no_cache(&pkg_reqs).await?; + + Ok(false) + } +} diff --git a/cli/npm/managed/resolution.rs b/cli/npm/installer/resolution.rs similarity index 50% rename from cli/npm/managed/resolution.rs rename to cli/npm/installer/resolution.rs index 5d9fcf4646..06bbcd4f76 100644 --- a/cli/npm/managed/resolution.rs +++ b/cli/npm/installer/resolution.rs @@ -1,27 +1,21 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use std::collections::HashMap; use std::collections::HashSet; use std::sync::Arc; use capacity_builder::StringBuilder; use deno_core::error::AnyError; +use deno_error::JsErrorBox; use deno_lockfile::NpmPackageDependencyLockfileInfo; use deno_lockfile::NpmPackageLockfileInfo; +use deno_npm::registry::NpmPackageInfo; use deno_npm::registry::NpmRegistryApi; +use deno_npm::registry::NpmRegistryPackageInfoLoadError; use deno_npm::resolution::AddPkgReqsOptions; -use deno_npm::resolution::NpmPackagesPartitioned; use deno_npm::resolution::NpmResolutionError; use deno_npm::resolution::NpmResolutionSnapshot; -use deno_npm::resolution::PackageCacheFolderIdNotFoundError; -use deno_npm::resolution::PackageNotFoundFromReferrerError; -use deno_npm::resolution::PackageNvNotFoundError; -use deno_npm::resolution::PackageReqNotFoundError; -use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot; -use deno_npm::NpmPackageCacheFolderId; -use deno_npm::NpmPackageId; use deno_npm::NpmResolutionPackage; -use deno_npm::NpmSystemInfo; +use deno_resolver::npm::managed::NpmResolutionCell; use deno_semver::jsr::JsrDepPackageReq; use deno_semver::package::PackageNv; use deno_semver::package::PackageReq; @@ -30,7 +24,7 @@ use deno_semver::VersionReq; use crate::args::CliLockfile; use crate::npm::CliNpmRegistryInfoProvider; -use crate::util::sync::SyncReadAsyncWriteLock; +use crate::util::sync::TaskQueue; pub struct AddPkgReqsResult { /// Results from adding the individual packages. @@ -39,63 +33,51 @@ pub struct AddPkgReqsResult { /// package requirements. pub results: Vec>, /// The final result of resolving and caching all the package requirements. - pub dependencies_result: Result<(), AnyError>, + pub dependencies_result: Result<(), JsErrorBox>, } -/// Handles updating and storing npm resolution in memory where the underlying -/// snapshot can be updated concurrently. Additionally handles updating the lockfile -/// based on changes to the resolution. -/// -/// This does not interact with the file system. -pub struct NpmResolution { +/// Updates the npm resolution with the provided package requirements. +#[derive(Debug)] +pub struct NpmResolutionInstaller { registry_info_provider: Arc, - snapshot: SyncReadAsyncWriteLock, + resolution: Arc, maybe_lockfile: Option>, + update_queue: TaskQueue, } -impl std::fmt::Debug for NpmResolution { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let snapshot = self.snapshot.read(); - f.debug_struct("NpmResolution") - .field("snapshot", &snapshot.as_valid_serialized().as_serialized()) - .finish() - } -} - -impl NpmResolution { - pub fn from_serialized( - registry_info_provider: Arc, - initial_snapshot: Option, - maybe_lockfile: Option>, - ) -> Self { - let snapshot = - NpmResolutionSnapshot::new(initial_snapshot.unwrap_or_default()); - Self::new(registry_info_provider, snapshot, maybe_lockfile) - } - +impl NpmResolutionInstaller { pub fn new( registry_info_provider: Arc, - initial_snapshot: NpmResolutionSnapshot, + resolution: Arc, maybe_lockfile: Option>, ) -> Self { Self { registry_info_provider, - snapshot: SyncReadAsyncWriteLock::new(initial_snapshot), + resolution, maybe_lockfile, + update_queue: Default::default(), } } + pub async fn cache_package_info( + &self, + package_name: &str, + ) -> Result, NpmRegistryPackageInfoLoadError> { + // this will internally cache the package information + self.registry_info_provider.package_info(package_name).await + } + pub async fn add_package_reqs( &self, package_reqs: &[PackageReq], ) -> AddPkgReqsResult { // only allow one thread in here at a time - let snapshot_lock = self.snapshot.acquire().await; + let _snapshot_lock = self.update_queue.acquire().await; let result = add_package_reqs_to_snapshot( &self.registry_info_provider, package_reqs, self.maybe_lockfile.clone(), - || snapshot_lock.read().clone(), + || self.resolution.snapshot(), ) .await; @@ -103,10 +85,10 @@ impl NpmResolution { results: result.results, dependencies_result: match result.dep_graph_result { Ok(snapshot) => { - *snapshot_lock.write() = snapshot; + self.resolution.set_snapshot(snapshot); Ok(()) } - Err(err) => Err(err.into()), + Err(err) => Err(JsErrorBox::from_err(err)), }, } } @@ -116,7 +98,7 @@ impl NpmResolution { package_reqs: &[PackageReq], ) -> Result<(), AnyError> { // only allow one thread in here at a time - let snapshot_lock = self.snapshot.acquire().await; + let _snapshot_lock = self.update_queue.acquire().await; let reqs_set = package_reqs.iter().collect::>(); let snapshot = add_package_reqs_to_snapshot( @@ -124,7 +106,7 @@ impl NpmResolution { package_reqs, self.maybe_lockfile.clone(), || { - let snapshot = snapshot_lock.read().clone(); + let snapshot = self.resolution.snapshot(); let has_removed_package = !snapshot .package_reqs() .keys() @@ -140,127 +122,10 @@ impl NpmResolution { .await .into_result()?; - *snapshot_lock.write() = snapshot; + self.resolution.set_snapshot(snapshot); Ok(()) } - - pub fn resolve_pkg_cache_folder_id_from_pkg_id( - &self, - id: &NpmPackageId, - ) -> Option { - self - .snapshot - .read() - .package_from_id(id) - .map(|p| p.get_package_cache_folder_id()) - } - - pub fn resolve_pkg_id_from_pkg_cache_folder_id( - &self, - id: &NpmPackageCacheFolderId, - ) -> Result { - self - .snapshot - .read() - .resolve_pkg_from_pkg_cache_folder_id(id) - .map(|pkg| pkg.id.clone()) - } - - pub fn resolve_package_from_package( - &self, - name: &str, - referrer: &NpmPackageCacheFolderId, - ) -> Result> { - self - .snapshot - .read() - .resolve_package_from_package(name, referrer) - .cloned() - } - - /// Resolve a node package from a deno module. - pub fn resolve_pkg_id_from_pkg_req( - &self, - req: &PackageReq, - ) -> Result { - self - .snapshot - .read() - .resolve_pkg_from_pkg_req(req) - .map(|pkg| pkg.id.clone()) - } - - pub fn resolve_pkg_reqs_from_pkg_id( - &self, - id: &NpmPackageId, - ) -> Vec { - let snapshot = self.snapshot.read(); - let mut pkg_reqs = snapshot - .package_reqs() - .iter() - .filter(|(_, nv)| *nv == &id.nv) - .map(|(req, _)| req.clone()) - .collect::>(); - pkg_reqs.sort(); // be deterministic - pkg_reqs - } - - pub fn resolve_pkg_id_from_deno_module( - &self, - id: &PackageNv, - ) -> Result { - self - .snapshot - .read() - .resolve_package_from_deno_module(id) - .map(|pkg| pkg.id.clone()) - } - - pub fn package_reqs(&self) -> HashMap { - self.snapshot.read().package_reqs().clone() - } - - pub fn all_system_packages( - &self, - system_info: &NpmSystemInfo, - ) -> Vec { - self.snapshot.read().all_system_packages(system_info) - } - - pub fn all_system_packages_partitioned( - &self, - system_info: &NpmSystemInfo, - ) -> NpmPackagesPartitioned { - self - .snapshot - .read() - .all_system_packages_partitioned(system_info) - } - - pub fn snapshot(&self) -> NpmResolutionSnapshot { - self.snapshot.read().clone() - } - - pub fn serialized_valid_snapshot( - &self, - ) -> ValidSerializedNpmResolutionSnapshot { - self.snapshot.read().as_valid_serialized() - } - - pub fn serialized_valid_snapshot_for_system( - &self, - system_info: &NpmSystemInfo, - ) -> ValidSerializedNpmResolutionSnapshot { - self - .snapshot - .read() - .as_valid_serialized_for_system(system_info) - } - - pub fn subset(&self, package_reqs: &[PackageReq]) -> NpmResolutionSnapshot { - self.snapshot.read().subset(package_reqs) - } } async fn add_package_reqs_to_snapshot( @@ -333,6 +198,25 @@ fn populate_lockfile_from_snapshot( lockfile: &CliLockfile, snapshot: &NpmResolutionSnapshot, ) { + fn npm_package_to_lockfile_info( + pkg: &NpmResolutionPackage, + ) -> NpmPackageLockfileInfo { + let dependencies = pkg + .dependencies + .iter() + .map(|(name, id)| NpmPackageDependencyLockfileInfo { + name: name.clone(), + id: id.as_serialized(), + }) + .collect(); + + NpmPackageLockfileInfo { + serialized_id: pkg.id.as_serialized(), + integrity: pkg.dist.integrity().for_lockfile(), + dependencies, + } + } + let mut lockfile = lockfile.lock(); for (package_req, nv) in snapshot.package_reqs() { let id = &snapshot.resolve_package_from_deno_module(nv).unwrap().id; @@ -351,22 +235,3 @@ fn populate_lockfile_from_snapshot( lockfile.insert_npm_package(npm_package_to_lockfile_info(package)); } } - -fn npm_package_to_lockfile_info( - pkg: &NpmResolutionPackage, -) -> NpmPackageLockfileInfo { - let dependencies = pkg - .dependencies - .iter() - .map(|(name, id)| NpmPackageDependencyLockfileInfo { - name: name.clone(), - id: id.as_serialized(), - }) - .collect(); - - NpmPackageLockfileInfo { - serialized_id: pkg.id.as_serialized(), - integrity: pkg.dist.integrity().for_lockfile(), - dependencies, - } -} diff --git a/cli/npm/managed.rs b/cli/npm/managed.rs new file mode 100644 index 0000000000..049e3541db --- /dev/null +++ b/cli/npm/managed.rs @@ -0,0 +1,233 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::path::Path; +use std::path::PathBuf; +use std::sync::Arc; + +use deno_core::parking_lot::Mutex; +use deno_core::serde_json; +use deno_error::JsError; +use deno_error::JsErrorBox; +use deno_npm::registry::NpmRegistryApi; +use deno_npm::resolution::NpmResolutionSnapshot; +use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot; +use deno_resolver::npm::managed::ManagedNpmResolverCreateOptions; +use deno_resolver::npm::managed::NpmResolutionCell; +use deno_resolver::npm::ManagedNpmResolverRc; +use deno_runtime::deno_process::NpmProcessStateProvider; +use thiserror::Error; + +use super::CliNpmRegistryInfoProvider; +use crate::args::CliLockfile; +use crate::args::NpmProcessState; +use crate::args::NpmProcessStateKind; +use crate::sys::CliSys; + +pub type CliManagedNpmResolverCreateOptions = + ManagedNpmResolverCreateOptions; + +#[derive(Debug, Clone)] +pub enum CliNpmResolverManagedSnapshotOption { + ResolveFromLockfile(Arc), + Specified(Option), +} + +#[derive(Debug)] +enum SyncState { + Pending(Option), + Err(ResolveSnapshotError), + Success, +} + +#[derive(Debug)] +pub struct NpmResolutionInitializer { + npm_registry_info_provider: Arc, + npm_resolution: Arc, + queue: tokio::sync::Mutex<()>, + sync_state: Mutex, +} + +impl NpmResolutionInitializer { + pub fn new( + npm_registry_info_provider: Arc, + npm_resolution: Arc, + snapshot_option: CliNpmResolverManagedSnapshotOption, + ) -> Self { + Self { + npm_registry_info_provider, + npm_resolution, + queue: tokio::sync::Mutex::new(()), + sync_state: Mutex::new(SyncState::Pending(Some(snapshot_option))), + } + } + + #[cfg(debug_assertions)] + pub fn debug_assert_initialized(&self) { + if !matches!(*self.sync_state.lock(), SyncState::Success) { + panic!("debug assert: npm resolution must be initialized before calling this code"); + } + } + + pub async fn ensure_initialized(&self) -> Result<(), JsErrorBox> { + // fast exit if not pending + { + match &*self.sync_state.lock() { + SyncState::Pending(_) => {} + SyncState::Err(err) => return Err(JsErrorBox::from_err(err.clone())), + SyncState::Success => return Ok(()), + } + } + + // only allow one task in here at a time + let _guard = self.queue.lock().await; + + let snapshot_option = { + let mut sync_state = self.sync_state.lock(); + match &mut *sync_state { + SyncState::Pending(snapshot_option) => { + // this should never panic, but if it does it means that a + // previous future was dropped while initialization occurred... + // that should never happen because this is initialized during + // startup + snapshot_option.take().unwrap() + } + // another thread updated the state while we were waiting + SyncState::Err(resolve_snapshot_error) => { + return Err(JsErrorBox::from_err(resolve_snapshot_error.clone())); + } + SyncState::Success => { + return Ok(()); + } + } + }; + + match resolve_snapshot(&self.npm_registry_info_provider, snapshot_option) + .await + { + Ok(maybe_snapshot) => { + if let Some(snapshot) = maybe_snapshot { + self + .npm_resolution + .set_snapshot(NpmResolutionSnapshot::new(snapshot)); + } + let mut sync_state = self.sync_state.lock(); + *sync_state = SyncState::Success; + Ok(()) + } + Err(err) => { + let mut sync_state = self.sync_state.lock(); + *sync_state = SyncState::Err(err.clone()); + Err(JsErrorBox::from_err(err)) + } + } + } +} + +#[derive(Debug, Error, Clone, JsError)] +#[error("failed reading lockfile '{}'", lockfile_path.display())] +#[class(inherit)] +pub struct ResolveSnapshotError { + lockfile_path: PathBuf, + #[inherit] + #[source] + source: SnapshotFromLockfileError, +} + +impl ResolveSnapshotError { + pub fn maybe_integrity_check_error( + &self, + ) -> Option<&deno_npm::resolution::IntegrityCheckFailedError> { + match &self.source { + SnapshotFromLockfileError::SnapshotFromLockfile( + deno_npm::resolution::SnapshotFromLockfileError::IntegrityCheckFailed( + err, + ), + ) => Some(err), + _ => None, + } + } +} + +async fn resolve_snapshot( + registry_info_provider: &Arc, + snapshot: CliNpmResolverManagedSnapshotOption, +) -> Result, ResolveSnapshotError> +{ + match snapshot { + CliNpmResolverManagedSnapshotOption::ResolveFromLockfile(lockfile) => { + if !lockfile.overwrite() { + let snapshot = snapshot_from_lockfile( + lockfile.clone(), + ®istry_info_provider.as_npm_registry_api(), + ) + .await + .map_err(|source| ResolveSnapshotError { + lockfile_path: lockfile.filename.clone(), + source, + })?; + Ok(Some(snapshot)) + } else { + Ok(None) + } + } + CliNpmResolverManagedSnapshotOption::Specified(snapshot) => Ok(snapshot), + } +} + +#[derive(Debug, Error, Clone, JsError)] +pub enum SnapshotFromLockfileError { + #[error(transparent)] + #[class(inherit)] + IncompleteError( + #[from] deno_npm::resolution::IncompleteSnapshotFromLockfileError, + ), + #[error(transparent)] + #[class(inherit)] + SnapshotFromLockfile(#[from] deno_npm::resolution::SnapshotFromLockfileError), +} + +async fn snapshot_from_lockfile( + lockfile: Arc, + api: &dyn NpmRegistryApi, +) -> Result { + let (incomplete_snapshot, skip_integrity_check) = { + let lock = lockfile.lock(); + ( + deno_npm::resolution::incomplete_snapshot_from_lockfile(&lock)?, + lock.overwrite, + ) + }; + let snapshot = deno_npm::resolution::snapshot_from_lockfile( + deno_npm::resolution::SnapshotFromLockfileParams { + incomplete_snapshot, + api, + skip_integrity_check, + }, + ) + .await?; + Ok(snapshot) +} + +pub fn npm_process_state( + snapshot: ValidSerializedNpmResolutionSnapshot, + node_modules_path: Option<&Path>, +) -> String { + serde_json::to_string(&NpmProcessState { + kind: NpmProcessStateKind::Snapshot(snapshot.into_serialized()), + local_node_modules_path: node_modules_path + .map(|p| p.to_string_lossy().to_string()), + }) + .unwrap() +} + +#[derive(Debug)] +pub struct CliManagedNpmProcessStateProvider(pub ManagedNpmResolverRc); + +impl NpmProcessStateProvider for CliManagedNpmProcessStateProvider { + fn get_npm_process_state(&self) -> String { + npm_process_state( + self.0.resolution().serialized_valid_snapshot(), + self.0.root_node_modules_path(), + ) + } +} diff --git a/cli/npm/managed/mod.rs b/cli/npm/managed/mod.rs deleted file mode 100644 index 97a87dd9b8..0000000000 --- a/cli/npm/managed/mod.rs +++ /dev/null @@ -1,786 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. - -use std::borrow::Cow; -use std::path::Path; -use std::path::PathBuf; -use std::sync::Arc; - -use crate::sys::CliSys; -use deno_ast::ModuleSpecifier; -use deno_cache_dir::npm::NpmCacheDir; -use deno_core::anyhow::Context; -use deno_core::error::AnyError; -use deno_core::serde_json; -use deno_core::url::Url; -use deno_npm::npm_rc::ResolvedNpmRc; -use deno_npm::registry::NpmPackageInfo; -use deno_npm::registry::NpmRegistryApi; -use deno_npm::resolution::NpmResolutionSnapshot; -use deno_npm::resolution::PackageReqNotFoundError; -use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot; -use deno_npm::NpmPackageId; -use deno_npm::NpmResolutionPackage; -use deno_npm::NpmSystemInfo; -use deno_npm_cache::NpmCacheSetting; -use deno_path_util::fs::canonicalize_path_maybe_not_exists; -use deno_resolver::npm::CliNpmReqResolver; -use deno_runtime::colors; -use deno_runtime::deno_node::NodePermissions; -use deno_runtime::ops::process::NpmProcessStateProvider; -use deno_semver::package::PackageNv; -use deno_semver::package::PackageReq; -use node_resolver::errors::PackageFolderResolveError; -use node_resolver::errors::PackageFolderResolveIoError; -use node_resolver::InNpmPackageChecker; -use node_resolver::NpmPackageFolderResolver; -use resolution::AddPkgReqsResult; - -use crate::args::CliLockfile; -use crate::args::LifecycleScriptsConfig; -use crate::args::NpmInstallDepsProvider; -use crate::args::NpmProcessState; -use crate::args::NpmProcessStateKind; -use crate::args::PackageJsonDepValueParseWithLocationError; -use crate::cache::FastInsecureHasher; -use crate::util::progress_bar::ProgressBar; -use crate::util::sync::AtomicFlag; - -use self::resolution::NpmResolution; -use self::resolvers::create_npm_fs_resolver; -use self::resolvers::NpmPackageFsResolver; - -use super::CliNpmCache; -use super::CliNpmCacheHttpClient; -use super::CliNpmRegistryInfoProvider; -use super::CliNpmResolver; -use super::CliNpmTarballCache; -use super::InnerCliNpmResolverRef; -use super::ResolvePkgFolderFromDenoReqError; - -mod resolution; -mod resolvers; - -pub enum CliNpmResolverManagedSnapshotOption { - ResolveFromLockfile(Arc), - Specified(Option), -} - -pub struct CliManagedNpmResolverCreateOptions { - pub snapshot: CliNpmResolverManagedSnapshotOption, - pub maybe_lockfile: Option>, - pub http_client_provider: Arc, - pub npm_cache_dir: Arc, - pub sys: CliSys, - pub cache_setting: deno_cache_dir::file_fetcher::CacheSetting, - pub text_only_progress_bar: crate::util::progress_bar::ProgressBar, - pub maybe_node_modules_path: Option, - pub npm_system_info: NpmSystemInfo, - pub npm_install_deps_provider: Arc, - pub npmrc: Arc, - pub lifecycle_scripts: LifecycleScriptsConfig, -} - -pub async fn create_managed_npm_resolver_for_lsp( - options: CliManagedNpmResolverCreateOptions, -) -> Arc { - let npm_cache = create_cache(&options); - let http_client = Arc::new(CliNpmCacheHttpClient::new( - options.http_client_provider.clone(), - options.text_only_progress_bar.clone(), - )); - let npm_api = create_api(npm_cache.clone(), http_client.clone(), &options); - // spawn due to the lsp's `Send` requirement - deno_core::unsync::spawn(async move { - let snapshot = match resolve_snapshot(&npm_api, options.snapshot).await { - Ok(snapshot) => snapshot, - Err(err) => { - log::warn!("failed to resolve snapshot: {}", err); - None - } - }; - create_inner( - http_client, - npm_cache, - options.npm_install_deps_provider, - npm_api, - options.sys, - options.text_only_progress_bar, - options.maybe_lockfile, - options.npmrc, - options.maybe_node_modules_path, - options.npm_system_info, - snapshot, - options.lifecycle_scripts, - ) - }) - .await - .unwrap() -} - -pub async fn create_managed_npm_resolver( - options: CliManagedNpmResolverCreateOptions, -) -> Result, AnyError> { - let npm_cache = create_cache(&options); - let http_client = Arc::new(CliNpmCacheHttpClient::new( - options.http_client_provider.clone(), - options.text_only_progress_bar.clone(), - )); - let api = create_api(npm_cache.clone(), http_client.clone(), &options); - let snapshot = resolve_snapshot(&api, options.snapshot).await?; - Ok(create_inner( - http_client, - npm_cache, - options.npm_install_deps_provider, - api, - options.sys, - options.text_only_progress_bar, - options.maybe_lockfile, - options.npmrc, - options.maybe_node_modules_path, - options.npm_system_info, - snapshot, - options.lifecycle_scripts, - )) -} - -#[allow(clippy::too_many_arguments)] -fn create_inner( - http_client: Arc, - npm_cache: Arc, - npm_install_deps_provider: Arc, - registry_info_provider: Arc, - sys: CliSys, - text_only_progress_bar: crate::util::progress_bar::ProgressBar, - maybe_lockfile: Option>, - npm_rc: Arc, - node_modules_dir_path: Option, - npm_system_info: NpmSystemInfo, - snapshot: Option, - lifecycle_scripts: LifecycleScriptsConfig, -) -> Arc { - let resolution = Arc::new(NpmResolution::from_serialized( - registry_info_provider.clone(), - snapshot, - maybe_lockfile.clone(), - )); - let tarball_cache = Arc::new(CliNpmTarballCache::new( - npm_cache.clone(), - http_client, - sys.clone(), - npm_rc.clone(), - )); - let fs_resolver = create_npm_fs_resolver( - npm_cache.clone(), - &npm_install_deps_provider, - &text_only_progress_bar, - resolution.clone(), - sys.clone(), - tarball_cache.clone(), - node_modules_dir_path, - npm_system_info.clone(), - lifecycle_scripts.clone(), - ); - Arc::new(ManagedCliNpmResolver::new( - fs_resolver, - maybe_lockfile, - registry_info_provider, - npm_cache, - npm_install_deps_provider, - resolution, - sys, - tarball_cache, - text_only_progress_bar, - npm_system_info, - lifecycle_scripts, - )) -} - -fn create_cache( - options: &CliManagedNpmResolverCreateOptions, -) -> Arc { - Arc::new(CliNpmCache::new( - options.npm_cache_dir.clone(), - options.sys.clone(), - NpmCacheSetting::from_cache_setting(&options.cache_setting), - options.npmrc.clone(), - )) -} - -fn create_api( - cache: Arc, - http_client: Arc, - options: &CliManagedNpmResolverCreateOptions, -) -> Arc { - Arc::new(CliNpmRegistryInfoProvider::new( - cache, - http_client, - options.npmrc.clone(), - )) -} - -async fn resolve_snapshot( - registry_info_provider: &Arc, - snapshot: CliNpmResolverManagedSnapshotOption, -) -> Result, AnyError> { - match snapshot { - CliNpmResolverManagedSnapshotOption::ResolveFromLockfile(lockfile) => { - if !lockfile.overwrite() { - let snapshot = snapshot_from_lockfile( - lockfile.clone(), - ®istry_info_provider.as_npm_registry_api(), - ) - .await - .with_context(|| { - format!("failed reading lockfile '{}'", lockfile.filename.display()) - })?; - Ok(Some(snapshot)) - } else { - Ok(None) - } - } - CliNpmResolverManagedSnapshotOption::Specified(snapshot) => Ok(snapshot), - } -} - -async fn snapshot_from_lockfile( - lockfile: Arc, - api: &dyn NpmRegistryApi, -) -> Result { - let (incomplete_snapshot, skip_integrity_check) = { - let lock = lockfile.lock(); - ( - deno_npm::resolution::incomplete_snapshot_from_lockfile(&lock)?, - lock.overwrite, - ) - }; - let snapshot = deno_npm::resolution::snapshot_from_lockfile( - deno_npm::resolution::SnapshotFromLockfileParams { - incomplete_snapshot, - api, - skip_integrity_check, - }, - ) - .await?; - Ok(snapshot) -} - -#[derive(Debug)] -struct ManagedInNpmPackageChecker { - root_dir: Url, -} - -impl InNpmPackageChecker for ManagedInNpmPackageChecker { - fn in_npm_package(&self, specifier: &Url) -> bool { - specifier.as_ref().starts_with(self.root_dir.as_str()) - } -} - -pub struct CliManagedInNpmPkgCheckerCreateOptions<'a> { - pub root_cache_dir_url: &'a Url, - pub maybe_node_modules_path: Option<&'a Path>, -} - -pub fn create_managed_in_npm_pkg_checker( - options: CliManagedInNpmPkgCheckerCreateOptions, -) -> Arc { - let root_dir = match options.maybe_node_modules_path { - Some(node_modules_folder) => { - deno_path_util::url_from_directory_path(node_modules_folder).unwrap() - } - None => options.root_cache_dir_url.clone(), - }; - debug_assert!(root_dir.as_str().ends_with('/')); - Arc::new(ManagedInNpmPackageChecker { root_dir }) -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum PackageCaching<'a> { - Only(Cow<'a, [PackageReq]>), - All, -} - -/// An npm resolver where the resolution is managed by Deno rather than -/// the user bringing their own node_modules (BYONM) on the file system. -pub struct ManagedCliNpmResolver { - fs_resolver: Arc, - maybe_lockfile: Option>, - registry_info_provider: Arc, - npm_cache: Arc, - npm_install_deps_provider: Arc, - sys: CliSys, - resolution: Arc, - tarball_cache: Arc, - text_only_progress_bar: ProgressBar, - npm_system_info: NpmSystemInfo, - top_level_install_flag: AtomicFlag, - lifecycle_scripts: LifecycleScriptsConfig, -} - -impl std::fmt::Debug for ManagedCliNpmResolver { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("ManagedNpmResolver") - .field("", &"") - .finish() - } -} - -impl ManagedCliNpmResolver { - #[allow(clippy::too_many_arguments)] - pub fn new( - fs_resolver: Arc, - maybe_lockfile: Option>, - registry_info_provider: Arc, - npm_cache: Arc, - npm_install_deps_provider: Arc, - resolution: Arc, - sys: CliSys, - tarball_cache: Arc, - text_only_progress_bar: ProgressBar, - npm_system_info: NpmSystemInfo, - lifecycle_scripts: LifecycleScriptsConfig, - ) -> Self { - Self { - fs_resolver, - maybe_lockfile, - registry_info_provider, - npm_cache, - npm_install_deps_provider, - text_only_progress_bar, - resolution, - sys, - tarball_cache, - npm_system_info, - top_level_install_flag: Default::default(), - lifecycle_scripts, - } - } - - pub fn resolve_pkg_folder_from_pkg_id( - &self, - pkg_id: &NpmPackageId, - ) -> Result { - let path = self.fs_resolver.package_folder(pkg_id)?; - let path = canonicalize_path_maybe_not_exists(&self.sys, &path)?; - log::debug!( - "Resolved package folder of {} to {}", - pkg_id.as_serialized(), - path.display() - ); - Ok(path) - } - - /// Resolves the package id from the provided specifier. - pub fn resolve_pkg_id_from_specifier( - &self, - specifier: &ModuleSpecifier, - ) -> Result, AnyError> { - let Some(cache_folder_id) = self - .fs_resolver - .resolve_package_cache_folder_id_from_specifier(specifier)? - else { - return Ok(None); - }; - Ok(Some( - self - .resolution - .resolve_pkg_id_from_pkg_cache_folder_id(&cache_folder_id)?, - )) - } - - pub fn resolve_pkg_reqs_from_pkg_id( - &self, - id: &NpmPackageId, - ) -> Vec { - self.resolution.resolve_pkg_reqs_from_pkg_id(id) - } - - /// Attempts to get the package size in bytes. - pub fn package_size( - &self, - package_id: &NpmPackageId, - ) -> Result { - let package_folder = self.fs_resolver.package_folder(package_id)?; - Ok(crate::util::fs::dir_size(&package_folder)?) - } - - pub fn all_system_packages( - &self, - system_info: &NpmSystemInfo, - ) -> Vec { - self.resolution.all_system_packages(system_info) - } - - /// Checks if the provided package req's folder is cached. - pub fn is_pkg_req_folder_cached(&self, req: &PackageReq) -> bool { - self - .resolve_pkg_id_from_pkg_req(req) - .ok() - .and_then(|id| self.fs_resolver.package_folder(&id).ok()) - .map(|folder| folder.exists()) - .unwrap_or(false) - } - - /// Adds package requirements to the resolver and ensures everything is setup. - /// This includes setting up the `node_modules` directory, if applicable. - pub async fn add_and_cache_package_reqs( - &self, - packages: &[PackageReq], - ) -> Result<(), AnyError> { - self - .add_package_reqs_raw( - packages, - Some(PackageCaching::Only(packages.into())), - ) - .await - .dependencies_result - } - - pub async fn add_package_reqs_no_cache( - &self, - packages: &[PackageReq], - ) -> Result<(), AnyError> { - self - .add_package_reqs_raw(packages, None) - .await - .dependencies_result - } - - pub async fn add_package_reqs( - &self, - packages: &[PackageReq], - caching: PackageCaching<'_>, - ) -> Result<(), AnyError> { - self - .add_package_reqs_raw(packages, Some(caching)) - .await - .dependencies_result - } - - pub async fn add_package_reqs_raw<'a>( - &self, - packages: &[PackageReq], - caching: Option>, - ) -> AddPkgReqsResult { - if packages.is_empty() { - return AddPkgReqsResult { - dependencies_result: Ok(()), - results: vec![], - }; - } - - let mut result = self.resolution.add_package_reqs(packages).await; - - if result.dependencies_result.is_ok() { - if let Some(lockfile) = self.maybe_lockfile.as_ref() { - result.dependencies_result = lockfile.error_if_changed(); - } - } - if result.dependencies_result.is_ok() { - if let Some(caching) = caching { - result.dependencies_result = self.cache_packages(caching).await; - } - } - - result - } - - /// Sets package requirements to the resolver, removing old requirements and adding new ones. - /// - /// This will retrieve and resolve package information, but not cache any package files. - pub async fn set_package_reqs( - &self, - packages: &[PackageReq], - ) -> Result<(), AnyError> { - self.resolution.set_package_reqs(packages).await - } - - pub fn snapshot(&self) -> NpmResolutionSnapshot { - self.resolution.snapshot() - } - - pub fn top_package_req_for_name(&self, name: &str) -> Option { - let package_reqs = self.resolution.package_reqs(); - let mut entries = package_reqs - .iter() - .filter(|(_, nv)| nv.name == name) - .collect::>(); - entries.sort_by_key(|(_, nv)| &nv.version); - Some(entries.last()?.0.clone()) - } - - pub fn serialized_valid_snapshot_for_system( - &self, - system_info: &NpmSystemInfo, - ) -> ValidSerializedNpmResolutionSnapshot { - self - .resolution - .serialized_valid_snapshot_for_system(system_info) - } - - pub async fn inject_synthetic_types_node_package( - &self, - ) -> Result<(), AnyError> { - let reqs = &[PackageReq::from_str("@types/node").unwrap()]; - // add and ensure this isn't added to the lockfile - self - .add_package_reqs(reqs, PackageCaching::Only(reqs.into())) - .await?; - - Ok(()) - } - - pub async fn cache_packages( - &self, - caching: PackageCaching<'_>, - ) -> Result<(), AnyError> { - self.fs_resolver.cache_packages(caching).await - } - - pub fn resolve_pkg_folder_from_deno_module( - &self, - nv: &PackageNv, - ) -> Result { - let pkg_id = self.resolution.resolve_pkg_id_from_deno_module(nv)?; - self.resolve_pkg_folder_from_pkg_id(&pkg_id) - } - - pub fn resolve_pkg_id_from_pkg_req( - &self, - req: &PackageReq, - ) -> Result { - self.resolution.resolve_pkg_id_from_pkg_req(req) - } - - pub fn ensure_no_pkg_json_dep_errors( - &self, - ) -> Result<(), Box> { - for err in self.npm_install_deps_provider.pkg_json_dep_errors() { - match err.source.as_kind() { - deno_package_json::PackageJsonDepValueParseErrorKind::VersionReq(_) => { - return Err(Box::new(err.clone())); - } - deno_package_json::PackageJsonDepValueParseErrorKind::Unsupported { - .. - } => { - // only warn for this one - log::warn!( - "{} {}\n at {}", - colors::yellow("Warning"), - err.source, - err.location, - ) - } - } - } - Ok(()) - } - - /// Ensures that the top level `package.json` dependencies are installed. - /// This may set up the `node_modules` directory. - /// - /// Returns `true` if the top level packages are already installed. A - /// return value of `false` means that new packages were added to the NPM resolution. - pub async fn ensure_top_level_package_json_install( - &self, - ) -> Result { - if !self.top_level_install_flag.raise() { - return Ok(true); // already did this - } - - let pkg_json_remote_pkgs = self.npm_install_deps_provider.remote_pkgs(); - if pkg_json_remote_pkgs.is_empty() { - return Ok(true); - } - - // check if something needs resolving before bothering to load all - // the package information (which is slow) - if pkg_json_remote_pkgs.iter().all(|pkg| { - self - .resolution - .resolve_pkg_id_from_pkg_req(&pkg.req) - .is_ok() - }) { - log::debug!( - "All package.json deps resolvable. Skipping top level install." - ); - return Ok(true); // everything is already resolvable - } - - let pkg_reqs = pkg_json_remote_pkgs - .iter() - .map(|pkg| pkg.req.clone()) - .collect::>(); - self.add_package_reqs_no_cache(&pkg_reqs).await?; - - Ok(false) - } - - pub async fn cache_package_info( - &self, - package_name: &str, - ) -> Result, AnyError> { - // this will internally cache the package information - self - .registry_info_provider - .package_info(package_name) - .await - .map_err(|err| err.into()) - } - - pub fn maybe_node_modules_path(&self) -> Option<&Path> { - self.fs_resolver.node_modules_path() - } - - pub fn global_cache_root_path(&self) -> &Path { - self.npm_cache.root_dir_path() - } - - pub fn global_cache_root_url(&self) -> &Url { - self.npm_cache.root_dir_url() - } -} - -fn npm_process_state( - snapshot: ValidSerializedNpmResolutionSnapshot, - node_modules_path: Option<&Path>, -) -> String { - serde_json::to_string(&NpmProcessState { - kind: NpmProcessStateKind::Snapshot(snapshot.into_serialized()), - local_node_modules_path: node_modules_path - .map(|p| p.to_string_lossy().to_string()), - }) - .unwrap() -} - -impl NpmPackageFolderResolver for ManagedCliNpmResolver { - fn resolve_package_folder_from_package( - &self, - name: &str, - referrer: &ModuleSpecifier, - ) -> Result { - let path = self - .fs_resolver - .resolve_package_folder_from_package(name, referrer)?; - let path = - canonicalize_path_maybe_not_exists(&self.sys, &path).map_err(|err| { - PackageFolderResolveIoError { - package_name: name.to_string(), - referrer: referrer.clone(), - source: err, - } - })?; - log::debug!("Resolved {} from {} to {}", name, referrer, path.display()); - Ok(path) - } -} - -impl NpmProcessStateProvider for ManagedCliNpmResolver { - fn get_npm_process_state(&self) -> String { - npm_process_state( - self.resolution.serialized_valid_snapshot(), - self.fs_resolver.node_modules_path(), - ) - } -} - -impl CliNpmReqResolver for ManagedCliNpmResolver { - fn resolve_pkg_folder_from_deno_module_req( - &self, - req: &PackageReq, - _referrer: &ModuleSpecifier, - ) -> Result { - let pkg_id = self - .resolve_pkg_id_from_pkg_req(req) - .map_err(|err| ResolvePkgFolderFromDenoReqError::Managed(err.into()))?; - self - .resolve_pkg_folder_from_pkg_id(&pkg_id) - .map_err(ResolvePkgFolderFromDenoReqError::Managed) - } -} - -impl CliNpmResolver for ManagedCliNpmResolver { - fn into_npm_pkg_folder_resolver( - self: Arc, - ) -> Arc { - self - } - - fn into_npm_req_resolver(self: Arc) -> Arc { - self - } - - fn into_process_state_provider( - self: Arc, - ) -> Arc { - self - } - - fn clone_snapshotted(&self) -> Arc { - // create a new snapshotted npm resolution and resolver - let npm_resolution = Arc::new(NpmResolution::new( - self.registry_info_provider.clone(), - self.resolution.snapshot(), - self.maybe_lockfile.clone(), - )); - - Arc::new(ManagedCliNpmResolver::new( - create_npm_fs_resolver( - self.npm_cache.clone(), - &self.npm_install_deps_provider, - &self.text_only_progress_bar, - npm_resolution.clone(), - self.sys.clone(), - self.tarball_cache.clone(), - self.root_node_modules_path().map(ToOwned::to_owned), - self.npm_system_info.clone(), - self.lifecycle_scripts.clone(), - ), - self.maybe_lockfile.clone(), - self.registry_info_provider.clone(), - self.npm_cache.clone(), - self.npm_install_deps_provider.clone(), - npm_resolution, - self.sys.clone(), - self.tarball_cache.clone(), - self.text_only_progress_bar.clone(), - self.npm_system_info.clone(), - self.lifecycle_scripts.clone(), - )) - } - - fn as_inner(&self) -> InnerCliNpmResolverRef { - InnerCliNpmResolverRef::Managed(self) - } - - fn root_node_modules_path(&self) -> Option<&Path> { - self.fs_resolver.node_modules_path() - } - - fn ensure_read_permission<'a>( - &self, - permissions: &mut dyn NodePermissions, - path: &'a Path, - ) -> Result, AnyError> { - self.fs_resolver.ensure_read_permission(permissions, path) - } - - fn check_state_hash(&self) -> Option { - // We could go further and check all the individual - // npm packages, but that's probably overkill. - let mut package_reqs = self - .resolution - .package_reqs() - .into_iter() - .collect::>(); - package_reqs.sort_by(|a, b| a.0.cmp(&b.0)); // determinism - let mut hasher = FastInsecureHasher::new_without_deno_version(); - // ensure the cache gets busted when turning nodeModulesDir on or off - // as this could cause changes in resolution - hasher.write_hashable(self.fs_resolver.node_modules_path().is_some()); - for (pkg_req, pkg_nv) in package_reqs { - hasher.write_hashable(&pkg_req); - hasher.write_hashable(&pkg_nv); - } - Some(hasher.finish()) - } -} diff --git a/cli/npm/managed/resolvers/common.rs b/cli/npm/managed/resolvers/common.rs deleted file mode 100644 index 26f6d8516d..0000000000 --- a/cli/npm/managed/resolvers/common.rs +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. - -pub mod bin_entries; -pub mod lifecycle_scripts; - -use std::borrow::Cow; -use std::collections::HashMap; -use std::io::ErrorKind; -use std::path::Path; -use std::path::PathBuf; -use std::sync::Arc; -use std::sync::Mutex; - -use async_trait::async_trait; -use deno_ast::ModuleSpecifier; -use deno_core::anyhow::Context; -use deno_core::error::AnyError; -use deno_core::futures; -use deno_core::futures::StreamExt; -use deno_npm::NpmPackageCacheFolderId; -use deno_npm::NpmPackageId; -use deno_npm::NpmResolutionPackage; -use deno_runtime::deno_node::NodePermissions; -use node_resolver::errors::PackageFolderResolveError; -use sys_traits::FsCanonicalize; - -use super::super::PackageCaching; -use crate::npm::CliNpmTarballCache; -use crate::sys::CliSys; - -/// Part of the resolution that interacts with the file system. -#[async_trait(?Send)] -pub trait NpmPackageFsResolver: Send + Sync { - /// The local node_modules folder if it is applicable to the implementation. - fn node_modules_path(&self) -> Option<&Path>; - - fn maybe_package_folder(&self, package_id: &NpmPackageId) -> Option; - - fn package_folder( - &self, - package_id: &NpmPackageId, - ) -> Result { - self.maybe_package_folder(package_id).ok_or_else(|| { - deno_core::anyhow::anyhow!( - "Package folder not found for '{}'", - package_id.as_serialized() - ) - }) - } - - fn resolve_package_folder_from_package( - &self, - name: &str, - referrer: &ModuleSpecifier, - ) -> Result; - - fn resolve_package_cache_folder_id_from_specifier( - &self, - specifier: &ModuleSpecifier, - ) -> Result, AnyError>; - - async fn cache_packages<'a>( - &self, - caching: PackageCaching<'a>, - ) -> Result<(), AnyError>; - - #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] - fn ensure_read_permission<'a>( - &self, - permissions: &mut dyn NodePermissions, - path: &'a Path, - ) -> Result, AnyError>; -} - -#[derive(Debug)] -pub struct RegistryReadPermissionChecker { - sys: CliSys, - cache: Mutex>, - registry_path: PathBuf, -} - -impl RegistryReadPermissionChecker { - pub fn new(sys: CliSys, registry_path: PathBuf) -> Self { - Self { - sys, - registry_path, - cache: Default::default(), - } - } - - pub fn ensure_registry_read_permission<'a>( - &self, - permissions: &mut dyn NodePermissions, - path: &'a Path, - ) -> Result, AnyError> { - if permissions.query_read_all() { - return Ok(Cow::Borrowed(path)); // skip permissions checks below - } - - // allow reading if it's in the node_modules - let is_path_in_node_modules = path.starts_with(&self.registry_path) - && path - .components() - .all(|c| !matches!(c, std::path::Component::ParentDir)); - - if is_path_in_node_modules { - let mut cache = self.cache.lock().unwrap(); - let mut canonicalize = - |path: &Path| -> Result, AnyError> { - match cache.get(path) { - Some(canon) => Ok(Some(canon.clone())), - None => match self.sys.fs_canonicalize(path) { - Ok(canon) => { - cache.insert(path.to_path_buf(), canon.clone()); - Ok(Some(canon)) - } - Err(e) => { - if e.kind() == ErrorKind::NotFound { - return Ok(None); - } - Err(AnyError::from(e)).with_context(|| { - format!("failed canonicalizing '{}'", path.display()) - }) - } - }, - } - }; - if let Some(registry_path_canon) = canonicalize(&self.registry_path)? { - if let Some(path_canon) = canonicalize(path)? { - if path_canon.starts_with(registry_path_canon) { - return Ok(Cow::Owned(path_canon)); - } - } else if path.starts_with(registry_path_canon) - || path.starts_with(&self.registry_path) - { - return Ok(Cow::Borrowed(path)); - } - } - } - - permissions.check_read_path(path).map_err(Into::into) - } -} - -/// Caches all the packages in parallel. -pub async fn cache_packages( - packages: &[NpmResolutionPackage], - tarball_cache: &Arc, -) -> Result<(), AnyError> { - let mut futures_unordered = futures::stream::FuturesUnordered::new(); - for package in packages { - futures_unordered.push(async move { - tarball_cache - .ensure_package(&package.id.nv, &package.dist) - .await - }); - } - while let Some(result) = futures_unordered.next().await { - // surface the first error - result?; - } - Ok(()) -} diff --git a/cli/npm/managed/resolvers/global.rs b/cli/npm/managed/resolvers/global.rs deleted file mode 100644 index 77e0d0ea3e..0000000000 --- a/cli/npm/managed/resolvers/global.rs +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. - -//! Code for global npm cache resolution. - -use std::borrow::Cow; -use std::path::Path; -use std::path::PathBuf; -use std::sync::Arc; - -use crate::colors; -use crate::npm::managed::PackageCaching; -use crate::npm::CliNpmCache; -use crate::npm::CliNpmTarballCache; -use crate::sys::CliSys; -use async_trait::async_trait; -use deno_ast::ModuleSpecifier; -use deno_core::error::AnyError; -use deno_npm::NpmPackageCacheFolderId; -use deno_npm::NpmPackageId; -use deno_npm::NpmResolutionPackage; -use deno_npm::NpmSystemInfo; -use deno_runtime::deno_node::NodePermissions; -use node_resolver::errors::PackageFolderResolveError; -use node_resolver::errors::PackageNotFoundError; -use node_resolver::errors::ReferrerNotFoundError; - -use crate::args::LifecycleScriptsConfig; -use crate::cache::FastInsecureHasher; - -use super::super::resolution::NpmResolution; -use super::common::cache_packages; -use super::common::lifecycle_scripts::LifecycleScriptsStrategy; -use super::common::NpmPackageFsResolver; -use super::common::RegistryReadPermissionChecker; - -/// Resolves packages from the global npm cache. -#[derive(Debug)] -pub struct GlobalNpmPackageResolver { - cache: Arc, - tarball_cache: Arc, - resolution: Arc, - system_info: NpmSystemInfo, - registry_read_permission_checker: RegistryReadPermissionChecker, - lifecycle_scripts: LifecycleScriptsConfig, -} - -impl GlobalNpmPackageResolver { - pub fn new( - cache: Arc, - tarball_cache: Arc, - resolution: Arc, - sys: CliSys, - system_info: NpmSystemInfo, - lifecycle_scripts: LifecycleScriptsConfig, - ) -> Self { - Self { - registry_read_permission_checker: RegistryReadPermissionChecker::new( - sys, - cache.root_dir_path().to_path_buf(), - ), - cache, - tarball_cache, - resolution, - system_info, - lifecycle_scripts, - } - } -} - -#[async_trait(?Send)] -impl NpmPackageFsResolver for GlobalNpmPackageResolver { - fn node_modules_path(&self) -> Option<&Path> { - None - } - - fn maybe_package_folder(&self, id: &NpmPackageId) -> Option { - let folder_id = self - .resolution - .resolve_pkg_cache_folder_id_from_pkg_id(id)?; - Some(self.cache.package_folder_for_id(&folder_id)) - } - - fn resolve_package_folder_from_package( - &self, - name: &str, - referrer: &ModuleSpecifier, - ) -> Result { - use deno_npm::resolution::PackageNotFoundFromReferrerError; - let Some(referrer_cache_folder_id) = self - .cache - .resolve_package_folder_id_from_specifier(referrer) - else { - return Err( - ReferrerNotFoundError { - referrer: referrer.clone(), - referrer_extra: None, - } - .into(), - ); - }; - let resolve_result = self - .resolution - .resolve_package_from_package(name, &referrer_cache_folder_id); - match resolve_result { - Ok(pkg) => match self.maybe_package_folder(&pkg.id) { - Some(folder) => Ok(folder), - None => Err( - PackageNotFoundError { - package_name: name.to_string(), - referrer: referrer.clone(), - referrer_extra: Some(format!( - "{} -> {}", - referrer_cache_folder_id, - pkg.id.as_serialized() - )), - } - .into(), - ), - }, - Err(err) => match *err { - PackageNotFoundFromReferrerError::Referrer(cache_folder_id) => Err( - ReferrerNotFoundError { - referrer: referrer.clone(), - referrer_extra: Some(cache_folder_id.to_string()), - } - .into(), - ), - PackageNotFoundFromReferrerError::Package { - name, - referrer: cache_folder_id_referrer, - } => Err( - PackageNotFoundError { - package_name: name, - referrer: referrer.clone(), - referrer_extra: Some(cache_folder_id_referrer.to_string()), - } - .into(), - ), - }, - } - } - - fn resolve_package_cache_folder_id_from_specifier( - &self, - specifier: &ModuleSpecifier, - ) -> Result, AnyError> { - Ok( - self - .cache - .resolve_package_folder_id_from_specifier(specifier), - ) - } - - async fn cache_packages<'a>( - &self, - caching: PackageCaching<'a>, - ) -> Result<(), AnyError> { - let package_partitions = match caching { - PackageCaching::All => self - .resolution - .all_system_packages_partitioned(&self.system_info), - PackageCaching::Only(reqs) => self - .resolution - .subset(&reqs) - .all_system_packages_partitioned(&self.system_info), - }; - cache_packages(&package_partitions.packages, &self.tarball_cache).await?; - - // create the copy package folders - for copy in package_partitions.copy_packages { - self - .cache - .ensure_copy_package(©.get_package_cache_folder_id())?; - } - - let mut lifecycle_scripts = - super::common::lifecycle_scripts::LifecycleScripts::new( - &self.lifecycle_scripts, - GlobalLifecycleScripts::new(self, &self.lifecycle_scripts.root_dir), - ); - for package in &package_partitions.packages { - let package_folder = self.cache.package_folder_for_nv(&package.id.nv); - lifecycle_scripts.add(package, Cow::Borrowed(&package_folder)); - } - - lifecycle_scripts.warn_not_run_scripts()?; - - Ok(()) - } - - fn ensure_read_permission<'a>( - &self, - permissions: &mut dyn NodePermissions, - path: &'a Path, - ) -> Result, AnyError> { - self - .registry_read_permission_checker - .ensure_registry_read_permission(permissions, path) - } -} - -struct GlobalLifecycleScripts<'a> { - resolver: &'a GlobalNpmPackageResolver, - path_hash: u64, -} - -impl<'a> GlobalLifecycleScripts<'a> { - fn new(resolver: &'a GlobalNpmPackageResolver, root_dir: &Path) -> Self { - let mut hasher = FastInsecureHasher::new_without_deno_version(); - hasher.write(root_dir.to_string_lossy().as_bytes()); - let path_hash = hasher.finish(); - Self { - resolver, - path_hash, - } - } - - fn warned_scripts_file(&self, package: &NpmResolutionPackage) -> PathBuf { - self - .package_path(package) - .join(format!(".scripts-warned-{}", self.path_hash)) - } -} - -impl<'a> super::common::lifecycle_scripts::LifecycleScriptsStrategy - for GlobalLifecycleScripts<'a> -{ - fn can_run_scripts(&self) -> bool { - false - } - fn package_path(&self, package: &NpmResolutionPackage) -> PathBuf { - self.resolver.cache.package_folder_for_nv(&package.id.nv) - } - - fn warn_on_scripts_not_run( - &self, - packages: &[(&NpmResolutionPackage, PathBuf)], - ) -> std::result::Result<(), deno_core::anyhow::Error> { - log::warn!("{} The following packages contained npm lifecycle scripts ({}) that were not executed:", colors::yellow("Warning"), colors::gray("preinstall/install/postinstall")); - for (package, _) in packages { - log::warn!("┠─ {}", colors::gray(format!("npm:{}", package.id.nv))); - } - log::warn!("┃"); - log::warn!( - "┠─ {}", - colors::italic("This may cause the packages to not work correctly.") - ); - log::warn!("┠─ {}", colors::italic("Lifecycle scripts are only supported when using a `node_modules` directory.")); - log::warn!( - "┠─ {}", - colors::italic("Enable it in your deno config file:") - ); - log::warn!("┖─ {}", colors::bold("\"nodeModulesDir\": \"auto\"")); - - for (package, _) in packages { - std::fs::write(self.warned_scripts_file(package), "")?; - } - Ok(()) - } - - fn did_run_scripts( - &self, - _package: &NpmResolutionPackage, - ) -> std::result::Result<(), deno_core::anyhow::Error> { - Ok(()) - } - - fn has_warned(&self, package: &NpmResolutionPackage) -> bool { - self.warned_scripts_file(package).exists() - } - - fn has_run(&self, _package: &NpmResolutionPackage) -> bool { - false - } -} diff --git a/cli/npm/managed/resolvers/mod.rs b/cli/npm/managed/resolvers/mod.rs deleted file mode 100644 index c2fc8d2d92..0000000000 --- a/cli/npm/managed/resolvers/mod.rs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. - -mod common; -mod global; -mod local; - -use std::path::PathBuf; -use std::sync::Arc; - -use crate::sys::CliSys; -use deno_npm::NpmSystemInfo; - -use crate::args::LifecycleScriptsConfig; -use crate::args::NpmInstallDepsProvider; -use crate::npm::CliNpmCache; -use crate::npm::CliNpmTarballCache; -use crate::util::progress_bar::ProgressBar; - -pub use self::common::NpmPackageFsResolver; - -use self::global::GlobalNpmPackageResolver; -use self::local::LocalNpmPackageResolver; - -use super::resolution::NpmResolution; - -#[allow(clippy::too_many_arguments)] -pub fn create_npm_fs_resolver( - npm_cache: Arc, - npm_install_deps_provider: &Arc, - progress_bar: &ProgressBar, - resolution: Arc, - sys: CliSys, - tarball_cache: Arc, - maybe_node_modules_path: Option, - system_info: NpmSystemInfo, - lifecycle_scripts: LifecycleScriptsConfig, -) -> Arc { - match maybe_node_modules_path { - Some(node_modules_folder) => Arc::new(LocalNpmPackageResolver::new( - npm_cache, - npm_install_deps_provider.clone(), - progress_bar.clone(), - resolution, - sys, - tarball_cache, - node_modules_folder, - system_info, - lifecycle_scripts, - )), - None => Arc::new(GlobalNpmPackageResolver::new( - npm_cache, - tarball_cache, - resolution, - sys, - system_info, - lifecycle_scripts, - )), - } -} diff --git a/cli/npm/mod.rs b/cli/npm/mod.rs index 34eaf21419..a2cbd81d5b 100644 --- a/cli/npm/mod.rs +++ b/cli/npm/mod.rs @@ -1,50 +1,42 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. mod byonm; +pub mod installer; mod managed; -use std::borrow::Cow; -use std::path::Path; use std::sync::Arc; -use crate::sys::CliSys; use dashmap::DashMap; -use deno_core::error::AnyError; use deno_core::serde_json; use deno_core::url::Url; +use deno_error::JsErrorBox; use deno_npm::npm_rc::ResolvedNpmRc; use deno_npm::registry::NpmPackageInfo; -use deno_resolver::npm::ByonmInNpmPackageChecker; -use deno_resolver::npm::ByonmNpmResolver; -use deno_resolver::npm::CliNpmReqResolver; -use deno_resolver::npm::ResolvePkgFolderFromDenoReqError; -use deno_runtime::deno_node::NodePermissions; -use deno_runtime::ops::process::NpmProcessStateProvider; +use deno_runtime::deno_process::NpmProcessStateProviderRc; use deno_semver::package::PackageNv; use deno_semver::package::PackageReq; use http::HeaderName; use http::HeaderValue; -use managed::create_managed_in_npm_pkg_checker; -use node_resolver::InNpmPackageChecker; -use node_resolver::NpmPackageFolderResolver; -use crate::file_fetcher::CliFileFetcher; -use crate::http_util::HttpClientProvider; -use crate::util::progress_bar::ProgressBar; - -pub use self::byonm::CliByonmNpmResolver; pub use self::byonm::CliByonmNpmResolverCreateOptions; -pub use self::managed::CliManagedInNpmPkgCheckerCreateOptions; pub use self::managed::CliManagedNpmResolverCreateOptions; pub use self::managed::CliNpmResolverManagedSnapshotOption; -pub use self::managed::ManagedCliNpmResolver; -pub use self::managed::PackageCaching; +pub use self::managed::NpmResolutionInitializer; +pub use self::managed::ResolveSnapshotError; +use crate::file_fetcher::CliFileFetcher; +use crate::http_util::HttpClientProvider; +use crate::sys::CliSys; +use crate::util::progress_bar::ProgressBar; pub type CliNpmTarballCache = deno_npm_cache::TarballCache; pub type CliNpmCache = deno_npm_cache::NpmCache; pub type CliNpmRegistryInfoProvider = deno_npm_cache::RegistryInfoProvider; +pub type CliNpmResolver = deno_resolver::npm::NpmResolver; +pub type CliManagedNpmResolver = deno_resolver::npm::ManagedNpmResolver; +pub type CliNpmResolverCreateOptions = + deno_resolver::npm::NpmResolverCreateOptions; #[derive(Debug)] pub struct CliNpmCacheHttpClient { @@ -64,6 +56,19 @@ impl CliNpmCacheHttpClient { } } +pub fn create_npm_process_state_provider( + npm_resolver: &CliNpmResolver, +) -> NpmProcessStateProviderRc { + match npm_resolver { + CliNpmResolver::Byonm(byonm_npm_resolver) => Arc::new( + byonm::CliByonmNpmProcessStateProvider(byonm_npm_resolver.clone()), + ), + CliNpmResolver::Managed(managed_npm_resolver) => Arc::new( + managed::CliManagedNpmProcessStateProvider(managed_npm_resolver.clone()), + ), + } +} + #[async_trait::async_trait(?Send)] impl deno_npm_cache::NpmCacheHttpClient for CliNpmCacheHttpClient { async fn download_with_retries_on_any_tokio_runtime( @@ -90,111 +95,21 @@ impl deno_npm_cache::NpmCacheHttpClient for CliNpmCacheHttpClient { | Json { .. } | ToStr { .. } | RedirectHeaderParse { .. } - | TooManyRedirects => None, + | TooManyRedirects + | NotFound + | Other(_) => None, BadResponse(bad_response_error) => { Some(bad_response_error.status_code) } }; deno_npm_cache::DownloadError { status_code, - error: err.into(), + error: JsErrorBox::from_err(err), } }) } } -pub enum CliNpmResolverCreateOptions { - Managed(CliManagedNpmResolverCreateOptions), - Byonm(CliByonmNpmResolverCreateOptions), -} - -pub async fn create_cli_npm_resolver_for_lsp( - options: CliNpmResolverCreateOptions, -) -> Arc { - use CliNpmResolverCreateOptions::*; - match options { - Managed(options) => { - managed::create_managed_npm_resolver_for_lsp(options).await - } - Byonm(options) => Arc::new(ByonmNpmResolver::new(options)), - } -} - -pub async fn create_cli_npm_resolver( - options: CliNpmResolverCreateOptions, -) -> Result, AnyError> { - use CliNpmResolverCreateOptions::*; - match options { - Managed(options) => managed::create_managed_npm_resolver(options).await, - Byonm(options) => Ok(Arc::new(ByonmNpmResolver::new(options))), - } -} - -pub enum CreateInNpmPkgCheckerOptions<'a> { - Managed(CliManagedInNpmPkgCheckerCreateOptions<'a>), - Byonm, -} - -pub fn create_in_npm_pkg_checker( - options: CreateInNpmPkgCheckerOptions, -) -> Arc { - match options { - CreateInNpmPkgCheckerOptions::Managed(options) => { - create_managed_in_npm_pkg_checker(options) - } - CreateInNpmPkgCheckerOptions::Byonm => Arc::new(ByonmInNpmPackageChecker), - } -} - -pub enum InnerCliNpmResolverRef<'a> { - Managed(&'a ManagedCliNpmResolver), - #[allow(dead_code)] - Byonm(&'a CliByonmNpmResolver), -} - -pub trait CliNpmResolver: NpmPackageFolderResolver + CliNpmReqResolver { - fn into_npm_pkg_folder_resolver( - self: Arc, - ) -> Arc; - fn into_npm_req_resolver(self: Arc) -> Arc; - fn into_process_state_provider( - self: Arc, - ) -> Arc; - fn into_maybe_byonm(self: Arc) -> Option> { - None - } - - fn clone_snapshotted(&self) -> Arc; - - fn as_inner(&self) -> InnerCliNpmResolverRef; - - fn as_managed(&self) -> Option<&ManagedCliNpmResolver> { - match self.as_inner() { - InnerCliNpmResolverRef::Managed(inner) => Some(inner), - InnerCliNpmResolverRef::Byonm(_) => None, - } - } - - fn as_byonm(&self) -> Option<&CliByonmNpmResolver> { - match self.as_inner() { - InnerCliNpmResolverRef::Managed(_) => None, - InnerCliNpmResolverRef::Byonm(inner) => Some(inner), - } - } - - fn root_node_modules_path(&self) -> Option<&Path>; - - fn ensure_read_permission<'a>( - &self, - permissions: &mut dyn NodePermissions, - path: &'a Path, - ) -> Result, AnyError>; - - /// Returns a hash returning the state of the npm resolver - /// or `None` if the state currently can't be determined. - fn check_state_hash(&self) -> Option; -} - #[derive(Debug)] pub struct NpmFetchResolver { nv_by_req: DashMap>, diff --git a/cli/ops/bench.rs b/cli/ops/bench.rs index a7c788a189..a06182fbd0 100644 --- a/cli/ops/bench.rs +++ b/cli/ops/bench.rs @@ -1,15 +1,13 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; -use deno_core::error::generic_error; -use deno_core::error::type_error; -use deno_core::error::AnyError; use deno_core::op2; use deno_core::v8; use deno_core::ModuleSpecifier; use deno_core::OpState; +use deno_error::JsErrorBox; use deno_runtime::deno_permissions::ChildPermissionsArg; use deno_runtime::deno_permissions::PermissionsContainer; use deno_runtime::deno_web::StartTime; @@ -78,7 +76,7 @@ pub fn op_pledge_test_permissions( pub fn op_restore_test_permissions( state: &mut OpState, #[serde] token: Uuid, -) -> Result<(), AnyError> { +) -> Result<(), JsErrorBox> { if let Some(permissions_holder) = state.try_take::() { if token != permissions_holder.0 { panic!("restore test permissions token does not match the stored token"); @@ -88,7 +86,7 @@ pub fn op_restore_test_permissions( state.put::(permissions); Ok(()) } else { - Err(generic_error("no permissions to restore")) + Err(JsErrorBox::generic("no permissions to restore")) } } @@ -106,9 +104,9 @@ fn op_register_bench( only: bool, warmup: bool, #[buffer] ret_buf: &mut [u8], -) -> Result<(), AnyError> { +) -> Result<(), JsErrorBox> { if ret_buf.len() != 4 { - return Err(type_error(format!( + return Err(JsErrorBox::type_error(format!( "Invalid ret_buf length: {}", ret_buf.len() ))); diff --git a/cli/ops/jupyter.rs b/cli/ops/jupyter.rs index 5bdf97e60f..3160f991bf 100644 --- a/cli/ops/jupyter.rs +++ b/cli/ops/jupyter.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // NOTE(bartlomieju): unfortunately it appears that clippy is broken // and can't allow a single line ignore for `await_holding_lock`. @@ -8,17 +8,16 @@ use std::cell::RefCell; use std::rc::Rc; use std::sync::Arc; -use jupyter_runtime::InputRequest; -use jupyter_runtime::JupyterMessage; -use jupyter_runtime::JupyterMessageContent; -use jupyter_runtime::KernelIoPubConnection; -use jupyter_runtime::StreamContent; - use deno_core::error::AnyError; use deno_core::op2; use deno_core::parking_lot::Mutex; use deno_core::serde_json; use deno_core::OpState; +use jupyter_runtime::InputRequest; +use jupyter_runtime::JupyterMessage; +use jupyter_runtime::JupyterMessageContent; +use jupyter_runtime::KernelIoPubConnection; +use jupyter_runtime::StreamContent; use tokio::sync::mpsc; use crate::tools::jupyter::server::StdinConnectionProxy; @@ -95,10 +94,12 @@ pub fn op_jupyter_input( None } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum JupyterBroadcastError { + #[class(inherit)] #[error(transparent)] SerdeJson(serde_json::Error), + #[class(generic)] #[error(transparent)] ZeroMq(AnyError), } diff --git a/cli/ops/lint.rs b/cli/ops/lint.rs index c38ac0c8a2..c13cb21a53 100644 --- a/cli/ops/lint.rs +++ b/cli/ops/lint.rs @@ -1,26 +1,37 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_ast::MediaType; use deno_ast::ModuleSpecifier; -use deno_core::error::generic_error; -use deno_core::error::AnyError; +use deno_ast::ParseDiagnostic; use deno_core::op2; use crate::tools::lint; deno_core::extension!(deno_lint, ops = [op_lint_create_serialized_ast,],); +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum LintError { + #[class(inherit)] + #[error(transparent)] + Io(#[from] std::io::Error), + #[class(inherit)] + #[error(transparent)] + ParseDiagnostic(#[from] ParseDiagnostic), + #[class(type)] + #[error("Failed to parse path as URL: {0}")] + PathParse(std::path::PathBuf), +} + #[op2] #[buffer] fn op_lint_create_serialized_ast( #[string] file_name: &str, #[string] source: String, -) -> Result, AnyError> { +) -> Result, LintError> { let file_text = deno_ast::strip_bom(source); let path = std::env::current_dir()?.join(file_name); - let specifier = ModuleSpecifier::from_file_path(&path).map_err(|_| { - generic_error(format!("Failed to parse path as URL: {}", path.display())) - })?; + let specifier = ModuleSpecifier::from_file_path(&path) + .map_err(|_| LintError::PathParse(path))?; let media_type = MediaType::from_specifier(&specifier); let parsed_source = deno_ast::parse_program(deno_ast::ParseParams { specifier, diff --git a/cli/ops/mod.rs b/cli/ops/mod.rs index 4ac1618816..7cee5bcfa1 100644 --- a/cli/ops/mod.rs +++ b/cli/ops/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. pub mod bench; pub mod jupyter; diff --git a/cli/ops/testing.rs b/cli/ops/testing.rs index 3c6936971a..c00ab949be 100644 --- a/cli/ops/testing.rs +++ b/cli/ops/testing.rs @@ -1,4 +1,16 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; + +use deno_core::op2; +use deno_core::v8; +use deno_core::ModuleSpecifier; +use deno_core::OpState; +use deno_error::JsErrorBox; +use deno_runtime::deno_permissions::ChildPermissionsArg; +use deno_runtime::deno_permissions::PermissionsContainer; +use uuid::Uuid; use crate::tools::test::TestContainer; use crate::tools::test::TestDescription; @@ -9,19 +21,6 @@ use crate::tools::test::TestLocation; use crate::tools::test::TestStepDescription; use crate::tools::test::TestStepResult; -use deno_core::error::generic_error; -use deno_core::error::type_error; -use deno_core::error::AnyError; -use deno_core::op2; -use deno_core::v8; -use deno_core::ModuleSpecifier; -use deno_core::OpState; -use deno_runtime::deno_permissions::ChildPermissionsArg; -use deno_runtime::deno_permissions::PermissionsContainer; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering; -use uuid::Uuid; - deno_core::extension!(deno_test, ops = [ op_pledge_test_permissions, @@ -72,7 +71,7 @@ pub fn op_pledge_test_permissions( pub fn op_restore_test_permissions( state: &mut OpState, #[serde] token: Uuid, -) -> Result<(), AnyError> { +) -> Result<(), JsErrorBox> { if let Some(permissions_holder) = state.try_take::() { if token != permissions_holder.0 { panic!("restore test permissions token does not match the stored token"); @@ -82,7 +81,7 @@ pub fn op_restore_test_permissions( state.put::(permissions); Ok(()) } else { - Err(generic_error("no permissions to restore")) + Err(JsErrorBox::generic("no permissions to restore")) } } @@ -102,9 +101,9 @@ fn op_register_test( #[smi] line_number: u32, #[smi] column_number: u32, #[buffer] ret_buf: &mut [u8], -) -> Result<(), AnyError> { +) -> Result<(), JsErrorBox> { if ret_buf.len() != 4 { - return Err(type_error(format!( + return Err(JsErrorBox::type_error(format!( "Invalid ret_buf length: {}", ret_buf.len() ))); diff --git a/cli/resolver.rs b/cli/resolver.rs index c4c8ef8b36..5677767fdd 100644 --- a/cli/resolver.rs +++ b/cli/resolver.rs @@ -1,28 +1,26 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; -use std::path::Path; -use std::path::PathBuf; use std::sync::Arc; -use crate::sys::CliSys; use async_trait::async_trait; -use dashmap::DashMap; use dashmap::DashSet; use deno_ast::MediaType; use deno_config::workspace::MappedResolutionDiagnostic; use deno_config::workspace::MappedResolutionError; -use deno_core::anyhow::anyhow; use deno_core::anyhow::Context; use deno_core::error::AnyError; use deno_core::url::Url; use deno_core::ModuleSourceCode; use deno_core::ModuleSpecifier; +use deno_error::JsErrorBox; use deno_graph::source::ResolveError; use deno_graph::source::UnknownBuiltInNodeModuleError; use deno_graph::NpmLoadError; use deno_graph::NpmResolvePkgReqsResult; use deno_npm::resolution::NpmResolutionError; +use deno_resolver::npm::DenoInNpmPackageChecker; +use deno_resolver::sloppy_imports::SloppyImportsCachedFs; use deno_resolver::sloppy_imports::SloppyImportsResolver; use deno_runtime::colors; use deno_runtime::deno_fs; @@ -31,29 +29,38 @@ use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker; use deno_semver::package::PackageReq; use node_resolver::NodeResolutionKind; use node_resolver::ResolutionMode; -use sys_traits::FsMetadata; -use sys_traits::FsMetadataValue; use thiserror::Error; use crate::args::NpmCachingStrategy; use crate::args::DENO_DISABLE_PEDANTIC_NODE_WARNINGS; use crate::node::CliNodeCodeTranslator; +use crate::npm::installer::NpmInstaller; +use crate::npm::installer::PackageCaching; use crate::npm::CliNpmResolver; -use crate::npm::InnerCliNpmResolverRef; +use crate::sys::CliSys; use crate::util::sync::AtomicFlag; use crate::util::text_encoding::from_utf8_lossy_cow; -pub type CjsTracker = deno_resolver::cjs::CjsTracker; -pub type IsCjsResolver = deno_resolver::cjs::IsCjsResolver; +pub type CliCjsTracker = + deno_resolver::cjs::CjsTracker; +pub type CliIsCjsResolver = + deno_resolver::cjs::IsCjsResolver; +pub type CliSloppyImportsCachedFs = SloppyImportsCachedFs; pub type CliSloppyImportsResolver = - SloppyImportsResolver; + SloppyImportsResolver; pub type CliDenoResolver = deno_resolver::DenoResolver< + DenoInNpmPackageChecker, RealIsBuiltInNodeModuleChecker, - SloppyImportsCachedFs, + CliNpmResolver, + CliSloppyImportsCachedFs, + CliSys, +>; +pub type CliNpmReqResolver = deno_resolver::npm::NpmReqResolver< + DenoInNpmPackageChecker, + RealIsBuiltInNodeModuleChecker, + CliNpmResolver, CliSys, >; -pub type CliNpmReqResolver = - deno_resolver::npm::NpmReqResolver; pub struct ModuleCodeStringSource { pub code: ModuleSourceCode, @@ -61,7 +68,8 @@ pub struct ModuleCodeStringSource { pub media_type: MediaType, } -#[derive(Debug, Error)] +#[derive(Debug, Error, deno_error::JsError)] +#[class(type)] #[error("{media_type} files are not supported in npm packages: {specifier}")] pub struct NotSupportedKindInNpmError { pub media_type: MediaType, @@ -71,14 +79,14 @@ pub struct NotSupportedKindInNpmError { // todo(dsherret): move to module_loader.rs (it seems to be here due to use in standalone) #[derive(Clone)] pub struct NpmModuleLoader { - cjs_tracker: Arc, + cjs_tracker: Arc, fs: Arc, node_code_translator: Arc, } impl NpmModuleLoader { pub fn new( - cjs_tracker: Arc, + cjs_tracker: Arc, fs: Arc, node_code_translator: Arc, ) -> Self { @@ -166,48 +174,30 @@ impl NpmModuleLoader { } } -pub struct CliResolverOptions { - pub deno_resolver: Arc, - pub npm_resolver: Option>, - pub bare_node_builtins_enabled: bool, -} +#[derive(Debug, Default)] +pub struct FoundPackageJsonDepFlag(AtomicFlag); /// A resolver that takes care of resolution, taking into account loaded /// import map, JSX settings. #[derive(Debug)] pub struct CliResolver { deno_resolver: Arc, - npm_resolver: Option>, - found_package_json_dep_flag: AtomicFlag, - bare_node_builtins_enabled: bool, + found_package_json_dep_flag: Arc, warned_pkgs: DashSet, } impl CliResolver { - pub fn new(options: CliResolverOptions) -> Self { + pub fn new( + deno_resolver: Arc, + found_package_json_dep_flag: Arc, + ) -> Self { Self { - deno_resolver: options.deno_resolver, - npm_resolver: options.npm_resolver, - found_package_json_dep_flag: Default::default(), - bare_node_builtins_enabled: options.bare_node_builtins_enabled, + deno_resolver, + found_package_json_dep_flag, warned_pkgs: Default::default(), } } - // todo(dsherret): move this off CliResolver as CliResolver is acting - // like a factory by doing this (it's beyond its responsibility) - pub fn create_graph_npm_resolver( - &self, - npm_caching: NpmCachingStrategy, - ) -> WorkerCliNpmGraphResolver { - WorkerCliNpmGraphResolver { - npm_resolver: self.npm_resolver.as_ref(), - found_package_json_dep_flag: &self.found_package_json_dep_flag, - bare_node_builtins_enabled: self.bare_node_builtins_enabled, - npm_caching, - } - } - pub fn resolve( &self, raw_specifier: &str, @@ -225,15 +215,17 @@ impl CliResolver { ) => match mapped_resolution_error { MappedResolutionError::Specifier(e) => ResolveError::Specifier(e), // deno_graph checks specifically for an ImportMapError - MappedResolutionError::ImportMap(e) => ResolveError::Other(e.into()), - err => ResolveError::Other(err.into()), + MappedResolutionError::ImportMap(e) => ResolveError::ImportMap(e), + MappedResolutionError::Workspace(e) => { + ResolveError::Other(JsErrorBox::from_err(e)) + } }, - err => ResolveError::Other(err.into()), + err => ResolveError::Other(JsErrorBox::from_err(err)), })?; if resolution.found_package_json_dep { // mark that we need to do an "npm install" later - self.found_package_json_dep_flag.raise(); + self.found_package_json_dep_flag.0.raise(); } if let Some(diagnostic) = resolution.maybe_diagnostic { @@ -260,15 +252,31 @@ impl CliResolver { } #[derive(Debug)] -pub struct WorkerCliNpmGraphResolver<'a> { - npm_resolver: Option<&'a Arc>, - found_package_json_dep_flag: &'a AtomicFlag, +pub struct CliNpmGraphResolver { + npm_installer: Option>, + found_package_json_dep_flag: Arc, bare_node_builtins_enabled: bool, npm_caching: NpmCachingStrategy, } +impl CliNpmGraphResolver { + pub fn new( + npm_installer: Option>, + found_package_json_dep_flag: Arc, + bare_node_builtins_enabled: bool, + npm_caching: NpmCachingStrategy, + ) -> Self { + Self { + npm_installer, + found_package_json_dep_flag, + bare_node_builtins_enabled, + npm_caching, + } + } +} + #[async_trait(?Send)] -impl<'a> deno_graph::source::NpmResolver for WorkerCliNpmGraphResolver<'a> { +impl deno_graph::source::NpmResolver for CliNpmGraphResolver { fn resolve_builtin_node_module( &self, specifier: &ModuleSpecifier, @@ -298,17 +306,12 @@ impl<'a> deno_graph::source::NpmResolver for WorkerCliNpmGraphResolver<'a> { } fn load_and_cache_npm_package_info(&self, package_name: &str) { - match self.npm_resolver { - Some(npm_resolver) if npm_resolver.as_managed().is_some() => { - let npm_resolver = npm_resolver.clone(); - let package_name = package_name.to_string(); - deno_core::unsync::spawn(async move { - if let Some(managed) = npm_resolver.as_managed() { - let _ignore = managed.cache_package_info(&package_name).await; - } - }); - } - _ => {} + if let Some(npm_installer) = &self.npm_installer { + let npm_installer = npm_installer.clone(); + let package_name = package_name.to_string(); + deno_core::unsync::spawn(async move { + let _ignore = npm_installer.cache_package_info(&package_name).await; + }); } } @@ -316,17 +319,11 @@ impl<'a> deno_graph::source::NpmResolver for WorkerCliNpmGraphResolver<'a> { &self, package_reqs: &[PackageReq], ) -> NpmResolvePkgReqsResult { - match &self.npm_resolver { - Some(npm_resolver) => { - let npm_resolver = match npm_resolver.as_inner() { - InnerCliNpmResolverRef::Managed(npm_resolver) => npm_resolver, - // if we are using byonm, then this should never be called because - // we don't use deno_graph's npm resolution in this case - InnerCliNpmResolverRef::Byonm(_) => unreachable!(), - }; - - let top_level_result = if self.found_package_json_dep_flag.is_raised() { - npm_resolver + match &self.npm_installer { + Some(npm_installer) => { + let top_level_result = if self.found_package_json_dep_flag.0.is_raised() + { + npm_installer .ensure_top_level_package_json_install() .await .map(|_| ()) @@ -334,15 +331,13 @@ impl<'a> deno_graph::source::NpmResolver for WorkerCliNpmGraphResolver<'a> { Ok(()) }; - let result = npm_resolver + let result = npm_installer .add_package_reqs_raw( package_reqs, match self.npm_caching { - NpmCachingStrategy::Eager => { - Some(crate::npm::PackageCaching::All) - } + NpmCachingStrategy::Eager => Some(PackageCaching::All), NpmCachingStrategy::Lazy => { - Some(crate::npm::PackageCaching::Only(package_reqs.into())) + Some(PackageCaching::Only(package_reqs.into())) } NpmCachingStrategy::Manual => None, }, @@ -356,26 +351,28 @@ impl<'a> deno_graph::source::NpmResolver for WorkerCliNpmGraphResolver<'a> { .map(|r| { r.map_err(|err| match err { NpmResolutionError::Registry(e) => { - NpmLoadError::RegistryInfo(Arc::new(e.into())) + NpmLoadError::RegistryInfo(Arc::new(e)) } NpmResolutionError::Resolution(e) => { - NpmLoadError::PackageReqResolution(Arc::new(e.into())) + NpmLoadError::PackageReqResolution(Arc::new(e)) } NpmResolutionError::DependencyEntry(e) => { - NpmLoadError::PackageReqResolution(Arc::new(e.into())) + NpmLoadError::PackageReqResolution(Arc::new(e)) } }) }) .collect(), dep_graph_result: match top_level_result { - Ok(()) => result.dependencies_result.map_err(Arc::new), + Ok(()) => result + .dependencies_result + .map_err(|e| Arc::new(e) as Arc), Err(err) => Err(Arc::new(err)), }, } } None => { - let err = Arc::new(anyhow!( - "npm specifiers were requested; but --no-npm is specified" + let err = Arc::new(JsErrorBox::generic( + "npm specifiers were requested; but --no-npm is specified", )); NpmResolvePkgReqsResult { results: package_reqs @@ -392,60 +389,3 @@ impl<'a> deno_graph::source::NpmResolver for WorkerCliNpmGraphResolver<'a> { self.bare_node_builtins_enabled } } - -#[derive(Debug)] -pub struct SloppyImportsCachedFs { - sys: CliSys, - cache: Option< - DashMap< - PathBuf, - Option, - >, - >, -} - -impl SloppyImportsCachedFs { - pub fn new(sys: CliSys) -> Self { - Self { - sys, - cache: Some(Default::default()), - } - } - - pub fn new_without_stat_cache(fs: CliSys) -> Self { - Self { - sys: fs, - cache: None, - } - } -} - -impl deno_resolver::sloppy_imports::SloppyImportResolverFs - for SloppyImportsCachedFs -{ - fn stat_sync( - &self, - path: &Path, - ) -> Option { - if let Some(cache) = &self.cache { - if let Some(entry) = cache.get(path) { - return *entry; - } - } - - let entry = self.sys.fs_metadata(path).ok().and_then(|stat| { - if stat.file_type().is_file() { - Some(deno_resolver::sloppy_imports::SloppyImportsFsEntry::File) - } else if stat.file_type().is_dir() { - Some(deno_resolver::sloppy_imports::SloppyImportsFsEntry::Dir) - } else { - None - } - }); - - if let Some(cache) = &self.cache { - cache.insert(path.to_owned(), entry); - } - entry - } -} diff --git a/cli/shared.rs b/cli/shared.rs index 808aff707b..6a28473edd 100644 --- a/cli/shared.rs +++ b/cli/shared.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// This module is shared between build script and the binaries. Use it sparsely. use deno_core::anyhow::bail; diff --git a/cli/standalone/binary.rs b/cli/standalone/binary.rs index 48af787f18..5334b4719d 100644 --- a/cli/standalone/binary.rs +++ b/cli/standalone/binary.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::collections::BTreeMap; @@ -38,6 +38,13 @@ use deno_core::futures::AsyncSeekExt; use deno_core::serde_json; use deno_core::url::Url; use deno_graph::ModuleGraph; +use deno_lib::cache::DenoDir; +use deno_lib::standalone::virtual_fs::FileSystemCaseSensitivity; +use deno_lib::standalone::virtual_fs::VfsEntry; +use deno_lib::standalone::virtual_fs::VfsFileSubDataKind; +use deno_lib::standalone::virtual_fs::VirtualDirectory; +use deno_lib::standalone::virtual_fs::VirtualDirectoryEntries; +use deno_lib::standalone::virtual_fs::WindowsSystemRootablePath; use deno_npm::resolution::SerializedNpmResolutionSnapshot; use deno_npm::resolution::SerializedNpmResolutionSnapshotPackage; use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot; @@ -51,6 +58,7 @@ use deno_runtime::deno_fs::FileSystem; use deno_runtime::deno_fs::RealFs; use deno_runtime::deno_io::fs::FsError; use deno_runtime::deno_node::PackageJson; +use deno_runtime::deno_permissions::PermissionsOptions; use deno_semver::npm::NpmVersionReqParseError; use deno_semver::package::PackageReq; use deno_semver::Version; @@ -61,28 +69,6 @@ use log::Level; use serde::Deserialize; use serde::Serialize; -use crate::args::CaData; -use crate::args::CliOptions; -use crate::args::CompileFlags; -use crate::args::NpmInstallDepsProvider; -use crate::args::PermissionFlags; -use crate::args::UnstableConfig; -use crate::cache::DenoDir; -use crate::cache::FastInsecureHasher; -use crate::emit::Emitter; -use crate::file_fetcher::CliFileFetcher; -use crate::http_util::HttpClientProvider; -use crate::npm::CliNpmResolver; -use crate::npm::InnerCliNpmResolverRef; -use crate::resolver::CjsTracker; -use crate::shared::ReleaseChannel; -use crate::standalone::virtual_fs::VfsEntry; -use crate::util::archive; -use crate::util::fs::canonicalize_path; -use crate::util::fs::canonicalize_path_maybe_not_exists; -use crate::util::progress_bar::ProgressBar; -use crate::util::progress_bar::ProgressBarStyle; - use super::file_system::DenoCompileFileSystem; use super::serialization::deserialize_binary_data_section; use super::serialization::serialize_binary_data_section; @@ -95,11 +81,26 @@ use super::virtual_fs::output_vfs; use super::virtual_fs::BuiltVfs; use super::virtual_fs::FileBackedVfs; use super::virtual_fs::VfsBuilder; -use super::virtual_fs::VfsFileSubDataKind; use super::virtual_fs::VfsRoot; -use super::virtual_fs::VirtualDirectory; -use super::virtual_fs::VirtualDirectoryEntries; -use super::virtual_fs::WindowsSystemRootablePath; +use crate::args::CaData; +use crate::args::CliOptions; +use crate::args::CompileFlags; +use crate::args::NpmInstallDepsProvider; +use crate::args::PermissionFlags; +use crate::args::UnstableConfig; +use crate::cache::FastInsecureHasher; +use crate::emit::Emitter; +use crate::file_fetcher::CliFileFetcher; +use crate::http_util::HttpClientProvider; +use crate::npm::CliNpmResolver; +use crate::resolver::CliCjsTracker; +use crate::shared::ReleaseChannel; +use crate::sys::CliSys; +use crate::util::archive; +use crate::util::fs::canonicalize_path; +use crate::util::fs::canonicalize_path_maybe_not_exists; +use crate::util::progress_bar::ProgressBar; +use crate::util::progress_bar::ProgressBarStyle; pub static DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME: &str = ".deno_compile_node_modules"; @@ -189,7 +190,7 @@ pub struct Metadata { pub argv: Vec, pub seed: Option, pub code_cache_key: Option, - pub permissions: PermissionFlags, + pub permissions: PermissionsOptions, pub location: Option, pub v8_flags: Vec, pub log_level: Option, @@ -202,6 +203,7 @@ pub struct Metadata { pub node_modules: Option, pub unstable_config: UnstableConfig, pub otel_config: OtelConfig, + pub vfs_case_sensitivity: FileSystemCaseSensitivity, } #[allow(clippy::too_many_arguments)] @@ -379,7 +381,11 @@ pub fn extract_standalone( root_path: root_path.clone(), start_file_offset: 0, }; - Arc::new(FileBackedVfs::new(Cow::Borrowed(vfs_files_data), fs_root)) + Arc::new(FileBackedVfs::new( + Cow::Borrowed(vfs_files_data), + fs_root, + metadata.vfs_case_sensitivity, + )) }; Ok(Some(StandaloneData { metadata, @@ -404,13 +410,13 @@ pub struct WriteBinOptions<'a> { } pub struct DenoCompileBinaryWriter<'a> { - cjs_tracker: &'a CjsTracker, + cjs_tracker: &'a CliCjsTracker, cli_options: &'a CliOptions, - deno_dir: &'a DenoDir, + deno_dir: &'a DenoDir, emitter: &'a Emitter, file_fetcher: &'a CliFileFetcher, http_client_provider: &'a HttpClientProvider, - npm_resolver: &'a dyn CliNpmResolver, + npm_resolver: &'a CliNpmResolver, workspace_resolver: &'a WorkspaceResolver, npm_system_info: NpmSystemInfo, } @@ -418,13 +424,13 @@ pub struct DenoCompileBinaryWriter<'a> { impl<'a> DenoCompileBinaryWriter<'a> { #[allow(clippy::too_many_arguments)] pub fn new( - cjs_tracker: &'a CjsTracker, + cjs_tracker: &'a CliCjsTracker, cli_options: &'a CliOptions, - deno_dir: &'a DenoDir, + deno_dir: &'a DenoDir, emitter: &'a Emitter, file_fetcher: &'a CliFileFetcher, http_client_provider: &'a HttpClientProvider, - npm_resolver: &'a dyn CliNpmResolver, + npm_resolver: &'a CliNpmResolver, workspace_resolver: &'a WorkspaceResolver, npm_system_info: NpmSystemInfo, ) -> Self { @@ -593,10 +599,11 @@ impl<'a> DenoCompileBinaryWriter<'a> { None => None, }; let mut vfs = VfsBuilder::new(); - let npm_snapshot = match self.npm_resolver.as_inner() { - InnerCliNpmResolverRef::Managed(managed) => { - let snapshot = - managed.serialized_valid_snapshot_for_system(&self.npm_system_info); + let npm_snapshot = match &self.npm_resolver { + CliNpmResolver::Managed(managed) => { + let snapshot = managed + .resolution() + .serialized_valid_snapshot_for_system(&self.npm_system_info); if !snapshot.as_serialized().packages.is_empty() { self.fill_npm_vfs(&mut vfs).context("Building npm vfs.")?; Some(snapshot) @@ -604,7 +611,7 @@ impl<'a> DenoCompileBinaryWriter<'a> { None } } - InnerCliNpmResolverRef::Byonm(_) => { + CliNpmResolver::Byonm(_) => { self.fill_npm_vfs(&mut vfs)?; None } @@ -745,8 +752,8 @@ impl<'a> DenoCompileBinaryWriter<'a> { ); } - let node_modules = match self.npm_resolver.as_inner() { - InnerCliNpmResolverRef::Managed(_) => { + let node_modules = match &self.npm_resolver { + CliNpmResolver::Managed(_) => { npm_snapshot.as_ref().map(|_| NodeModules::Managed { node_modules_dir: self.npm_resolver.root_node_modules_path().map( |path| { @@ -759,7 +766,7 @@ impl<'a> DenoCompileBinaryWriter<'a> { ), }) } - InnerCliNpmResolverRef::Byonm(resolver) => Some(NodeModules::Byonm { + CliNpmResolver::Byonm(resolver) => Some(NodeModules::Byonm { root_node_modules_dir: resolver.root_node_modules_path().map( |node_modules_dir| { root_dir_url @@ -794,7 +801,7 @@ impl<'a> DenoCompileBinaryWriter<'a> { seed: self.cli_options.seed(), code_cache_key, location: self.cli_options.location_flag().clone(), - permissions: self.cli_options.permission_flags().clone(), + permissions: self.cli_options.permissions_options(), v8_flags: self.cli_options.v8_flags().clone(), unsafely_ignore_certificate_errors: self .cli_options @@ -851,6 +858,7 @@ impl<'a> DenoCompileBinaryWriter<'a> { npm_lazy_caching: self.cli_options.unstable_npm_lazy_caching(), }, otel_config: self.cli_options.otel_config(), + vfs_case_sensitivity: vfs.case_sensitivity, }; write_binary_bytes( @@ -873,16 +881,17 @@ impl<'a> DenoCompileBinaryWriter<'a> { } } - match self.npm_resolver.as_inner() { - InnerCliNpmResolverRef::Managed(npm_resolver) => { + match &self.npm_resolver { + CliNpmResolver::Managed(npm_resolver) => { if let Some(node_modules_path) = npm_resolver.root_node_modules_path() { maybe_warn_different_system(&self.npm_system_info); builder.add_dir_recursive(node_modules_path)?; Ok(()) } else { // we'll flatten to remove any custom registries later - let mut packages = - npm_resolver.all_system_packages(&self.npm_system_info); + let mut packages = npm_resolver + .resolution() + .all_system_packages(&self.npm_system_info); packages.sort_by(|a, b| a.id.cmp(&b.id)); // determinism for package in packages { let folder = @@ -892,7 +901,7 @@ impl<'a> DenoCompileBinaryWriter<'a> { Ok(()) } } - InnerCliNpmResolverRef::Byonm(_) => { + CliNpmResolver::Byonm(_) => { maybe_warn_different_system(&self.npm_system_info); for pkg_json in self.cli_options.workspace().package_jsons() { builder.add_file_at_path(&pkg_json.path)?; @@ -935,8 +944,8 @@ impl<'a> DenoCompileBinaryWriter<'a> { &self, mut vfs: VfsBuilder, ) -> BuiltVfs { - match self.npm_resolver.as_inner() { - InnerCliNpmResolverRef::Managed(npm_resolver) => { + match &self.npm_resolver { + CliNpmResolver::Managed(npm_resolver) => { if npm_resolver.root_node_modules_path().is_some() { return vfs.build(); } @@ -984,11 +993,15 @@ impl<'a> DenoCompileBinaryWriter<'a> { // it's better to not expose the user's cache directory, so take it out // of there + let case_sensitivity = vfs.case_sensitivity(); let parent = global_cache_root_path.parent().unwrap(); let parent_dir = vfs.get_dir_mut(parent).unwrap(); let index = parent_dir .entries - .binary_search(DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME) + .binary_search( + DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME, + case_sensitivity, + ) .unwrap(); let npm_global_cache_dir_entry = parent_dir.entries.remove(index); @@ -996,9 +1009,19 @@ impl<'a> DenoCompileBinaryWriter<'a> { // this is not as optimized as it could be let mut last_name = Cow::Borrowed(DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME); - for ancestor in parent.ancestors() { - let dir = vfs.get_dir_mut(ancestor).unwrap(); - if let Ok(index) = dir.entries.binary_search(&last_name) { + for ancestor in + parent.ancestors().map(Some).chain(std::iter::once(None)) + { + let dir = if let Some(ancestor) = ancestor { + vfs.get_dir_mut(ancestor).unwrap() + } else if cfg!(windows) { + vfs.get_system_root_dir_mut() + } else { + break; + }; + if let Ok(index) = + dir.entries.binary_search(&last_name, case_sensitivity) + { dir.entries.remove(index); } last_name = Cow::Owned(dir.name.clone()); @@ -1009,10 +1032,12 @@ impl<'a> DenoCompileBinaryWriter<'a> { // now build the vfs and add the global cache dir entry there let mut built_vfs = vfs.build(); - built_vfs.entries.insert(npm_global_cache_dir_entry); + built_vfs + .entries + .insert(npm_global_cache_dir_entry, case_sensitivity); built_vfs } - InnerCliNpmResolverRef::Byonm(_) => vfs.build(), + CliNpmResolver::Byonm(_) => vfs.build(), } } } diff --git a/cli/standalone/code_cache.rs b/cli/standalone/code_cache.rs index ec89c3ab1b..de9ff2a141 100644 --- a/cli/standalone/code_cache.rs +++ b/cli/standalone/code_cache.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::BTreeMap; use std::collections::HashMap; @@ -395,10 +395,11 @@ fn deserialize_with_reader( #[cfg(test)] mod test { + use std::fs::File; + use test_util::TempDir; use super::*; - use std::fs::File; #[test] fn serialize_deserialize() { diff --git a/cli/standalone/file_system.rs b/cli/standalone/file_system.rs index 0a11d4550f..c4b3ebe728 100644 --- a/cli/standalone/file_system.rs +++ b/cli/standalone/file_system.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::io::ErrorKind; @@ -9,6 +9,7 @@ use std::sync::Arc; use std::time::Duration; use std::time::SystemTime; +use deno_lib::standalone::virtual_fs::VfsFileSubDataKind; use deno_runtime::deno_fs::AccessCheckCb; use deno_runtime::deno_fs::FileSystem; use deno_runtime::deno_fs::FsDirEntry; @@ -23,13 +24,13 @@ use sys_traits::boxed::BoxedFsDirEntry; use sys_traits::boxed::BoxedFsMetadataValue; use sys_traits::boxed::FsMetadataBoxed; use sys_traits::boxed::FsReadDirBoxed; +use sys_traits::FsCopy; use sys_traits::FsMetadata; use super::virtual_fs::FileBackedVfs; use super::virtual_fs::FileBackedVfsDirEntry; use super::virtual_fs::FileBackedVfsFile; use super::virtual_fs::FileBackedVfsMetadata; -use super::virtual_fs::VfsFileSubDataKind; #[derive(Debug, Clone)] pub struct DenoCompileFileSystem(Arc); @@ -47,24 +48,32 @@ impl DenoCompileFileSystem { } } - fn copy_to_real_path(&self, oldpath: &Path, newpath: &Path) -> FsResult<()> { + fn copy_to_real_path( + &self, + oldpath: &Path, + newpath: &Path, + ) -> std::io::Result { let old_file = self.0.file_entry(oldpath)?; let old_file_bytes = self.0.read_file_all(old_file, VfsFileSubDataKind::Raw)?; - RealFs.write_file_sync( - newpath, - OpenOptions { - read: false, - write: true, - create: true, - truncate: true, - append: false, - create_new: false, - mode: None, - }, - None, - &old_file_bytes, - ) + let len = old_file_bytes.len() as u64; + RealFs + .write_file_sync( + newpath, + OpenOptions { + read: false, + write: true, + create: true, + truncate: true, + append: false, + create_new: false, + mode: None, + }, + None, + &old_file_bytes, + ) + .map_err(|err| err.into_io_error())?; + Ok(len) } } @@ -191,7 +200,10 @@ impl FileSystem for DenoCompileFileSystem { fn copy_file_sync(&self, oldpath: &Path, newpath: &Path) -> FsResult<()> { self.error_if_in_vfs(newpath)?; if self.0.is_path_within(oldpath) { - self.copy_to_real_path(oldpath, newpath) + self + .copy_to_real_path(oldpath, newpath) + .map(|_| ()) + .map_err(FsError::Io) } else { RealFs.copy_file_sync(oldpath, newpath) } @@ -206,6 +218,8 @@ impl FileSystem for DenoCompileFileSystem { let fs = self.clone(); tokio::task::spawn_blocking(move || { fs.copy_to_real_path(&oldpath, &newpath) + .map(|_| ()) + .map_err(FsError::Io) }) .await? } else { @@ -593,6 +607,32 @@ impl sys_traits::BaseFsMetadata for DenoCompileFileSystem { } } +impl sys_traits::BaseFsCopy for DenoCompileFileSystem { + #[inline] + fn base_fs_copy(&self, from: &Path, to: &Path) -> std::io::Result { + self + .error_if_in_vfs(to) + .map_err(|err| err.into_io_error())?; + if self.0.is_path_within(from) { + self.copy_to_real_path(from, to) + } else { + #[allow(clippy::disallowed_types)] // ok because we're implementing the fs + sys_traits::impls::RealSys.fs_copy(from, to) + } + } +} + +impl sys_traits::BaseFsCloneFile for DenoCompileFileSystem { + fn base_fs_clone_file( + &self, + _from: &Path, + _to: &Path, + ) -> std::io::Result<()> { + // will cause a fallback in the code that uses this + Err(not_supported("cloning files")) + } +} + impl sys_traits::BaseFsCreateDir for DenoCompileFileSystem { #[inline] fn base_fs_create_dir( @@ -794,6 +834,14 @@ impl sys_traits::BaseFsOpen for DenoCompileFileSystem { } } +impl sys_traits::BaseFsSymlinkDir for DenoCompileFileSystem { + fn base_fs_symlink_dir(&self, src: &Path, dst: &Path) -> std::io::Result<()> { + self + .symlink_sync(src, dst, Some(FsFileType::Directory)) + .map_err(|err| err.into_io_error()) + } +} + impl sys_traits::SystemRandom for DenoCompileFileSystem { #[inline] fn sys_random(&self, buf: &mut [u8]) -> std::io::Result<()> { diff --git a/cli/standalone/mod.rs b/cli/standalone/mod.rs index 0fe6de0b9a..f2a0859e8f 100644 --- a/cli/standalone/mod.rs +++ b/cli/standalone/mod.rs @@ -1,10 +1,15 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Allow unused code warnings because we share // code between the two bin targets. #![allow(dead_code)] #![allow(unused_imports)] +use std::borrow::Cow; +use std::path::PathBuf; +use std::rc::Rc; +use std::sync::Arc; + use binary::StandaloneData; use binary::StandaloneModules; use code_cache::DenoCompileCodeCache; @@ -16,9 +21,8 @@ use deno_config::workspace::MappedResolutionError; use deno_config::workspace::ResolverWorkspaceJsrPackage; use deno_config::workspace::WorkspaceResolver; use deno_core::anyhow::Context; -use deno_core::error::generic_error; -use deno_core::error::type_error; use deno_core::error::AnyError; +use deno_core::error::ModuleLoaderError; use deno_core::futures::future::LocalBoxFuture; use deno_core::futures::FutureExt; use deno_core::v8_set_flags; @@ -31,9 +35,25 @@ use deno_core::ModuleType; use deno_core::RequestedModuleType; use deno_core::ResolutionKind; use deno_core::SourceCodeCacheInfo; +use deno_error::JsErrorBox; +use deno_lib::cache::DenoDirProvider; +use deno_lib::npm::NpmRegistryReadPermissionChecker; +use deno_lib::npm::NpmRegistryReadPermissionCheckerMode; +use deno_lib::standalone::virtual_fs::VfsFileSubDataKind; +use deno_lib::worker::CreateModuleLoaderResult; +use deno_lib::worker::LibMainWorkerFactory; +use deno_lib::worker::LibMainWorkerOptions; +use deno_lib::worker::ModuleLoaderFactory; +use deno_lib::worker::StorageKeyResolver; use deno_npm::npm_rc::ResolvedNpmRc; +use deno_npm::resolution::NpmResolutionSnapshot; use deno_package_json::PackageJsonDepValue; use deno_resolver::cjs::IsCjsResolutionMode; +use deno_resolver::npm::managed::ManagedInNpmPkgCheckerCreateOptions; +use deno_resolver::npm::managed::NpmResolutionCell; +use deno_resolver::npm::ByonmNpmResolverCreateOptions; +use deno_resolver::npm::CreateInNpmPkgCheckerOptions; +use deno_resolver::npm::DenoInNpmPackageChecker; use deno_resolver::npm::NpmReqResolverOptions; use deno_runtime::deno_fs; use deno_runtime::deno_fs::FileSystem; @@ -57,20 +77,14 @@ use node_resolver::NodeResolutionKind; use node_resolver::ResolutionMode; use serialization::DenoCompileModuleSource; use serialization::SourceMapStore; -use std::borrow::Cow; -use std::rc::Rc; -use std::sync::Arc; use virtual_fs::FileBackedVfs; -use virtual_fs::VfsFileSubDataKind; use crate::args::create_default_npmrc; use crate::args::get_root_cert_store; use crate::args::npm_pkg_req_ref_to_binary_command; use crate::args::CaData; use crate::args::NpmInstallDepsProvider; -use crate::args::StorageKeyResolver; use crate::cache::Caches; -use crate::cache::DenoDirProvider; use crate::cache::FastInsecureHasher; use crate::cache::NodeAnalysisCache; use crate::http_util::HttpClientProvider; @@ -78,16 +92,14 @@ use crate::node::CliCjsCodeAnalyzer; use crate::node::CliNodeCodeTranslator; use crate::node::CliNodeResolver; use crate::node::CliPackageJsonResolver; -use crate::npm::create_cli_npm_resolver; -use crate::npm::create_in_npm_pkg_checker; +use crate::npm::create_npm_process_state_provider; use crate::npm::CliByonmNpmResolverCreateOptions; -use crate::npm::CliManagedInNpmPkgCheckerCreateOptions; use crate::npm::CliManagedNpmResolverCreateOptions; use crate::npm::CliNpmResolver; use crate::npm::CliNpmResolverCreateOptions; use crate::npm::CliNpmResolverManagedSnapshotOption; -use crate::npm::CreateInNpmPkgCheckerOptions; -use crate::resolver::CjsTracker; +use crate::npm::NpmResolutionInitializer; +use crate::resolver::CliCjsTracker; use crate::resolver::CliNpmReqResolver; use crate::resolver::NpmModuleLoader; use crate::sys::CliSys; @@ -98,8 +110,6 @@ use crate::util::v8::construct_v8_flags; use crate::worker::CliCodeCache; use crate::worker::CliMainWorkerFactory; use crate::worker::CliMainWorkerOptions; -use crate::worker::CreateModuleLoaderResult; -use crate::worker::ModuleLoaderFactory; pub mod binary; mod code_cache; @@ -107,23 +117,24 @@ mod file_system; mod serialization; mod virtual_fs; -pub use self::file_system::DenoCompileFileSystem; pub use binary::extract_standalone; pub use binary::is_standalone_binary; pub use binary::DenoCompileBinaryWriter; use self::binary::Metadata; +pub use self::file_system::DenoCompileFileSystem; struct SharedModuleLoaderState { - cjs_tracker: Arc, + cjs_tracker: Arc, code_cache: Option>, fs: Arc, modules: StandaloneModules, node_code_translator: Arc, node_resolver: Arc, npm_module_loader: Arc, + npm_registry_permission_checker: NpmRegistryReadPermissionChecker, npm_req_resolver: Arc, - npm_resolver: Arc, + npm_resolver: CliNpmResolver, source_maps: SourceMapStore, vfs: Arc, workspace_resolver: WorkspaceResolver, @@ -177,25 +188,32 @@ impl ModuleLoader for EmbeddedModuleLoader { raw_specifier: &str, referrer: &str, kind: ResolutionKind, - ) -> Result { + ) -> Result { let referrer = if referrer == "." { if kind != ResolutionKind::MainModule { - return Err(generic_error(format!( - "Expected to resolve main module, got {:?} instead.", - kind - ))); + return Err( + JsErrorBox::generic(format!( + "Expected to resolve main module, got {:?} instead.", + kind + )) + .into(), + ); } let current_dir = std::env::current_dir().unwrap(); deno_core::resolve_path(".", ¤t_dir)? } else { ModuleSpecifier::parse(referrer).map_err(|err| { - type_error(format!("Referrer uses invalid specifier: {}", err)) + JsErrorBox::type_error(format!( + "Referrer uses invalid specifier: {}", + err + )) })? }; let referrer_kind = if self .shared .cjs_tracker - .is_maybe_cjs(&referrer, MediaType::from_specifier(&referrer))? + .is_maybe_cjs(&referrer, MediaType::from_specifier(&referrer)) + .map_err(JsErrorBox::from_err)? { ResolutionMode::Require } else { @@ -212,7 +230,8 @@ impl ModuleLoader for EmbeddedModuleLoader { &referrer, referrer_kind, NodeResolutionKind::Execution, - )? + ) + .map_err(JsErrorBox::from_err)? .into_url(), ); } @@ -240,14 +259,18 @@ impl ModuleLoader for EmbeddedModuleLoader { Some(&referrer), referrer_kind, NodeResolutionKind::Execution, - )?, + ) + .map_err(JsErrorBox::from_err)?, ), Ok(MappedResolution::PackageJson { dep_result, sub_path, alias, .. - }) => match dep_result.as_ref().map_err(|e| AnyError::from(e.clone()))? { + }) => match dep_result + .as_ref() + .map_err(|e| JsErrorBox::from_err(e.clone()))? + { PackageJsonDepValue::Req(req) => self .shared .npm_req_resolver @@ -258,7 +281,7 @@ impl ModuleLoader for EmbeddedModuleLoader { referrer_kind, NodeResolutionKind::Execution, ) - .map_err(AnyError::from), + .map_err(|e| JsErrorBox::from_err(e).into()), PackageJsonDepValue::Workspace(version_req) => { let pkg_folder = self .shared @@ -266,7 +289,8 @@ impl ModuleLoader for EmbeddedModuleLoader { .resolve_workspace_pkg_json_folder_for_pkg_json_dep( alias, version_req, - )?; + ) + .map_err(JsErrorBox::from_err)?; Ok( self .shared @@ -277,7 +301,8 @@ impl ModuleLoader for EmbeddedModuleLoader { Some(&referrer), referrer_kind, NodeResolutionKind::Execution, - )?, + ) + .map_err(JsErrorBox::from_err)?, ) } }, @@ -286,12 +311,18 @@ impl ModuleLoader for EmbeddedModuleLoader { if let Ok(reference) = NpmPackageReqReference::from_specifier(&specifier) { - return Ok(self.shared.npm_req_resolver.resolve_req_reference( - &reference, - &referrer, - referrer_kind, - NodeResolutionKind::Execution, - )?); + return Ok( + self + .shared + .npm_req_resolver + .resolve_req_reference( + &reference, + &referrer, + referrer_kind, + NodeResolutionKind::Execution, + ) + .map_err(JsErrorBox::from_err)?, + ); } if specifier.scheme() == "jsr" { @@ -313,18 +344,22 @@ impl ModuleLoader for EmbeddedModuleLoader { Err(err) if err.is_unmapped_bare_specifier() && referrer.scheme() == "file" => { - let maybe_res = self.shared.npm_req_resolver.resolve_if_for_npm_pkg( - raw_specifier, - &referrer, - referrer_kind, - NodeResolutionKind::Execution, - )?; + let maybe_res = self + .shared + .npm_req_resolver + .resolve_if_for_npm_pkg( + raw_specifier, + &referrer, + referrer_kind, + NodeResolutionKind::Execution, + ) + .map_err(JsErrorBox::from_err)?; if let Some(res) = maybe_res { return Ok(res.into_url()); } - Err(err.into()) + Err(JsErrorBox::from_err(err).into()) } - Err(err) => Err(err.into()), + Err(err) => Err(JsErrorBox::from_err(err).into()), } } @@ -355,9 +390,9 @@ impl ModuleLoader for EmbeddedModuleLoader { { Ok(response) => response, Err(err) => { - return deno_core::ModuleLoadResponse::Sync(Err(type_error( - format!("{:#}", err), - ))); + return deno_core::ModuleLoadResponse::Sync(Err( + JsErrorBox::type_error(format!("{:#}", err)).into(), + )); } }; return deno_core::ModuleLoadResponse::Sync(Ok( @@ -415,9 +450,9 @@ impl ModuleLoader for EmbeddedModuleLoader { { Ok(is_maybe_cjs) => is_maybe_cjs, Err(err) => { - return deno_core::ModuleLoadResponse::Sync(Err(type_error( - format!("{:?}", err), - ))); + return deno_core::ModuleLoadResponse::Sync(Err( + JsErrorBox::type_error(format!("{:?}", err)).into(), + )); } }; if is_maybe_cjs { @@ -477,12 +512,16 @@ impl ModuleLoader for EmbeddedModuleLoader { )) } } - Ok(None) => deno_core::ModuleLoadResponse::Sync(Err(type_error( - format!("{MODULE_NOT_FOUND}: {}", original_specifier), - ))), - Err(err) => deno_core::ModuleLoadResponse::Sync(Err(type_error( - format!("{:?}", err), - ))), + Ok(None) => deno_core::ModuleLoadResponse::Sync(Err( + JsErrorBox::type_error(format!( + "{MODULE_NOT_FOUND}: {}", + original_specifier + )) + .into(), + )), + Err(err) => deno_core::ModuleLoadResponse::Sync(Err( + JsErrorBox::type_error(format!("{:?}", err)).into(), + )), } } @@ -548,7 +587,7 @@ impl NodeRequireLoader for EmbeddedModuleLoader { &self, permissions: &mut dyn deno_runtime::deno_node::NodePermissions, path: &'a std::path::Path, - ) -> Result, AnyError> { + ) -> Result, JsErrorBox> { if self.shared.modules.has_file(path) { // allow reading if the file is in the snapshot return Ok(Cow::Borrowed(path)); @@ -556,19 +595,25 @@ impl NodeRequireLoader for EmbeddedModuleLoader { self .shared - .npm_resolver + .npm_registry_permission_checker .ensure_read_permission(permissions, path) + .map_err(JsErrorBox::from_err) } fn load_text_file_lossy( &self, path: &std::path::Path, - ) -> Result, AnyError> { - let file_entry = self.shared.vfs.file_entry(path)?; + ) -> Result, JsErrorBox> { + let file_entry = self + .shared + .vfs + .file_entry(path) + .map_err(JsErrorBox::from_err)?; let file_bytes = self .shared .vfs - .read_file_all(file_entry, VfsFileSubDataKind::ModuleGraph)?; + .read_file_all(file_entry, VfsFileSubDataKind::ModuleGraph) + .map_err(JsErrorBox::from_err)?; Ok(from_utf8_lossy_cow(file_bytes)) } @@ -621,10 +666,10 @@ struct StandaloneRootCertStoreProvider { } impl RootCertStoreProvider for StandaloneRootCertStoreProvider { - fn get_or_try_init(&self) -> Result<&RootCertStore, AnyError> { + fn get_or_try_init(&self) -> Result<&RootCertStore, JsErrorBox> { self.cell.get_or_try_init(|| { get_root_cert_store(None, self.ca_stores.clone(), self.ca_data.clone()) - .map_err(|err| err.into()) + .map_err(JsErrorBox::from_err) }) } } @@ -648,19 +693,30 @@ pub async fn run( ca_data: metadata.ca_data.map(CaData::Bytes), cell: Default::default(), }); - let progress_bar = ProgressBar::new(ProgressBarStyle::TextOnly); - let http_client_provider = Arc::new(HttpClientProvider::new( - Some(root_cert_store_provider.clone()), - metadata.unsafely_ignore_certificate_errors.clone(), - )); // use a dummy npm registry url let npm_registry_url = ModuleSpecifier::parse("https://localhost/").unwrap(); let root_dir_url = Arc::new(ModuleSpecifier::from_directory_path(&root_path).unwrap()); let main_module = root_dir_url.join(&metadata.entrypoint_key).unwrap(); let npm_global_cache_dir = root_path.join(".deno_compile_node_modules"); - let cache_setting = CacheSetting::Only; let pkg_json_resolver = Arc::new(CliPackageJsonResolver::new(sys.clone())); + let npm_registry_permission_checker = { + let mode = match &metadata.node_modules { + Some(binary::NodeModules::Managed { + node_modules_dir: Some(path), + }) => NpmRegistryReadPermissionCheckerMode::Local(PathBuf::from(path)), + Some(binary::NodeModules::Byonm { .. }) => { + NpmRegistryReadPermissionCheckerMode::Byonm + } + Some(binary::NodeModules::Managed { + node_modules_dir: None, + }) + | None => NpmRegistryReadPermissionCheckerMode::Global( + npm_global_cache_dir.clone(), + ), + }; + NpmRegistryReadPermissionChecker::new(sys.clone(), mode) + }; let (in_npm_pkg_checker, npm_resolver) = match metadata.node_modules { Some(binary::NodeModules::Managed { node_modules_dir }) => { // create an npmrc that uses the fake npm_registry_url to resolve packages @@ -681,35 +737,25 @@ pub async fn run( let maybe_node_modules_path = node_modules_dir .map(|node_modules_dir| root_path.join(node_modules_dir)); let in_npm_pkg_checker = - create_in_npm_pkg_checker(CreateInNpmPkgCheckerOptions::Managed( - CliManagedInNpmPkgCheckerCreateOptions { + DenoInNpmPackageChecker::new(CreateInNpmPkgCheckerOptions::Managed( + ManagedInNpmPkgCheckerCreateOptions { root_cache_dir_url: npm_cache_dir.root_dir_url(), maybe_node_modules_path: maybe_node_modules_path.as_deref(), }, )); + let npm_resolution = + Arc::new(NpmResolutionCell::new(NpmResolutionSnapshot::new(snapshot))); let npm_resolver = - create_cli_npm_resolver(CliNpmResolverCreateOptions::Managed( + CliNpmResolver::new(CliNpmResolverCreateOptions::Managed( CliManagedNpmResolverCreateOptions { - snapshot: CliNpmResolverManagedSnapshotOption::Specified(Some( - snapshot, - )), - maybe_lockfile: None, - http_client_provider: http_client_provider.clone(), + npm_resolution, npm_cache_dir, - npm_install_deps_provider: Arc::new( - // this is only used for installing packages, which isn't necessary with deno compile - NpmInstallDepsProvider::empty(), - ), sys: sys.clone(), - text_only_progress_bar: progress_bar, - cache_setting, maybe_node_modules_path, npm_system_info: Default::default(), npmrc, - lifecycle_scripts: Default::default(), }, - )) - .await?; + )); (in_npm_pkg_checker, npm_resolver) } Some(binary::NodeModules::Byonm { @@ -718,15 +764,14 @@ pub async fn run( let root_node_modules_dir = root_node_modules_dir.map(|p| vfs.root().join(p)); let in_npm_pkg_checker = - create_in_npm_pkg_checker(CreateInNpmPkgCheckerOptions::Byonm); - let npm_resolver = create_cli_npm_resolver( + DenoInNpmPackageChecker::new(CreateInNpmPkgCheckerOptions::Byonm); + let npm_resolver = CliNpmResolver::new( CliNpmResolverCreateOptions::Byonm(CliByonmNpmResolverCreateOptions { sys: sys.clone(), pkg_json_resolver: pkg_json_resolver.clone(), root_node_modules_dir, }), - ) - .await?; + ); (in_npm_pkg_checker, npm_resolver) } None => { @@ -739,33 +784,24 @@ pub async fn run( npmrc.get_all_known_registries_urls(), )); let in_npm_pkg_checker = - create_in_npm_pkg_checker(CreateInNpmPkgCheckerOptions::Managed( - CliManagedInNpmPkgCheckerCreateOptions { + DenoInNpmPackageChecker::new(CreateInNpmPkgCheckerOptions::Managed( + ManagedInNpmPkgCheckerCreateOptions { root_cache_dir_url: npm_cache_dir.root_dir_url(), maybe_node_modules_path: None, }, )); + let npm_resolution = Arc::new(NpmResolutionCell::default()); let npm_resolver = - create_cli_npm_resolver(CliNpmResolverCreateOptions::Managed( + CliNpmResolver::new(CliNpmResolverCreateOptions::Managed( CliManagedNpmResolverCreateOptions { - snapshot: CliNpmResolverManagedSnapshotOption::Specified(None), - http_client_provider: http_client_provider.clone(), - npm_install_deps_provider: Arc::new( - // this is only used for installing packages, which isn't necessary with deno compile - NpmInstallDepsProvider::empty(), - ), + npm_resolution, sys: sys.clone(), - cache_setting, - text_only_progress_bar: progress_bar, npm_cache_dir, - maybe_lockfile: None, maybe_node_modules_path: None, npm_system_info: Default::default(), npmrc: create_default_npmrc(), - lifecycle_scripts: Default::default(), }, - )) - .await?; + )); (in_npm_pkg_checker, npm_resolver) } }; @@ -774,11 +810,12 @@ pub async fn run( let node_resolver = Arc::new(NodeResolver::new( in_npm_pkg_checker.clone(), RealIsBuiltInNodeModuleChecker, - npm_resolver.clone().into_npm_pkg_folder_resolver(), + npm_resolver.clone(), pkg_json_resolver.clone(), sys.clone(), + node_resolver::ConditionsFromResolutionMode::default(), )); - let cjs_tracker = Arc::new(CjsTracker::new( + let cjs_tracker = Arc::new(CliCjsTracker::new( in_npm_pkg_checker.clone(), pkg_json_resolver.clone(), if metadata.unstable_config.detect_cjs { @@ -793,11 +830,10 @@ pub async fn run( let node_analysis_cache = NodeAnalysisCache::new(cache_db.node_analysis_db()); let npm_req_resolver = Arc::new(CliNpmReqResolver::new(NpmReqResolverOptions { - byonm_resolver: (npm_resolver.clone()).into_maybe_byonm(), sys: sys.clone(), in_npm_pkg_checker: in_npm_pkg_checker.clone(), node_resolver: node_resolver.clone(), - npm_req_resolver: npm_resolver.clone().into_npm_req_resolver(), + npm_resolver: npm_resolver.clone(), })); let cjs_esm_code_analyzer = CliCjsCodeAnalyzer::new( node_analysis_cache, @@ -809,7 +845,7 @@ pub async fn run( cjs_esm_code_analyzer, in_npm_pkg_checker, node_resolver.clone(), - npm_resolver.clone().into_npm_pkg_folder_resolver(), + npm_resolver.clone(), pkg_json_resolver.clone(), sys.clone(), )); @@ -888,6 +924,7 @@ pub async fn run( fs.clone(), node_code_translator, )), + npm_registry_permission_checker, npm_resolver: npm_resolver.clone(), npm_req_resolver, source_maps, @@ -897,8 +934,7 @@ pub async fn run( }; let permissions = { - let mut permissions = - metadata.permissions.to_options(/* cli_arg_urls */ &[]); + let mut permissions = metadata.permissions; // grant read access to the vfs match &mut permissions.allow_read { Some(vec) if vec.is_empty() => { @@ -929,53 +965,67 @@ pub async fn run( } checker }); - let worker_factory = CliMainWorkerFactory::new( + let lib_main_worker_options = LibMainWorkerOptions { + argv: metadata.argv, + log_level: WorkerLogLevel::Info, + enable_op_summary_metrics: false, + enable_testing_features: false, + has_node_modules_dir, + inspect_brk: false, + inspect_wait: false, + strace_ops: None, + is_inspecting: false, + skip_op_registration: true, + location: metadata.location, + argv0: NpmPackageReqReference::from_specifier(&main_module) + .ok() + .map(|req_ref| npm_pkg_req_ref_to_binary_command(&req_ref)) + .or(std::env::args().next()), + node_debug: std::env::var("NODE_DEBUG").ok(), + origin_data_folder_path: None, + seed: metadata.seed, + unsafely_ignore_certificate_errors: metadata + .unsafely_ignore_certificate_errors, + node_ipc: None, + serve_port: None, + serve_host: None, + deno_version: crate::version::DENO_VERSION_INFO.deno, + deno_user_agent: crate::version::DENO_VERSION_INFO.user_agent, + otel_config: metadata.otel_config, + startup_snapshot: crate::js::deno_isolate_init(), + }; + let lib_main_worker_factory = LibMainWorkerFactory::new( Arc::new(BlobStore::default()), - code_cache, + code_cache.map(|c| c.as_code_cache()), feature_checker, fs, None, - None, - None, Box::new(module_loader_factory), - node_resolver, - npm_resolver, + node_resolver.clone(), + create_npm_process_state_provider(&npm_resolver), pkg_json_resolver, root_cert_store_provider, - permissions, StorageKeyResolver::empty(), + sys.clone(), + lib_main_worker_options, + ); + // todo(dsherret): use LibMainWorker directly here and don't use CliMainWorkerFactory + let cli_main_worker_options = CliMainWorkerOptions { + create_hmr_runner: None, + create_coverage_collector: None, + needs_test_modules: false, + default_npm_caching_strategy: crate::args::NpmCachingStrategy::Lazy, + }; + let worker_factory = CliMainWorkerFactory::new( + lib_main_worker_factory, + None, + None, + node_resolver, + None, + npm_resolver, sys, - crate::args::DenoSubcommand::Run(Default::default()), - CliMainWorkerOptions { - argv: metadata.argv, - log_level: WorkerLogLevel::Info, - enable_op_summary_metrics: false, - enable_testing_features: false, - has_node_modules_dir, - hmr: false, - inspect_brk: false, - inspect_wait: false, - strace_ops: None, - is_inspecting: false, - skip_op_registration: true, - location: metadata.location, - argv0: NpmPackageReqReference::from_specifier(&main_module) - .ok() - .map(|req_ref| npm_pkg_req_ref_to_binary_command(&req_ref)) - .or(std::env::args().next()), - node_debug: std::env::var("NODE_DEBUG").ok(), - origin_data_folder_path: None, - seed: metadata.seed, - unsafely_ignore_certificate_errors: metadata - .unsafely_ignore_certificate_errors, - create_hmr_runner: None, - create_coverage_collector: None, - node_ipc: None, - serve_port: None, - serve_host: None, - }, - metadata.otel_config, - crate::args::NpmCachingStrategy::Lazy, + cli_main_worker_options, + permissions, ); // Initialize v8 once from the main thread. diff --git a/cli/standalone/serialization.rs b/cli/standalone/serialization.rs index 30802aa081..ab345917a3 100644 --- a/cli/standalone/serialization.rs +++ b/cli/standalone/serialization.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::cell::Cell; @@ -17,6 +17,7 @@ use deno_core::url::Url; use deno_core::FastString; use deno_core::ModuleSourceCode; use deno_core::ModuleType; +use deno_lib::standalone::virtual_fs::VirtualDirectoryEntries; use deno_npm::resolution::SerializedNpmResolutionSnapshot; use deno_npm::resolution::SerializedNpmResolutionSnapshotPackage; use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot; @@ -25,12 +26,9 @@ use deno_semver::package::PackageReq; use deno_semver::StackString; use indexmap::IndexMap; -use crate::standalone::virtual_fs::VirtualDirectory; - use super::binary::Metadata; use super::virtual_fs::BuiltVfs; use super::virtual_fs::VfsBuilder; -use super::virtual_fs::VirtualDirectoryEntries; const MAGIC_BYTES: &[u8; 8] = b"d3n0l4nd"; diff --git a/cli/standalone/virtual_fs.rs b/cli/standalone/virtual_fs.rs index 370d07a488..4f761d0d15 100644 --- a/cli/standalone/virtual_fs.rs +++ b/cli/standalone/virtual_fs.rs @@ -1,7 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::cell::RefCell; +use std::cmp::Ordering; use std::collections::HashMap; use std::collections::HashSet; use std::fs::File; @@ -22,6 +23,17 @@ use deno_core::parking_lot::Mutex; use deno_core::BufMutView; use deno_core::BufView; use deno_core::ResourceHandleFd; +use deno_lib::standalone::virtual_fs::FileSystemCaseSensitivity; +use deno_lib::standalone::virtual_fs::OffsetWithLength; +use deno_lib::standalone::virtual_fs::VfsEntry; +use deno_lib::standalone::virtual_fs::VfsEntryRef; +use deno_lib::standalone::virtual_fs::VfsFileSubDataKind; +use deno_lib::standalone::virtual_fs::VirtualDirectory; +use deno_lib::standalone::virtual_fs::VirtualDirectoryEntries; +use deno_lib::standalone::virtual_fs::VirtualFile; +use deno_lib::standalone::virtual_fs::VirtualSymlink; +use deno_lib::standalone::virtual_fs::VirtualSymlinkParts; +use deno_lib::standalone::virtual_fs::WindowsSystemRootablePath; use deno_path_util::normalize_path; use deno_path_util::strip_unc_prefix; use deno_runtime::deno_fs::FsDirEntry; @@ -34,60 +46,20 @@ use serde::Deserialize; use serde::Serialize; use thiserror::Error; +use super::binary::DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME; use crate::util; use crate::util::display::human_size; use crate::util::display::DisplayTreeNode; use crate::util::fs::canonicalize_path; -use super::binary::DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME; - -#[derive(Debug, PartialEq, Eq)] -pub enum WindowsSystemRootablePath { - /// The root of the system above any drive letters. - WindowSystemRoot, - Path(PathBuf), -} - -impl WindowsSystemRootablePath { - pub fn join(&self, name_component: &str) -> PathBuf { - // this method doesn't handle multiple components - debug_assert!( - !name_component.contains('\\'), - "Invalid component: {}", - name_component - ); - debug_assert!( - !name_component.contains('/'), - "Invalid component: {}", - name_component - ); - - match self { - WindowsSystemRootablePath::WindowSystemRoot => { - // windows drive letter - PathBuf::from(&format!("{}\\", name_component)) - } - WindowsSystemRootablePath::Path(path) => path.join(name_component), - } - } -} - #[derive(Debug)] pub struct BuiltVfs { pub root_path: WindowsSystemRootablePath, + pub case_sensitivity: FileSystemCaseSensitivity, pub entries: VirtualDirectoryEntries, pub files: Vec>, } -#[derive(Debug, Copy, Clone)] -pub enum VfsFileSubDataKind { - /// Raw bytes of the file. - Raw, - /// Bytes to use for module loading. For example, for TypeScript - /// files this will be the transpiled JavaScript source. - ModuleGraph, -} - #[derive(Debug)] pub struct VfsBuilder { executable_root: VirtualDirectory, @@ -96,6 +68,7 @@ pub struct VfsBuilder { file_offsets: HashMap, /// The minimum root directory that should be included in the VFS. min_root_dir: Option, + case_sensitivity: FileSystemCaseSensitivity, } impl VfsBuilder { @@ -109,9 +82,23 @@ impl VfsBuilder { current_offset: 0, file_offsets: Default::default(), min_root_dir: Default::default(), + // This is not exactly correct because file systems on these OSes + // may be case-sensitive or not based on the directory, but this + // is a good enough approximation and limitation. In the future, + // we may want to store this information per directory instead + // depending on the feedback we get. + case_sensitivity: if cfg!(windows) || cfg!(target_os = "macos") { + FileSystemCaseSensitivity::Insensitive + } else { + FileSystemCaseSensitivity::Sensitive + }, } } + pub fn case_sensitivity(&self) -> FileSystemCaseSensitivity { + self.case_sensitivity + } + /// Add a directory that might be the minimum root directory /// of the VFS. /// @@ -216,21 +203,21 @@ impl VfsBuilder { continue; } let name = component.as_os_str().to_string_lossy(); - let index = match current_dir.entries.binary_search(&name) { - Ok(index) => index, - Err(insert_index) => { - current_dir.entries.0.insert( - insert_index, - VfsEntry::Dir(VirtualDirectory { - name: name.to_string(), - entries: Default::default(), - }), - ); - insert_index - } - }; - match &mut current_dir.entries.0[index] { - VfsEntry::Dir(dir) => { + let index = current_dir.entries.insert_or_modify( + &name, + self.case_sensitivity, + || { + VfsEntry::Dir(VirtualDirectory { + name: name.to_string(), + entries: Default::default(), + }) + }, + |_| { + // ignore + }, + ); + match current_dir.entries.get_mut_by_index(index) { + Some(VfsEntry::Dir(dir)) => { current_dir = dir; } _ => unreachable!(), @@ -253,7 +240,9 @@ impl VfsBuilder { continue; } let name = component.as_os_str().to_string_lossy(); - let entry = current_dir.entries.get_mut_by_name(&name)?; + let entry = current_dir + .entries + .get_mut_by_name(&name, self.case_sensitivity)?; match entry { VfsEntry::Dir(dir) => { current_dir = dir; @@ -304,7 +293,8 @@ impl VfsBuilder { sub_data_kind: VfsFileSubDataKind, ) -> Result<(), AnyError> { log::debug!("Adding file '{}'", path.display()); - let checksum = util::checksum::gen(&[&data]); + let checksum = deno_lib::util::checksum::gen(&[&data]); + let case_sensitivity = self.case_sensitivity; let offset = if let Some(offset) = self.file_offsets.get(&checksum) { // duplicate file, reuse an old offset *offset @@ -319,32 +309,28 @@ impl VfsBuilder { offset, len: data.len() as u64, }; - match dir.entries.binary_search(&name) { - Ok(index) => { - let entry = &mut dir.entries.0[index]; - match entry { - VfsEntry::File(virtual_file) => match sub_data_kind { - VfsFileSubDataKind::Raw => { - virtual_file.offset = offset_and_len; - } - VfsFileSubDataKind::ModuleGraph => { - virtual_file.module_graph_offset = offset_and_len; - } - }, - VfsEntry::Dir(_) | VfsEntry::Symlink(_) => unreachable!(), - } - } - Err(insert_index) => { - dir.entries.0.insert( - insert_index, - VfsEntry::File(VirtualFile { - name: name.to_string(), - offset: offset_and_len, - module_graph_offset: offset_and_len, - }), - ); - } - } + dir.entries.insert_or_modify( + &name, + case_sensitivity, + || { + VfsEntry::File(VirtualFile { + name: name.to_string(), + offset: offset_and_len, + module_graph_offset: offset_and_len, + }) + }, + |entry| match entry { + VfsEntry::File(virtual_file) => match sub_data_kind { + VfsFileSubDataKind::Raw => { + virtual_file.offset = offset_and_len; + } + VfsFileSubDataKind::ModuleGraph => { + virtual_file.module_graph_offset = offset_and_len; + } + }, + VfsEntry::Dir(_) | VfsEntry::Symlink(_) => unreachable!(), + }, + ); // new file, update the list of files if self.current_offset == offset { @@ -380,21 +366,23 @@ impl VfsBuilder { std::fs::read_link(path) .with_context(|| format!("Reading symlink '{}'", path.display()))?, ); + let case_sensitivity = self.case_sensitivity; let target = normalize_path(path.parent().unwrap().join(&target)); let dir = self.add_dir_raw(path.parent().unwrap()); let name = path.file_name().unwrap().to_string_lossy(); - match dir.entries.binary_search(&name) { - Ok(_) => {} // previously inserted - Err(insert_index) => { - dir.entries.0.insert( - insert_index, - VfsEntry::Symlink(VirtualSymlink { - name: name.to_string(), - dest_parts: VirtualSymlinkParts::from_path(&target), - }), - ); - } - } + dir.entries.insert_or_modify( + &name, + case_sensitivity, + || { + VfsEntry::Symlink(VirtualSymlink { + name: name.to_string(), + dest_parts: VirtualSymlinkParts::from_path(&target), + }) + }, + |_| { + // ignore previously inserted + }, + ); let target_metadata = std::fs::symlink_metadata(&target).with_context(|| { format!("Reading symlink target '{}'", target.display()) @@ -425,16 +413,20 @@ impl VfsBuilder { dir: &mut VirtualDirectory, parts: &[String], ) { - for entry in &mut dir.entries.0 { + for entry in dir.entries.iter_mut() { match entry { VfsEntry::Dir(dir) => { strip_prefix_from_symlinks(dir, parts); } VfsEntry::File(_) => {} VfsEntry::Symlink(symlink) => { - let old_parts = std::mem::take(&mut symlink.dest_parts.0); - symlink.dest_parts.0 = - old_parts.into_iter().skip(parts.len()).collect(); + let parts = symlink + .dest_parts + .take_parts() + .into_iter() + .skip(parts.len()) + .collect(); + symlink.dest_parts.set_parts(parts); } } } @@ -453,13 +445,13 @@ impl VfsBuilder { if self.min_root_dir.as_ref() == Some(¤t_path) { break; } - match ¤t_dir.entries.0[0] { + match current_dir.entries.iter().next().unwrap() { VfsEntry::Dir(dir) => { if dir.name == DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME { // special directory we want to maintain break; } - match current_dir.entries.0.remove(0) { + match current_dir.entries.remove(0) { VfsEntry::Dir(dir) => { current_path = WindowsSystemRootablePath::Path(current_path.join(&dir.name)); @@ -474,11 +466,12 @@ impl VfsBuilder { if let WindowsSystemRootablePath::Path(path) = ¤t_path { strip_prefix_from_symlinks( &mut current_dir, - &VirtualSymlinkParts::from_path(path).0, + VirtualSymlinkParts::from_path(path).parts(), ); } BuiltVfs { root_path: current_path, + case_sensitivity: self.case_sensitivity, entries: current_dir.entries, files: self.files, } @@ -553,7 +546,7 @@ fn vfs_as_display_tree( All(Size), Subset(Vec>), File(Size), - Symlink(&'a [String]), + Symlink(&'a VirtualSymlinkParts), } impl<'a> EntryOutput<'a> { @@ -602,7 +595,7 @@ fn vfs_as_display_tree( format!("{} ({})", name, format_size(*size)) } EntryOutput::Symlink(parts) => { - format!("{} --> {}", name, parts.join("/")) + format!("{} --> {}", name, parts.display()) } }, children: match self { @@ -745,7 +738,7 @@ fn vfs_as_display_tree( EntryOutput::File(file_size(file, seen_offsets)) } VfsEntry::Symlink(virtual_symlink) => { - EntryOutput::Symlink(&virtual_symlink.dest_parts.0) + EntryOutput::Symlink(&virtual_symlink.dest_parts) } }, }) @@ -782,7 +775,7 @@ fn vfs_as_display_tree( } VfsEntry::File(file) => EntryOutput::File(file_size(file, seen_offsets)), VfsEntry::Symlink(virtual_symlink) => { - EntryOutput::Symlink(&virtual_symlink.dest_parts.0) + EntryOutput::Symlink(&virtual_symlink.dest_parts) } } } @@ -848,187 +841,6 @@ fn vfs_as_display_tree( } } -#[derive(Debug)] -enum VfsEntryRef<'a> { - Dir(&'a VirtualDirectory), - File(&'a VirtualFile), - Symlink(&'a VirtualSymlink), -} - -impl VfsEntryRef<'_> { - pub fn as_metadata(&self) -> FileBackedVfsMetadata { - FileBackedVfsMetadata { - file_type: match self { - Self::Dir(_) => sys_traits::FileType::Dir, - Self::File(_) => sys_traits::FileType::File, - Self::Symlink(_) => sys_traits::FileType::Symlink, - }, - name: self.name().to_string(), - len: match self { - Self::Dir(_) => 0, - Self::File(file) => file.offset.len, - Self::Symlink(_) => 0, - }, - } - } - - pub fn name(&self) -> &str { - match self { - Self::Dir(dir) => &dir.name, - Self::File(file) => &file.name, - Self::Symlink(symlink) => &symlink.name, - } - } -} - -// todo(dsherret): we should store this more efficiently in the binary -#[derive(Debug, Serialize, Deserialize)] -pub enum VfsEntry { - Dir(VirtualDirectory), - File(VirtualFile), - Symlink(VirtualSymlink), -} - -impl VfsEntry { - pub fn name(&self) -> &str { - match self { - Self::Dir(dir) => &dir.name, - Self::File(file) => &file.name, - Self::Symlink(symlink) => &symlink.name, - } - } - - fn as_ref(&self) -> VfsEntryRef { - match self { - VfsEntry::Dir(dir) => VfsEntryRef::Dir(dir), - VfsEntry::File(file) => VfsEntryRef::File(file), - VfsEntry::Symlink(symlink) => VfsEntryRef::Symlink(symlink), - } - } -} - -#[derive(Debug, Default, Serialize, Deserialize)] -pub struct VirtualDirectoryEntries(Vec); - -impl VirtualDirectoryEntries { - pub fn new(mut entries: Vec) -> Self { - // needs to be sorted by name - entries.sort_by(|a, b| a.name().cmp(b.name())); - Self(entries) - } - - pub fn take_inner(&mut self) -> Vec { - std::mem::take(&mut self.0) - } - - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - pub fn len(&self) -> usize { - self.0.len() - } - - pub fn get_by_name(&self, name: &str) -> Option<&VfsEntry> { - self.binary_search(name).ok().map(|index| &self.0[index]) - } - - pub fn get_mut_by_name(&mut self, name: &str) -> Option<&mut VfsEntry> { - self - .binary_search(name) - .ok() - .map(|index| &mut self.0[index]) - } - - pub fn binary_search(&self, name: &str) -> Result { - self.0.binary_search_by(|e| e.name().cmp(name)) - } - - pub fn insert(&mut self, entry: VfsEntry) { - match self.binary_search(entry.name()) { - Ok(index) => { - self.0[index] = entry; - } - Err(insert_index) => { - self.0.insert(insert_index, entry); - } - } - } - - pub fn remove(&mut self, index: usize) -> VfsEntry { - self.0.remove(index) - } - - pub fn iter(&self) -> std::slice::Iter<'_, VfsEntry> { - self.0.iter() - } -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct VirtualDirectory { - #[serde(rename = "n")] - pub name: String, - // should be sorted by name - #[serde(rename = "e")] - pub entries: VirtualDirectoryEntries, -} - -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] -pub struct OffsetWithLength { - #[serde(rename = "o")] - pub offset: u64, - #[serde(rename = "l")] - pub len: u64, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct VirtualFile { - #[serde(rename = "n")] - pub name: String, - #[serde(rename = "o")] - pub offset: OffsetWithLength, - /// Offset file to use for module loading when it differs from the - /// raw file. Often this will be the same offset as above for data - /// such as JavaScript files, but for TypeScript files the `offset` - /// will be the original raw bytes when included as an asset and this - /// offset will be to the transpiled JavaScript source. - #[serde(rename = "m")] - pub module_graph_offset: OffsetWithLength, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct VirtualSymlinkParts(Vec); - -impl VirtualSymlinkParts { - pub fn from_path(path: &Path) -> Self { - Self( - path - .components() - .filter(|c| !matches!(c, std::path::Component::RootDir)) - .map(|c| c.as_os_str().to_string_lossy().to_string()) - .collect(), - ) - } -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct VirtualSymlink { - #[serde(rename = "n")] - pub name: String, - #[serde(rename = "p")] - pub dest_parts: VirtualSymlinkParts, -} - -impl VirtualSymlink { - pub fn resolve_dest_from_root(&self, root: &Path) -> PathBuf { - let mut dest = root.to_path_buf(); - for part in &self.dest_parts.0 { - dest.push(part); - } - dest - } -} - #[derive(Debug)] pub struct VfsRoot { pub dir: VirtualDirectory, @@ -1040,19 +852,21 @@ impl VfsRoot { fn find_entry<'a>( &'a self, path: &Path, + case_sensitivity: FileSystemCaseSensitivity, ) -> std::io::Result<(PathBuf, VfsEntryRef<'a>)> { - self.find_entry_inner(path, &mut HashSet::new()) + self.find_entry_inner(path, &mut HashSet::new(), case_sensitivity) } fn find_entry_inner<'a>( &'a self, path: &Path, seen: &mut HashSet, + case_sensitivity: FileSystemCaseSensitivity, ) -> std::io::Result<(PathBuf, VfsEntryRef<'a>)> { let mut path = Cow::Borrowed(path); loop { let (resolved_path, entry) = - self.find_entry_no_follow_inner(&path, seen)?; + self.find_entry_no_follow_inner(&path, seen, case_sensitivity)?; match entry { VfsEntryRef::Symlink(symlink) => { if !seen.insert(path.to_path_buf()) { @@ -1073,14 +887,16 @@ impl VfsRoot { fn find_entry_no_follow( &self, path: &Path, + case_sensitivity: FileSystemCaseSensitivity, ) -> std::io::Result<(PathBuf, VfsEntryRef)> { - self.find_entry_no_follow_inner(path, &mut HashSet::new()) + self.find_entry_no_follow_inner(path, &mut HashSet::new(), case_sensitivity) } fn find_entry_no_follow_inner<'a>( &'a self, path: &Path, seen: &mut HashSet, + case_sensitivity: FileSystemCaseSensitivity, ) -> std::io::Result<(PathBuf, VfsEntryRef<'a>)> { let relative_path = match path.strip_prefix(&self.root_path) { Ok(p) => p, @@ -1102,7 +918,8 @@ impl VfsRoot { } VfsEntryRef::Symlink(symlink) => { let dest = symlink.resolve_dest_from_root(&self.root_path); - let (resolved_path, entry) = self.find_entry_inner(&dest, seen)?; + let (resolved_path, entry) = + self.find_entry_inner(&dest, seen, case_sensitivity)?; final_path = resolved_path; // overwrite with the new resolved path match entry { VfsEntryRef::Dir(dir) => { @@ -1127,7 +944,7 @@ impl VfsRoot { let component = component.to_string_lossy(); current_entry = current_dir .entries - .get_by_name(&component) + .get_by_name(&component, case_sensitivity) .ok_or_else(|| { std::io::Error::new(std::io::ErrorKind::NotFound, "path not found") })? @@ -1362,6 +1179,21 @@ pub struct FileBackedVfsMetadata { } impl FileBackedVfsMetadata { + pub fn from_vfs_entry_ref(vfs_entry: VfsEntryRef) -> Self { + FileBackedVfsMetadata { + file_type: match vfs_entry { + VfsEntryRef::Dir(_) => sys_traits::FileType::Dir, + VfsEntryRef::File(_) => sys_traits::FileType::File, + VfsEntryRef::Symlink(_) => sys_traits::FileType::Symlink, + }, + name: vfs_entry.name().to_string(), + len: match vfs_entry { + VfsEntryRef::Dir(_) => 0, + VfsEntryRef::File(file) => file.offset.len, + VfsEntryRef::Symlink(_) => 0, + }, + } + } pub fn as_fs_stat(&self) -> FsStat { FsStat { is_directory: self.file_type == sys_traits::FileType::Dir, @@ -1393,13 +1225,19 @@ impl FileBackedVfsMetadata { pub struct FileBackedVfs { vfs_data: Cow<'static, [u8]>, fs_root: VfsRoot, + case_sensitivity: FileSystemCaseSensitivity, } impl FileBackedVfs { - pub fn new(data: Cow<'static, [u8]>, fs_root: VfsRoot) -> Self { + pub fn new( + data: Cow<'static, [u8]>, + fs_root: VfsRoot, + case_sensitivity: FileSystemCaseSensitivity, + ) -> Self { Self { vfs_data: data, fs_root, + case_sensitivity, } } @@ -1447,12 +1285,14 @@ impl FileBackedVfs { let path = path.to_path_buf(); Ok(dir.entries.iter().map(move |entry| FileBackedVfsDirEntry { parent_path: path.to_path_buf(), - metadata: entry.as_ref().as_metadata(), + metadata: FileBackedVfsMetadata::from_vfs_entry_ref(entry.as_ref()), })) } pub fn read_link(&self, path: &Path) -> std::io::Result { - let (_, entry) = self.fs_root.find_entry_no_follow(path)?; + let (_, entry) = self + .fs_root + .find_entry_no_follow(path, self.case_sensitivity)?; match entry { VfsEntryRef::Symlink(symlink) => { Ok(symlink.resolve_dest_from_root(&self.fs_root.root_path)) @@ -1465,17 +1305,19 @@ impl FileBackedVfs { } pub fn lstat(&self, path: &Path) -> std::io::Result { - let (_, entry) = self.fs_root.find_entry_no_follow(path)?; - Ok(entry.as_metadata()) + let (_, entry) = self + .fs_root + .find_entry_no_follow(path, self.case_sensitivity)?; + Ok(FileBackedVfsMetadata::from_vfs_entry_ref(entry)) } pub fn stat(&self, path: &Path) -> std::io::Result { - let (_, entry) = self.fs_root.find_entry(path)?; - Ok(entry.as_metadata()) + let (_, entry) = self.fs_root.find_entry(path, self.case_sensitivity)?; + Ok(FileBackedVfsMetadata::from_vfs_entry_ref(entry)) } pub fn canonicalize(&self, path: &Path) -> std::io::Result { - let (path, _) = self.fs_root.find_entry(path)?; + let (path, _) = self.fs_root.find_entry(path, self.case_sensitivity)?; Ok(path) } @@ -1537,7 +1379,7 @@ impl FileBackedVfs { } pub fn dir_entry(&self, path: &Path) -> std::io::Result<&VirtualDirectory> { - let (_, entry) = self.fs_root.find_entry(path)?; + let (_, entry) = self.fs_root.find_entry(path, self.case_sensitivity)?; match entry { VfsEntryRef::Dir(dir) => Ok(dir), VfsEntryRef::Symlink(_) => unreachable!(), @@ -1549,7 +1391,7 @@ impl FileBackedVfs { } pub fn file_entry(&self, path: &Path) -> std::io::Result<&VirtualFile> { - let (_, entry) = self.fs_root.find_entry(path)?; + let (_, entry) = self.fs_root.find_entry(path, self.case_sensitivity)?; match entry { VfsEntryRef::Dir(_) => Err(std::io::Error::new( std::io::ErrorKind::Other, @@ -1563,9 +1405,10 @@ impl FileBackedVfs { #[cfg(test)] mod test { + use std::io::Write; + use console_static_text::ansi::strip_ansi_codes; use deno_io::fs::File; - use std::io::Write; use test_util::assert_contains; use test_util::TempDir; @@ -1685,6 +1528,7 @@ mod test { temp_dir.write("src/a.txt", "data"); temp_dir.write("src/b.txt", "data"); util::fs::symlink_dir( + &crate::sys::CliSys::default(), temp_dir_path.join("src/nested/sub_dir").as_path(), temp_dir_path.join("src/sub_dir_link").as_path(), ) @@ -1753,6 +1597,7 @@ mod test { root_path: dest_path.to_path_buf(), start_file_offset: 0, }, + FileSystemCaseSensitivity::Sensitive, ), ) } diff --git a/cli/sys.rs b/cli/sys.rs index 55b50a199d..e551eab2e8 100644 --- a/cli/sys.rs +++ b/cli/sys.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // todo(dsherret): this should instead use conditional compilation and directly // surface the underlying implementation. @@ -7,6 +7,8 @@ // denort or the deno binary. We should extract out denort to a separate binary. use std::borrow::Cow; +use std::path::Path; +use std::path::PathBuf; use sys_traits::boxed::BoxedFsDirEntry; use sys_traits::boxed::BoxedFsFile; @@ -27,6 +29,8 @@ pub enum CliSys { DenoCompile(DenoCompileFileSystem), } +impl deno_lib::sys::DenoLibSys for CliSys {} + impl Default for CliSys { fn default() -> Self { Self::Real(sys_traits::impls::RealSys) @@ -35,12 +39,35 @@ impl Default for CliSys { impl deno_runtime::deno_node::ExtNodeSys for CliSys {} +impl sys_traits::BaseFsCloneFile for CliSys { + fn base_fs_clone_file(&self, src: &Path, dst: &Path) -> std::io::Result<()> { + match self { + Self::Real(sys) => sys.base_fs_clone_file(src, dst), + Self::DenoCompile(sys) => sys.base_fs_clone_file(src, dst), + } + } +} + +impl sys_traits::BaseFsSymlinkDir for CliSys { + fn base_fs_symlink_dir(&self, src: &Path, dst: &Path) -> std::io::Result<()> { + match self { + Self::Real(sys) => sys.base_fs_symlink_dir(src, dst), + Self::DenoCompile(sys) => sys.base_fs_symlink_dir(src, dst), + } + } +} + +impl sys_traits::BaseFsCopy for CliSys { + fn base_fs_copy(&self, src: &Path, dst: &Path) -> std::io::Result { + match self { + Self::Real(sys) => sys.base_fs_copy(src, dst), + Self::DenoCompile(sys) => sys.base_fs_copy(src, dst), + } + } +} + impl sys_traits::BaseFsHardLink for CliSys { - fn base_fs_hard_link( - &self, - src: &std::path::Path, - dst: &std::path::Path, - ) -> std::io::Result<()> { + fn base_fs_hard_link(&self, src: &Path, dst: &Path) -> std::io::Result<()> { match self { Self::Real(sys) => sys.base_fs_hard_link(src, dst), Self::DenoCompile(sys) => sys.base_fs_hard_link(src, dst), @@ -49,10 +76,7 @@ impl sys_traits::BaseFsHardLink for CliSys { } impl sys_traits::BaseFsRead for CliSys { - fn base_fs_read( - &self, - p: &std::path::Path, - ) -> std::io::Result> { + fn base_fs_read(&self, p: &Path) -> std::io::Result> { match self { Self::Real(sys) => sys.base_fs_read(p), Self::DenoCompile(sys) => sys.base_fs_read(p), @@ -65,7 +89,7 @@ impl sys_traits::BaseFsReadDir for CliSys { fn base_fs_read_dir( &self, - p: &std::path::Path, + p: &Path, ) -> std::io::Result< Box> + '_>, > { @@ -77,10 +101,7 @@ impl sys_traits::BaseFsReadDir for CliSys { } impl sys_traits::BaseFsCanonicalize for CliSys { - fn base_fs_canonicalize( - &self, - p: &std::path::Path, - ) -> std::io::Result { + fn base_fs_canonicalize(&self, p: &Path) -> std::io::Result { match self { Self::Real(sys) => sys.base_fs_canonicalize(p), Self::DenoCompile(sys) => sys.base_fs_canonicalize(p), @@ -91,10 +112,7 @@ impl sys_traits::BaseFsCanonicalize for CliSys { impl sys_traits::BaseFsMetadata for CliSys { type Metadata = BoxedFsMetadataValue; - fn base_fs_metadata( - &self, - path: &std::path::Path, - ) -> std::io::Result { + fn base_fs_metadata(&self, path: &Path) -> std::io::Result { match self { Self::Real(sys) => sys.fs_metadata_boxed(path), Self::DenoCompile(sys) => sys.fs_metadata_boxed(path), @@ -103,7 +121,7 @@ impl sys_traits::BaseFsMetadata for CliSys { fn base_fs_symlink_metadata( &self, - path: &std::path::Path, + path: &Path, ) -> std::io::Result { match self { Self::Real(sys) => sys.fs_symlink_metadata_boxed(path), @@ -115,7 +133,7 @@ impl sys_traits::BaseFsMetadata for CliSys { impl sys_traits::BaseFsCreateDir for CliSys { fn base_fs_create_dir( &self, - p: &std::path::Path, + p: &Path, options: &CreateDirOptions, ) -> std::io::Result<()> { match self { @@ -130,7 +148,7 @@ impl sys_traits::BaseFsOpen for CliSys { fn base_fs_open( &self, - path: &std::path::Path, + path: &Path, options: &sys_traits::OpenOptions, ) -> std::io::Result { match self { @@ -141,7 +159,7 @@ impl sys_traits::BaseFsOpen for CliSys { } impl sys_traits::BaseFsRemoveFile for CliSys { - fn base_fs_remove_file(&self, p: &std::path::Path) -> std::io::Result<()> { + fn base_fs_remove_file(&self, p: &Path) -> std::io::Result<()> { match self { Self::Real(sys) => sys.base_fs_remove_file(p), Self::DenoCompile(sys) => sys.base_fs_remove_file(p), @@ -150,11 +168,7 @@ impl sys_traits::BaseFsRemoveFile for CliSys { } impl sys_traits::BaseFsRename for CliSys { - fn base_fs_rename( - &self, - old: &std::path::Path, - new: &std::path::Path, - ) -> std::io::Result<()> { + fn base_fs_rename(&self, old: &Path, new: &Path) -> std::io::Result<()> { match self { Self::Real(sys) => sys.base_fs_rename(old, new), Self::DenoCompile(sys) => sys.base_fs_rename(old, new), @@ -190,7 +204,7 @@ impl sys_traits::ThreadSleep for CliSys { } impl sys_traits::EnvCurrentDir for CliSys { - fn env_current_dir(&self) -> std::io::Result { + fn env_current_dir(&self) -> std::io::Result { match self { Self::Real(sys) => sys.env_current_dir(), Self::DenoCompile(sys) => sys.env_current_dir(), @@ -211,7 +225,7 @@ impl sys_traits::BaseEnvVar for CliSys { } impl sys_traits::EnvHomeDir for CliSys { - fn env_home_dir(&self) -> Option { + fn env_home_dir(&self) -> Option { #[allow(clippy::disallowed_types)] // ok because sys impl sys_traits::impls::RealSys.env_home_dir() } diff --git a/cli/task_runner.rs b/cli/task_runner.rs index c7232387ca..14e850ee76 100644 --- a/cli/task_runner.rs +++ b/cli/task_runner.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashMap; use std::path::Path; @@ -25,9 +25,8 @@ use tokio::task::LocalSet; use tokio_util::sync::CancellationToken; use crate::node::CliNodeResolver; +use crate::npm::CliManagedNpmResolver; use crate::npm::CliNpmResolver; -use crate::npm::InnerCliNpmResolverRef; -use crate::npm::ManagedCliNpmResolver; pub fn get_script_with_args(script: &str, argv: &[String]) -> String { let additional_args = argv @@ -414,15 +413,15 @@ impl ShellCommand for NodeModulesFileRunCommand { } pub fn resolve_custom_commands( - npm_resolver: &dyn CliNpmResolver, + npm_resolver: &CliNpmResolver, node_resolver: &CliNodeResolver, ) -> Result>, AnyError> { - let mut commands = match npm_resolver.as_inner() { - InnerCliNpmResolverRef::Byonm(npm_resolver) => { + let mut commands = match npm_resolver { + CliNpmResolver::Byonm(npm_resolver) => { let node_modules_dir = npm_resolver.root_node_modules_path().unwrap(); resolve_npm_commands_from_bin_dir(node_modules_dir) } - InnerCliNpmResolverRef::Managed(npm_resolver) => { + CliNpmResolver::Managed(npm_resolver) => { resolve_managed_npm_commands(npm_resolver, node_resolver)? } }; @@ -521,13 +520,12 @@ fn resolve_execution_path_from_npx_shim( } fn resolve_managed_npm_commands( - npm_resolver: &ManagedCliNpmResolver, + npm_resolver: &CliManagedNpmResolver, node_resolver: &CliNodeResolver, ) -> Result>, AnyError> { let mut result = HashMap::new(); - let snapshot = npm_resolver.snapshot(); - for id in snapshot.top_level_packages() { - let package_folder = npm_resolver.resolve_pkg_folder_from_pkg_id(id)?; + for id in npm_resolver.resolution().top_level_packages() { + let package_folder = npm_resolver.resolve_pkg_folder_from_pkg_id(&id)?; let bin_commands = node_resolver.resolve_binary_commands(&package_folder)?; for bin_command in bin_commands { @@ -598,7 +596,7 @@ async fn listen_ctrl_c(kill_signal: KillSignal) { #[cfg(unix)] async fn listen_and_forward_all_signals(kill_signal: KillSignal) { use deno_core::futures::FutureExt; - use deno_runtime::signal::SIGNAL_NUMS; + use deno_runtime::deno_os::signal::SIGNAL_NUMS; // listen and forward every signal we support let mut futures = Vec::with_capacity(SIGNAL_NUMS.len()); diff --git a/cli/tools/bench/mod.rs b/cli/tools/bench/mod.rs index 1b47c9bfb0..6a57c4ce6c 100644 --- a/cli/tools/bench/mod.rs +++ b/cli/tools/bench/mod.rs @@ -1,4 +1,37 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::collections::HashSet; +use std::path::Path; +use std::sync::Arc; +use std::time::Duration; + +use deno_config::glob::WalkEntry; +use deno_core::anyhow::anyhow; +use deno_core::error::AnyError; +use deno_core::error::CoreError; +use deno_core::error::JsError; +use deno_core::futures::future; +use deno_core::futures::stream; +use deno_core::futures::StreamExt; +use deno_core::serde_v8; +use deno_core::unsync::spawn; +use deno_core::unsync::spawn_blocking; +use deno_core::v8; +use deno_core::ModuleSpecifier; +use deno_core::PollEventLoopOptions; +use deno_error::JsErrorBox; +use deno_runtime::deno_permissions::Permissions; +use deno_runtime::deno_permissions::PermissionsContainer; +use deno_runtime::permissions::RuntimePermissionDescriptorParser; +use deno_runtime::tokio_util::create_and_run_current_thread; +use deno_runtime::WorkerExecutionMode; +use indexmap::IndexMap; +use indexmap::IndexSet; +use log::Level; +use serde::Deserialize; +use serde::Serialize; +use tokio::sync::mpsc::unbounded_channel; +use tokio::sync::mpsc::UnboundedSender; use crate::args::BenchFlags; use crate::args::Flags; @@ -16,36 +49,6 @@ use crate::util::path::is_script_ext; use crate::util::path::matches_pattern_or_exact_path; use crate::worker::CliMainWorkerFactory; -use deno_config::glob::WalkEntry; -use deno_core::error::generic_error; -use deno_core::error::AnyError; -use deno_core::error::JsError; -use deno_core::futures::future; -use deno_core::futures::stream; -use deno_core::futures::StreamExt; -use deno_core::serde_v8; -use deno_core::unsync::spawn; -use deno_core::unsync::spawn_blocking; -use deno_core::v8; -use deno_core::ModuleSpecifier; -use deno_core::PollEventLoopOptions; -use deno_runtime::deno_permissions::Permissions; -use deno_runtime::deno_permissions::PermissionsContainer; -use deno_runtime::permissions::RuntimePermissionDescriptorParser; -use deno_runtime::tokio_util::create_and_run_current_thread; -use deno_runtime::WorkerExecutionMode; -use indexmap::IndexMap; -use indexmap::IndexSet; -use log::Level; -use serde::Deserialize; -use serde::Serialize; -use std::collections::HashSet; -use std::path::Path; -use std::sync::Arc; -use std::time::Duration; -use tokio::sync::mpsc::unbounded_channel; -use tokio::sync::mpsc::UnboundedSender; - mod mitata; mod reporters; @@ -161,17 +164,14 @@ async fn bench_specifier( .await { Ok(()) => Ok(()), - Err(error) => { - if error.is::() { - sender.send(BenchEvent::UncaughtError( - specifier.to_string(), - Box::new(error.downcast::().unwrap()), - ))?; - Ok(()) - } else { - Err(error) - } + Err(CoreError::Js(error)) => { + sender.send(BenchEvent::UncaughtError( + specifier.to_string(), + Box::new(error), + ))?; + Ok(()) } + Err(e) => Err(e.into()), } } @@ -182,7 +182,7 @@ async fn bench_specifier_inner( specifier: ModuleSpecifier, sender: &UnboundedSender, filter: TestFilter, -) -> Result<(), AnyError> { +) -> Result<(), CoreError> { let mut worker = worker_factory .create_custom_worker( WorkerExecutionMode::Bench, @@ -229,14 +229,18 @@ async fn bench_specifier_inner( .partial_cmp(&groups.get_index_of(&d2.group).unwrap()) .unwrap() }); - sender.send(BenchEvent::Plan(BenchPlan { - origin: specifier.to_string(), - total: benchmarks.len(), - used_only, - names: benchmarks.iter().map(|(d, _)| d.name.clone()).collect(), - }))?; + sender + .send(BenchEvent::Plan(BenchPlan { + origin: specifier.to_string(), + total: benchmarks.len(), + used_only, + names: benchmarks.iter().map(|(d, _)| d.name.clone()).collect(), + })) + .map_err(JsErrorBox::from_err)?; for (desc, function) in benchmarks { - sender.send(BenchEvent::Wait(desc.id))?; + sender + .send(BenchEvent::Wait(desc.id)) + .map_err(JsErrorBox::from_err)?; let call = worker.js_runtime.call(&function); let result = worker .js_runtime @@ -244,8 +248,11 @@ async fn bench_specifier_inner( .await?; let scope = &mut worker.js_runtime.handle_scope(); let result = v8::Local::new(scope, result); - let result = serde_v8::from_v8::(scope, result)?; - sender.send(BenchEvent::Result(desc.id, result))?; + let result = serde_v8::from_v8::(scope, result) + .map_err(JsErrorBox::from_err)?; + sender + .send(BenchEvent::Result(desc.id, result)) + .map_err(JsErrorBox::from_err)?; } // Ignore `defaultPrevented` of the `beforeunload` event. We don't allow the @@ -355,13 +362,13 @@ async fn bench_specifiers( reporter.report_end(&report); if used_only { - return Err(generic_error( + return Err(anyhow!( "Bench failed because the \"only\" option was used", )); } if report.failed > 0 { - return Err(generic_error("Bench failed")); + return Err(anyhow!("Bench failed")); } Ok(()) @@ -439,7 +446,7 @@ pub async fn run_benchmarks( .collect::>(); if specifiers.is_empty() { - return Err(generic_error("No bench modules found")); + return Err(anyhow!("No bench modules found")); } let main_graph_container = factory.main_module_graph_container().await?; diff --git a/cli/tools/bench/reporters.rs b/cli/tools/bench/reporters.rs index 9aabd760b3..68a0c56bce 100644 --- a/cli/tools/bench/reporters.rs +++ b/cli/tools/bench/reporters.rs @@ -1,12 +1,11 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use serde::Serialize; +use super::*; use crate::tools::test::TestFailureFormatOptions; use crate::version; -use super::*; - pub trait BenchReporter { fn report_group_summary(&mut self); fn report_plan(&mut self, plan: &BenchPlan); diff --git a/cli/tools/check.rs b/cli/tools/check.rs index acfff70401..e850b1900f 100644 --- a/cli/tools/check.rs +++ b/cli/tools/check.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashSet; use std::collections::VecDeque; @@ -6,9 +6,14 @@ use std::sync::Arc; use deno_ast::MediaType; use deno_ast::ModuleSpecifier; +use deno_config::deno_json; use deno_core::error::AnyError; +use deno_error::JsErrorBox; use deno_graph::Module; +use deno_graph::ModuleError; use deno_graph::ModuleGraph; +use deno_graph::ModuleLoadError; +use deno_semver::npm::NpmPackageNvReference; use deno_terminal::colors; use once_cell::sync::Lazy; use regex::Regex; @@ -26,10 +31,13 @@ use crate::cache::Caches; use crate::cache::FastInsecureHasher; use crate::cache::TypeCheckCache; use crate::factory::CliFactory; +use crate::graph_util::maybe_additional_sloppy_imports_message; use crate::graph_util::BuildFastCheckGraphOptions; use crate::graph_util::ModuleGraphBuilder; use crate::node::CliNodeResolver; +use crate::npm::installer::NpmInstaller; use crate::npm::CliNpmResolver; +use crate::sys::CliSys; use crate::tsc; use crate::tsc::Diagnostics; use crate::tsc::TypeCheckingCjsTracker; @@ -103,18 +111,44 @@ pub struct TypeChecker { cjs_tracker: Arc, cli_options: Arc, module_graph_builder: Arc, + npm_installer: Option>, node_resolver: Arc, - npm_resolver: Arc, + npm_resolver: CliNpmResolver, + sys: CliSys, +} + +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum CheckError { + #[class(inherit)] + #[error(transparent)] + Diagnostics(#[from] Diagnostics), + #[class(inherit)] + #[error(transparent)] + ConfigFile(#[from] deno_json::ConfigFileError), + #[class(inherit)] + #[error(transparent)] + ToMaybeJsxImportSourceConfig( + #[from] deno_json::ToMaybeJsxImportSourceConfigError, + ), + #[class(inherit)] + #[error(transparent)] + TscExec(#[from] tsc::ExecError), + #[class(inherit)] + #[error(transparent)] + Other(#[from] JsErrorBox), } impl TypeChecker { + #[allow(clippy::too_many_arguments)] pub fn new( caches: Arc, cjs_tracker: Arc, cli_options: Arc, module_graph_builder: Arc, node_resolver: Arc, - npm_resolver: Arc, + npm_installer: Option>, + npm_resolver: CliNpmResolver, + sys: CliSys, ) -> Self { Self { caches, @@ -122,7 +156,9 @@ impl TypeChecker { cli_options, module_graph_builder, node_resolver, + npm_installer, npm_resolver, + sys, } } @@ -134,7 +170,7 @@ impl TypeChecker { &self, graph: ModuleGraph, options: CheckOptions, - ) -> Result, AnyError> { + ) -> Result, CheckError> { let (graph, mut diagnostics) = self.check_diagnostics(graph, options).await?; diagnostics.emit_warnings(); @@ -153,7 +189,30 @@ impl TypeChecker { &self, mut graph: ModuleGraph, options: CheckOptions, - ) -> Result<(Arc, Diagnostics), AnyError> { + ) -> Result<(Arc, Diagnostics), CheckError> { + fn check_state_hash(resolver: &CliNpmResolver) -> Option { + match resolver { + CliNpmResolver::Byonm(_) => { + // not feasible and probably slower to compute + None + } + CliNpmResolver::Managed(resolver) => { + // we should probably go further and check all the individual npm packages + let mut package_reqs = resolver.resolution().package_reqs(); + package_reqs.sort_by(|a, b| a.0.cmp(&b.0)); // determinism + let mut hasher = FastInsecureHasher::new_without_deno_version(); + // ensure the cache gets busted when turning nodeModulesDir on or off + // as this could cause changes in resolution + hasher.write_hashable(resolver.root_node_modules_path().is_some()); + for (pkg_req, pkg_nv) in package_reqs { + hasher.write_hashable(&pkg_req); + hasher.write_hashable(&pkg_nv); + } + Some(hasher.finish()) + } + } + } + if !options.type_check_mode.is_true() || graph.roots.is_empty() { return Ok((graph.into(), Default::default())); } @@ -161,9 +220,9 @@ impl TypeChecker { // node built-in specifiers use the @types/node package to determine // types, so inject that now (the caller should do this after the lockfile // has been written) - if let Some(npm_resolver) = self.npm_resolver.as_managed() { + if let Some(npm_installer) = &self.npm_installer { if graph.has_node_specifier { - npm_resolver.inject_synthetic_types_node_package().await?; + npm_installer.inject_synthetic_types_node_package().await?; } } @@ -177,26 +236,49 @@ impl TypeChecker { let type_check_mode = options.type_check_mode; let ts_config = ts_config_result.ts_config; - let maybe_check_hash = match self.npm_resolver.check_state_hash() { - Some(npm_check_hash) => { - match get_check_hash( - &graph, - npm_check_hash, - type_check_mode, - &ts_config, - ) { - CheckHashResult::NoFiles => { - return Ok((graph.into(), Default::default())) - } - CheckHashResult::Hash(hash) => Some(hash), - } - } - None => None, // we can't determine a check hash - }; - - // do not type check if we know this is type checked let cache = TypeCheckCache::new(self.caches.type_checking_cache_db()); + let check_js = ts_config.get_check_js(); + + // add fast check to the graph before getting the roots + if options.build_fast_check_graph { + self.module_graph_builder.build_fast_check_graph( + &mut graph, + BuildFastCheckGraphOptions { + workspace_fast_check: deno_graph::WorkspaceFastCheckOption::Disabled, + }, + )?; + } + + let filter_remote_diagnostics = |d: &tsc::Diagnostic| { + if self.is_remote_diagnostic(d) { + type_check_mode == TypeCheckMode::All && d.include_when_remote() + } else { + true + } + }; + let TscRoots { + roots: root_names, + missing_diagnostics, + maybe_check_hash, + } = get_tsc_roots( + &self.sys, + &self.npm_resolver, + &self.node_resolver, + &graph, + check_js, + check_state_hash(&self.npm_resolver), + type_check_mode, + &ts_config, + ); + + let missing_diagnostics = + missing_diagnostics.filter(filter_remote_diagnostics); + + if root_names.is_empty() && missing_diagnostics.is_empty() { + return Ok((graph.into(), Default::default())); + } if !options.reload { + // do not type check if we know this is type checked if let Some(check_hash) = maybe_check_hash { if cache.has_check_hash(check_hash) { log::debug!("Already type checked."); @@ -214,7 +296,6 @@ impl TypeChecker { ); } - let check_js = ts_config.get_check_js(); // while there might be multiple roots, we can't "merge" the build info, so we // try to retrieve the build info for first root, which is the most common use // case. @@ -226,27 +307,15 @@ impl TypeChecker { // to make tsc build info work, we need to consistently hash modules, so that // tsc can better determine if an emit is still valid or not, so we provide // that data here. - let hash_data = FastInsecureHasher::new_deno_versioned() + let tsconfig_hash_data = FastInsecureHasher::new_deno_versioned() .write(&ts_config.as_bytes()) .finish(); - - // add fast check to the graph before getting the roots - if options.build_fast_check_graph { - self.module_graph_builder.build_fast_check_graph( - &mut graph, - BuildFastCheckGraphOptions { - workspace_fast_check: deno_graph::WorkspaceFastCheckOption::Disabled, - }, - )?; - } - - let root_names = get_tsc_roots(&graph, check_js); let graph = Arc::new(graph); let response = tsc::exec(tsc::Request { config: ts_config, debug: self.cli_options.log_level() == Some(log::Level::Debug), graph: graph.clone(), - hash_data, + hash_data: tsconfig_hash_data, maybe_npm: Some(tsc::RequestNpmState { cjs_tracker: self.cjs_tracker.clone(), node_resolver: self.node_resolver.clone(), @@ -257,13 +326,11 @@ impl TypeChecker { check_mode: type_check_mode, })?; - let mut diagnostics = response.diagnostics.filter(|d| { - if self.is_remote_diagnostic(d) { - type_check_mode == TypeCheckMode::All && d.include_when_remote() - } else { - true - } - }); + let response_diagnostics = + response.diagnostics.filter(filter_remote_diagnostics); + + let mut diagnostics = missing_diagnostics; + diagnostics.extend(response_diagnostics); diagnostics.apply_fast_check_source_maps(&graph); @@ -297,108 +364,10 @@ impl TypeChecker { } } -enum CheckHashResult { - Hash(CacheDBHash), - NoFiles, -} - -/// Gets a hash of the inputs for type checking. This can then -/// be used to tell -fn get_check_hash( - graph: &ModuleGraph, - package_reqs_hash: u64, - type_check_mode: TypeCheckMode, - ts_config: &TsConfig, -) -> CheckHashResult { - let mut hasher = FastInsecureHasher::new_deno_versioned(); - hasher.write_u8(match type_check_mode { - TypeCheckMode::All => 0, - TypeCheckMode::Local => 1, - TypeCheckMode::None => 2, - }); - hasher.write(&ts_config.as_bytes()); - - let check_js = ts_config.get_check_js(); - let mut has_file = false; - let mut has_file_to_type_check = false; - // this iterator of modules is already deterministic, so no need to sort it - for module in graph.modules() { - match module { - Module::Js(module) => { - let ts_check = has_ts_check(module.media_type, &module.source); - if ts_check { - has_file_to_type_check = true; - } - - match module.media_type { - MediaType::TypeScript - | MediaType::Dts - | MediaType::Dmts - | MediaType::Dcts - | MediaType::Mts - | MediaType::Cts - | MediaType::Tsx => { - has_file = true; - has_file_to_type_check = true; - } - MediaType::JavaScript - | MediaType::Mjs - | MediaType::Cjs - | MediaType::Jsx => { - has_file = true; - if !check_js && !ts_check { - continue; - } - } - MediaType::Json - | MediaType::Css - | MediaType::SourceMap - | MediaType::Wasm - | MediaType::Unknown => continue, - } - - hasher.write_str(module.specifier.as_str()); - hasher.write_str( - // the fast check module will only be set when publishing - module - .fast_check_module() - .map(|s| s.source.as_ref()) - .unwrap_or(&module.source), - ); - } - Module::Node(_) => { - // the @types/node package will be in the resolved - // snapshot below so don't bother including it here - } - Module::Npm(_) => { - // don't bother adding this specifier to the hash - // because what matters is the resolved npm snapshot, - // which is hashed below - } - Module::Json(module) => { - has_file_to_type_check = true; - hasher.write_str(module.specifier.as_str()); - hasher.write_str(&module.source); - } - Module::Wasm(module) => { - has_file_to_type_check = true; - hasher.write_str(module.specifier.as_str()); - hasher.write_str(&module.source_dts); - } - Module::External(module) => { - hasher.write_str(module.specifier.as_str()); - } - } - } - - hasher.write_hashable(package_reqs_hash); - - if !has_file || !check_js && !has_file_to_type_check { - // no files to type check - CheckHashResult::NoFiles - } else { - CheckHashResult::Hash(CacheDBHash::new(hasher.finish())) - } +struct TscRoots { + roots: Vec<(ModuleSpecifier, MediaType)>, + missing_diagnostics: tsc::Diagnostics, + maybe_check_hash: Option, } /// Transform the graph into root specifiers that we can feed `tsc`. We have to @@ -407,53 +376,120 @@ fn get_check_hash( /// redirects resolved. We need to include all the emittable files in /// the roots, so they get type checked and optionally emitted, /// otherwise they would be ignored if only imported into JavaScript. +#[allow(clippy::too_many_arguments)] fn get_tsc_roots( + sys: &CliSys, + npm_resolver: &CliNpmResolver, + node_resolver: &CliNodeResolver, graph: &ModuleGraph, check_js: bool, -) -> Vec<(ModuleSpecifier, MediaType)> { + npm_cache_state_hash: Option, + type_check_mode: TypeCheckMode, + ts_config: &TsConfig, +) -> TscRoots { fn maybe_get_check_entry( module: &deno_graph::Module, check_js: bool, + hasher: Option<&mut FastInsecureHasher>, ) -> Option<(ModuleSpecifier, MediaType)> { match module { - Module::Js(module) => match module.media_type { - MediaType::TypeScript - | MediaType::Tsx - | MediaType::Mts - | MediaType::Cts - | MediaType::Dts - | MediaType::Dmts - | MediaType::Dcts => { - Some((module.specifier.clone(), module.media_type)) - } - MediaType::JavaScript - | MediaType::Mjs - | MediaType::Cjs - | MediaType::Jsx => { - if check_js || has_ts_check(module.media_type, &module.source) { + Module::Js(module) => { + let result = match module.media_type { + MediaType::TypeScript + | MediaType::Tsx + | MediaType::Mts + | MediaType::Cts + | MediaType::Dts + | MediaType::Dmts + | MediaType::Dcts => { Some((module.specifier.clone(), module.media_type)) - } else { - None + } + MediaType::JavaScript + | MediaType::Mjs + | MediaType::Cjs + | MediaType::Jsx => { + if check_js || has_ts_check(module.media_type, &module.source) { + Some((module.specifier.clone(), module.media_type)) + } else { + None + } + } + MediaType::Json + | MediaType::Wasm + | MediaType::Css + | MediaType::SourceMap + | MediaType::Unknown => None, + }; + if result.is_some() { + if let Some(hasher) = hasher { + hasher.write_str(module.specifier.as_str()); + hasher.write_str( + // the fast check module will only be set when publishing + module + .fast_check_module() + .map(|s| s.source.as_ref()) + .unwrap_or(&module.source), + ); } } - MediaType::Json - | MediaType::Wasm - | MediaType::Css - | MediaType::SourceMap - | MediaType::Unknown => None, - }, - Module::Wasm(module) => Some((module.specifier.clone(), MediaType::Dmts)), - Module::External(_) - | Module::Node(_) - | Module::Npm(_) - | Module::Json(_) => None, + result + } + Module::Node(_) => { + // the @types/node package will be in the resolved + // snapshot so don't bother including it in the hash + None + } + Module::Npm(_) => { + // don't bother adding this specifier to the hash + // because what matters is the resolved npm snapshot, + // which is hashed below + None + } + Module::Json(module) => { + if let Some(hasher) = hasher { + hasher.write_str(module.specifier.as_str()); + hasher.write_str(&module.source); + } + None + } + Module::Wasm(module) => { + if let Some(hasher) = hasher { + hasher.write_str(module.specifier.as_str()); + hasher.write_str(&module.source_dts); + } + Some((module.specifier.clone(), MediaType::Dmts)) + } + Module::External(module) => { + if let Some(hasher) = hasher { + hasher.write_str(module.specifier.as_str()); + } + + None + } } } - let mut result = Vec::with_capacity(graph.specifiers_count()); + let mut result = TscRoots { + roots: Vec::with_capacity(graph.specifiers_count()), + missing_diagnostics: Default::default(), + maybe_check_hash: None, + }; + let mut maybe_hasher = npm_cache_state_hash.map(|npm_cache_state_hash| { + let mut hasher = FastInsecureHasher::new_deno_versioned(); + hasher.write_hashable(npm_cache_state_hash); + hasher.write_u8(match type_check_mode { + TypeCheckMode::All => 0, + TypeCheckMode::Local => 1, + TypeCheckMode::None => 2, + }); + hasher.write_hashable(graph.has_node_specifier); + hasher.write(&ts_config.as_bytes()); + hasher + }); + if graph.has_node_specifier { // inject a specifier that will resolve node types - result.push(( + result.roots.push(( ModuleSpecifier::parse("asset:///node_types.d.ts").unwrap(), MediaType::Dts, )); @@ -464,13 +500,31 @@ fn get_tsc_roots( let mut pending = VecDeque::new(); // put in the global types first so that they're resolved before anything else - for import in graph.imports.values() { - for dep in import.dependencies.values() { - let specifier = dep.get_type().or_else(|| dep.get_code()); - if let Some(specifier) = &specifier { - let specifier = graph.resolve(specifier); - if seen.insert(specifier.clone()) { - pending.push_back(specifier); + for (referrer, import) in graph.imports.iter() { + for specifier in import + .dependencies + .values() + .filter_map(|dep| dep.get_type().or_else(|| dep.get_code())) + { + let specifier = graph.resolve(specifier); + if seen.insert(specifier) { + if let Ok(nv_ref) = NpmPackageNvReference::from_specifier(specifier) { + let Some(resolved) = + resolve_npm_nv_ref(npm_resolver, node_resolver, &nv_ref, referrer) + else { + result.missing_diagnostics.push( + tsc::Diagnostic::from_missing_error( + specifier, + None, + maybe_additional_sloppy_imports_message(sys, specifier), + ), + ); + continue; + }; + let mt = MediaType::from_specifier(&resolved); + result.roots.push((resolved, mt)); + } else { + pending.push_back((specifier, false)); } } } @@ -479,53 +533,143 @@ fn get_tsc_roots( // then the roots for root in &graph.roots { let specifier = graph.resolve(root); - if seen.insert(specifier.clone()) { - pending.push_back(specifier); + if seen.insert(specifier) { + pending.push_back((specifier, false)); } } // now walk the graph that only includes the fast check dependencies - while let Some(specifier) = pending.pop_front() { - let Some(module) = graph.get(specifier) else { - continue; + while let Some((specifier, is_dynamic)) = pending.pop_front() { + let module = match graph.try_get(specifier) { + Ok(Some(module)) => module, + Ok(None) => continue, + Err(ModuleError::Missing(specifier, maybe_range)) => { + if !is_dynamic { + result + .missing_diagnostics + .push(tsc::Diagnostic::from_missing_error( + specifier, + maybe_range.as_ref(), + maybe_additional_sloppy_imports_message(sys, specifier), + )); + } + continue; + } + Err(ModuleError::LoadingErr( + specifier, + maybe_range, + ModuleLoadError::Loader(_), + )) => { + // these will be errors like attempting to load a directory + if !is_dynamic { + result + .missing_diagnostics + .push(tsc::Diagnostic::from_missing_error( + specifier, + maybe_range.as_ref(), + maybe_additional_sloppy_imports_message(sys, specifier), + )); + } + continue; + } + Err(_) => continue, }; - if let Some(entry) = maybe_get_check_entry(module, check_js) { - result.push(entry); + if is_dynamic && !seen.insert(specifier) { + continue; } - if let Some(module) = module.js() { - let deps = module.dependencies_prefer_fast_check(); + if let Some(entry) = + maybe_get_check_entry(module, check_js, maybe_hasher.as_mut()) + { + result.roots.push(entry); + } + + let mut maybe_module_dependencies = None; + let mut maybe_types_dependency = None; + if let Module::Js(module) = module { + maybe_module_dependencies = Some(module.dependencies_prefer_fast_check()); + maybe_types_dependency = module + .maybe_types_dependency + .as_ref() + .and_then(|d| d.dependency.ok()); + } else if let Module::Wasm(module) = module { + maybe_module_dependencies = Some(&module.dependencies); + } + + fn handle_specifier<'a>( + graph: &'a ModuleGraph, + seen: &mut HashSet<&'a ModuleSpecifier>, + pending: &mut VecDeque<(&'a ModuleSpecifier, bool)>, + specifier: &'a ModuleSpecifier, + is_dynamic: bool, + ) { + let specifier = graph.resolve(specifier); + if is_dynamic { + if !seen.contains(specifier) { + pending.push_back((specifier, true)); + } + } else if seen.insert(specifier) { + pending.push_back((specifier, false)); + } + } + + if let Some(deps) = maybe_module_dependencies { for dep in deps.values() { // walk both the code and type dependencies if let Some(specifier) = dep.get_code() { - let specifier = graph.resolve(specifier); - if seen.insert(specifier.clone()) { - pending.push_back(specifier); - } + handle_specifier( + graph, + &mut seen, + &mut pending, + specifier, + dep.is_dynamic, + ); } if let Some(specifier) = dep.get_type() { - let specifier = graph.resolve(specifier); - if seen.insert(specifier.clone()) { - pending.push_back(specifier); - } - } - } - - if let Some(dep) = module - .maybe_types_dependency - .as_ref() - .and_then(|d| d.dependency.ok()) - { - let specifier = graph.resolve(&dep.specifier); - if seen.insert(specifier.clone()) { - pending.push_back(specifier); + handle_specifier( + graph, + &mut seen, + &mut pending, + specifier, + dep.is_dynamic, + ); } } } + + if let Some(dep) = maybe_types_dependency { + handle_specifier(graph, &mut seen, &mut pending, &dep.specifier, false); + } } + result.maybe_check_hash = + maybe_hasher.map(|hasher| CacheDBHash::new(hasher.finish())); + result } +fn resolve_npm_nv_ref( + npm_resolver: &CliNpmResolver, + node_resolver: &CliNodeResolver, + nv_ref: &NpmPackageNvReference, + referrer: &ModuleSpecifier, +) -> Option { + let pkg_dir = npm_resolver + .as_managed() + .unwrap() + .resolve_pkg_folder_from_deno_module(nv_ref.nv()) + .ok()?; + let resolved = node_resolver + .resolve_package_subpath_from_deno_module( + &pkg_dir, + nv_ref.sub_path(), + Some(referrer), + node_resolver::ResolutionMode::Import, + node_resolver::NodeResolutionKind::Types, + ) + .ok()?; + Some(resolved) +} + /// Matches the `@ts-check` pragma. static TS_CHECK_RE: Lazy = lazy_regex::lazy_regex!(r#"(?i)^\s*@ts-check(?:\s+|$)"#); diff --git a/cli/tools/clean.rs b/cli/tools/clean.rs index cdc1c51dcd..a550d2826a 100644 --- a/cli/tools/clean.rs +++ b/cli/tools/clean.rs @@ -1,10 +1,11 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::path::Path; use deno_core::anyhow::Context; use deno_core::error::AnyError; -use std::path::Path; +use deno_lib::cache::DenoDir; -use crate::cache::DenoDir; use crate::colors; use crate::display; use crate::sys::CliSys; diff --git a/cli/tools/compile.rs b/cli/tools/compile.rs index cbd376bae2..96dd6798f5 100644 --- a/cli/tools/compile.rs +++ b/cli/tools/compile.rs @@ -1,17 +1,16 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::collections::HashSet; +use std::collections::VecDeque; +use std::path::Path; +use std::path::PathBuf; +use std::sync::Arc; -use crate::args::check_warn_tsconfig; -use crate::args::CompileFlags; -use crate::args::Flags; -use crate::factory::CliFactory; -use crate::http_util::HttpClientProvider; -use crate::standalone::binary::is_standalone_binary; -use crate::standalone::binary::WriteBinOptions; use deno_ast::MediaType; use deno_ast::ModuleSpecifier; +use deno_core::anyhow::anyhow; use deno_core::anyhow::bail; use deno_core::anyhow::Context; -use deno_core::error::generic_error; use deno_core::error::AnyError; use deno_core::resolve_url_or_path; use deno_graph::GraphKind; @@ -19,13 +18,15 @@ use deno_path_util::url_from_file_path; use deno_path_util::url_to_file_path; use deno_terminal::colors; use rand::Rng; -use std::collections::HashSet; -use std::collections::VecDeque; -use std::path::Path; -use std::path::PathBuf; -use std::sync::Arc; use super::installer::infer_name_from_url; +use crate::args::check_warn_tsconfig; +use crate::args::CompileFlags; +use crate::args::Flags; +use crate::factory::CliFactory; +use crate::http_util::HttpClientProvider; +use crate::standalone::binary::is_standalone_binary; +use crate::standalone::binary::WriteBinOptions; pub async fn compile( flags: Arc, @@ -329,7 +330,7 @@ async fn resolve_compile_executable_output_path( .map(PathBuf::from) } - output_path.ok_or_else(|| generic_error( + output_path.ok_or_else(|| anyhow!( "An executable name was not provided. One could not be inferred from the URL. Aborting.", )).map(|output_path| { get_os_specific_filepath(output_path, &compile_flags.target) diff --git a/cli/tools/coverage/merge.rs b/cli/tools/coverage/merge.rs index 81317df559..9c898e78d3 100644 --- a/cli/tools/coverage/merge.rs +++ b/cli/tools/coverage/merge.rs @@ -1,16 +1,17 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // // Forked from https://github.com/demurgos/v8-coverage/tree/d0ca18da8740198681e0bc68971b0a6cdb11db3e/rust // Copyright 2021 Charles Samborski. All rights reserved. MIT license. -use super::range_tree::RangeTree; -use super::range_tree::RangeTreeArena; -use crate::cdp; use std::collections::BTreeMap; use std::collections::BTreeSet; use std::collections::HashMap; use std::iter::Peekable; +use super::range_tree::RangeTree; +use super::range_tree::RangeTreeArena; +use crate::cdp; + #[derive(Eq, PartialEq, Clone, Debug)] pub struct ProcessCoverage { pub result: Vec, diff --git a/cli/tools/coverage/mod.rs b/cli/tools/coverage/mod.rs index a9054207b0..9b6ef81ea3 100644 --- a/cli/tools/coverage/mod.rs +++ b/cli/tools/coverage/mod.rs @@ -1,4 +1,32 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::fs; +use std::fs::File; +use std::io::BufWriter; +use std::io::Write; +use std::path::Path; +use std::path::PathBuf; +use std::sync::Arc; + +use deno_ast::MediaType; +use deno_ast::ModuleKind; +use deno_ast::ModuleSpecifier; +use deno_config::glob::FileCollector; +use deno_config::glob::FilePatterns; +use deno_config::glob::PathOrPattern; +use deno_config::glob::PathOrPatternSet; +use deno_core::anyhow::anyhow; +use deno_core::anyhow::Context; +use deno_core::error::AnyError; +use deno_core::serde_json; +use deno_core::sourcemap::SourceMap; +use deno_core::url::Url; +use deno_core::LocalInspectorSession; +use deno_resolver::npm::DenoInNpmPackageChecker; +use node_resolver::InNpmPackageChecker; +use regex::Regex; +use text_lines::TextLines; +use uuid::Uuid; use crate::args::CliOptions; use crate::args::CoverageFlags; @@ -12,33 +40,6 @@ use crate::tools::fmt::format_json; use crate::tools::test::is_supported_test_path; use crate::util::text_encoding::source_map_from_code; -use deno_ast::MediaType; -use deno_ast::ModuleKind; -use deno_ast::ModuleSpecifier; -use deno_config::glob::FileCollector; -use deno_config::glob::FilePatterns; -use deno_config::glob::PathOrPattern; -use deno_config::glob::PathOrPatternSet; -use deno_core::anyhow::anyhow; -use deno_core::anyhow::Context; -use deno_core::error::generic_error; -use deno_core::error::AnyError; -use deno_core::serde_json; -use deno_core::sourcemap::SourceMap; -use deno_core::url::Url; -use deno_core::LocalInspectorSession; -use node_resolver::InNpmPackageChecker; -use regex::Regex; -use std::fs; -use std::fs::File; -use std::io::BufWriter; -use std::io::Write; -use std::path::Path; -use std::path::PathBuf; -use std::sync::Arc; -use text_lines::TextLines; -use uuid::Uuid; - mod merge; mod range_tree; mod reporter; @@ -429,7 +430,7 @@ fn collect_coverages( .ignore_git_folder() .ignore_node_modules() .set_vendor_folder(cli_options.vendor_dir_path().map(ToOwned::to_owned)) - .collect_file_patterns(&CliSys::default(), file_patterns)?; + .collect_file_patterns(&CliSys::default(), file_patterns); let coverage_patterns = FilePatterns { base: initial_cwd.to_path_buf(), @@ -464,7 +465,7 @@ fn filter_coverages( coverages: Vec, include: Vec, exclude: Vec, - in_npm_pkg_checker: &dyn InNpmPackageChecker, + in_npm_pkg_checker: &DenoInNpmPackageChecker, ) -> Vec { let include: Vec = include.iter().map(|e| Regex::new(e).unwrap()).collect(); @@ -504,7 +505,7 @@ pub fn cover_files( coverage_flags: CoverageFlags, ) -> Result<(), AnyError> { if coverage_flags.files.include.is_empty() { - return Err(generic_error("No matching coverage profiles found")); + return Err(anyhow!("No matching coverage profiles found")); } let factory = CliFactory::from_flags(flags); @@ -526,16 +527,16 @@ pub fn cover_files( cli_options.initial_cwd(), )?; if script_coverages.is_empty() { - return Err(generic_error("No coverage files found")); + return Err(anyhow!("No coverage files found")); } let script_coverages = filter_coverages( script_coverages, coverage_flags.include, coverage_flags.exclude, - in_npm_pkg_checker.as_ref(), + in_npm_pkg_checker, ); if script_coverages.is_empty() { - return Err(generic_error("No covered files included in the report")); + return Err(anyhow!("No covered files included in the report")); } let proc_coverages: Vec<_> = script_coverages diff --git a/cli/tools/coverage/range_tree.rs b/cli/tools/coverage/range_tree.rs index bca52844c0..08ac914cd2 100644 --- a/cli/tools/coverage/range_tree.rs +++ b/cli/tools/coverage/range_tree.rs @@ -1,12 +1,14 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // // Forked from https://github.com/demurgos/v8-coverage/tree/d0ca18da8740198681e0bc68971b0a6cdb11db3e/rust // Copyright 2021 Charles Samborski. All rights reserved. MIT license. -use crate::cdp; use std::iter::Peekable; + use typed_arena::Arena; +use crate::cdp; + pub struct RangeTreeArena<'a>(Arena>); impl<'a> RangeTreeArena<'a> { diff --git a/cli/tools/coverage/reporter.rs b/cli/tools/coverage/reporter.rs index 6b0e5c885e..bc6e85b47e 100644 --- a/cli/tools/coverage/reporter.rs +++ b/cli/tools/coverage/reporter.rs @@ -1,11 +1,5 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use super::util; -use super::CoverageReport; -use crate::args::CoverageType; -use crate::colors; -use deno_core::error::AnyError; -use deno_core::url::Url; use std::collections::HashMap; use std::fs; use std::fs::File; @@ -15,6 +9,14 @@ use std::io::{self}; use std::path::Path; use std::path::PathBuf; +use deno_core::error::AnyError; +use deno_core::url::Url; + +use super::util; +use super::CoverageReport; +use crate::args::CoverageType; +use crate::colors; + #[derive(Default)] pub struct CoverageStats<'a> { pub line_hit: usize, diff --git a/cli/tools/coverage/util.rs b/cli/tools/coverage/util.rs index e9518e1f78..e61830b7fe 100644 --- a/cli/tools/coverage/util.rs +++ b/cli/tools/coverage/util.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::url::Url; diff --git a/cli/tools/doc.rs b/cli/tools/doc.rs index 0ff1806a9e..114c8f958a 100644 --- a/cli/tools/doc.rs +++ b/cli/tools/doc.rs @@ -1,18 +1,9 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::collections::BTreeMap; +use std::rc::Rc; +use std::sync::Arc; -use crate::args::DocFlags; -use crate::args::DocHtmlFlag; -use crate::args::DocSourceFileFlag; -use crate::args::Flags; -use crate::colors; -use crate::display; -use crate::factory::CliFactory; -use crate::graph_util::graph_exit_integrity_errors; -use crate::graph_util::graph_walk_errors; -use crate::graph_util::GraphWalkErrorsOptions; -use crate::sys::CliSys; -use crate::tsc::get_types_declaration_file_text; -use crate::util::fs::collect_specifiers; use deno_ast::diagnostics::Diagnostic; use deno_config::glob::FilePatterns; use deno_config::glob::PathOrPatternSet; @@ -32,9 +23,20 @@ use deno_graph::ModuleSpecifier; use doc::html::ShortPath; use doc::DocDiagnostic; use indexmap::IndexMap; -use std::collections::BTreeMap; -use std::rc::Rc; -use std::sync::Arc; + +use crate::args::DocFlags; +use crate::args::DocHtmlFlag; +use crate::args::DocSourceFileFlag; +use crate::args::Flags; +use crate::colors; +use crate::display; +use crate::factory::CliFactory; +use crate::graph_util::graph_exit_integrity_errors; +use crate::graph_util::graph_walk_errors; +use crate::graph_util::GraphWalkErrorsOptions; +use crate::sys::CliSys; +use crate::tsc::get_types_declaration_file_text; +use crate::util::fs::collect_specifiers; const JSON_SCHEMA_VERSION: u8 = 1; @@ -60,10 +62,11 @@ async fn generate_doc_nodes_for_builtin_types( )], Vec::new(), ); + let roots = vec![source_file_specifier.clone()]; let mut graph = deno_graph::ModuleGraph::new(GraphKind::TypesOnly); graph .build( - vec![source_file_specifier.clone()], + roots.clone(), &loader, deno_graph::BuildOptions { imports: Vec::new(), @@ -83,14 +86,13 @@ async fn generate_doc_nodes_for_builtin_types( let doc_parser = doc::DocParser::new( &graph, parser, + &roots, doc::DocParserOptions { diagnostics: false, private: doc_flags.private, }, )?; - let nodes = doc_parser.parse_module(&source_file_specifier)?.definitions; - - Ok(IndexMap::from([(source_file_specifier, nodes)])) + Ok(doc_parser.parse()?) } pub async fn doc( @@ -156,19 +158,13 @@ pub async fn doc( let doc_parser = doc::DocParser::new( &graph, &capturing_parser, + &module_specifiers, doc::DocParserOptions { private: doc_flags.private, diagnostics: doc_flags.lint, }, )?; - - let mut doc_nodes_by_url = - IndexMap::with_capacity(module_specifiers.len()); - - for module_specifier in module_specifiers { - let nodes = doc_parser.parse_with_reexports(&module_specifier)?; - doc_nodes_by_url.insert(module_specifier, nodes); - } + let doc_nodes_by_url = doc_parser.parse()?; if doc_flags.lint { let diagnostics = doc_parser.take_diagnostics(); @@ -189,29 +185,9 @@ pub async fn doc( .await?; let (_, deno_ns) = deno_ns.into_iter().next().unwrap(); - let short_path = Rc::new(ShortPath::new( - ModuleSpecifier::parse("file:///lib.deno.d.ts").unwrap(), - None, - None, - None, - )); - - deno_doc::html::compute_namespaced_symbols( - &deno_ns - .into_iter() - .map(|node| deno_doc::html::DocNodeWithContext { - origin: short_path.clone(), - ns_qualifiers: Rc::new([]), - kind_with_drilldown: - deno_doc::html::DocNodeKindWithDrilldown::Other(node.kind()), - inner: Rc::new(node), - drilldown_name: None, - parent: None, - }) - .collect::>(), - ) + Some(deno_ns) } else { - Default::default() + None }; let mut main_entrypoint = None; @@ -391,7 +367,7 @@ impl UsageComposer for DocComposer { fn generate_docs_directory( doc_nodes_by_url: IndexMap>, html_options: &DocHtmlFlag, - deno_ns: std::collections::HashMap, Option>>, + built_in_types: Option>, rewrite_map: Option>, main_entrypoint: Option, ) -> Result<(), AnyError> { @@ -424,12 +400,12 @@ fn generate_docs_directory( None }; - let options = deno_doc::html::GenerateOptions { + let mut options = deno_doc::html::GenerateOptions { package_name: html_options.name.clone(), main_entrypoint, rewrite_map, href_resolver: Rc::new(DocResolver { - deno_ns, + deno_ns: Default::default(), strip_trailing_html: html_options.strip_trailing_html, }), usage_composer: Rc::new(DocComposer), @@ -449,7 +425,58 @@ fn generate_docs_directory( })), }; - let mut files = deno_doc::html::generate(options, doc_nodes_by_url) + if let Some(built_in_types) = built_in_types { + let ctx = deno_doc::html::GenerateCtx::create_basic( + deno_doc::html::GenerateOptions { + package_name: None, + main_entrypoint: Some( + ModuleSpecifier::parse("file:///lib.deno.d.ts").unwrap(), + ), + href_resolver: Rc::new(DocResolver { + deno_ns: Default::default(), + strip_trailing_html: false, + }), + usage_composer: Rc::new(DocComposer), + rewrite_map: Default::default(), + category_docs: Default::default(), + disable_search: Default::default(), + symbol_redirect_map: Default::default(), + default_symbol_map: Default::default(), + markdown_renderer: deno_doc::html::comrak::create_renderer( + None, None, None, + ), + markdown_stripper: Rc::new(deno_doc::html::comrak::strip), + head_inject: None, + }, + IndexMap::from([( + ModuleSpecifier::parse("file:///lib.deno.d.ts").unwrap(), + built_in_types, + )]), + )?; + + let deno_ns = deno_doc::html::compute_namespaced_symbols( + &ctx, + Box::new( + ctx + .doc_nodes + .values() + .next() + .unwrap() + .iter() + .map(std::borrow::Cow::Borrowed), + ), + ); + + options.href_resolver = Rc::new(DocResolver { + deno_ns, + strip_trailing_html: html_options.strip_trailing_html, + }); + } + + let ctx = + deno_doc::html::GenerateCtx::create_basic(options, doc_nodes_by_url)?; + + let mut files = deno_doc::html::generate(ctx) .context("Failed to generate HTML documentation")?; files.insert("prism.js".to_string(), PRISM_JS.to_string()); diff --git a/cli/tools/fmt.rs b/cli/tools/fmt.rs index 7f9a15f4b2..d0948fd4f7 100644 --- a/cli/tools/fmt.rs +++ b/cli/tools/fmt.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. //! This module provides file formatting utilities using //! [`dprint-plugin-typescript`](https://github.com/dprint/dprint-plugin-typescript). @@ -7,37 +7,6 @@ //! the future it can be easily extended to provide //! the same functions as ops available in JS runtime. -use crate::args::CliOptions; -use crate::args::Flags; -use crate::args::FmtFlags; -use crate::args::FmtOptions; -use crate::args::FmtOptionsConfig; -use crate::args::ProseWrap; -use crate::args::UnstableFmtOptions; -use crate::cache::Caches; -use crate::colors; -use crate::factory::CliFactory; -use crate::sys::CliSys; -use crate::util::diff::diff; -use crate::util::file_watcher; -use crate::util::fs::canonicalize_path; -use crate::util::path::get_extension; -use async_trait::async_trait; -use deno_ast::ParsedSource; -use deno_config::glob::FileCollector; -use deno_config::glob::FilePatterns; -use deno_core::anyhow::anyhow; -use deno_core::anyhow::bail; -use deno_core::anyhow::Context; -use deno_core::error::generic_error; -use deno_core::error::AnyError; -use deno_core::futures; -use deno_core::parking_lot::Mutex; -use deno_core::unsync::spawn_blocking; -use deno_core::url::Url; -use log::debug; -use log::info; -use log::warn; use std::borrow::Cow; use std::fs; use std::io::stdin; @@ -50,7 +19,39 @@ use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; use std::sync::Arc; +use async_trait::async_trait; +use deno_ast::ParsedSource; +use deno_config::glob::FileCollector; +use deno_config::glob::FilePatterns; +use deno_core::anyhow::anyhow; +use deno_core::anyhow::bail; +use deno_core::anyhow::Context; +use deno_core::error::AnyError; +use deno_core::futures; +use deno_core::parking_lot::Mutex; +use deno_core::unsync::spawn_blocking; +use deno_core::url::Url; +use log::debug; +use log::info; +use log::warn; + +use crate::args::CliOptions; +use crate::args::Flags; +use crate::args::FmtFlags; +use crate::args::FmtOptions; +use crate::args::FmtOptionsConfig; +use crate::args::ProseWrap; +use crate::args::UnstableFmtOptions; +use crate::cache::CacheDBHash; +use crate::cache::Caches; use crate::cache::IncrementalCache; +use crate::colors; +use crate::factory::CliFactory; +use crate::sys::CliSys; +use crate::util::diff::diff; +use crate::util::file_watcher; +use crate::util::fs::canonicalize_path; +use crate::util::path::get_extension; /// Format JavaScript/TypeScript files. pub async fn format( @@ -165,7 +166,7 @@ fn resolve_paths_with_options_batches( Vec::with_capacity(members_fmt_options.len()); for (_ctx, member_fmt_options) in members_fmt_options { let files = - collect_fmt_files(cli_options, member_fmt_options.files.clone())?; + collect_fmt_files(cli_options, member_fmt_options.files.clone()); if !files.is_empty() { paths_with_options_batches.push(PathsWithOptions { base: member_fmt_options.files.base.clone(), @@ -175,7 +176,7 @@ fn resolve_paths_with_options_batches( } } if paths_with_options_batches.is_empty() { - return Err(generic_error("No target files found.")); + return Err(anyhow!("No target files found.")); } Ok(paths_with_options_batches) } @@ -201,7 +202,7 @@ async fn format_files( let paths = paths_with_options.paths; let incremental_cache = Arc::new(IncrementalCache::new( caches.fmt_incremental_cache_db(), - &(&fmt_options.options, &fmt_options.unstable), // cache key + CacheDBHash::from_hashable((&fmt_options.options, &fmt_options.unstable)), &paths, )); formatter @@ -222,7 +223,7 @@ async fn format_files( fn collect_fmt_files( cli_options: &CliOptions, files: FilePatterns, -) -> Result, AnyError> { +) -> Vec { FileCollector::new(|e| { is_supported_ext_fmt(e.path) || (e.path.extension().is_none() && cli_options.ext_flag().is_some()) @@ -482,7 +483,7 @@ pub fn format_html( } if let Some(error_msg) = inner(&error, file_path) { - AnyError::from(generic_error(error_msg)) + AnyError::msg(error_msg) } else { AnyError::from(error) } @@ -730,9 +731,9 @@ impl Formatter for CheckFormatter { Ok(()) } else { let not_formatted_files_str = files_str(not_formatted_files_count); - Err(generic_error(format!( + Err(anyhow!( "Found {not_formatted_files_count} not formatted {not_formatted_files_str} in {checked_files_str}", - ))) + )) } } } diff --git a/cli/tools/info.rs b/cli/tools/info.rs index 39a7a912bf..1b2542d427 100644 --- a/cli/tools/info.rs +++ b/cli/tools/info.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashMap; use std::collections::HashSet; @@ -11,12 +11,14 @@ use deno_core::error::AnyError; use deno_core::resolve_url_or_path; use deno_core::serde_json; use deno_core::url; +use deno_error::JsErrorClass; use deno_graph::Dependency; use deno_graph::GraphKind; use deno_graph::Module; use deno_graph::ModuleError; use deno_graph::ModuleGraph; use deno_graph::Resolution; +use deno_lib::util::checksum; use deno_npm::npm_rc::ResolvedNpmRc; use deno_npm::resolution::NpmResolutionSnapshot; use deno_npm::NpmPackageId; @@ -31,9 +33,7 @@ use crate::args::InfoFlags; use crate::display; use crate::factory::CliFactory; use crate::graph_util::graph_exit_integrity_errors; -use crate::npm::CliNpmResolver; -use crate::npm::ManagedCliNpmResolver; -use crate::util::checksum; +use crate::npm::CliManagedNpmResolver; use crate::util::display::DisplayTreeNode; const JSON_SCHEMA_VERSION: u8 = 1; @@ -137,6 +137,10 @@ pub async fn info( lockfile.write_if_changed()?; } + let maybe_npm_info = npm_resolver + .as_managed() + .map(|r| (r, r.resolution().snapshot())); + if info_flags.json { let mut json_graph = serde_json::json!(graph); if let Some(output) = json_graph.as_object_mut() { @@ -147,11 +151,19 @@ pub async fn info( ); } - add_npm_packages_to_json(&mut json_graph, npm_resolver.as_ref(), npmrc); + add_npm_packages_to_json( + &mut json_graph, + maybe_npm_info.as_ref().map(|(_, s)| s), + npmrc, + ); display::write_json_to_stdout(&json_graph)?; } else { let mut output = String::new(); - GraphDisplayContext::write(&graph, npm_resolver.as_ref(), &mut output)?; + GraphDisplayContext::write( + &graph, + maybe_npm_info.as_ref().map(|(r, s)| (*r, s)), + &mut output, + )?; display::write_to_stdout_ignore_sigpipe(output.as_bytes())?; } } else { @@ -179,7 +191,7 @@ fn print_cache_info( let registry_cache = dir.registries_folder_path(); let mut origin_dir = dir.origin_data_folder_path(); let deno_dir = dir.root_path_for_display().to_string(); - let web_cache_dir = crate::worker::get_cache_storage_dir(); + let web_cache_dir = deno_lib::worker::get_cache_storage_dir(); if let Some(location) = &location { origin_dir = @@ -250,15 +262,14 @@ fn print_cache_info( fn add_npm_packages_to_json( json: &mut serde_json::Value, - npm_resolver: &dyn CliNpmResolver, + npm_snapshot: Option<&NpmResolutionSnapshot>, npmrc: &ResolvedNpmRc, ) { - let Some(npm_resolver) = npm_resolver.as_managed() else { + let Some(npm_snapshot) = npm_snapshot else { return; // does not include byonm to deno info's output }; // ideally deno_graph could handle this, but for now we just modify the json here - let snapshot = npm_resolver.snapshot(); let json = json.as_object_mut().unwrap(); let modules = json.get_mut("modules").and_then(|m| m.as_array_mut()); if let Some(modules) = modules { @@ -272,7 +283,7 @@ fn add_npm_packages_to_json( .and_then(|k| k.as_str()) .and_then(|specifier| NpmPackageNvReference::from_str(specifier).ok()) .and_then(|package_ref| { - snapshot + npm_snapshot .resolve_package_from_deno_module(package_ref.nv()) .ok() }); @@ -294,7 +305,8 @@ fn add_npm_packages_to_json( if let Some(specifier) = dep.get("specifier").and_then(|s| s.as_str()) { if let Ok(npm_ref) = NpmPackageReqReference::from_str(specifier) { - if let Ok(pkg) = snapshot.resolve_pkg_from_pkg_req(npm_ref.req()) + if let Ok(pkg) = + npm_snapshot.resolve_pkg_from_pkg_req(npm_ref.req()) { dep.insert( "npmPackage".to_string(), @@ -320,8 +332,9 @@ fn add_npm_packages_to_json( } } - let mut sorted_packages = - snapshot.all_packages_for_every_system().collect::>(); + let mut sorted_packages = npm_snapshot + .all_packages_for_every_system() + .collect::>(); sorted_packages.sort_by(|a, b| a.id.cmp(&b.id)); let mut json_packages = serde_json::Map::with_capacity(sorted_packages.len()); for pkg in sorted_packages { @@ -355,7 +368,7 @@ struct NpmInfo { impl NpmInfo { pub fn build<'a>( graph: &'a ModuleGraph, - npm_resolver: &'a ManagedCliNpmResolver, + npm_resolver: &'a CliManagedNpmResolver, npm_snapshot: &'a NpmResolutionSnapshot, ) -> Self { let mut info = NpmInfo::default(); @@ -381,12 +394,15 @@ impl NpmInfo { fn fill_package_info<'a>( &mut self, package: &NpmResolutionPackage, - npm_resolver: &'a ManagedCliNpmResolver, + npm_resolver: &'a CliManagedNpmResolver, npm_snapshot: &'a NpmResolutionSnapshot, ) { self.packages.insert(package.id.clone(), package.clone()); - if let Ok(size) = npm_resolver.package_size(&package.id) { - self.package_sizes.insert(package.id.clone(), size); + if let Ok(folder) = npm_resolver.resolve_pkg_folder_from_pkg_id(&package.id) + { + if let Ok(size) = crate::util::fs::dir_size(&folder) { + self.package_sizes.insert(package.id.clone(), size); + } } for id in package.dependencies.values() { if !self.packages.contains_key(id) { @@ -415,13 +431,15 @@ struct GraphDisplayContext<'a> { impl<'a> GraphDisplayContext<'a> { pub fn write( graph: &'a ModuleGraph, - npm_resolver: &'a dyn CliNpmResolver, + managed_npm_info: Option<( + &'a CliManagedNpmResolver, + &'a NpmResolutionSnapshot, + )>, writer: &mut TWrite, ) -> Result<(), AnyError> { - let npm_info = match npm_resolver.as_managed() { - Some(npm_resolver) => { - let npm_snapshot = npm_resolver.snapshot(); - NpmInfo::build(graph, npm_resolver, &npm_snapshot) + let npm_info = match managed_npm_info { + Some((npm_resolver, npm_snapshot)) => { + NpmInfo::build(graph, npm_resolver, npm_snapshot) } None => NpmInfo::default(), }; @@ -664,9 +682,10 @@ impl<'a> GraphDisplayContext<'a> { HttpsChecksumIntegrity(_) => "(checksum integrity error)", Decode(_) => "(loading decode error)", Loader(err) => { - match deno_runtime::errors::get_error_class_name(err) { - Some("NotCapable") => "(not capable, requires --allow-import)", - _ => "(loading error)", + if err.get_class() == "NotCapable" { + "(not capable, requires --allow-import)" + } else { + "(loading error)" } } Jsr(_) => "(loading error)", diff --git a/cli/tools/init/mod.rs b/cli/tools/init/mod.rs index 36bdbac2bc..d077de44ce 100644 --- a/cli/tools/init/mod.rs +++ b/cli/tools/init/mod.rs @@ -1,12 +1,9 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::io::IsTerminal; +use std::io::Write; +use std::path::Path; -use crate::args::DenoSubcommand; -use crate::args::Flags; -use crate::args::InitFlags; -use crate::args::PackagesAllowedScripts; -use crate::args::PermissionFlags; -use crate::args::RunFlags; -use crate::colors; use color_print::cformat; use color_print::cstr; use deno_config::deno_json::NodeModulesDirMode; @@ -15,9 +12,14 @@ use deno_core::error::AnyError; use deno_core::serde_json::json; use deno_runtime::WorkerExecutionMode; use log::info; -use std::io::IsTerminal; -use std::io::Write; -use std::path::Path; + +use crate::args::DenoSubcommand; +use crate::args::Flags; +use crate::args::InitFlags; +use crate::args::PackagesAllowedScripts; +use crate::args::PermissionFlags; +use crate::args::RunFlags; +use crate::colors; pub async fn init_project(init_flags: InitFlags) -> Result { if let Some(package) = &init_flags.package { diff --git a/cli/tools/installer.rs b/cli/tools/installer.rs index 1bfd17f30d..596d087589 100644 --- a/cli/tools/installer.rs +++ b/cli/tools/installer.rs @@ -1,4 +1,28 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::env; +use std::fs; +use std::fs::File; +use std::io; +use std::io::Write; +#[cfg(not(windows))] +use std::os::unix::fs::PermissionsExt; +use std::path::Path; +use std::path::PathBuf; +use std::sync::Arc; + +use deno_cache_dir::file_fetcher::CacheSetting; +use deno_core::anyhow::anyhow; +use deno_core::anyhow::bail; +use deno_core::anyhow::Context; +use deno_core::error::AnyError; +use deno_core::resolve_url_or_path; +use deno_core::url::Url; +use deno_semver::npm::NpmPackageReqReference; +use log::Level; +use once_cell::sync::Lazy; +use regex::Regex; +use regex::RegexBuilder; use crate::args::resolve_no_prompt; use crate::args::AddFlags; @@ -19,30 +43,6 @@ use crate::jsr::JsrFetchResolver; use crate::npm::NpmFetchResolver; use crate::util::fs::canonicalize_path_maybe_not_exists; -use deno_cache_dir::file_fetcher::CacheSetting; -use deno_core::anyhow::bail; -use deno_core::anyhow::Context; -use deno_core::error::generic_error; -use deno_core::error::AnyError; -use deno_core::resolve_url_or_path; -use deno_core::url::Url; -use deno_semver::npm::NpmPackageReqReference; -use log::Level; -use once_cell::sync::Lazy; -use regex::Regex; -use regex::RegexBuilder; -use std::env; -use std::fs; -use std::fs::File; -use std::io; -use std::io::Write; -use std::path::Path; -use std::path::PathBuf; - -#[cfg(not(windows))] -use std::os::unix::fs::PermissionsExt; -use std::sync::Arc; - static EXEC_NAME_RE: Lazy = Lazy::new(|| { RegexBuilder::new(r"^[a-z0-9][\w-]*$") .case_insensitive(true) @@ -54,9 +54,7 @@ fn validate_name(exec_name: &str) -> Result<(), AnyError> { if EXEC_NAME_RE.is_match(exec_name) { Ok(()) } else { - Err(generic_error(format!( - "Invalid executable name: {exec_name}" - ))) + Err(anyhow!("Invalid executable name: {exec_name}")) } } @@ -223,7 +221,7 @@ pub async fn uninstall( // ensure directory exists if let Ok(metadata) = fs::metadata(&installation_dir) { if !metadata.is_dir() { - return Err(generic_error("Installation path is not a directory")); + return Err(anyhow!("Installation path is not a directory")); } } @@ -247,10 +245,10 @@ pub async fn uninstall( } if !removed { - return Err(generic_error(format!( + return Err(anyhow!( "No installation found for {}", uninstall_flags.name - ))); + )); } // There might be some extra files to delete @@ -302,8 +300,8 @@ async fn install_local( InstallFlagsLocal::TopLevel => { let factory = CliFactory::from_flags(flags); // surface any errors in the package.json - if let Some(npm_resolver) = factory.npm_resolver().await?.as_managed() { - npm_resolver.ensure_no_pkg_json_dep_errors()?; + if let Some(npm_installer) = factory.npm_installer_if_managed()? { + npm_installer.ensure_no_pkg_json_dep_errors()?; } crate::tools::registry::cache_top_level_deps(&factory, None).await?; @@ -423,14 +421,14 @@ async fn create_install_shim( // ensure directory exists if let Ok(metadata) = fs::metadata(&shim_data.installation_dir) { if !metadata.is_dir() { - return Err(generic_error("Installation path is not a directory")); + return Err(anyhow!("Installation path is not a directory")); } } else { fs::create_dir_all(&shim_data.installation_dir)?; }; if shim_data.file_path.exists() && !install_flags_global.force { - return Err(generic_error( + return Err(anyhow!( "Existing installation found. Aborting (Use -f to overwrite).", )); }; @@ -492,7 +490,7 @@ async fn resolve_shim_data( let name = match name { Some(name) => name, - None => return Err(generic_error( + None => return Err(anyhow!( "An executable name was not provided. One could not be inferred from the URL. Aborting.", )), }; @@ -524,9 +522,7 @@ async fn resolve_shim_data( let log_level = match log_level { Level::Debug => "debug", Level::Info => "info", - _ => { - return Err(generic_error(format!("invalid log level {log_level}"))) - } + _ => return Err(anyhow!(format!("invalid log level {log_level}"))), }; executable_args.push(log_level.to_string()); } @@ -659,16 +655,17 @@ fn is_in_path(dir: &Path) -> bool { #[cfg(test)] mod tests { - use super::*; + use std::process::Command; + use test_util::testdata_path; + use test_util::TempDir; + + use super::*; use crate::args::ConfigFlag; use crate::args::PermissionFlags; use crate::args::UninstallFlagsGlobal; use crate::args::UnstableConfig; use crate::util::fs::canonicalize_path; - use std::process::Command; - use test_util::testdata_path; - use test_util::TempDir; #[tokio::test] async fn install_infer_name_from_url() { diff --git a/cli/tools/jupyter/install.rs b/cli/tools/jupyter/install.rs index aeff89ccf4..d76c59343b 100644 --- a/cli/tools/jupyter/install.rs +++ b/cli/tools/jupyter/install.rs @@ -1,12 +1,12 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use deno_core::error::AnyError; -use deno_core::serde_json; -use deno_core::serde_json::json; use std::env::current_exe; use std::io::Write; use std::path::Path; +use deno_core::error::AnyError; +use deno_core::serde_json; +use deno_core::serde_json::json; use jupyter_runtime::dirs::user_data_dir; const DENO_ICON_32: &[u8] = include_bytes!("./resources/deno-logo-32x32.png"); diff --git a/cli/tools/jupyter/mod.rs b/cli/tools/jupyter/mod.rs index 732f95c49f..67c604118c 100644 --- a/cli/tools/jupyter/mod.rs +++ b/cli/tools/jupyter/mod.rs @@ -1,21 +1,10 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::sync::Arc; -use crate::args::Flags; -use crate::args::JupyterFlags; -use crate::cdp; -use crate::lsp::ReplCompletionItem; -use crate::ops; -use crate::tools::repl; -use crate::tools::test::create_single_test_event_channel; -use crate::tools::test::reporters::PrettyTestReporter; -use crate::tools::test::TestEventWorkerSender; -use crate::tools::test::TestFailureFormatOptions; -use crate::CliFactory; +use deno_core::anyhow::anyhow; use deno_core::anyhow::bail; use deno_core::anyhow::Context; -use deno_core::error::generic_error; use deno_core::error::AnyError; use deno_core::futures::FutureExt; use deno_core::located_script_name; @@ -34,6 +23,18 @@ use tokio::sync::mpsc; use tokio::sync::mpsc::UnboundedSender; use tokio::sync::oneshot; +use crate::args::Flags; +use crate::args::JupyterFlags; +use crate::cdp; +use crate::lsp::ReplCompletionItem; +use crate::ops; +use crate::tools::repl; +use crate::tools::test::create_single_test_event_channel; +use crate::tools::test::reporters::PrettyTestReporter; +use crate::tools::test::TestEventWorkerSender; +use crate::tools::test::TestFailureFormatOptions; +use crate::CliFactory; + mod install; pub mod server; @@ -66,7 +67,7 @@ pub async fn kernel( // TODO(bartlomieju): should we run with all permissions? let permissions = PermissionsContainer::allow_all(factory.permission_desc_parser()?.clone()); - let npm_resolver = factory.npm_resolver().await?.clone(); + let npm_installer = factory.npm_installer_if_managed()?.cloned(); let resolver = factory.resolver().await?.clone(); let worker_factory = factory.create_cli_main_worker_factory().await?; let (stdio_tx, stdio_rx) = mpsc::unbounded_channel(); @@ -114,7 +115,7 @@ pub async fn kernel( let worker = worker.into_main_worker(); let mut repl_session = repl::ReplSession::initialize( cli_options, - npm_resolver, + npm_installer, resolver, worker, main_module, @@ -136,10 +137,10 @@ pub async fn kernel( } let cwd_url = Url::from_directory_path(cli_options.initial_cwd()).map_err(|_| { - generic_error(format!( + anyhow!( "Unable to construct URL from the path of cwd: {}", cli_options.initial_cwd().to_string_lossy(), - )) + ) })?; repl_session.set_test_reporter_factory(Box::new(move || { Box::new( diff --git a/cli/tools/jupyter/server.rs b/cli/tools/jupyter/server.rs index 5680ed4c13..bc045d9d9b 100644 --- a/cli/tools/jupyter/server.rs +++ b/cli/tools/jupyter/server.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // This file is forked/ported from // Copyright 2020 The Evcxr Authors. MIT license. @@ -11,8 +11,6 @@ use std::collections::HashMap; use std::rc::Rc; use std::sync::Arc; -use crate::cdp; -use crate::tools::repl; use deno_core::anyhow::bail; use deno_core::error::AnyError; use deno_core::futures; @@ -20,12 +18,9 @@ use deno_core::parking_lot::Mutex; use deno_core::serde_json; use deno_core::CancelFuture; use deno_core::CancelHandle; -use jupyter_runtime::ExecutionCount; -use tokio::sync::mpsc; -use tokio::sync::oneshot; - use jupyter_runtime::messaging; use jupyter_runtime::ConnectionInfo; +use jupyter_runtime::ExecutionCount; use jupyter_runtime::JupyterMessage; use jupyter_runtime::JupyterMessageContent; use jupyter_runtime::KernelControlConnection; @@ -34,9 +29,13 @@ use jupyter_runtime::KernelShellConnection; use jupyter_runtime::ReplyError; use jupyter_runtime::ReplyStatus; use jupyter_runtime::StreamContent; +use tokio::sync::mpsc; +use tokio::sync::oneshot; use uuid::Uuid; use super::JupyterReplProxy; +use crate::cdp; +use crate::tools::repl; pub struct JupyterServer { execution_count: ExecutionCount, diff --git a/cli/tools/lint/ast_buffer/buffer.rs b/cli/tools/lint/ast_buffer/buffer.rs index b6387a0ef9..a884ee24f9 100644 --- a/cli/tools/lint/ast_buffer/buffer.rs +++ b/cli/tools/lint/ast_buffer/buffer.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::fmt::Display; @@ -14,9 +14,14 @@ pub enum PropFlags { Ref, RefArr, String, + Number, Bool, Null, Undefined, + Object, + Regex, + BigInt, + Array, } impl From for u8 { @@ -33,21 +38,29 @@ impl TryFrom for PropFlags { 0 => Ok(PropFlags::Ref), 1 => Ok(PropFlags::RefArr), 2 => Ok(PropFlags::String), - 3 => Ok(PropFlags::Bool), - 4 => Ok(PropFlags::Null), - 5 => Ok(PropFlags::Undefined), + 3 => Ok(PropFlags::Number), + 4 => Ok(PropFlags::Bool), + 5 => Ok(PropFlags::Null), + 6 => Ok(PropFlags::Undefined), + 7 => Ok(PropFlags::Object), + 8 => Ok(PropFlags::Regex), + 9 => Ok(PropFlags::BigInt), + 10 => Ok(PropFlags::Array), _ => Err("Unknown Prop flag"), } } } +pub type Index = u32; + +const GROUP_KIND: u8 = 1; const MASK_U32_1: u32 = 0b11111111_00000000_00000000_00000000; const MASK_U32_2: u32 = 0b00000000_11111111_00000000_00000000; const MASK_U32_3: u32 = 0b00000000_00000000_11111111_00000000; const MASK_U32_4: u32 = 0b00000000_00000000_00000000_11111111; -// TODO: There is probably a native Rust function to do this. -pub fn append_u32(result: &mut Vec, value: u32) { +#[inline] +fn append_u32(result: &mut Vec, value: u32) { let v1: u8 = ((value & MASK_U32_1) >> 24) as u8; let v2: u8 = ((value & MASK_U32_2) >> 16) as u8; let v3: u8 = ((value & MASK_U32_3) >> 8) as u8; @@ -59,25 +72,11 @@ pub fn append_u32(result: &mut Vec, value: u32) { result.push(v4); } -pub fn append_usize(result: &mut Vec, value: usize) { +fn append_usize(result: &mut Vec, value: usize) { let raw = u32::try_from(value).unwrap(); append_u32(result, raw); } -pub fn write_usize(result: &mut [u8], value: usize, idx: usize) { - let raw = u32::try_from(value).unwrap(); - - let v1: u8 = ((raw & MASK_U32_1) >> 24) as u8; - let v2: u8 = ((raw & MASK_U32_2) >> 16) as u8; - let v3: u8 = ((raw & MASK_U32_3) >> 8) as u8; - let v4: u8 = (raw & MASK_U32_4) as u8; - - result[idx] = v1; - result[idx + 1] = v2; - result[idx + 2] = v3; - result[idx + 3] = v4; -} - #[derive(Debug)] pub struct StringTable { id: usize, @@ -119,71 +118,47 @@ impl StringTable { } #[derive(Debug, Clone, Copy, PartialEq)] -pub struct NodeRef(pub usize); - -/// Represents an offset to a node whose schema hasn't been committed yet +pub struct NodeRef(pub Index); #[derive(Debug, Clone, Copy, PartialEq)] -pub struct PendingNodeRef(pub NodeRef); +pub struct PendingRef(pub Index); -#[derive(Debug)] -pub struct BoolPos(pub usize); -#[derive(Debug)] -pub struct FieldPos(pub usize); -#[derive(Debug)] -pub struct FieldArrPos(pub usize); -#[derive(Debug)] -pub struct StrPos(pub usize); -#[derive(Debug)] -pub struct UndefPos(pub usize); -#[derive(Debug)] -pub struct NullPos(pub usize); - -#[derive(Debug)] -pub enum NodePos { - Bool(BoolPos), - #[allow(dead_code)] - Field(FieldPos), - #[allow(dead_code)] - FieldArr(FieldArrPos), - Str(StrPos), - Undef(UndefPos), - #[allow(dead_code)] - Null(NullPos), +pub trait AstBufSerializer { + fn serialize(&mut self) -> Vec; } -pub trait AstBufSerializer -where - K: Into + Display, - P: Into + Display, -{ - fn header(&mut self, kind: K, parent: NodeRef, span: &Span) - -> PendingNodeRef; - fn ref_field(&mut self, prop: P) -> FieldPos; - fn ref_vec_field(&mut self, prop: P, len: usize) -> FieldArrPos; - fn str_field(&mut self, prop: P) -> StrPos; - fn bool_field(&mut self, prop: P) -> BoolPos; - fn undefined_field(&mut self, prop: P) -> UndefPos; - #[allow(dead_code)] - fn null_field(&mut self, prop: P) -> NullPos; - fn commit_schema(&mut self, offset: PendingNodeRef) -> NodeRef; - - fn write_ref(&mut self, pos: FieldPos, value: NodeRef); - fn write_maybe_ref(&mut self, pos: FieldPos, value: Option); - fn write_refs(&mut self, pos: FieldArrPos, value: Vec); - fn write_str(&mut self, pos: StrPos, value: &str); - fn write_bool(&mut self, pos: BoolPos, value: bool); - - fn serialize(&mut self) -> Vec; +/// +/// +/// +/// +/// +#[derive(Debug)] +struct Node { + kind: u8, + prop_offset: u32, + child: u32, + next: u32, + parent: u32, } #[derive(Debug)] pub struct SerializeCtx { - buf: Vec, - start_buf: NodeRef, + root_idx: Index, + + nodes: Vec, + prop_stack: Vec>, + field_count: Vec, + field_buf: Vec, + prev_sibling_stack: Vec, + + /// Vec of spans + spans: Vec, + + /// Maps string id to the actual string str_table: StringTable, - kind_map: Vec, - prop_map: Vec, - field_count: u8, + /// Maps kind id to string id + kind_name_map: Vec, + /// Maps prop id to string id + prop_name_map: Vec, } /// This is the internal context used to allocate and fill the buffer. The point @@ -198,20 +173,24 @@ impl SerializeCtx { let kind_size = kind_len as usize; let prop_size = prop_len as usize; let mut ctx = Self { - start_buf: NodeRef(0), - buf: vec![], + spans: Vec::with_capacity(512), + root_idx: 0, + nodes: Vec::with_capacity(512), + prop_stack: vec![vec![]], + prev_sibling_stack: vec![0], + field_count: vec![0], + field_buf: Vec::with_capacity(1024), str_table: StringTable::new(), - kind_map: vec![0; kind_size], - prop_map: vec![0; prop_size], - field_count: 0, + kind_name_map: vec![0; kind_size], + prop_name_map: vec![0; prop_size], }; let empty_str = ctx.str_table.insert(""); // Placeholder node is always 0 - ctx.append_node(0, NodeRef(0), &DUMMY_SP, 0); - ctx.kind_map[0] = empty_str; - ctx.start_buf = NodeRef(ctx.buf.len()); + ctx.append_node(0, &DUMMY_SP); + ctx.kind_name_map[0] = empty_str; + ctx.kind_name_map[1] = empty_str; // Insert default props that are always present let type_str = ctx.str_table.insert("type"); @@ -220,258 +199,306 @@ impl SerializeCtx { let length_str = ctx.str_table.insert("length"); // These values are expected to be in this order on the JS side - ctx.prop_map[0] = empty_str; - ctx.prop_map[1] = type_str; - ctx.prop_map[2] = parent_str; - ctx.prop_map[3] = range_str; - ctx.prop_map[4] = length_str; + ctx.prop_name_map[0] = empty_str; + ctx.prop_name_map[1] = type_str; + ctx.prop_name_map[2] = parent_str; + ctx.prop_name_map[3] = range_str; + ctx.prop_name_map[4] = length_str; ctx } + pub fn set_root_idx(&mut self, idx: Index) { + self.root_idx = idx; + } + /// Allocate a node's header - fn field_header

(&mut self, prop: P, prop_flags: PropFlags) -> usize + fn field_header

(&mut self, prop: P, prop_flags: PropFlags) where P: Into + Display + Clone, { - self.field_count += 1; - - let offset = self.buf.len(); - + let flags: u8 = prop_flags.into(); let n: u8 = prop.clone().into(); - self.buf.push(n); - if let Some(v) = self.prop_map.get::(n.into()) { + if let Some(v) = self.prop_name_map.get::(n.into()) { if *v == 0 { let id = self.str_table.insert(&format!("{prop}")); - self.prop_map[n as usize] = id; + self.prop_name_map[n as usize] = id; } } - let flags: u8 = prop_flags.into(); - self.buf.push(flags); + // Increment field counter + let idx = self.field_count.len() - 1; + let count = self.field_count[idx]; + self.field_count[idx] = count + 1; - offset + let buf = self.prop_stack.last_mut().unwrap(); + buf.push(n); + buf.push(flags); } - /// Allocate a property pointing to another node. - fn field

(&mut self, prop: P, prop_flags: PropFlags) -> usize + fn get_node(&mut self, id: Index) -> &mut Node { + self.nodes.get_mut(id as usize).unwrap() + } + + fn set_parent(&mut self, child_id: Index, parent_id: Index) { + let child = self.get_node(child_id); + child.parent = parent_id; + } + + fn set_child(&mut self, parent_id: Index, child_id: Index) { + let parent = self.get_node(parent_id); + parent.child = child_id; + } + + fn set_next(&mut self, node_id: Index, next_id: Index) { + let node = self.get_node(node_id); + node.next = next_id; + } + + fn update_ref_links(&mut self, parent_id: Index, child_id: Index) { + let last_idx = self.prev_sibling_stack.len() - 1; + let parent = self.get_node(parent_id); + if parent.child == 0 { + parent.child = child_id; + } else { + let prev_id = self.prev_sibling_stack[last_idx]; + self.set_next(prev_id, child_id); + } + + self.prev_sibling_stack[last_idx] = child_id; + self.set_parent(child_id, parent_id); + } + + pub fn append_node(&mut self, kind: K, span: &Span) -> PendingRef where - P: Into + Display + Clone, + K: Into + Display + Clone, { - let offset = self.field_header(prop, prop_flags); - - append_usize(&mut self.buf, 0); - - offset + self.append_inner(kind, span.lo.0, span.hi.0) } - fn append_node( + pub fn append_inner( &mut self, - kind: u8, - parent: NodeRef, - span: &Span, - prop_count: usize, - ) -> PendingNodeRef { - let offset = self.buf.len(); - - // Node type fits in a u8 - self.buf.push(kind); - - // Offset to the parent node. Will be 0 if none exists - append_usize(&mut self.buf, parent.0); - - // Span, the start and end location of this node - append_u32(&mut self.buf, span.lo.0); - append_u32(&mut self.buf, span.hi.0); - - // No node has more than <10 properties - debug_assert!(prop_count < 10); - self.buf.push(prop_count as u8); - - PendingNodeRef(NodeRef(offset)) - } - - pub fn commit_schema(&mut self, node_ref: PendingNodeRef) -> NodeRef { - let mut offset = node_ref.0 .0; - - // type + parentId + span lo + span hi - offset += 1 + 4 + 4 + 4; - - self.buf[offset] = self.field_count; - self.field_count = 0; - - node_ref.0 - } - - /// Allocate the node header. It's always the same for every node. - /// - /// - /// - /// - /// (There is no node with more than 10 properties) - pub fn header( - &mut self, - kind: N, - parent: NodeRef, - span: &Span, - ) -> PendingNodeRef + kind: K, + span_lo: u32, + span_hi: u32, + ) -> PendingRef where - N: Into + Display + Clone, + K: Into + Display + Clone, { - let n: u8 = kind.clone().into(); + let kind_u8: u8 = kind.clone().into(); - if let Some(v) = self.kind_map.get::(n.into()) { + let id: Index = self.nodes.len() as u32; + + self.nodes.push(Node { + kind: kind_u8, + prop_offset: 0, + child: 0, + next: 0, + parent: 0, + }); + + if let Some(v) = self.kind_name_map.get::(kind_u8.into()) { if *v == 0 { - let id = self.str_table.insert(&format!("{kind}")); - self.kind_map[n as usize] = id; + let s_id = self.str_table.insert(&format!("{kind}")); + self.kind_name_map[kind_u8 as usize] = s_id; } } - // Prop count will be filled with the actual value when the - // schema is committed. - self.append_node(n, parent, span, 0) + self.field_count.push(0); + self.prop_stack.push(vec![]); + self.prev_sibling_stack.push(0); + + // write spans + self.spans.push(span_lo); + self.spans.push(span_hi); + + PendingRef(id) } - /// Allocate a reference property that will hold the offset of - /// another node. - pub fn ref_field

(&mut self, prop: P) -> usize + pub fn commit_node(&mut self, id: PendingRef) -> NodeRef { + let mut buf = self.prop_stack.pop().unwrap(); + let count = self.field_count.pop().unwrap(); + let offset = self.field_buf.len(); + + // All nodes have <10 fields + self.field_buf.push(count as u8); + self.field_buf.append(&mut buf); + + let node = self.nodes.get_mut(id.0 as usize).unwrap(); + node.prop_offset = offset as u32; + + self.prev_sibling_stack.pop(); + + NodeRef(id.0) + } + + // Allocate an object field + pub fn open_obj(&mut self) { + self.field_count.push(0); + self.prop_stack.push(vec![]); + } + + pub fn commit_obj

(&mut self, prop: P) where P: Into + Display + Clone, { - self.field(prop, PropFlags::Ref) + let mut buf = self.prop_stack.pop().unwrap(); + let count = self.field_count.pop().unwrap(); + let offset = self.field_buf.len(); + append_usize(&mut self.field_buf, count); + self.field_buf.append(&mut buf); + + self.field_header(prop, PropFlags::Object); + let buf = self.prop_stack.last_mut().unwrap(); + append_usize(buf, offset); } - /// Allocate a property that is a vec of node offsets pointing to other - /// nodes. - pub fn ref_vec_field

(&mut self, prop: P, len: usize) -> usize + /// Allocate an null field + pub fn write_null

(&mut self, prop: P) where P: Into + Display + Clone, { - let offset = self.field(prop, PropFlags::RefArr); + self.field_header(prop, PropFlags::Null); - for _ in 0..len { - append_u32(&mut self.buf, 0); - } - - offset + let buf = self.prop_stack.last_mut().unwrap(); + append_u32(buf, 0); } - // Allocate a property representing a string. Strings are deduplicated - // in the message and the property will only contain the string id. - pub fn str_field

(&mut self, prop: P) -> usize + /// Allocate an null field + pub fn write_undefined

(&mut self, prop: P) where P: Into + Display + Clone, { - self.field(prop, PropFlags::String) + self.field_header(prop, PropFlags::Undefined); + + let buf = self.prop_stack.last_mut().unwrap(); + append_u32(buf, 0); } - /// Allocate a bool field - pub fn bool_field

(&mut self, prop: P) -> usize + /// Allocate a number field + pub fn write_num

(&mut self, prop: P, value: &str) where P: Into + Display + Clone, { - let offset = self.field_header(prop, PropFlags::Bool); - self.buf.push(0); - offset + self.field_header(prop, PropFlags::Number); + + let id = self.str_table.insert(value); + let buf = self.prop_stack.last_mut().unwrap(); + append_usize(buf, id); } - /// Allocate an undefined field - pub fn undefined_field

(&mut self, prop: P) -> usize + /// Allocate a bigint field + pub fn write_bigint

(&mut self, prop: P, value: &str) where P: Into + Display + Clone, { - self.field_header(prop, PropFlags::Undefined) + self.field_header(prop, PropFlags::BigInt); + + let id = self.str_table.insert(value); + let buf = self.prop_stack.last_mut().unwrap(); + append_usize(buf, id); } - /// Allocate an undefined field - #[allow(dead_code)] - pub fn null_field

(&mut self, prop: P) -> usize + /// Allocate a RegExp field + pub fn write_regex

(&mut self, prop: P, value: &str) where P: Into + Display + Clone, { - self.field_header(prop, PropFlags::Null) - } + self.field_header(prop, PropFlags::Regex); - /// Replace the placeholder of a reference field with the actual offset - /// to the node we want to point to. - pub fn write_ref(&mut self, field_offset: usize, value: NodeRef) { - #[cfg(debug_assertions)] - { - let value_kind = self.buf[field_offset + 1]; - if PropFlags::try_from(value_kind).unwrap() != PropFlags::Ref { - panic!("Trying to write a ref into a non-ref field") - } - } - - write_usize(&mut self.buf, value.0, field_offset + 2); - } - - /// Helper for writing optional node offsets - pub fn write_maybe_ref( - &mut self, - field_offset: usize, - value: Option, - ) { - #[cfg(debug_assertions)] - { - let value_kind = self.buf[field_offset + 1]; - if PropFlags::try_from(value_kind).unwrap() != PropFlags::Ref { - panic!("Trying to write a ref into a non-ref field") - } - } - - let ref_value = if let Some(v) = value { v } else { NodeRef(0) }; - write_usize(&mut self.buf, ref_value.0, field_offset + 2); - } - - /// Write a vec of node offsets into the property. The necessary space - /// has been reserved earlier. - pub fn write_refs(&mut self, field_offset: usize, value: Vec) { - #[cfg(debug_assertions)] - { - let value_kind = self.buf[field_offset + 1]; - if PropFlags::try_from(value_kind).unwrap() != PropFlags::RefArr { - panic!("Trying to write a ref into a non-ref array field") - } - } - - let mut offset = field_offset + 2; - write_usize(&mut self.buf, value.len(), offset); - offset += 4; - - for item in value { - write_usize(&mut self.buf, item.0, offset); - offset += 4; - } + let id = self.str_table.insert(value); + let buf = self.prop_stack.last_mut().unwrap(); + append_usize(buf, id); } /// Store the string in our string table and save the id of the string /// in the current field. - pub fn write_str(&mut self, field_offset: usize, value: &str) { - #[cfg(debug_assertions)] - { - let value_kind = self.buf[field_offset + 1]; - if PropFlags::try_from(value_kind).unwrap() != PropFlags::String { - panic!("Trying to write a ref into a non-string field") - } - } + pub fn write_str

(&mut self, prop: P, value: &str) + where + P: Into + Display + Clone, + { + self.field_header(prop, PropFlags::String); let id = self.str_table.insert(value); - write_usize(&mut self.buf, id, field_offset + 2); + let buf = self.prop_stack.last_mut().unwrap(); + append_usize(buf, id); } /// Write a bool to a field. - pub fn write_bool(&mut self, field_offset: usize, value: bool) { - #[cfg(debug_assertions)] - { - let value_kind = self.buf[field_offset + 1]; - if PropFlags::try_from(value_kind).unwrap() != PropFlags::Bool { - panic!("Trying to write a ref into a non-bool field") - } - } + pub fn write_bool

(&mut self, prop: P, value: bool) + where + P: Into + Display + Clone, + { + self.field_header(prop, PropFlags::Bool); - self.buf[field_offset + 2] = if value { 1 } else { 0 }; + let n = if value { 1 } else { 0 }; + let buf = self.prop_stack.last_mut().unwrap(); + append_u32(buf, n); + } + + /// Replace the placeholder of a reference field with the actual offset + /// to the node we want to point to. + pub fn write_ref

(&mut self, prop: P, parent: &PendingRef, value: NodeRef) + where + P: Into + Display + Clone, + { + self.field_header(prop, PropFlags::Ref); + let buf = self.prop_stack.last_mut().unwrap(); + append_u32(buf, value.0); + + if parent.0 > 0 { + self.update_ref_links(parent.0, value.0); + } + } + + /// Helper for writing optional node offsets + pub fn write_maybe_ref

( + &mut self, + prop: P, + parent: &PendingRef, + value: Option, + ) where + P: Into + Display + Clone, + { + if let Some(v) = value { + self.write_ref(prop, parent, v); + } else { + self.write_null(prop); + }; + } + + /// Write a vec of node offsets into the property. The necessary space + /// has been reserved earlier. + pub fn write_ref_vec

( + &mut self, + prop: P, + parent_ref: &PendingRef, + value: Vec, + ) where + P: Into + Display + Clone, + { + self.field_header(prop, PropFlags::RefArr); + let group_id = self.append_node(GROUP_KIND, &DUMMY_SP); + let group_id = self.commit_node(group_id).0; + + let buf = self.prop_stack.last_mut().unwrap(); + append_u32(buf, group_id); + + self.update_ref_links(parent_ref.0, group_id); + + let mut prev_id = 0; + for (i, item) in value.iter().enumerate() { + self.set_parent(item.0, group_id); + + if i == 0 { + self.set_child(group_id, item.0); + } else { + self.set_next(prev_id, item.0); + } + + prev_id = item.0; + } } /// Serialize all information we have into a buffer that can be sent to JS. @@ -481,6 +508,8 @@ impl SerializeCtx { /// /// <- node kind id maps to string id /// <- node property id maps to string id + /// <- List of spans, rarely needed + /// /// /// /// @@ -490,7 +519,13 @@ impl SerializeCtx { // The buffer starts with the serialized AST first, because that // contains absolute offsets. By butting this at the start of the // message we don't have to waste time updating any offsets. - buf.append(&mut self.buf); + for node in &self.nodes { + buf.push(node.kind); + append_u32(&mut buf, node.prop_offset); + append_u32(&mut buf, node.child); + append_u32(&mut buf, node.next); + append_u32(&mut buf, node.parent); + } // Next follows the string table. We'll keep track of the offset // in the message of where the string table begins @@ -507,8 +542,8 @@ impl SerializeCtx { // Write the total number of entries in the kind -> str mapping table // TODO: make this a u8 - append_usize(&mut buf, self.kind_map.len()); - for v in &self.kind_map { + append_usize(&mut buf, self.kind_name_map.len()); + for v in &self.kind_name_map { append_usize(&mut buf, *v); } @@ -517,19 +552,35 @@ impl SerializeCtx { // as u8. let offset_prop_map = buf.len(); // Write the total number of entries in the kind -> str mapping table - append_usize(&mut buf, self.prop_map.len()); - for v in &self.prop_map { + append_usize(&mut buf, self.prop_name_map.len()); + for v in &self.prop_name_map { append_usize(&mut buf, *v); } + // Spans are rarely needed, so they're stored in a separate array. + // They're indexed by the node id. + let offset_spans = buf.len(); + for v in &self.spans { + append_u32(&mut buf, *v); + } + + // The field value table. They're detached from nodes as they're not + // as frequently needed as the nodes themselves. The most common + // operation is traversal and we can traverse nodes without knowing + // about the fields. + let offset_props = buf.len(); + buf.append(&mut self.field_buf); + // Putting offsets of relevant parts of the buffer at the end. This // allows us to hop to the relevant part by merely looking at the last // for values in the message. Each value represents an offset into the // buffer. + append_usize(&mut buf, offset_props); + append_usize(&mut buf, offset_spans); append_usize(&mut buf, offset_kind_map); append_usize(&mut buf, offset_prop_map); append_usize(&mut buf, offset_str_table); - append_usize(&mut buf, self.start_buf.0); + append_u32(&mut buf, self.root_idx); buf } diff --git a/cli/tools/lint/ast_buffer/mod.rs b/cli/tools/lint/ast_buffer/mod.rs index 8838bcc5f2..fc4045fb60 100644 --- a/cli/tools/lint/ast_buffer/mod.rs +++ b/cli/tools/lint/ast_buffer/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_ast::ParsedSource; use swc::serialize_swc_to_buffer; diff --git a/cli/tools/lint/ast_buffer/swc.rs b/cli/tools/lint/ast_buffer/swc.rs index b26c213105..925d1bcd17 100644 --- a/cli/tools/lint/ast_buffer/swc.rs +++ b/cli/tools/lint/ast_buffer/swc.rs @@ -1,11 +1,14 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_ast::swc::ast::AssignTarget; use deno_ast::swc::ast::AssignTargetPat; +use deno_ast::swc::ast::BindingIdent; use deno_ast::swc::ast::BlockStmtOrExpr; use deno_ast::swc::ast::Callee; use deno_ast::swc::ast::ClassMember; use deno_ast::swc::ast::Decl; +use deno_ast::swc::ast::Decorator; +use deno_ast::swc::ast::DefaultDecl; use deno_ast::swc::ast::ExportSpecifier; use deno_ast::swc::ast::Expr; use deno_ast::swc::ast::ExprOrSpread; @@ -14,13 +17,13 @@ use deno_ast::swc::ast::ForHead; use deno_ast::swc::ast::Function; use deno_ast::swc::ast::Ident; use deno_ast::swc::ast::IdentName; +use deno_ast::swc::ast::ImportSpecifier; use deno_ast::swc::ast::JSXAttrName; use deno_ast::swc::ast::JSXAttrOrSpread; use deno_ast::swc::ast::JSXAttrValue; use deno_ast::swc::ast::JSXElement; use deno_ast::swc::ast::JSXElementChild; use deno_ast::swc::ast::JSXElementName; -use deno_ast::swc::ast::JSXEmptyExpr; use deno_ast::swc::ast::JSXExpr; use deno_ast::swc::ast::JSXExprContainer; use deno_ast::swc::ast::JSXFragment; @@ -28,12 +31,14 @@ use deno_ast::swc::ast::JSXMemberExpr; use deno_ast::swc::ast::JSXNamespacedName; use deno_ast::swc::ast::JSXObject; use deno_ast::swc::ast::JSXOpeningElement; +use deno_ast::swc::ast::Key; use deno_ast::swc::ast::Lit; use deno_ast::swc::ast::MemberExpr; use deno_ast::swc::ast::MemberProp; use deno_ast::swc::ast::ModuleDecl; use deno_ast::swc::ast::ModuleExportName; use deno_ast::swc::ast::ModuleItem; +use deno_ast::swc::ast::ObjectLit; use deno_ast::swc::ast::ObjectPatProp; use deno_ast::swc::ast::OptChainBase; use deno_ast::swc::ast::Param; @@ -47,14 +52,18 @@ use deno_ast::swc::ast::PropOrSpread; use deno_ast::swc::ast::SimpleAssignTarget; use deno_ast::swc::ast::Stmt; use deno_ast::swc::ast::SuperProp; -use deno_ast::swc::ast::Tpl; use deno_ast::swc::ast::TsEntityName; use deno_ast::swc::ast::TsEnumMemberId; +use deno_ast::swc::ast::TsExprWithTypeArgs; use deno_ast::swc::ast::TsFnOrConstructorType; use deno_ast::swc::ast::TsFnParam; use deno_ast::swc::ast::TsIndexSignature; use deno_ast::swc::ast::TsLit; use deno_ast::swc::ast::TsLitType; +use deno_ast::swc::ast::TsModuleName; +use deno_ast::swc::ast::TsModuleRef; +use deno_ast::swc::ast::TsNamespaceBody; +use deno_ast::swc::ast::TsParamPropParam; use deno_ast::swc::ast::TsThisTypeOrIdent; use deno_ast::swc::ast::TsType; use deno_ast::swc::ast::TsTypeAnn; @@ -71,7 +80,7 @@ use deno_ast::swc::common::SyntaxContext; use deno_ast::view::Accessibility; use deno_ast::view::AssignOp; use deno_ast::view::BinaryOp; -use deno_ast::view::TruePlusMinus; +use deno_ast::view::MethodKind; use deno_ast::view::TsKeywordTypeKind; use deno_ast::view::TsTypeOperatorOp; use deno_ast::view::UnaryOp; @@ -80,53 +89,39 @@ use deno_ast::view::VarDeclKind; use deno_ast::ParsedSource; use super::buffer::AstBufSerializer; -use super::buffer::BoolPos; -use super::buffer::NodePos; use super::buffer::NodeRef; -use super::buffer::StrPos; use super::ts_estree::AstNode; -use super::ts_estree::AstProp; use super::ts_estree::TsEsTreeBuilder; +use super::ts_estree::TsKeywordKind; pub fn serialize_swc_to_buffer(parsed_source: &ParsedSource) -> Vec { let mut ctx = TsEsTreeBuilder::new(); let program = &parsed_source.program(); - let raw = ctx.header(AstNode::Program, NodeRef(0), &program.span()); - let source_type_pos = ctx.str_field(AstProp::SourceType); - match program.as_ref() { Program::Module(module) => { - let body_pos = ctx.ref_vec_field(AstProp::Body, module.body.len()); - let pos = ctx.commit_schema(raw); - let children = module .body .iter() .map(|item| match item { ModuleItem::ModuleDecl(module_decl) => { - serialize_module_decl(&mut ctx, module_decl, pos) + serialize_module_decl(&mut ctx, module_decl) } - ModuleItem::Stmt(stmt) => serialize_stmt(&mut ctx, stmt, pos), + ModuleItem::Stmt(stmt) => serialize_stmt(&mut ctx, stmt), }) .collect::>(); - ctx.write_str(source_type_pos, "module"); - ctx.write_refs(body_pos, children); + ctx.write_program(&module.span, "module", children); } Program::Script(script) => { - let body_pos = ctx.ref_vec_field(AstProp::Body, script.body.len()); - let pos = ctx.commit_schema(raw); - let children = script .body .iter() - .map(|stmt| serialize_stmt(&mut ctx, stmt, pos)) + .map(|stmt| serialize_stmt(&mut ctx, stmt)) .collect::>(); - ctx.write_str(source_type_pos, "script"); - ctx.write_refs(body_pos, children); + ctx.write_program(&script.span, "script", children); } } @@ -136,539 +131,521 @@ pub fn serialize_swc_to_buffer(parsed_source: &ParsedSource) -> Vec { fn serialize_module_decl( ctx: &mut TsEsTreeBuilder, module_decl: &ModuleDecl, - parent: NodeRef, ) -> NodeRef { match module_decl { ModuleDecl::Import(node) => { - let raw = ctx.header(AstNode::ImportExpression, parent, &node.span); - ctx.commit_schema(raw) - } - ModuleDecl::ExportDecl(node) => { - let raw = ctx.header(AstNode::ExportNamedDeclaration, parent, &node.span); - let decl_pos = ctx.ref_field(AstProp::Declarations); - let pos = ctx.commit_schema(raw); + let src = serialize_lit(ctx, &Lit::Str(node.src.as_ref().clone())); + let attrs = serialize_import_attrs(ctx, &node.with); - let decl = serialize_decl(ctx, &node.decl, pos); - - ctx.write_ref(decl_pos, decl); - - pos - } - ModuleDecl::ExportNamed(node) => { - let raw = ctx.header(AstNode::ExportNamedDeclaration, parent, &node.span); - let src_pos = ctx.ref_field(AstProp::Source); - let spec_pos = - ctx.ref_vec_field(AstProp::Specifiers, node.specifiers.len()); - let id = ctx.commit_schema(raw); - - // FIXME: Flags - // let mut flags = FlagValue::new(); - // flags.set(Flag::ExportType); - - let src_id = node - .src - .as_ref() - .map(|src| serialize_lit(ctx, &Lit::Str(*src.clone()), id)); - - let spec_ids = node + let specifiers = node .specifiers .iter() - .map(|spec| { - match spec { - ExportSpecifier::Named(child) => { - let raw = ctx.header(AstNode::ExportSpecifier, id, &child.span); - let local_pos = ctx.ref_field(AstProp::Local); - let exp_pos = ctx.ref_field(AstProp::Exported); - let spec_pos = ctx.commit_schema(raw); - - // let mut flags = FlagValue::new(); - // flags.set(Flag::ExportType); - - let local = - serialize_module_exported_name(ctx, &child.orig, spec_pos); - - let exported = child.exported.as_ref().map(|exported| { - serialize_module_exported_name(ctx, exported, spec_pos) + .map(|spec| match spec { + ImportSpecifier::Named(spec) => { + let local = serialize_ident(ctx, &spec.local, None); + let imported = spec + .imported + .as_ref() + .map_or(serialize_ident(ctx, &spec.local, None), |v| { + serialize_module_export_name(ctx, v) }); - - // ctx.write_flags(&flags); - ctx.write_ref(local_pos, local); - ctx.write_maybe_ref(exp_pos, exported); - - spec_pos - } - - // These two aren't syntactically valid - ExportSpecifier::Namespace(_) => todo!(), - ExportSpecifier::Default(_) => todo!(), + ctx.write_import_spec( + &spec.span, + spec.is_type_only, + local, + imported, + ) + } + ImportSpecifier::Default(spec) => { + let local = serialize_ident(ctx, &spec.local, None); + ctx.write_import_default_spec(&spec.span, local) + } + ImportSpecifier::Namespace(spec) => { + let local = serialize_ident(ctx, &spec.local, None); + ctx.write_import_ns_spec(&spec.span, local) } }) .collect::>(); - // ctx.write_flags(&flags); - ctx.write_maybe_ref(src_pos, src_id); - ctx.write_refs(spec_pos, spec_ids); + ctx.write_import_decl(&node.span, node.type_only, src, specifiers, attrs) + } + ModuleDecl::ExportDecl(node) => { + let decl = serialize_decl(ctx, &node.decl); + ctx.write_export_decl(&node.span, decl) + } + ModuleDecl::ExportNamed(node) => { + let attrs = serialize_import_attrs(ctx, &node.with); + let source = node + .src + .as_ref() + .map(|src| serialize_lit(ctx, &Lit::Str(*src.clone()))); - id + if let Some(ExportSpecifier::Namespace(ns)) = node.specifiers.first() { + let exported = serialize_module_export_name(ctx, &ns.name); + ctx.write_export_all_decl( + &node.span, + node.type_only, + exported, + source, + attrs, + ) + } else { + let specifiers = node + .specifiers + .iter() + .map(|spec| { + match spec { + ExportSpecifier::Named(spec) => { + let local = serialize_module_export_name(ctx, &spec.orig); + + let exported = spec.exported.as_ref().map_or( + serialize_module_export_name(ctx, &spec.orig), + |exported| serialize_module_export_name(ctx, exported), + ); + + ctx.write_export_spec( + &spec.span, + spec.is_type_only, + local, + exported, + ) + } + + // Already handled earlier + ExportSpecifier::Namespace(_) => unreachable!(), + // this is not syntactically valid + ExportSpecifier::Default(_) => unreachable!(), + } + }) + .collect::>(); + + ctx.write_export_named_decl(&node.span, specifiers, source, attrs) + } } ModuleDecl::ExportDefaultDecl(node) => { - let raw = - ctx.header(AstNode::ExportDefaultDeclaration, parent, &node.span); - ctx.commit_schema(raw) + let (is_type_only, decl) = match &node.decl { + DefaultDecl::Class(node) => { + let ident = node + .ident + .as_ref() + .map(|ident| serialize_ident(ctx, ident, None)); + + let super_class = node + .class + .super_class + .as_ref() + .map(|expr| serialize_expr(ctx, expr.as_ref())); + + let implements = node + .class + .implements + .iter() + .map(|item| serialize_ts_expr_with_type_args(ctx, item)) + .collect::>(); + + let members = node + .class + .body + .iter() + .filter_map(|member| serialize_class_member(ctx, member)) + .collect::>(); + + let body = ctx.write_class_body(&node.class.span, members); + + let decl = ctx.write_class_decl( + &node.class.span, + false, + node.class.is_abstract, + ident, + super_class, + implements, + body, + ); + + (false, decl) + } + DefaultDecl::Fn(node) => { + let ident = node + .ident + .as_ref() + .map(|ident| serialize_ident(ctx, ident, None)); + + let fn_obj = node.function.as_ref(); + + let type_params = + maybe_serialize_ts_type_param_decl(ctx, &fn_obj.type_params); + + let params = fn_obj + .params + .iter() + .map(|param| serialize_pat(ctx, ¶m.pat)) + .collect::>(); + + let return_type = + maybe_serialize_ts_type_ann(ctx, &fn_obj.return_type); + let body = fn_obj + .body + .as_ref() + .map(|block| serialize_stmt(ctx, &Stmt::Block(block.clone()))); + + let decl = ctx.write_fn_decl( + &fn_obj.span, + false, + fn_obj.is_async, + fn_obj.is_generator, + ident, + type_params, + return_type, + body, + params, + ); + + (false, decl) + } + DefaultDecl::TsInterfaceDecl(node) => { + let ident_id = serialize_ident(ctx, &node.id, None); + let type_param = + maybe_serialize_ts_type_param_decl(ctx, &node.type_params); + + let extend_ids = node + .extends + .iter() + .map(|item| { + let expr = serialize_expr(ctx, &item.expr); + let type_args = item + .type_args + .clone() + .map(|params| serialize_ts_param_inst(ctx, params.as_ref())); + + ctx.write_ts_interface_heritage(&item.span, expr, type_args) + }) + .collect::>(); + + let body_elem_ids = node + .body + .body + .iter() + .map(|item| serialize_ts_type_elem(ctx, item)) + .collect::>(); + + let body_pos = + ctx.write_ts_interface_body(&node.body.span, body_elem_ids); + + let decl = ctx.write_ts_interface_decl( + &node.span, + node.declare, + ident_id, + type_param, + extend_ids, + body_pos, + ); + + (true, decl) + } + }; + + ctx.write_export_default_decl(&node.span, is_type_only, decl) } ModuleDecl::ExportDefaultExpr(node) => { - let raw = - ctx.header(AstNode::ExportDefaultDeclaration, parent, &node.span); - ctx.commit_schema(raw) + let expr = serialize_expr(ctx, &node.expr); + ctx.write_export_default_decl(&node.span, false, expr) } ModuleDecl::ExportAll(node) => { - let raw = ctx.header(AstNode::ExportAllDeclaration, parent, &node.span); - ctx.commit_schema(raw) + let src = serialize_lit(ctx, &Lit::Str(node.src.as_ref().clone())); + let attrs = serialize_import_attrs(ctx, &node.with); + + ctx.write_export_all_decl(&node.span, node.type_only, src, None, attrs) } ModuleDecl::TsImportEquals(node) => { - let raw = ctx.header(AstNode::TsImportEquals, parent, &node.span); - ctx.commit_schema(raw) + let ident = serialize_ident(ctx, &node.id, None); + let module_ref = match &node.module_ref { + TsModuleRef::TsEntityName(entity) => { + serialize_ts_entity_name(ctx, entity) + } + TsModuleRef::TsExternalModuleRef(external) => { + let expr = serialize_lit(ctx, &Lit::Str(external.expr.clone())); + ctx.write_ts_external_mod_ref(&external.span, expr) + } + }; + + ctx.write_export_ts_import_equals( + &node.span, + node.is_type_only, + ident, + module_ref, + ) } ModuleDecl::TsExportAssignment(node) => { - let raw = ctx.header(AstNode::TsExportAssignment, parent, &node.span); - ctx.commit_schema(raw) + let expr = serialize_expr(ctx, &node.expr); + ctx.write_export_assign(&node.span, expr) } ModuleDecl::TsNamespaceExport(node) => { - let raw = ctx.header(AstNode::TsNamespaceExport, parent, &node.span); - ctx.commit_schema(raw) + let decl = serialize_ident(ctx, &node.id, None); + ctx.write_export_ts_namespace(&node.span, decl) } } } -fn serialize_stmt( +fn serialize_import_attrs( ctx: &mut TsEsTreeBuilder, - stmt: &Stmt, - parent: NodeRef, -) -> NodeRef { + raw_attrs: &Option>, +) -> Vec { + raw_attrs.as_ref().map_or(vec![], |obj| { + obj + .props + .iter() + .map(|prop| { + let (key, value) = match prop { + // Invalid syntax + PropOrSpread::Spread(_) => unreachable!(), + PropOrSpread::Prop(prop) => { + match prop.as_ref() { + Prop::Shorthand(ident) => ( + serialize_ident(ctx, ident, None), + serialize_ident(ctx, ident, None), + ), + Prop::KeyValue(kv) => ( + serialize_prop_name(ctx, &kv.key), + serialize_expr(ctx, kv.value.as_ref()), + ), + // Invalid syntax + Prop::Assign(_) + | Prop::Getter(_) + | Prop::Setter(_) + | Prop::Method(_) => unreachable!(), + } + } + }; + + ctx.write_import_attr(&prop.span(), key, value) + }) + .collect::>() + }) +} + +fn serialize_stmt(ctx: &mut TsEsTreeBuilder, stmt: &Stmt) -> NodeRef { match stmt { Stmt::Block(node) => { - let raw = ctx.header(AstNode::BlockStatement, parent, &node.span); - let body_pos = ctx.ref_vec_field(AstProp::Body, node.stmts.len()); - let pos = ctx.commit_schema(raw); - let children = node .stmts .iter() - .map(|stmt| serialize_stmt(ctx, stmt, pos)) + .map(|stmt| serialize_stmt(ctx, stmt)) .collect::>(); - ctx.write_refs(body_pos, children); - - pos + ctx.write_block_stmt(&node.span, children) } Stmt::Empty(_) => NodeRef(0), - Stmt::Debugger(node) => { - let raw = ctx.header(AstNode::DebuggerStatement, parent, &node.span); - ctx.commit_schema(raw) + Stmt::Debugger(node) => ctx.write_debugger_stmt(&node.span), + Stmt::With(node) => { + let obj = serialize_expr(ctx, &node.obj); + let body = serialize_stmt(ctx, &node.body); + + ctx.write_with_stmt(&node.span, obj, body) } - Stmt::With(_) => todo!(), Stmt::Return(node) => { - let raw = ctx.header(AstNode::ReturnStatement, parent, &node.span); - let arg_pos = ctx.ref_field(AstProp::Argument); - let pos = ctx.commit_schema(raw); - - let arg = node.arg.as_ref().map(|arg| serialize_expr(ctx, arg, pos)); - ctx.write_maybe_ref(arg_pos, arg); - - pos + let arg = node.arg.as_ref().map(|arg| serialize_expr(ctx, arg)); + ctx.write_return_stmt(&node.span, arg) } Stmt::Labeled(node) => { - let raw = ctx.header(AstNode::LabeledStatement, parent, &node.span); - let label_pos = ctx.ref_field(AstProp::Label); - let body_pos = ctx.ref_field(AstProp::Body); - let pos = ctx.commit_schema(raw); + let ident = serialize_ident(ctx, &node.label, None); + let stmt = serialize_stmt(ctx, &node.body); - let ident = serialize_ident(ctx, &node.label, pos); - let stmt = serialize_stmt(ctx, &node.body, pos); - - ctx.write_ref(label_pos, ident); - ctx.write_ref(body_pos, stmt); - - pos + ctx.write_labeled_stmt(&node.span, ident, stmt) } Stmt::Break(node) => { - let raw = ctx.header(AstNode::BreakStatement, parent, &node.span); - let label_pos = ctx.ref_field(AstProp::Label); - let pos = ctx.commit_schema(raw); - let arg = node .label .as_ref() - .map(|label| serialize_ident(ctx, label, pos)); - - ctx.write_maybe_ref(label_pos, arg); - - pos + .map(|label| serialize_ident(ctx, label, None)); + ctx.write_break_stmt(&node.span, arg) } Stmt::Continue(node) => { - let raw = ctx.header(AstNode::ContinueStatement, parent, &node.span); - let label_pos = ctx.ref_field(AstProp::Label); - let pos = ctx.commit_schema(raw); - let arg = node .label .as_ref() - .map(|label| serialize_ident(ctx, label, pos)); + .map(|label| serialize_ident(ctx, label, None)); - ctx.write_maybe_ref(label_pos, arg); - - pos + ctx.write_continue_stmt(&node.span, arg) } Stmt::If(node) => { - let raw = ctx.header(AstNode::IfStatement, parent, &node.span); - let test_pos = ctx.ref_field(AstProp::Test); - let cons_pos = ctx.ref_field(AstProp::Consequent); - let alt_pos = ctx.ref_field(AstProp::Alternate); - let pos = ctx.commit_schema(raw); + let test = serialize_expr(ctx, node.test.as_ref()); + let cons = serialize_stmt(ctx, node.cons.as_ref()); + let alt = node.alt.as_ref().map(|alt| serialize_stmt(ctx, alt)); - let test = serialize_expr(ctx, node.test.as_ref(), pos); - let cons = serialize_stmt(ctx, node.cons.as_ref(), pos); - let alt = node.alt.as_ref().map(|alt| serialize_stmt(ctx, alt, pos)); - - ctx.write_ref(test_pos, test); - ctx.write_ref(cons_pos, cons); - ctx.write_maybe_ref(alt_pos, alt); - - pos + ctx.write_if_stmt(&node.span, test, cons, alt) } Stmt::Switch(node) => { - let raw = ctx.header(AstNode::SwitchStatement, parent, &node.span); - let disc_pos = ctx.ref_field(AstProp::Discriminant); - let cases_pos = ctx.ref_vec_field(AstProp::Cases, node.cases.len()); - let pos = ctx.commit_schema(raw); - - let disc = serialize_expr(ctx, &node.discriminant, pos); + let disc = serialize_expr(ctx, &node.discriminant); let cases = node .cases .iter() .map(|case| { - let raw = ctx.header(AstNode::SwitchCase, pos, &case.span); - let test_pos = ctx.ref_field(AstProp::Test); - let cons_pos = - ctx.ref_vec_field(AstProp::Consequent, case.cons.len()); - let case_pos = ctx.commit_schema(raw); - - let test = case - .test - .as_ref() - .map(|test| serialize_expr(ctx, test, case_pos)); + let test = case.test.as_ref().map(|test| serialize_expr(ctx, test)); let cons = case .cons .iter() - .map(|cons| serialize_stmt(ctx, cons, case_pos)) + .map(|cons| serialize_stmt(ctx, cons)) .collect::>(); - ctx.write_maybe_ref(test_pos, test); - ctx.write_refs(cons_pos, cons); - - case_pos + ctx.write_switch_case(&case.span, test, cons) }) .collect::>(); - ctx.write_ref(disc_pos, disc); - ctx.write_refs(cases_pos, cases); - - pos + ctx.write_switch_stmt(&node.span, disc, cases) } Stmt::Throw(node) => { - let raw = ctx.header(AstNode::ThrowStatement, parent, &node.span); - let arg_pos = ctx.ref_field(AstProp::Argument); - let pos = ctx.commit_schema(raw); - - let arg = serialize_expr(ctx, &node.arg, pos); - ctx.write_ref(arg_pos, arg); - - pos + let arg = serialize_expr(ctx, &node.arg); + ctx.write_throw_stmt(&node.span, arg) } Stmt::Try(node) => { - let raw = ctx.header(AstNode::TryStatement, parent, &node.span); - let block_pos = ctx.ref_field(AstProp::Block); - let handler_pos = ctx.ref_field(AstProp::Handler); - let finalizer_pos = ctx.ref_field(AstProp::Finalizer); - let pos = ctx.commit_schema(raw); - - let block = serialize_stmt(ctx, &Stmt::Block(node.block.clone()), pos); + let block = serialize_stmt(ctx, &Stmt::Block(node.block.clone())); let handler = node.handler.as_ref().map(|catch| { - let raw = ctx.header(AstNode::CatchClause, pos, &catch.span); - let param_pos = ctx.ref_field(AstProp::Param); - let body_pos = ctx.ref_field(AstProp::Body); - let clause_pos = ctx.commit_schema(raw); + let param = catch.param.as_ref().map(|param| serialize_pat(ctx, param)); - let param = catch - .param - .as_ref() - .map(|param| serialize_pat(ctx, param, clause_pos)); + let body = serialize_stmt(ctx, &Stmt::Block(catch.body.clone())); - let body = - serialize_stmt(ctx, &Stmt::Block(catch.body.clone()), clause_pos); - - ctx.write_maybe_ref(param_pos, param); - ctx.write_ref(body_pos, body); - - clause_pos + ctx.write_catch_clause(&catch.span, param, body) }); - let finalizer = node.finalizer.as_ref().map(|finalizer| { - serialize_stmt(ctx, &Stmt::Block(finalizer.clone()), pos) - }); + let finalizer = node + .finalizer + .as_ref() + .map(|finalizer| serialize_stmt(ctx, &Stmt::Block(finalizer.clone()))); - ctx.write_ref(block_pos, block); - ctx.write_maybe_ref(handler_pos, handler); - ctx.write_maybe_ref(finalizer_pos, finalizer); - - pos + ctx.write_try_stmt(&node.span, block, handler, finalizer) } Stmt::While(node) => { - let raw = ctx.header(AstNode::WhileStatement, parent, &node.span); - let test_pos = ctx.ref_field(AstProp::Test); - let body_pos = ctx.ref_field(AstProp::Body); - let pos = ctx.commit_schema(raw); + let test = serialize_expr(ctx, node.test.as_ref()); + let stmt = serialize_stmt(ctx, node.body.as_ref()); - let test = serialize_expr(ctx, node.test.as_ref(), pos); - let stmt = serialize_stmt(ctx, node.body.as_ref(), pos); - - ctx.write_ref(test_pos, test); - ctx.write_ref(body_pos, stmt); - - pos + ctx.write_while_stmt(&node.span, test, stmt) } Stmt::DoWhile(node) => { - let raw = ctx.header(AstNode::DoWhileStatement, parent, &node.span); - let test_pos = ctx.ref_field(AstProp::Test); - let body_pos = ctx.ref_field(AstProp::Body); - let pos = ctx.commit_schema(raw); + let expr = serialize_expr(ctx, node.test.as_ref()); + let stmt = serialize_stmt(ctx, node.body.as_ref()); - let expr = serialize_expr(ctx, node.test.as_ref(), pos); - let stmt = serialize_stmt(ctx, node.body.as_ref(), pos); - - ctx.write_ref(test_pos, expr); - ctx.write_ref(body_pos, stmt); - - pos + ctx.write_do_while_stmt(&node.span, expr, stmt) } Stmt::For(node) => { - let raw = ctx.header(AstNode::ForStatement, parent, &node.span); - let init_pos = ctx.ref_field(AstProp::Init); - let test_pos = ctx.ref_field(AstProp::Test); - let update_pos = ctx.ref_field(AstProp::Update); - let body_pos = ctx.ref_field(AstProp::Body); - let pos = ctx.commit_schema(raw); - let init = node.init.as_ref().map(|init| match init { VarDeclOrExpr::VarDecl(var_decl) => { - serialize_stmt(ctx, &Stmt::Decl(Decl::Var(var_decl.clone())), pos) + serialize_stmt(ctx, &Stmt::Decl(Decl::Var(var_decl.clone()))) } - VarDeclOrExpr::Expr(expr) => serialize_expr(ctx, expr, pos), + VarDeclOrExpr::Expr(expr) => serialize_expr(ctx, expr), }); - let test = node - .test - .as_ref() - .map(|expr| serialize_expr(ctx, expr, pos)); - let update = node - .update - .as_ref() - .map(|expr| serialize_expr(ctx, expr, pos)); - let body = serialize_stmt(ctx, node.body.as_ref(), pos); + let test = node.test.as_ref().map(|expr| serialize_expr(ctx, expr)); + let update = node.update.as_ref().map(|expr| serialize_expr(ctx, expr)); + let body = serialize_stmt(ctx, node.body.as_ref()); - ctx.write_maybe_ref(init_pos, init); - ctx.write_maybe_ref(test_pos, test); - ctx.write_maybe_ref(update_pos, update); - ctx.write_ref(body_pos, body); - - pos + ctx.write_for_stmt(&node.span, init, test, update, body) } Stmt::ForIn(node) => { - let raw = ctx.header(AstNode::ForInStatement, parent, &node.span); - let left_pos = ctx.ref_field(AstProp::Left); - let right_pos = ctx.ref_field(AstProp::Right); - let body_pos = ctx.ref_field(AstProp::Body); - let pos = ctx.commit_schema(raw); + let left = serialize_for_head(ctx, &node.left); + let right = serialize_expr(ctx, node.right.as_ref()); + let body = serialize_stmt(ctx, node.body.as_ref()); - let left = serialize_for_head(ctx, &node.left, pos); - let right = serialize_expr(ctx, node.right.as_ref(), pos); - let body = serialize_stmt(ctx, node.body.as_ref(), pos); - - ctx.write_ref(left_pos, left); - ctx.write_ref(right_pos, right); - ctx.write_ref(body_pos, body); - - pos + ctx.write_for_in_stmt(&node.span, left, right, body) } Stmt::ForOf(node) => { - let raw = ctx.header(AstNode::ForOfStatement, parent, &node.span); - let await_pos = ctx.bool_field(AstProp::Await); - let left_pos = ctx.ref_field(AstProp::Left); - let right_pos = ctx.ref_field(AstProp::Right); - let body_pos = ctx.ref_field(AstProp::Body); - let pos = ctx.commit_schema(raw); + let left = serialize_for_head(ctx, &node.left); + let right = serialize_expr(ctx, node.right.as_ref()); + let body = serialize_stmt(ctx, node.body.as_ref()); - let left = serialize_for_head(ctx, &node.left, pos); - let right = serialize_expr(ctx, node.right.as_ref(), pos); - let body = serialize_stmt(ctx, node.body.as_ref(), pos); - - ctx.write_bool(await_pos, node.is_await); - ctx.write_ref(left_pos, left); - ctx.write_ref(right_pos, right); - ctx.write_ref(body_pos, body); - - pos + ctx.write_for_of_stmt(&node.span, node.is_await, left, right, body) } - Stmt::Decl(node) => serialize_decl(ctx, node, parent), + Stmt::Decl(node) => serialize_decl(ctx, node), Stmt::Expr(node) => { - let raw = ctx.header(AstNode::ExpressionStatement, parent, &node.span); - let expr_pos = ctx.ref_field(AstProp::Expression); - let pos = ctx.commit_schema(raw); - - let expr = serialize_expr(ctx, node.expr.as_ref(), pos); - ctx.write_ref(expr_pos, expr); - - pos + let expr = serialize_expr(ctx, node.expr.as_ref()); + ctx.write_expr_stmt(&node.span, expr) } } } -fn serialize_expr( - ctx: &mut TsEsTreeBuilder, - expr: &Expr, - parent: NodeRef, -) -> NodeRef { +fn serialize_expr(ctx: &mut TsEsTreeBuilder, expr: &Expr) -> NodeRef { match expr { - Expr::This(node) => { - let raw = ctx.header(AstNode::ThisExpression, parent, &node.span); - ctx.commit_schema(raw) - } + Expr::This(node) => ctx.write_this_expr(&node.span), Expr::Array(node) => { - let raw = ctx.header(AstNode::ArrayExpression, parent, &node.span); - let elems_pos = ctx.ref_vec_field(AstProp::Elements, node.elems.len()); - let pos = ctx.commit_schema(raw); - let elems = node .elems .iter() .map(|item| { item .as_ref() - .map_or(NodeRef(0), |item| serialize_expr_or_spread(ctx, item, pos)) + .map_or(NodeRef(0), |item| serialize_expr_or_spread(ctx, item)) }) .collect::>(); - ctx.write_refs(elems_pos, elems); - - pos + ctx.write_arr_expr(&node.span, elems) } Expr::Object(node) => { - let raw = ctx.header(AstNode::ObjectExpression, parent, &node.span); - let props_pos = ctx.ref_vec_field(AstProp::Properties, node.props.len()); - let pos = ctx.commit_schema(raw); - - let prop_ids = node + let props = node .props .iter() - .map(|prop| serialize_prop_or_spread(ctx, prop, pos)) + .map(|prop| serialize_prop_or_spread(ctx, prop)) .collect::>(); - ctx.write_refs(props_pos, prop_ids); - - pos + ctx.write_obj_expr(&node.span, props) } Expr::Fn(node) => { let fn_obj = node.function.as_ref(); - let raw = ctx.header(AstNode::FunctionExpression, parent, &fn_obj.span); - - let async_pos = ctx.bool_field(AstProp::Async); - let gen_pos = ctx.bool_field(AstProp::Generator); - let id_pos = ctx.ref_field(AstProp::Id); - let tparams_pos = ctx.ref_field(AstProp::TypeParameters); - let params_pos = ctx.ref_vec_field(AstProp::Params, fn_obj.params.len()); - let return_pos = ctx.ref_field(AstProp::ReturnType); - let body_pos = ctx.ref_field(AstProp::Body); - let pos = ctx.commit_schema(raw); - let ident = node .ident .as_ref() - .map(|ident| serialize_ident(ctx, ident, pos)); + .map(|ident| serialize_ident(ctx, ident, None)); let type_params = - maybe_serialize_ts_type_param(ctx, &fn_obj.type_params, pos); + maybe_serialize_ts_type_param_decl(ctx, &fn_obj.type_params); let params = fn_obj .params .iter() - .map(|param| serialize_pat(ctx, ¶m.pat, pos)) + .map(|param| serialize_pat(ctx, ¶m.pat)) .collect::>(); - let return_id = - maybe_serialize_ts_type_ann(ctx, &fn_obj.return_type, pos); + let return_id = maybe_serialize_ts_type_ann(ctx, &fn_obj.return_type); let body = fn_obj .body .as_ref() - .map(|block| serialize_stmt(ctx, &Stmt::Block(block.clone()), pos)); + .map(|block| serialize_stmt(ctx, &Stmt::Block(block.clone()))); - ctx.write_bool(async_pos, fn_obj.is_async); - ctx.write_bool(gen_pos, fn_obj.is_generator); - ctx.write_maybe_ref(id_pos, ident); - ctx.write_maybe_ref(tparams_pos, type_params); - ctx.write_refs(params_pos, params); - ctx.write_maybe_ref(return_pos, return_id); - ctx.write_maybe_ref(body_pos, body); - - pos + ctx.write_fn_expr( + &fn_obj.span, + fn_obj.is_async, + fn_obj.is_generator, + ident, + type_params, + params, + return_id, + body, + ) } Expr::Unary(node) => { - let raw = ctx.header(AstNode::UnaryExpression, parent, &node.span); - let flag_pos = ctx.str_field(AstProp::Operator); - let arg_pos = ctx.ref_field(AstProp::Argument); - let pos = ctx.commit_schema(raw); + let arg = serialize_expr(ctx, &node.arg); + let op = match node.op { + UnaryOp::Minus => "-", + UnaryOp::Plus => "+", + UnaryOp::Bang => "!", + UnaryOp::Tilde => "~", + UnaryOp::TypeOf => "typeof", + UnaryOp::Void => "void", + UnaryOp::Delete => "delete", + }; - let arg = serialize_expr(ctx, &node.arg, pos); - - ctx.write_str( - flag_pos, - match node.op { - UnaryOp::Minus => "-", - UnaryOp::Plus => "+", - UnaryOp::Bang => "!", - UnaryOp::Tilde => "~", - UnaryOp::TypeOf => "typeof", - UnaryOp::Void => "void", - UnaryOp::Delete => "delete", - }, - ); - ctx.write_ref(arg_pos, arg); - - pos + ctx.write_unary_expr(&node.span, op, arg) } Expr::Update(node) => { - let raw = ctx.header(AstNode::UpdateExpression, parent, &node.span); - let prefix_pos = ctx.bool_field(AstProp::Prefix); - let arg_pos = ctx.ref_field(AstProp::Argument); - let op_ops = ctx.str_field(AstProp::Operator); - let pos = ctx.commit_schema(raw); + let arg = serialize_expr(ctx, node.arg.as_ref()); + let op = match node.op { + UpdateOp::PlusPlus => "++", + UpdateOp::MinusMinus => "--", + }; - let arg = serialize_expr(ctx, node.arg.as_ref(), pos); - - ctx.write_bool(prefix_pos, node.prefix); - ctx.write_ref(arg_pos, arg); - ctx.write_str( - op_ops, - match node.op { - UpdateOp::PlusPlus => "++", - UpdateOp::MinusMinus => "--", - }, - ); - - pos + ctx.write_update_expr(&node.span, node.prefix, op, arg) } Expr::Bin(node) => { let (node_type, flag_str) = match node.op { @@ -699,501 +676,361 @@ fn serialize_expr( BinaryOp::Exp => (AstNode::BinaryExpression, "**"), }; - let raw = ctx.header(node_type, parent, &node.span); - let op_pos = ctx.str_field(AstProp::Operator); - let left_pos = ctx.ref_field(AstProp::Left); - let right_pos = ctx.ref_field(AstProp::Right); - let pos = ctx.commit_schema(raw); + let left = serialize_expr(ctx, node.left.as_ref()); + let right = serialize_expr(ctx, node.right.as_ref()); - let left_id = serialize_expr(ctx, node.left.as_ref(), pos); - let right_id = serialize_expr(ctx, node.right.as_ref(), pos); - - ctx.write_str(op_pos, flag_str); - ctx.write_ref(left_pos, left_id); - ctx.write_ref(right_pos, right_id); - - pos + match node_type { + AstNode::LogicalExpression => { + ctx.write_logical_expr(&node.span, flag_str, left, right) + } + AstNode::BinaryExpression => { + ctx.write_bin_expr(&node.span, flag_str, left, right) + } + _ => unreachable!(), + } } Expr::Assign(node) => { - let raw = ctx.header(AstNode::AssignmentExpression, parent, &node.span); - let op_pos = ctx.str_field(AstProp::Operator); - let left_pos = ctx.ref_field(AstProp::Left); - let right_pos = ctx.ref_field(AstProp::Right); - let pos = ctx.commit_schema(raw); - let left = match &node.left { AssignTarget::Simple(simple_assign_target) => { match simple_assign_target { SimpleAssignTarget::Ident(target) => { - serialize_ident(ctx, &target.id, pos) + serialize_binding_ident(ctx, target) } SimpleAssignTarget::Member(target) => { - serialize_expr(ctx, &Expr::Member(target.clone()), pos) + serialize_expr(ctx, &Expr::Member(target.clone())) } SimpleAssignTarget::SuperProp(target) => { - serialize_expr(ctx, &Expr::SuperProp(target.clone()), pos) + serialize_expr(ctx, &Expr::SuperProp(target.clone())) } SimpleAssignTarget::Paren(target) => { - serialize_expr(ctx, &target.expr, pos) + serialize_expr(ctx, &target.expr) } SimpleAssignTarget::OptChain(target) => { - serialize_expr(ctx, &Expr::OptChain(target.clone()), pos) + serialize_expr(ctx, &Expr::OptChain(target.clone())) } SimpleAssignTarget::TsAs(target) => { - serialize_expr(ctx, &Expr::TsAs(target.clone()), pos) + serialize_expr(ctx, &Expr::TsAs(target.clone())) } SimpleAssignTarget::TsSatisfies(target) => { - serialize_expr(ctx, &Expr::TsSatisfies(target.clone()), pos) + serialize_expr(ctx, &Expr::TsSatisfies(target.clone())) } SimpleAssignTarget::TsNonNull(target) => { - serialize_expr(ctx, &Expr::TsNonNull(target.clone()), pos) + serialize_expr(ctx, &Expr::TsNonNull(target.clone())) } SimpleAssignTarget::TsTypeAssertion(target) => { - serialize_expr(ctx, &Expr::TsTypeAssertion(target.clone()), pos) + serialize_expr(ctx, &Expr::TsTypeAssertion(target.clone())) } SimpleAssignTarget::TsInstantiation(target) => { - serialize_expr(ctx, &Expr::TsInstantiation(target.clone()), pos) + serialize_expr(ctx, &Expr::TsInstantiation(target.clone())) } SimpleAssignTarget::Invalid(_) => unreachable!(), } } AssignTarget::Pat(target) => match target { AssignTargetPat::Array(array_pat) => { - serialize_pat(ctx, &Pat::Array(array_pat.clone()), pos) + serialize_pat(ctx, &Pat::Array(array_pat.clone())) } AssignTargetPat::Object(object_pat) => { - serialize_pat(ctx, &Pat::Object(object_pat.clone()), pos) + serialize_pat(ctx, &Pat::Object(object_pat.clone())) } AssignTargetPat::Invalid(_) => unreachable!(), }, }; - let right = serialize_expr(ctx, node.right.as_ref(), pos); + let right = serialize_expr(ctx, node.right.as_ref()); - ctx.write_str( - op_pos, - match node.op { - AssignOp::Assign => "=", - AssignOp::AddAssign => "+=", - AssignOp::SubAssign => "-=", - AssignOp::MulAssign => "*=", - AssignOp::DivAssign => "/=", - AssignOp::ModAssign => "%=", - AssignOp::LShiftAssign => "<<=", - AssignOp::RShiftAssign => ">>=", - AssignOp::ZeroFillRShiftAssign => ">>>=", - AssignOp::BitOrAssign => "|=", - AssignOp::BitXorAssign => "^=", - AssignOp::BitAndAssign => "&=", - AssignOp::ExpAssign => "**=", - AssignOp::AndAssign => "&&=", - AssignOp::OrAssign => "||=", - AssignOp::NullishAssign => "??=", - }, - ); - ctx.write_ref(left_pos, left); - ctx.write_ref(right_pos, right); + let op = match node.op { + AssignOp::Assign => "=", + AssignOp::AddAssign => "+=", + AssignOp::SubAssign => "-=", + AssignOp::MulAssign => "*=", + AssignOp::DivAssign => "/=", + AssignOp::ModAssign => "%=", + AssignOp::LShiftAssign => "<<=", + AssignOp::RShiftAssign => ">>=", + AssignOp::ZeroFillRShiftAssign => ">>>=", + AssignOp::BitOrAssign => "|=", + AssignOp::BitXorAssign => "^=", + AssignOp::BitAndAssign => "&=", + AssignOp::ExpAssign => "**=", + AssignOp::AndAssign => "&&=", + AssignOp::OrAssign => "||=", + AssignOp::NullishAssign => "??=", + }; - pos + ctx.write_assignment_expr(&node.span, op, left, right) } - Expr::Member(node) => serialize_member_expr(ctx, node, parent, false), + Expr::Member(node) => serialize_member_expr(ctx, node, false), Expr::SuperProp(node) => { - let raw = ctx.header(AstNode::MemberExpression, parent, &node.span); - let computed_pos = ctx.bool_field(AstProp::Computed); - let obj_pos = ctx.ref_field(AstProp::Object); - let prop_pos = ctx.ref_field(AstProp::Property); - let pos = ctx.commit_schema(raw); - - let raw = ctx.header(AstNode::Super, pos, &node.obj.span); - let obj = ctx.commit_schema(raw); + let obj = ctx.write_super(&node.obj.span); let mut computed = false; let prop = match &node.prop { - SuperProp::Ident(ident_name) => { - serialize_ident_name(ctx, ident_name, pos) - } + SuperProp::Ident(ident_name) => serialize_ident_name(ctx, ident_name), SuperProp::Computed(prop) => { computed = true; - serialize_expr(ctx, &prop.expr, pos) + serialize_expr(ctx, &prop.expr) } }; - ctx.write_bool(computed_pos, computed); - ctx.write_ref(obj_pos, obj); - ctx.write_ref(prop_pos, prop); - - pos + ctx.write_member_expr(&node.span, false, computed, obj, prop) } Expr::Cond(node) => { - let raw = ctx.header(AstNode::ConditionalExpression, parent, &node.span); - let test_pos = ctx.ref_field(AstProp::Test); - let cons_pos = ctx.ref_field(AstProp::Consequent); - let alt_pos = ctx.ref_field(AstProp::Alternate); - let pos = ctx.commit_schema(raw); + let test = serialize_expr(ctx, node.test.as_ref()); + let cons = serialize_expr(ctx, node.cons.as_ref()); + let alt = serialize_expr(ctx, node.alt.as_ref()); - let test = serialize_expr(ctx, node.test.as_ref(), pos); - let cons = serialize_expr(ctx, node.cons.as_ref(), pos); - let alt = serialize_expr(ctx, node.alt.as_ref(), pos); - - ctx.write_ref(test_pos, test); - ctx.write_ref(cons_pos, cons); - ctx.write_ref(alt_pos, alt); - - pos + ctx.write_conditional_expr(&node.span, test, cons, alt) } Expr::Call(node) => { - let raw = ctx.header(AstNode::CallExpression, parent, &node.span); - let opt_pos = ctx.bool_field(AstProp::Optional); - let callee_pos = ctx.ref_field(AstProp::Callee); - let type_args_pos = ctx.ref_field(AstProp::TypeArguments); - let args_pos = ctx.ref_vec_field(AstProp::Arguments, node.args.len()); - let pos = ctx.commit_schema(raw); + if let Callee::Import(_) = node.callee { + let source = node + .args + .first() + .map_or(NodeRef(0), |arg| serialize_expr_or_spread(ctx, arg)); - let callee = match &node.callee { - Callee::Super(super_node) => { - let raw = ctx.header(AstNode::Super, pos, &super_node.span); - ctx.commit_schema(raw) - } - Callee::Import(_) => todo!(), - Callee::Expr(expr) => serialize_expr(ctx, expr, pos), - }; + let options = node + .args + .get(1) + .map_or(NodeRef(0), |arg| serialize_expr_or_spread(ctx, arg)); - let type_arg = node.type_args.clone().map(|param_node| { - serialize_ts_param_inst(ctx, param_node.as_ref(), pos) - }); + ctx.write_import_expr(&node.span, source, options) + } else { + let callee = match &node.callee { + Callee::Super(super_node) => ctx.write_super(&super_node.span), + Callee::Import(_) => unreachable!("Already handled"), + Callee::Expr(expr) => serialize_expr(ctx, expr), + }; - let args = node - .args - .iter() - .map(|arg| serialize_expr_or_spread(ctx, arg, pos)) - .collect::>(); + let type_arg = node + .type_args + .clone() + .map(|param_node| serialize_ts_param_inst(ctx, param_node.as_ref())); - ctx.write_bool(opt_pos, false); - ctx.write_ref(callee_pos, callee); - ctx.write_maybe_ref(type_args_pos, type_arg); - ctx.write_refs(args_pos, args); + let args = node + .args + .iter() + .map(|arg| serialize_expr_or_spread(ctx, arg)) + .collect::>(); - pos + ctx.write_call_expr(&node.span, false, callee, type_arg, args) + } } Expr::New(node) => { - let raw = ctx.header(AstNode::NewExpression, parent, &node.span); - let callee_pos = ctx.ref_field(AstProp::Callee); - let type_args_pos = ctx.ref_field(AstProp::TypeArguments); - let args_pos = ctx.ref_vec_field( - AstProp::Arguments, - node.args.as_ref().map_or(0, |v| v.len()), - ); - let pos = ctx.commit_schema(raw); - - let callee = serialize_expr(ctx, node.callee.as_ref(), pos); + let callee = serialize_expr(ctx, node.callee.as_ref()); let args: Vec = node.args.as_ref().map_or(vec![], |args| { args .iter() - .map(|arg| serialize_expr_or_spread(ctx, arg, pos)) + .map(|arg| serialize_expr_or_spread(ctx, arg)) .collect::>() }); - let type_args = node.type_args.clone().map(|param_node| { - serialize_ts_param_inst(ctx, param_node.as_ref(), pos) - }); + let type_args = node + .type_args + .clone() + .map(|param_node| serialize_ts_param_inst(ctx, param_node.as_ref())); - ctx.write_ref(callee_pos, callee); - ctx.write_maybe_ref(type_args_pos, type_args); - ctx.write_refs(args_pos, args); - - pos + ctx.write_new_expr(&node.span, callee, type_args, args) } Expr::Seq(node) => { - let raw = ctx.header(AstNode::SequenceExpression, parent, &node.span); - let exprs_pos = ctx.ref_vec_field(AstProp::Expressions, node.exprs.len()); - let pos = ctx.commit_schema(raw); - let children = node .exprs .iter() - .map(|expr| serialize_expr(ctx, expr, pos)) + .map(|expr| serialize_expr(ctx, expr)) .collect::>(); - ctx.write_refs(exprs_pos, children); - - pos + ctx.write_sequence_expr(&node.span, children) } - Expr::Ident(node) => serialize_ident(ctx, node, parent), - Expr::Lit(node) => serialize_lit(ctx, node, parent), + Expr::Ident(node) => serialize_ident(ctx, node, None), + Expr::Lit(node) => serialize_lit(ctx, node), Expr::Tpl(node) => { - let raw = ctx.header(AstNode::TemplateLiteral, parent, &node.span); - let quasis_pos = ctx.ref_vec_field(AstProp::Quasis, node.quasis.len()); - let exprs_pos = ctx.ref_vec_field(AstProp::Expressions, node.exprs.len()); - let pos = ctx.commit_schema(raw); - let quasis = node .quasis .iter() .map(|quasi| { - let raw = ctx.header(AstNode::TemplateElement, pos, &quasi.span); - let tail_pos = ctx.bool_field(AstProp::Tail); - let raw_pos = ctx.str_field(AstProp::Raw); - let cooked_pos = ctx.str_field(AstProp::Cooked); - let tpl_pos = ctx.commit_schema(raw); - - ctx.write_bool(tail_pos, quasi.tail); - ctx.write_str(raw_pos, &quasi.raw); - ctx.write_str( - cooked_pos, + ctx.write_template_elem( + &quasi.span, + quasi.tail, + &quasi.raw, &quasi .cooked .as_ref() .map_or("".to_string(), |v| v.to_string()), - ); - - tpl_pos + ) }) .collect::>(); let exprs = node .exprs .iter() - .map(|expr| serialize_expr(ctx, expr, pos)) + .map(|expr| serialize_expr(ctx, expr)) .collect::>(); - ctx.write_refs(quasis_pos, quasis); - ctx.write_refs(exprs_pos, exprs); - - pos + ctx.write_template_lit(&node.span, quasis, exprs) } Expr::TaggedTpl(node) => { - let raw = - ctx.header(AstNode::TaggedTemplateExpression, parent, &node.span); - let tag_pos = ctx.ref_field(AstProp::Tag); - let type_arg_pos = ctx.ref_field(AstProp::TypeArguments); - let quasi_pos = ctx.ref_field(AstProp::Quasi); - let pos = ctx.commit_schema(raw); - - let tag = serialize_expr(ctx, &node.tag, pos); - - let type_param_id = node + let tag = serialize_expr(ctx, &node.tag); + let type_param = node .type_params .clone() - .map(|params| serialize_ts_param_inst(ctx, params.as_ref(), pos)); - let quasi = serialize_expr(ctx, &Expr::Tpl(*node.tpl.clone()), pos); + .map(|params| serialize_ts_param_inst(ctx, params.as_ref())); + let quasi = serialize_expr(ctx, &Expr::Tpl(*node.tpl.clone())); - ctx.write_ref(tag_pos, tag); - ctx.write_maybe_ref(type_arg_pos, type_param_id); - ctx.write_ref(quasi_pos, quasi); - - pos + ctx.write_tagged_template_expr(&node.span, tag, type_param, quasi) } Expr::Arrow(node) => { - let raw = - ctx.header(AstNode::ArrowFunctionExpression, parent, &node.span); - let async_pos = ctx.bool_field(AstProp::Async); - let gen_pos = ctx.bool_field(AstProp::Generator); - let type_param_pos = ctx.ref_field(AstProp::TypeParameters); - let params_pos = ctx.ref_vec_field(AstProp::Params, node.params.len()); - let body_pos = ctx.ref_field(AstProp::Body); - let return_type_pos = ctx.ref_field(AstProp::ReturnType); - let pos = ctx.commit_schema(raw); - let type_param = - maybe_serialize_ts_type_param(ctx, &node.type_params, pos); + maybe_serialize_ts_type_param_decl(ctx, &node.type_params); let params = node .params .iter() - .map(|param| serialize_pat(ctx, param, pos)) + .map(|param| serialize_pat(ctx, param)) .collect::>(); let body = match node.body.as_ref() { BlockStmtOrExpr::BlockStmt(block_stmt) => { - serialize_stmt(ctx, &Stmt::Block(block_stmt.clone()), pos) + serialize_stmt(ctx, &Stmt::Block(block_stmt.clone())) } - BlockStmtOrExpr::Expr(expr) => serialize_expr(ctx, expr.as_ref(), pos), + BlockStmtOrExpr::Expr(expr) => serialize_expr(ctx, expr.as_ref()), }; - let return_type = - maybe_serialize_ts_type_ann(ctx, &node.return_type, pos); + let return_type = maybe_serialize_ts_type_ann(ctx, &node.return_type); - ctx.write_bool(async_pos, node.is_async); - ctx.write_bool(gen_pos, node.is_generator); - ctx.write_maybe_ref(type_param_pos, type_param); - ctx.write_refs(params_pos, params); - ctx.write_ref(body_pos, body); - ctx.write_maybe_ref(return_type_pos, return_type); - - pos + ctx.write_arrow_fn_expr( + &node.span, + node.is_async, + node.is_generator, + type_param, + params, + return_type, + body, + ) } Expr::Class(node) => { - // FIXME - let raw = ctx.header(AstNode::ClassExpression, parent, &node.class.span); - ctx.commit_schema(raw) + let ident = node + .ident + .as_ref() + .map(|ident| serialize_ident(ctx, ident, None)); + + let super_class = node + .class + .super_class + .as_ref() + .map(|expr| serialize_expr(ctx, expr.as_ref())); + + let implements = node + .class + .implements + .iter() + .map(|item| serialize_ts_expr_with_type_args(ctx, item)) + .collect::>(); + + let members = node + .class + .body + .iter() + .filter_map(|member| serialize_class_member(ctx, member)) + .collect::>(); + + let body = ctx.write_class_body(&node.class.span, members); + + ctx.write_class_expr( + &node.class.span, + false, + node.class.is_abstract, + ident, + super_class, + implements, + body, + ) } Expr::Yield(node) => { - let raw = ctx.header(AstNode::YieldExpression, parent, &node.span); - let delegate_pos = ctx.bool_field(AstProp::Delegate); - let arg_pos = ctx.ref_field(AstProp::Argument); - let pos = ctx.commit_schema(raw); - let arg = node .arg .as_ref() - .map(|arg| serialize_expr(ctx, arg.as_ref(), pos)); + .map(|arg| serialize_expr(ctx, arg.as_ref())); - ctx.write_bool(delegate_pos, node.delegate); - ctx.write_maybe_ref(arg_pos, arg); - - pos + ctx.write_yield_expr(&node.span, node.delegate, arg) } Expr::MetaProp(node) => { - let raw = ctx.header(AstNode::MetaProp, parent, &node.span); - ctx.commit_schema(raw) + let prop = ctx.write_identifier(&node.span, "meta", false, None); + ctx.write_meta_prop(&node.span, prop) } Expr::Await(node) => { - let raw = ctx.header(AstNode::AwaitExpression, parent, &node.span); - let arg_pos = ctx.ref_field(AstProp::Argument); - let pos = ctx.commit_schema(raw); - - let arg = serialize_expr(ctx, node.arg.as_ref(), pos); - - ctx.write_ref(arg_pos, arg); - - pos + let arg = serialize_expr(ctx, node.arg.as_ref()); + ctx.write_await_expr(&node.span, arg) } Expr::Paren(node) => { // Paren nodes are treated as a syntax only thing in TSEStree // and are never materialized to actual AST nodes. - serialize_expr(ctx, &node.expr, parent) + serialize_expr(ctx, &node.expr) } - Expr::JSXMember(node) => serialize_jsx_member_expr(ctx, node, parent), - Expr::JSXNamespacedName(node) => { - serialize_jsx_namespaced_name(ctx, node, parent) - } - Expr::JSXEmpty(node) => serialize_jsx_empty_expr(ctx, node, parent), - Expr::JSXElement(node) => serialize_jsx_element(ctx, node, parent), - Expr::JSXFragment(node) => serialize_jsx_fragment(ctx, node, parent), + Expr::JSXMember(node) => serialize_jsx_member_expr(ctx, node), + Expr::JSXNamespacedName(node) => serialize_jsx_namespaced_name(ctx, node), + Expr::JSXEmpty(node) => ctx.write_jsx_empty_expr(&node.span), + Expr::JSXElement(node) => serialize_jsx_element(ctx, node), + Expr::JSXFragment(node) => serialize_jsx_fragment(ctx, node), Expr::TsTypeAssertion(node) => { - let raw = ctx.header(AstNode::TSTypeAssertion, parent, &node.span); - let expr_pos = ctx.ref_field(AstProp::Expression); - let type_ann_pos = ctx.ref_field(AstProp::TypeAnnotation); - let pos = ctx.commit_schema(raw); + let expr = serialize_expr(ctx, &node.expr); + let type_ann = serialize_ts_type(ctx, &node.type_ann); - let expr = serialize_expr(ctx, &node.expr, parent); - let type_ann = serialize_ts_type(ctx, &node.type_ann, pos); - - ctx.write_ref(expr_pos, expr); - ctx.write_ref(type_ann_pos, type_ann); - - pos + ctx.write_ts_type_assertion(&node.span, expr, type_ann) } Expr::TsConstAssertion(node) => { - let raw = ctx.header(AstNode::TsConstAssertion, parent, &node.span); - let arg_pos = ctx.ref_field(AstProp::Argument); - let pos = ctx.commit_schema(raw); + let expr = serialize_expr(ctx, node.expr.as_ref()); - let arg = serialize_expr(ctx, node.expr.as_ref(), pos); + let type_name = ctx.write_identifier(&node.span, "const", false, None); + let type_ann = ctx.write_ts_type_ref(&node.span, type_name, None); - // FIXME - ctx.write_ref(arg_pos, arg); - - pos + ctx.write_ts_as_expr(&node.span, expr, type_ann) } Expr::TsNonNull(node) => { - let raw = ctx.header(AstNode::TSNonNullExpression, parent, &node.span); - let expr_pos = ctx.ref_field(AstProp::Expression); - let pos = ctx.commit_schema(raw); - - let expr_id = serialize_expr(ctx, node.expr.as_ref(), pos); - - ctx.write_ref(expr_pos, expr_id); - - pos + let expr = serialize_expr(ctx, node.expr.as_ref()); + ctx.write_ts_non_null(&node.span, expr) } Expr::TsAs(node) => { - let raw = ctx.header(AstNode::TSAsExpression, parent, &node.span); - let expr_pos = ctx.ref_field(AstProp::Expression); - let type_ann_pos = ctx.ref_field(AstProp::TypeAnnotation); - let pos = ctx.commit_schema(raw); + let expr = serialize_expr(ctx, node.expr.as_ref()); + let type_ann = serialize_ts_type(ctx, node.type_ann.as_ref()); - let expr = serialize_expr(ctx, node.expr.as_ref(), pos); - let type_ann = serialize_ts_type(ctx, node.type_ann.as_ref(), pos); - - ctx.write_ref(expr_pos, expr); - ctx.write_ref(type_ann_pos, type_ann); - - pos + ctx.write_ts_as_expr(&node.span, expr, type_ann) } - Expr::TsInstantiation(node) => { - let raw = ctx.header(AstNode::TsInstantiation, parent, &node.span); - let expr_pos = ctx.ref_field(AstProp::Expression); - let type_args_pos = ctx.ref_field(AstProp::TypeArguments); - let pos = ctx.commit_schema(raw); - - let expr = serialize_expr(ctx, node.expr.as_ref(), pos); - - let type_arg = serialize_ts_param_inst(ctx, node.type_args.as_ref(), pos); - - ctx.write_ref(expr_pos, expr); - ctx.write_ref(type_args_pos, type_arg); - - pos + Expr::TsInstantiation(_) => { + // Invalid syntax + unreachable!() } Expr::TsSatisfies(node) => { - let raw = ctx.header(AstNode::TSSatisfiesExpression, parent, &node.span); - let expr_pos = ctx.ref_field(AstProp::Expression); - let type_ann_pos = ctx.ref_field(AstProp::TypeAnnotation); - let pos = ctx.commit_schema(raw); + let expr = serialize_expr(ctx, node.expr.as_ref()); + let type_ann = serialize_ts_type(ctx, node.type_ann.as_ref()); - let epxr = serialize_expr(ctx, node.expr.as_ref(), pos); - let type_ann = serialize_ts_type(ctx, node.type_ann.as_ref(), pos); - - ctx.write_ref(expr_pos, epxr); - ctx.write_ref(type_ann_pos, type_ann); - - pos + ctx.write_ts_satisfies_expr(&node.span, expr, type_ann) } - Expr::PrivateName(node) => serialize_private_name(ctx, node, parent), + Expr::PrivateName(node) => serialize_private_name(ctx, node), Expr::OptChain(node) => { - let raw = ctx.header(AstNode::ChainExpression, parent, &node.span); - let arg_pos = ctx.ref_field(AstProp::Argument); - let pos = ctx.commit_schema(raw); - - let arg = match node.base.as_ref() { + let expr = match node.base.as_ref() { OptChainBase::Member(member_expr) => { - serialize_member_expr(ctx, member_expr, pos, true) + serialize_member_expr(ctx, member_expr, true) } OptChainBase::Call(opt_call) => { - let raw = ctx.header(AstNode::CallExpression, pos, &opt_call.span); - let opt_pos = ctx.bool_field(AstProp::Optional); - let callee_pos = ctx.ref_field(AstProp::Callee); - let type_args_pos = ctx.ref_field(AstProp::TypeArguments); - let args_pos = - ctx.ref_vec_field(AstProp::Arguments, opt_call.args.len()); - let call_pos = ctx.commit_schema(raw); + let callee = serialize_expr(ctx, &opt_call.callee); - let callee = serialize_expr(ctx, &opt_call.callee, pos); - - let type_param_id = opt_call.type_args.clone().map(|params| { - serialize_ts_param_inst(ctx, params.as_ref(), call_pos) - }); + let type_param_id = opt_call + .type_args + .clone() + .map(|params| serialize_ts_param_inst(ctx, params.as_ref())); let args = opt_call .args .iter() - .map(|arg| serialize_expr_or_spread(ctx, arg, pos)) + .map(|arg| serialize_expr_or_spread(ctx, arg)) .collect::>(); - ctx.write_bool(opt_pos, true); - ctx.write_ref(callee_pos, callee); - ctx.write_maybe_ref(type_args_pos, type_param_id); - ctx.write_refs(args_pos, args); - - call_pos + ctx.write_call_expr(&opt_call.span, true, callee, type_param_id, args) } }; - ctx.write_ref(arg_pos, arg); - - pos + ctx.write_chain_expr(&node.span, expr) } Expr::Invalid(_) => { unreachable!() @@ -1204,69 +1041,49 @@ fn serialize_expr( fn serialize_prop_or_spread( ctx: &mut TsEsTreeBuilder, prop: &PropOrSpread, - parent: NodeRef, ) -> NodeRef { match prop { PropOrSpread::Spread(spread_element) => serialize_spread( ctx, spread_element.expr.as_ref(), &spread_element.dot3_token, - parent, ), PropOrSpread::Prop(prop) => { - let raw = ctx.header(AstNode::Property, parent, &prop.span()); - - let shorthand_pos = ctx.bool_field(AstProp::Shorthand); - let computed_pos = ctx.bool_field(AstProp::Computed); - let method_pos = ctx.bool_field(AstProp::Method); - let kind_pos = ctx.str_field(AstProp::Kind); - let key_pos = ctx.ref_field(AstProp::Key); - let value_pos = ctx.ref_field(AstProp::Value); - let pos = ctx.commit_schema(raw); - let mut shorthand = false; let mut computed = false; let mut method = false; let mut kind = "init"; - // FIXME: optional - let (key_id, value_id) = match prop.as_ref() { + let (key, value) = match prop.as_ref() { Prop::Shorthand(ident) => { shorthand = true; - let value = serialize_ident(ctx, ident, pos); - (value, value) + let value = serialize_ident(ctx, ident, None); + let value2 = serialize_ident(ctx, ident, None); + (value, value2) } Prop::KeyValue(key_value_prop) => { if let PropName::Computed(_) = key_value_prop.key { computed = true; } - let key = serialize_prop_name(ctx, &key_value_prop.key, pos); - let value = serialize_expr(ctx, key_value_prop.value.as_ref(), pos); + let key = serialize_prop_name(ctx, &key_value_prop.key); + let value = serialize_expr(ctx, key_value_prop.value.as_ref()); (key, value) } Prop::Assign(assign_prop) => { - let raw = - ctx.header(AstNode::AssignmentPattern, pos, &assign_prop.span); - let left_pos = ctx.ref_field(AstProp::Left); - let right_pos = ctx.ref_field(AstProp::Right); - let child_pos = ctx.commit_schema(raw); + let left = serialize_ident(ctx, &assign_prop.key, None); + let right = serialize_expr(ctx, assign_prop.value.as_ref()); - let left = serialize_ident(ctx, &assign_prop.key, child_pos); - let right = - serialize_expr(ctx, assign_prop.value.as_ref(), child_pos); - - ctx.write_ref(left_pos, left); - ctx.write_ref(right_pos, right); + let child_pos = ctx.write_assign_pat(&assign_prop.span, left, right); (left, child_pos) } Prop::Getter(getter_prop) => { kind = "get"; - let key = serialize_prop_name(ctx, &getter_prop.key, pos); + let key = serialize_prop_name(ctx, &getter_prop.key); let value = serialize_expr( ctx, @@ -1280,11 +1097,10 @@ fn serialize_prop_or_spread( body: getter_prop.body.clone(), is_generator: false, is_async: false, - type_params: None, // FIXME - return_type: None, + type_params: None, + return_type: getter_prop.type_ann.clone(), }), }), - pos, ); (key, value) @@ -1292,7 +1108,7 @@ fn serialize_prop_or_spread( Prop::Setter(setter_prop) => { kind = "set"; - let key_id = serialize_prop_name(ctx, &setter_prop.key, pos); + let key_id = serialize_prop_name(ctx, &setter_prop.key); let param = Param::from(*setter_prop.param.clone()); @@ -1312,7 +1128,6 @@ fn serialize_prop_or_spread( return_type: None, }), }), - pos, ); (key_id, value_id) @@ -1320,7 +1135,7 @@ fn serialize_prop_or_spread( Prop::Method(method_prop) => { method = true; - let key_id = serialize_prop_name(ctx, &method_prop.key, pos); + let key_id = serialize_prop_name(ctx, &method_prop.key); let value_id = serialize_expr( ctx, @@ -1328,21 +1143,21 @@ fn serialize_prop_or_spread( ident: None, function: method_prop.function.clone(), }), - pos, ); (key_id, value_id) } }; - ctx.write_bool(shorthand_pos, shorthand); - ctx.write_bool(computed_pos, computed); - ctx.write_bool(method_pos, method); - ctx.write_str(kind_pos, kind); - ctx.write_ref(key_pos, key_id); - ctx.write_ref(value_pos, value_id); - - pos + ctx.write_property( + &prop.span(), + shorthand, + computed, + method, + kind, + key, + value, + ) } } } @@ -1350,396 +1165,190 @@ fn serialize_prop_or_spread( fn serialize_member_expr( ctx: &mut TsEsTreeBuilder, node: &MemberExpr, - parent: NodeRef, optional: bool, ) -> NodeRef { - let raw = ctx.header(AstNode::MemberExpression, parent, &node.span); - let opt_pos = ctx.bool_field(AstProp::Optional); - let computed_pos = ctx.bool_field(AstProp::Computed); - let obj_pos = ctx.ref_field(AstProp::Object); - let prop_pos = ctx.ref_field(AstProp::Property); - let pos = ctx.commit_schema(raw); - - let obj = serialize_expr(ctx, node.obj.as_ref(), pos); - let mut computed = false; + let obj = serialize_expr(ctx, node.obj.as_ref()); let prop = match &node.prop { - MemberProp::Ident(ident_name) => serialize_ident_name(ctx, ident_name, pos), + MemberProp::Ident(ident_name) => serialize_ident_name(ctx, ident_name), MemberProp::PrivateName(private_name) => { - serialize_private_name(ctx, private_name, pos) + serialize_private_name(ctx, private_name) } MemberProp::Computed(computed_prop_name) => { computed = true; - serialize_expr(ctx, computed_prop_name.expr.as_ref(), pos) + serialize_expr(ctx, computed_prop_name.expr.as_ref()) } }; - ctx.write_bool(opt_pos, optional); - ctx.write_bool(computed_pos, computed); - ctx.write_ref(obj_pos, obj); - ctx.write_ref(prop_pos, prop); - - pos -} - -fn serialize_class_member( - ctx: &mut TsEsTreeBuilder, - member: &ClassMember, - parent: NodeRef, -) -> NodeRef { - match member { - ClassMember::Constructor(constructor) => { - let raw = - ctx.header(AstNode::MethodDefinition, parent, &constructor.span); - let key_pos = ctx.ref_field(AstProp::Key); - let body_pos = ctx.ref_field(AstProp::Body); - let args_pos = - ctx.ref_vec_field(AstProp::Arguments, constructor.params.len()); - let acc_pos = if constructor.accessibility.is_some() { - NodePos::Str(ctx.str_field(AstProp::Accessibility)) - } else { - NodePos::Undef(ctx.undefined_field(AstProp::Accessibility)) - }; - let member_id = ctx.commit_schema(raw); - - // FIXME flags - - let key = serialize_prop_name(ctx, &constructor.key, member_id); - let body = constructor - .body - .as_ref() - .map(|body| serialize_stmt(ctx, &Stmt::Block(body.clone()), member_id)); - - let params = constructor - .params - .iter() - .map(|param| match param { - ParamOrTsParamProp::TsParamProp(_) => { - todo!() - } - ParamOrTsParamProp::Param(param) => { - serialize_pat(ctx, ¶m.pat, member_id) - } - }) - .collect::>(); - - if let Some(acc) = constructor.accessibility { - if let NodePos::Str(str_pos) = acc_pos { - ctx.write_str(str_pos, &accessibility_to_str(acc)); - } - } - - ctx.write_ref(key_pos, key); - ctx.write_maybe_ref(body_pos, body); - // FIXME - ctx.write_refs(args_pos, params); - - member_id - } - ClassMember::Method(method) => { - let raw = ctx.header(AstNode::MethodDefinition, parent, &method.span); - - let member_id = ctx.commit_schema(raw); - - // let mut flags = FlagValue::new(); - // flags.set(Flag::ClassMethod); - if method.function.is_async { - // FIXME - } - - // accessibility_to_flag(&mut flags, method.accessibility); - - let _key_id = serialize_prop_name(ctx, &method.key, member_id); - - let _body_id = - method.function.body.as_ref().map(|body| { - serialize_stmt(ctx, &Stmt::Block(body.clone()), member_id) - }); - - let _params = method - .function - .params - .iter() - .map(|param| serialize_pat(ctx, ¶m.pat, member_id)) - .collect::>(); - - // ctx.write_node(member_id, ); - // ctx.write_flags(&flags); - // ctx.write_id(key_id); - // ctx.write_id(body_id); - // ctx.write_ids(AstProp::Params, params); - - member_id - } - ClassMember::PrivateMethod(_) => todo!(), - ClassMember::ClassProp(_) => todo!(), - ClassMember::PrivateProp(_) => todo!(), - ClassMember::TsIndexSignature(member) => { - serialize_ts_index_sig(ctx, member, parent) - } - ClassMember::Empty(_) => unreachable!(), - ClassMember::StaticBlock(_) => todo!(), - ClassMember::AutoAccessor(_) => todo!(), - } + ctx.write_member_expr(&node.span, optional, computed, obj, prop) } fn serialize_expr_or_spread( ctx: &mut TsEsTreeBuilder, arg: &ExprOrSpread, - parent: NodeRef, ) -> NodeRef { if let Some(spread) = &arg.spread { - serialize_spread(ctx, &arg.expr, spread, parent) + serialize_spread(ctx, &arg.expr, spread) } else { - serialize_expr(ctx, arg.expr.as_ref(), parent) + serialize_expr(ctx, arg.expr.as_ref()) } } fn serialize_ident( ctx: &mut TsEsTreeBuilder, ident: &Ident, - parent: NodeRef, + type_ann: Option, ) -> NodeRef { - let raw = ctx.header(AstNode::Identifier, parent, &ident.span); - let name_pos = ctx.str_field(AstProp::Name); - let pos = ctx.commit_schema(raw); - - ctx.write_str(name_pos, ident.sym.as_str()); - - pos + ctx.write_identifier( + &ident.span, + ident.sym.as_str(), + ident.optional, + type_ann, + ) } -fn serialize_module_exported_name( +fn serialize_module_export_name( ctx: &mut TsEsTreeBuilder, name: &ModuleExportName, - parent: NodeRef, ) -> NodeRef { match &name { - ModuleExportName::Ident(ident) => serialize_ident(ctx, ident, parent), - ModuleExportName::Str(lit) => { - serialize_lit(ctx, &Lit::Str(lit.clone()), parent) - } + ModuleExportName::Ident(ident) => serialize_ident(ctx, ident, None), + ModuleExportName::Str(lit) => serialize_lit(ctx, &Lit::Str(lit.clone())), } } -fn serialize_decl( - ctx: &mut TsEsTreeBuilder, - decl: &Decl, - parent: NodeRef, -) -> NodeRef { +fn serialize_decl(ctx: &mut TsEsTreeBuilder, decl: &Decl) -> NodeRef { match decl { Decl::Class(node) => { - let raw = ctx.header(AstNode::ClassDeclaration, parent, &node.class.span); - let declare_pos = ctx.bool_field(AstProp::Declare); - let abstract_pos = ctx.bool_field(AstProp::Abstract); - let id_pos = ctx.ref_field(AstProp::Id); - let body_pos = ctx.ref_field(AstProp::Body); - let type_params_pos = ctx.ref_field(AstProp::TypeParameters); - let super_pos = ctx.ref_field(AstProp::SuperClass); - let super_type_pos = ctx.ref_field(AstProp::SuperTypeArguments); - let impl_pos = - ctx.ref_vec_field(AstProp::Implements, node.class.implements.len()); - let id = ctx.commit_schema(raw); - - let body_raw = ctx.header(AstNode::ClassBody, id, &node.class.span); - let body_body_pos = - ctx.ref_vec_field(AstProp::Body, node.class.body.len()); - let body_id = ctx.commit_schema(body_raw); - - let ident = serialize_ident(ctx, &node.ident, id); - let type_params = - maybe_serialize_ts_type_param(ctx, &node.class.type_params, id); + let ident = serialize_ident(ctx, &node.ident, None); let super_class = node .class .super_class .as_ref() - .map(|super_class| serialize_expr(ctx, super_class, id)); + .map(|expr| serialize_expr(ctx, expr.as_ref())); - let super_type_params = node - .class - .super_type_params - .as_ref() - .map(|super_params| serialize_ts_param_inst(ctx, super_params, id)); - - let implement_ids = node + let implements = node .class .implements .iter() - .map(|implements| { - let raw = - ctx.header(AstNode::TSClassImplements, id, &implements.span); - - let expr_pos = ctx.ref_field(AstProp::Expression); - let type_args_pos = ctx.ref_field(AstProp::TypeArguments); - let child_pos = ctx.commit_schema(raw); - - let type_args = implements - .type_args - .clone() - .map(|args| serialize_ts_param_inst(ctx, &args, child_pos)); - - let expr = serialize_expr(ctx, &implements.expr, child_pos); - - ctx.write_ref(expr_pos, expr); - ctx.write_maybe_ref(type_args_pos, type_args); - - child_pos - }) + .map(|item| serialize_ts_expr_with_type_args(ctx, item)) .collect::>(); - let member_ids = node + let members = node .class .body .iter() - .map(|member| serialize_class_member(ctx, member, parent)) + .filter_map(|member| serialize_class_member(ctx, member)) .collect::>(); - ctx.write_ref(body_pos, body_id); + let body = ctx.write_class_body(&node.class.span, members); - ctx.write_bool(declare_pos, node.declare); - ctx.write_bool(abstract_pos, node.class.is_abstract); - ctx.write_ref(id_pos, ident); - ctx.write_maybe_ref(type_params_pos, type_params); - ctx.write_maybe_ref(super_pos, super_class); - ctx.write_maybe_ref(super_type_pos, super_type_params); - ctx.write_refs(impl_pos, implement_ids); - - // body - ctx.write_refs(body_body_pos, member_ids); - - id + ctx.write_class_decl( + &node.class.span, + false, + node.class.is_abstract, + Some(ident), + super_class, + implements, + body, + ) } Decl::Fn(node) => { - let raw = - ctx.header(AstNode::FunctionDeclaration, parent, &node.function.span); - let declare_pos = ctx.bool_field(AstProp::Declare); - let async_pos = ctx.bool_field(AstProp::Async); - let gen_pos = ctx.bool_field(AstProp::Generator); - let id_pos = ctx.ref_field(AstProp::Id); - let type_params_pos = ctx.ref_field(AstProp::TypeParameters); - let return_pos = ctx.ref_field(AstProp::ReturnType); - let body_pos = ctx.ref_field(AstProp::Body); - let params_pos = - ctx.ref_vec_field(AstProp::Params, node.function.params.len()); - let pos = ctx.commit_schema(raw); - - let ident_id = serialize_ident(ctx, &node.ident, parent); + let ident_id = serialize_ident(ctx, &node.ident, None); let type_param_id = - maybe_serialize_ts_type_param(ctx, &node.function.type_params, pos); + maybe_serialize_ts_type_param_decl(ctx, &node.function.type_params); let return_type = - maybe_serialize_ts_type_ann(ctx, &node.function.return_type, pos); + maybe_serialize_ts_type_ann(ctx, &node.function.return_type); let body = node .function .body .as_ref() - .map(|body| serialize_stmt(ctx, &Stmt::Block(body.clone()), pos)); + .map(|body| serialize_stmt(ctx, &Stmt::Block(body.clone()))); let params = node .function .params .iter() - .map(|param| serialize_pat(ctx, ¶m.pat, pos)) + .map(|param| serialize_pat(ctx, ¶m.pat)) .collect::>(); - ctx.write_bool(declare_pos, node.declare); - ctx.write_bool(async_pos, node.function.is_async); - ctx.write_bool(gen_pos, node.function.is_generator); - ctx.write_ref(id_pos, ident_id); - ctx.write_maybe_ref(type_params_pos, type_param_id); - ctx.write_maybe_ref(return_pos, return_type); - ctx.write_maybe_ref(body_pos, body); - ctx.write_refs(params_pos, params); - - pos + ctx.write_fn_decl( + &node.function.span, + node.declare, + node.function.is_async, + node.function.is_generator, + Some(ident_id), + type_param_id, + return_type, + body, + params, + ) } Decl::Var(node) => { - let raw = ctx.header(AstNode::VariableDeclaration, parent, &node.span); - let declare_pos = ctx.bool_field(AstProp::Declare); - let kind_pos = ctx.str_field(AstProp::Kind); - let decls_pos = - ctx.ref_vec_field(AstProp::Declarations, node.decls.len()); - let id = ctx.commit_schema(raw); + let children = node + .decls + .iter() + .map(|decl| { + let ident = serialize_pat(ctx, &decl.name); + let init = decl + .init + .as_ref() + .map(|init| serialize_expr(ctx, init.as_ref())); + + ctx.write_var_declarator(&decl.span, ident, init) + }) + .collect::>(); + + let kind = match node.kind { + VarDeclKind::Var => "var", + VarDeclKind::Let => "let", + VarDeclKind::Const => "const", + }; + + ctx.write_var_decl(&node.span, node.declare, kind, children) + } + Decl::Using(node) => { + let kind = if node.is_await { + "await using" + } else { + "using" + }; let children = node .decls .iter() .map(|decl| { - let raw = ctx.header(AstNode::VariableDeclarator, id, &decl.span); - let id_pos = ctx.ref_field(AstProp::Id); - let init_pos = ctx.ref_field(AstProp::Init); - let child_id = ctx.commit_schema(raw); - - // FIXME: Definite? - - let ident = serialize_pat(ctx, &decl.name, child_id); - + let ident = serialize_pat(ctx, &decl.name); let init = decl .init .as_ref() - .map(|init| serialize_expr(ctx, init.as_ref(), child_id)); + .map(|init| serialize_expr(ctx, init.as_ref())); - ctx.write_ref(id_pos, ident); - ctx.write_maybe_ref(init_pos, init); - - child_id + ctx.write_var_declarator(&decl.span, ident, init) }) .collect::>(); - ctx.write_bool(declare_pos, node.declare); - ctx.write_str( - kind_pos, - match node.kind { - VarDeclKind::Var => "var", - VarDeclKind::Let => "let", - VarDeclKind::Const => "const", - }, - ); - ctx.write_refs(decls_pos, children); - - id - } - Decl::Using(_) => { - todo!(); + ctx.write_var_decl(&node.span, false, kind, children) } Decl::TsInterface(node) => { - let raw = ctx.header(AstNode::TSInterface, parent, &node.span); - let declare_pos = ctx.bool_field(AstProp::Declare); - let id_pos = ctx.ref_field(AstProp::Id); - let extends_pos = ctx.ref_vec_field(AstProp::Extends, node.extends.len()); - let type_param_pos = ctx.ref_field(AstProp::TypeParameters); - let body_pos = ctx.ref_field(AstProp::Body); - let pos = ctx.commit_schema(raw); - - let body_raw = ctx.header(AstNode::TSInterfaceBody, pos, &node.body.span); - let body_body_pos = - ctx.ref_vec_field(AstProp::Body, node.body.body.len()); - let body_id = ctx.commit_schema(body_raw); - - let ident_id = serialize_ident(ctx, &node.id, pos); + let ident_id = serialize_ident(ctx, &node.id, None); let type_param = - maybe_serialize_ts_type_param(ctx, &node.type_params, pos); + maybe_serialize_ts_type_param_decl(ctx, &node.type_params); let extend_ids = node .extends .iter() .map(|item| { - let raw = ctx.header(AstNode::TSInterfaceHeritage, pos, &item.span); - let type_args_pos = ctx.ref_field(AstProp::TypeArguments); - let expr_pos = ctx.ref_field(AstProp::Expression); - let child_pos = ctx.commit_schema(raw); + let expr = serialize_expr(ctx, &item.expr); + let type_args = item + .type_args + .clone() + .map(|params| serialize_ts_param_inst(ctx, params.as_ref())); - let expr = serialize_expr(ctx, &item.expr, child_pos); - let type_args = item.type_args.clone().map(|params| { - serialize_ts_param_inst(ctx, params.as_ref(), child_pos) - }); - - ctx.write_ref(expr_pos, expr); - ctx.write_maybe_ref(type_args_pos, type_args); - - child_pos + ctx.write_ts_interface_heritage(&item.span, expr, type_args) }) .collect::>(); @@ -1747,269 +1356,211 @@ fn serialize_decl( .body .body .iter() - .map(|item| match item { - TsTypeElement::TsCallSignatureDecl(ts_call) => { - let raw = ctx.header( - AstNode::TsCallSignatureDeclaration, - pos, - &ts_call.span, - ); - let type_ann_pos = ctx.ref_field(AstProp::TypeAnnotation); - let params_pos = - ctx.ref_vec_field(AstProp::Params, ts_call.params.len()); - let return_pos = ctx.ref_field(AstProp::ReturnType); - let item_id = ctx.commit_schema(raw); - - let type_param = - maybe_serialize_ts_type_param(ctx, &ts_call.type_params, pos); - let return_type = - maybe_serialize_ts_type_ann(ctx, &ts_call.type_ann, pos); - let params = ts_call - .params - .iter() - .map(|param| serialize_ts_fn_param(ctx, param, pos)) - .collect::>(); - - ctx.write_maybe_ref(type_ann_pos, type_param); - ctx.write_refs(params_pos, params); - ctx.write_maybe_ref(return_pos, return_type); - - item_id - } - TsTypeElement::TsConstructSignatureDecl(_) => todo!(), - TsTypeElement::TsPropertySignature(sig) => { - let raw = ctx.header(AstNode::TSPropertySignature, pos, &sig.span); - - let computed_pos = ctx.bool_field(AstProp::Computed); - let optional_pos = ctx.bool_field(AstProp::Optional); - let readonly_pos = ctx.bool_field(AstProp::Readonly); - // TODO: where is this coming from? - let _static_bos = ctx.bool_field(AstProp::Static); - let key_pos = ctx.ref_field(AstProp::Key); - let type_ann_pos = ctx.ref_field(AstProp::TypeAnnotation); - let item_pos = ctx.commit_schema(raw); - - let key = serialize_expr(ctx, &sig.key, item_pos); - let type_ann = - maybe_serialize_ts_type_ann(ctx, &sig.type_ann, item_pos); - - ctx.write_bool(computed_pos, sig.computed); - ctx.write_bool(optional_pos, sig.optional); - ctx.write_bool(readonly_pos, sig.readonly); - ctx.write_ref(key_pos, key); - ctx.write_maybe_ref(type_ann_pos, type_ann); - - item_pos - } - TsTypeElement::TsGetterSignature(sig) => { - let raw = ctx.header(AstNode::TSMethodSignature, pos, &sig.span); - let computed_pos = ctx.bool_field(AstProp::Computed); - let optional_pos = ctx.bool_field(AstProp::Optional); - let readonly_pos = ctx.bool_field(AstProp::Readonly); - // TODO: where is this coming from? - let _static_bos = ctx.bool_field(AstProp::Static); - let kind_pos = ctx.str_field(AstProp::Kind); - let key_pos = ctx.ref_field(AstProp::Key); - let return_type_pos = ctx.ref_field(AstProp::ReturnType); - let item_pos = ctx.commit_schema(raw); - - let key = serialize_expr(ctx, sig.key.as_ref(), item_pos); - let return_type = - maybe_serialize_ts_type_ann(ctx, &sig.type_ann, item_pos); - - ctx.write_bool(computed_pos, false); - ctx.write_bool(optional_pos, false); - ctx.write_bool(readonly_pos, false); - ctx.write_str(kind_pos, "getter"); - ctx.write_maybe_ref(return_type_pos, return_type); - ctx.write_ref(key_pos, key); - - item_pos - } - TsTypeElement::TsSetterSignature(sig) => { - let raw = ctx.header(AstNode::TSMethodSignature, pos, &sig.span); - let computed_pos = ctx.bool_field(AstProp::Computed); - let optional_pos = ctx.bool_field(AstProp::Optional); - let readonly_pos = ctx.bool_field(AstProp::Readonly); - // TODO: where is this coming from? - let _static_bos = ctx.bool_field(AstProp::Static); - let kind_pos = ctx.str_field(AstProp::Kind); - let key_pos = ctx.ref_field(AstProp::Key); - let params_pos = ctx.ref_vec_field(AstProp::Params, 1); - let item_pos = ctx.commit_schema(raw); - - let key = serialize_expr(ctx, sig.key.as_ref(), item_pos); - let params = serialize_ts_fn_param(ctx, &sig.param, item_pos); - - ctx.write_bool(computed_pos, false); - ctx.write_bool(optional_pos, false); - ctx.write_bool(readonly_pos, false); - ctx.write_str(kind_pos, "setter"); - ctx.write_ref(key_pos, key); - ctx.write_refs(params_pos, vec![params]); - - item_pos - } - TsTypeElement::TsMethodSignature(sig) => { - let raw = ctx.header(AstNode::TSMethodSignature, pos, &sig.span); - let computed_pos = ctx.bool_field(AstProp::Computed); - let optional_pos = ctx.bool_field(AstProp::Optional); - let readonly_pos = ctx.bool_field(AstProp::Readonly); - // TODO: where is this coming from? - let _static_bos = ctx.bool_field(AstProp::Static); - let kind_pos = ctx.str_field(AstProp::Kind); - let key_pos = ctx.ref_field(AstProp::Key); - let params_pos = - ctx.ref_vec_field(AstProp::Params, sig.params.len()); - let return_type_pos = ctx.ref_field(AstProp::ReturnType); - let item_pos = ctx.commit_schema(raw); - - let key = serialize_expr(ctx, sig.key.as_ref(), item_pos); - let params = sig - .params - .iter() - .map(|param| serialize_ts_fn_param(ctx, param, item_pos)) - .collect::>(); - let return_type = - maybe_serialize_ts_type_ann(ctx, &sig.type_ann, item_pos); - - ctx.write_bool(computed_pos, false); - ctx.write_bool(optional_pos, false); - ctx.write_bool(readonly_pos, false); - ctx.write_str(kind_pos, "method"); - ctx.write_ref(key_pos, key); - ctx.write_refs(params_pos, params); - ctx.write_maybe_ref(return_type_pos, return_type); - - item_pos - } - TsTypeElement::TsIndexSignature(sig) => { - serialize_ts_index_sig(ctx, sig, pos) - } - }) + .map(|item| serialize_ts_type_elem(ctx, item)) .collect::>(); - ctx.write_bool(declare_pos, node.declare); - ctx.write_ref(id_pos, ident_id); - ctx.write_maybe_ref(type_param_pos, type_param); - ctx.write_refs(extends_pos, extend_ids); - ctx.write_ref(body_pos, body_id); - - // Body - ctx.write_refs(body_body_pos, body_elem_ids); - - pos + let body_pos = + ctx.write_ts_interface_body(&node.body.span, body_elem_ids); + ctx.write_ts_interface( + &node.span, + node.declare, + ident_id, + type_param, + extend_ids, + body_pos, + ) } Decl::TsTypeAlias(node) => { - let raw = ctx.header(AstNode::TsTypeAlias, parent, &node.span); - let declare_pos = ctx.bool_field(AstProp::Declare); - let id_pos = ctx.ref_field(AstProp::Id); - let type_params_pos = ctx.ref_field(AstProp::TypeParameters); - let type_ann_pos = ctx.ref_field(AstProp::TypeAnnotation); - let pos = ctx.commit_schema(raw); - - let ident = serialize_ident(ctx, &node.id, pos); - let type_ann = serialize_ts_type(ctx, &node.type_ann, pos); + let ident = serialize_ident(ctx, &node.id, None); + let type_ann = serialize_ts_type(ctx, &node.type_ann); let type_param = - maybe_serialize_ts_type_param(ctx, &node.type_params, pos); + maybe_serialize_ts_type_param_decl(ctx, &node.type_params); - ctx.write_bool(declare_pos, node.declare); - ctx.write_ref(id_pos, ident); - ctx.write_maybe_ref(type_params_pos, type_param); - ctx.write_ref(type_ann_pos, type_ann); - - pos + ctx.write_ts_type_alias( + &node.span, + node.declare, + ident, + type_param, + type_ann, + ) } Decl::TsEnum(node) => { - let raw = ctx.header(AstNode::TSEnumDeclaration, parent, &node.span); - let declare_pos = ctx.bool_field(AstProp::Declare); - let const_pos = ctx.bool_field(AstProp::Const); - let id_pos = ctx.ref_field(AstProp::Id); - let body_pos = ctx.ref_field(AstProp::Body); - let pos = ctx.commit_schema(raw); - - let body_raw = ctx.header(AstNode::TSEnumBody, pos, &node.span); - let members_pos = ctx.ref_vec_field(AstProp::Members, node.members.len()); - let body = ctx.commit_schema(body_raw); - - let ident_id = serialize_ident(ctx, &node.id, parent); + let id = serialize_ident(ctx, &node.id, None); let members = node .members .iter() .map(|member| { - let raw = ctx.header(AstNode::TSEnumMember, body, &member.span); - let id_pos = ctx.ref_field(AstProp::Id); - let init_pos = ctx.ref_field(AstProp::Initializer); - let member_id = ctx.commit_schema(raw); - let ident = match &member.id { - TsEnumMemberId::Ident(ident) => { - serialize_ident(ctx, ident, member_id) - } + TsEnumMemberId::Ident(ident) => serialize_ident(ctx, ident, None), TsEnumMemberId::Str(lit_str) => { - serialize_lit(ctx, &Lit::Str(lit_str.clone()), member_id) + serialize_lit(ctx, &Lit::Str(lit_str.clone())) } }; - let init = member - .init - .as_ref() - .map(|init| serialize_expr(ctx, init, member_id)); + let init = member.init.as_ref().map(|init| serialize_expr(ctx, init)); - ctx.write_ref(id_pos, ident); - ctx.write_maybe_ref(init_pos, init); - - member_id + ctx.write_ts_enum_member(&member.span, ident, init) }) .collect::>(); - ctx.write_refs(members_pos, members); - - ctx.write_bool(declare_pos, node.declare); - ctx.write_bool(const_pos, node.is_const); - ctx.write_ref(id_pos, ident_id); - ctx.write_ref(body_pos, body); - - pos + let body = ctx.write_ts_enum_body(&node.span, members); + ctx.write_ts_enum(&node.span, node.declare, node.is_const, id, body) } - Decl::TsModule(ts_module_decl) => { - let raw = ctx.header(AstNode::TsModule, parent, &ts_module_decl.span); - ctx.commit_schema(raw) + Decl::TsModule(node) => { + let ident = match &node.id { + TsModuleName::Ident(ident) => serialize_ident(ctx, ident, None), + TsModuleName::Str(str_lit) => { + serialize_lit(ctx, &Lit::Str(str_lit.clone())) + } + }; + + let body = node + .body + .as_ref() + .map(|body| serialize_ts_namespace_body(ctx, body)); + + ctx.write_ts_module_decl( + &node.span, + node.declare, + node.global, + ident, + body, + ) } } } +fn serialize_ts_namespace_body( + ctx: &mut TsEsTreeBuilder, + node: &TsNamespaceBody, +) -> NodeRef { + match node { + TsNamespaceBody::TsModuleBlock(mod_block) => { + let items = mod_block + .body + .iter() + .map(|item| match item { + ModuleItem::ModuleDecl(decl) => serialize_module_decl(ctx, decl), + ModuleItem::Stmt(stmt) => serialize_stmt(ctx, stmt), + }) + .collect::>(); + + ctx.write_ts_module_block(&mod_block.span, items) + } + TsNamespaceBody::TsNamespaceDecl(node) => { + let ident = serialize_ident(ctx, &node.id, None); + let body = serialize_ts_namespace_body(ctx, &node.body); + + ctx.write_ts_module_decl( + &node.span, + node.declare, + node.global, + ident, + Some(body), + ) + } + } +} + +fn serialize_ts_type_elem( + ctx: &mut TsEsTreeBuilder, + node: &TsTypeElement, +) -> NodeRef { + match node { + TsTypeElement::TsCallSignatureDecl(ts_call) => { + let type_ann = + maybe_serialize_ts_type_param_decl(ctx, &ts_call.type_params); + let return_type = maybe_serialize_ts_type_ann(ctx, &ts_call.type_ann); + let params = ts_call + .params + .iter() + .map(|param| serialize_ts_fn_param(ctx, param)) + .collect::>(); + + ctx.write_ts_call_sig_decl(&ts_call.span, type_ann, params, return_type) + } + TsTypeElement::TsConstructSignatureDecl(sig) => { + let type_params = + maybe_serialize_ts_type_param_decl(ctx, &sig.type_params); + + let params = sig + .params + .iter() + .map(|param| serialize_ts_fn_param(ctx, param)) + .collect::>(); + + // Must be present + let return_type = + maybe_serialize_ts_type_ann(ctx, &sig.type_ann).unwrap(); + + ctx.write_ts_construct_sig(&sig.span, type_params, params, return_type) + } + TsTypeElement::TsPropertySignature(sig) => { + let key = serialize_expr(ctx, &sig.key); + let type_ann = maybe_serialize_ts_type_ann(ctx, &sig.type_ann); + + ctx.write_ts_property_sig( + &sig.span, + sig.computed, + sig.optional, + sig.readonly, + key, + type_ann, + ) + } + TsTypeElement::TsGetterSignature(sig) => { + let key = serialize_expr(ctx, sig.key.as_ref()); + let return_type = maybe_serialize_ts_type_ann(ctx, &sig.type_ann); + + ctx.write_ts_getter_sig(&sig.span, key, return_type) + } + TsTypeElement::TsSetterSignature(sig) => { + let key = serialize_expr(ctx, sig.key.as_ref()); + let param = serialize_ts_fn_param(ctx, &sig.param); + + ctx.write_ts_setter_sig(&sig.span, key, param) + } + TsTypeElement::TsMethodSignature(sig) => { + let key = serialize_expr(ctx, &sig.key); + let type_parms = + maybe_serialize_ts_type_param_decl(ctx, &sig.type_params); + let params = sig + .params + .iter() + .map(|param| serialize_ts_fn_param(ctx, param)) + .collect::>(); + let return_type = maybe_serialize_ts_type_ann(ctx, &sig.type_ann); + + ctx.write_ts_method_sig( + &sig.span, + sig.computed, + sig.optional, + key, + type_parms, + params, + return_type, + ) + } + TsTypeElement::TsIndexSignature(sig) => serialize_ts_index_sig(ctx, sig), + } +} + fn serialize_ts_index_sig( ctx: &mut TsEsTreeBuilder, node: &TsIndexSignature, - parent: NodeRef, ) -> NodeRef { - let raw = ctx.header(AstNode::TSMethodSignature, parent, &node.span); - let readonly_pos = ctx.bool_field(AstProp::Readonly); - // TODO: where is this coming from? - let static_pos = ctx.bool_field(AstProp::Static); - let params_pos = ctx.ref_vec_field(AstProp::Params, node.params.len()); - let type_ann_pos = ctx.ref_field(AstProp::TypeAnnotation); - let pos = ctx.commit_schema(raw); - - let type_ann = maybe_serialize_ts_type_ann(ctx, &node.type_ann, pos); - let params = node .params .iter() - .map(|param| serialize_ts_fn_param(ctx, param, pos)) + .map(|param| serialize_ts_fn_param(ctx, param)) .collect::>(); + let type_ann = maybe_serialize_ts_type_ann(ctx, &node.type_ann); - ctx.write_bool(readonly_pos, false); - ctx.write_bool(static_pos, node.is_static); - ctx.write_refs(params_pos, params); - ctx.write_maybe_ref(type_ann_pos, type_ann); - - pos + ctx.write_ts_index_sig(&node.span, node.readonly, params, type_ann) } -fn accessibility_to_str(accessibility: Accessibility) -> String { +fn accessibility_to_str(accessibility: &Accessibility) -> String { match accessibility { Accessibility::Public => "public".to_string(), Accessibility::Protected => "protected".to_string(), @@ -2020,106 +1571,53 @@ fn accessibility_to_str(accessibility: Accessibility) -> String { fn serialize_private_name( ctx: &mut TsEsTreeBuilder, node: &PrivateName, - parent: NodeRef, ) -> NodeRef { - let raw = ctx.header(AstNode::PrivateIdentifier, parent, &node.span); - let name_pos = ctx.str_field(AstProp::Name); - let pos = ctx.commit_schema(raw); - - ctx.write_str(name_pos, node.name.as_str()); - - pos + ctx.write_private_identifier(&node.span, node.name.as_str()) } fn serialize_jsx_element( ctx: &mut TsEsTreeBuilder, node: &JSXElement, - parent: NodeRef, ) -> NodeRef { - let raw = ctx.header(AstNode::JSXElement, parent, &node.span); - let open_pos = ctx.ref_field(AstProp::OpeningElement); - let close_pos = ctx.ref_field(AstProp::ClosingElement); - let children_pos = ctx.ref_vec_field(AstProp::Children, node.children.len()); - let pos = ctx.commit_schema(raw); - - let open = serialize_jsx_opening_element(ctx, &node.opening, pos); + let open = serialize_jsx_opening_element(ctx, &node.opening); let close = node.closing.as_ref().map(|closing| { - let raw = ctx.header(AstNode::JSXClosingElement, pos, &closing.span); - let name_pos = ctx.ref_field(AstProp::Name); - let closing_pos = ctx.commit_schema(raw); - - let name = serialize_jsx_element_name(ctx, &closing.name, closing_pos); - ctx.write_ref(name_pos, name); - - closing_pos + let name = serialize_jsx_element_name(ctx, &closing.name); + ctx.write_jsx_closing_elem(&closing.span, name) }); - let children = serialize_jsx_children(ctx, &node.children, pos); + let children = serialize_jsx_children(ctx, &node.children); - ctx.write_ref(open_pos, open); - ctx.write_maybe_ref(close_pos, close); - ctx.write_refs(children_pos, children); - - pos + ctx.write_jsx_elem(&node.span, open, close, children) } fn serialize_jsx_fragment( ctx: &mut TsEsTreeBuilder, node: &JSXFragment, - parent: NodeRef, ) -> NodeRef { - let raw = ctx.header(AstNode::JSXFragment, parent, &node.span); + let opening = ctx.write_jsx_opening_frag(&node.opening.span); + let closing = ctx.write_jsx_closing_frag(&node.closing.span); + let children = serialize_jsx_children(ctx, &node.children); - let opening_pos = ctx.ref_field(AstProp::OpeningFragment); - let closing_pos = ctx.ref_field(AstProp::ClosingFragment); - let children_pos = ctx.ref_vec_field(AstProp::Children, node.children.len()); - let pos = ctx.commit_schema(raw); - - let raw = ctx.header(AstNode::JSXOpeningFragment, pos, &node.opening.span); - let opening_id = ctx.commit_schema(raw); - - let raw = ctx.header(AstNode::JSXClosingFragment, pos, &node.closing.span); - let closing_id = ctx.commit_schema(raw); - - let children = serialize_jsx_children(ctx, &node.children, pos); - - ctx.write_ref(opening_pos, opening_id); - ctx.write_ref(closing_pos, closing_id); - ctx.write_refs(children_pos, children); - - pos + ctx.write_jsx_frag(&node.span, opening, closing, children) } fn serialize_jsx_children( ctx: &mut TsEsTreeBuilder, children: &[JSXElementChild], - parent: NodeRef, ) -> Vec { children .iter() .map(|child| { match child { JSXElementChild::JSXText(text) => { - let raw = ctx.header(AstNode::JSXText, parent, &text.span); - let raw_pos = ctx.str_field(AstProp::Raw); - let value_pos = ctx.str_field(AstProp::Value); - let pos = ctx.commit_schema(raw); - - ctx.write_str(raw_pos, &text.raw); - ctx.write_str(value_pos, &text.value); - - pos + ctx.write_jsx_text(&text.span, &text.raw, &text.value) } JSXElementChild::JSXExprContainer(container) => { - serialize_jsx_container_expr(ctx, container, parent) - } - JSXElementChild::JSXElement(el) => { - serialize_jsx_element(ctx, el, parent) - } - JSXElementChild::JSXFragment(frag) => { - serialize_jsx_fragment(ctx, frag, parent) + serialize_jsx_container_expr(ctx, container) } + JSXElementChild::JSXElement(el) => serialize_jsx_element(ctx, el), + JSXElementChild::JSXFragment(frag) => serialize_jsx_fragment(ctx, frag), // No parser supports this JSXElementChild::JSXSpreadChild(_) => unreachable!(), } @@ -2130,42 +1628,28 @@ fn serialize_jsx_children( fn serialize_jsx_member_expr( ctx: &mut TsEsTreeBuilder, node: &JSXMemberExpr, - parent: NodeRef, ) -> NodeRef { - let raw = ctx.header(AstNode::JSXMemberExpression, parent, &node.span); - let obj_ref = ctx.ref_field(AstProp::Object); - let prop_ref = ctx.ref_field(AstProp::Property); - let pos = ctx.commit_schema(raw); - let obj = match &node.obj { - JSXObject::JSXMemberExpr(member) => { - serialize_jsx_member_expr(ctx, member, pos) - } - JSXObject::Ident(ident) => serialize_jsx_identifier(ctx, ident, parent), + JSXObject::JSXMemberExpr(member) => serialize_jsx_member_expr(ctx, member), + JSXObject::Ident(ident) => serialize_jsx_identifier(ctx, ident), }; - let prop = serialize_ident_name_as_jsx_identifier(ctx, &node.prop, pos); + let prop = serialize_ident_name_as_jsx_identifier(ctx, &node.prop); - ctx.write_ref(obj_ref, obj); - ctx.write_ref(prop_ref, prop); - - pos + ctx.write_jsx_member_expr(&node.span, obj, prop) } fn serialize_jsx_element_name( ctx: &mut TsEsTreeBuilder, node: &JSXElementName, - parent: NodeRef, ) -> NodeRef { match &node { - JSXElementName::Ident(ident) => { - serialize_jsx_identifier(ctx, ident, parent) - } + JSXElementName::Ident(ident) => serialize_jsx_identifier(ctx, ident), JSXElementName::JSXMemberExpr(member) => { - serialize_jsx_member_expr(ctx, member, parent) + serialize_jsx_member_expr(ctx, member) } JSXElementName::JSXNamespacedName(ns) => { - serialize_jsx_namespaced_name(ctx, ns, parent) + serialize_jsx_namespaced_name(ctx, ns) } } } @@ -2173,294 +1657,183 @@ fn serialize_jsx_element_name( fn serialize_jsx_opening_element( ctx: &mut TsEsTreeBuilder, node: &JSXOpeningElement, - parent: NodeRef, ) -> NodeRef { - let raw = ctx.header(AstNode::JSXOpeningElement, parent, &node.span); - let sclose_pos = ctx.bool_field(AstProp::SelfClosing); - let name_pos = ctx.ref_field(AstProp::Name); - let attrs_pos = ctx.ref_vec_field(AstProp::Attributes, node.attrs.len()); - let pos = ctx.commit_schema(raw); + let name = serialize_jsx_element_name(ctx, &node.name); - let name = serialize_jsx_element_name(ctx, &node.name, pos); - - // FIXME: type args + let type_args = node + .type_args + .as_ref() + .map(|arg| serialize_ts_param_inst(ctx, arg)); let attrs = node .attrs .iter() .map(|attr| match attr { JSXAttrOrSpread::JSXAttr(attr) => { - let raw = ctx.header(AstNode::JSXAttribute, pos, &attr.span); - let name_pos = ctx.ref_field(AstProp::Name); - let value_pos = ctx.ref_field(AstProp::Value); - let attr_pos = ctx.commit_schema(raw); - let name = match &attr.name { JSXAttrName::Ident(name) => { - serialize_ident_name_as_jsx_identifier(ctx, name, attr_pos) + serialize_ident_name_as_jsx_identifier(ctx, name) } JSXAttrName::JSXNamespacedName(node) => { - serialize_jsx_namespaced_name(ctx, node, attr_pos) + serialize_jsx_namespaced_name(ctx, node) } }; let value = attr.value.as_ref().map(|value| match value { - JSXAttrValue::Lit(lit) => serialize_lit(ctx, lit, attr_pos), + JSXAttrValue::Lit(lit) => serialize_lit(ctx, lit), JSXAttrValue::JSXExprContainer(container) => { - serialize_jsx_container_expr(ctx, container, attr_pos) - } - JSXAttrValue::JSXElement(el) => { - serialize_jsx_element(ctx, el, attr_pos) - } - JSXAttrValue::JSXFragment(frag) => { - serialize_jsx_fragment(ctx, frag, attr_pos) + serialize_jsx_container_expr(ctx, container) } + JSXAttrValue::JSXElement(el) => serialize_jsx_element(ctx, el), + JSXAttrValue::JSXFragment(frag) => serialize_jsx_fragment(ctx, frag), }); - ctx.write_ref(name_pos, name); - ctx.write_maybe_ref(value_pos, value); - - attr_pos + ctx.write_jsx_attr(&attr.span, name, value) } JSXAttrOrSpread::SpreadElement(spread) => { - let raw = ctx.header(AstNode::JSXAttribute, pos, &spread.dot3_token); - let arg_pos = ctx.ref_field(AstProp::Argument); - let attr_pos = ctx.commit_schema(raw); - - let arg = serialize_expr(ctx, &spread.expr, attr_pos); - - ctx.write_ref(arg_pos, arg); - - attr_pos + let arg = serialize_expr(ctx, &spread.expr); + ctx.write_jsx_spread_attr(&spread.dot3_token, arg) } }) .collect::>(); - ctx.write_bool(sclose_pos, node.self_closing); - ctx.write_ref(name_pos, name); - ctx.write_refs(attrs_pos, attrs); - - pos + ctx.write_jsx_opening_elem( + &node.span, + node.self_closing, + name, + attrs, + type_args, + ) } fn serialize_jsx_container_expr( ctx: &mut TsEsTreeBuilder, node: &JSXExprContainer, - parent: NodeRef, ) -> NodeRef { - let raw = ctx.header(AstNode::JSXExpressionContainer, parent, &node.span); - let expr_pos = ctx.ref_field(AstProp::Expression); - let pos = ctx.commit_schema(raw); - let expr = match &node.expr { - JSXExpr::JSXEmptyExpr(expr) => serialize_jsx_empty_expr(ctx, expr, pos), - JSXExpr::Expr(expr) => serialize_expr(ctx, expr, pos), + JSXExpr::JSXEmptyExpr(expr) => ctx.write_jsx_empty_expr(&expr.span), + JSXExpr::Expr(expr) => serialize_expr(ctx, expr), }; - ctx.write_ref(expr_pos, expr); - - pos -} - -fn serialize_jsx_empty_expr( - ctx: &mut TsEsTreeBuilder, - node: &JSXEmptyExpr, - parent: NodeRef, -) -> NodeRef { - let raw = ctx.header(AstNode::JSXEmptyExpression, parent, &node.span); - ctx.commit_schema(raw) + ctx.write_jsx_expr_container(&node.span, expr) } fn serialize_jsx_namespaced_name( ctx: &mut TsEsTreeBuilder, node: &JSXNamespacedName, - parent: NodeRef, ) -> NodeRef { - let raw = ctx.header(AstNode::JSXNamespacedName, parent, &node.span); - let ns_pos = ctx.ref_field(AstProp::Namespace); - let name_pos = ctx.ref_field(AstProp::Name); - let pos = ctx.commit_schema(raw); + let ns = ctx.write_jsx_identifier(&node.ns.span, &node.ns.sym); + let name = ctx.write_jsx_identifier(&node.name.span, &node.name.sym); - let ns_id = serialize_ident_name_as_jsx_identifier(ctx, &node.ns, pos); - let name_id = serialize_ident_name_as_jsx_identifier(ctx, &node.name, pos); - - ctx.write_ref(ns_pos, ns_id); - ctx.write_ref(name_pos, name_id); - - pos + ctx.write_jsx_namespaced_name(&node.span, ns, name) } fn serialize_ident_name_as_jsx_identifier( ctx: &mut TsEsTreeBuilder, node: &IdentName, - parent: NodeRef, ) -> NodeRef { - let raw = ctx.header(AstNode::JSXIdentifier, parent, &node.span); - let name_pos = ctx.str_field(AstProp::Name); - let pos = ctx.commit_schema(raw); - - ctx.write_str(name_pos, &node.sym); - - pos + ctx.write_jsx_identifier(&node.span, &node.sym) } fn serialize_jsx_identifier( ctx: &mut TsEsTreeBuilder, node: &Ident, - parent: NodeRef, ) -> NodeRef { - let raw = ctx.header(AstNode::JSXIdentifier, parent, &node.span); - let name_pos = ctx.str_field(AstProp::Name); - let pos = ctx.commit_schema(raw); - - ctx.write_str(name_pos, &node.sym); - - pos + ctx.write_jsx_identifier(&node.span, &node.sym) } -fn serialize_pat( - ctx: &mut TsEsTreeBuilder, - pat: &Pat, - parent: NodeRef, -) -> NodeRef { +fn serialize_pat(ctx: &mut TsEsTreeBuilder, pat: &Pat) -> NodeRef { match pat { - Pat::Ident(node) => serialize_ident(ctx, &node.id, parent), + Pat::Ident(node) => serialize_binding_ident(ctx, node), Pat::Array(node) => { - let raw = ctx.header(AstNode::ArrayPattern, parent, &node.span); - let opt_pos = ctx.bool_field(AstProp::Optional); - let type_pos = ctx.ref_field(AstProp::TypeAnnotation); - let elems_pos = ctx.ref_vec_field(AstProp::Elements, node.elems.len()); - let pos = ctx.commit_schema(raw); - - let type_ann = maybe_serialize_ts_type_ann(ctx, &node.type_ann, pos); + let type_ann = maybe_serialize_ts_type_ann(ctx, &node.type_ann); let children = node .elems .iter() - .map(|pat| { - pat - .as_ref() - .map_or(NodeRef(0), |v| serialize_pat(ctx, v, pos)) - }) + .map(|pat| pat.as_ref().map_or(NodeRef(0), |v| serialize_pat(ctx, v))) .collect::>(); - ctx.write_bool(opt_pos, node.optional); - ctx.write_maybe_ref(type_pos, type_ann); - ctx.write_refs(elems_pos, children); - - pos + ctx.write_arr_pat(&node.span, node.optional, type_ann, children) } Pat::Rest(node) => { - let raw = ctx.header(AstNode::RestElement, parent, &node.span); - let type_ann_pos = ctx.ref_field(AstProp::TypeAnnotation); - let arg_pos = ctx.ref_field(AstProp::Argument); - let pos = ctx.commit_schema(raw); + let type_ann = maybe_serialize_ts_type_ann(ctx, &node.type_ann); + let arg = serialize_pat(ctx, &node.arg); - let type_ann = maybe_serialize_ts_type_ann(ctx, &node.type_ann, pos); - let arg = serialize_pat(ctx, &node.arg, parent); - - ctx.write_maybe_ref(type_ann_pos, type_ann); - ctx.write_ref(arg_pos, arg); - - pos + ctx.write_rest_elem(&node.span, type_ann, arg) } Pat::Object(node) => { - let raw = ctx.header(AstNode::ObjectPattern, parent, &node.span); - let opt_pos = ctx.bool_field(AstProp::Optional); - let props_pos = ctx.ref_vec_field(AstProp::Properties, node.props.len()); - let type_ann_pos = ctx.ref_field(AstProp::TypeAnnotation); - let pos = ctx.commit_schema(raw); - - let type_ann = maybe_serialize_ts_type_ann(ctx, &node.type_ann, pos); + let type_ann = maybe_serialize_ts_type_ann(ctx, &node.type_ann); let children = node .props .iter() .map(|prop| match prop { ObjectPatProp::KeyValue(key_value_prop) => { - let raw = - ctx.header(AstNode::Property, pos, &key_value_prop.span()); - let computed_pos = ctx.bool_field(AstProp::Computed); - let key_pos = ctx.ref_field(AstProp::Key); - let value_pos = ctx.ref_field(AstProp::Value); - let child_pos = ctx.commit_schema(raw); - let computed = matches!(key_value_prop.key, PropName::Computed(_)); - let key = serialize_prop_name(ctx, &key_value_prop.key, child_pos); - let value = - serialize_pat(ctx, key_value_prop.value.as_ref(), child_pos); + let key = serialize_prop_name(ctx, &key_value_prop.key); + let value = serialize_pat(ctx, key_value_prop.value.as_ref()); - ctx.write_bool(computed_pos, computed); - ctx.write_ref(key_pos, key); - ctx.write_ref(value_pos, value); - - child_pos + ctx.write_property( + &key_value_prop.span(), + false, + computed, + false, + "init", + key, + value, + ) } ObjectPatProp::Assign(assign_pat_prop) => { - let raw = ctx.header(AstNode::Property, pos, &assign_pat_prop.span); - // TOOD: Doesn't seem to be present in SWC ast - let _computed_pos = ctx.bool_field(AstProp::Computed); - let key_pos = ctx.ref_field(AstProp::Key); - let value_pos = ctx.ref_field(AstProp::Value); - let child_pos = ctx.commit_schema(raw); - - let ident = serialize_ident(ctx, &assign_pat_prop.key.id, parent); + let ident = serialize_binding_ident(ctx, &assign_pat_prop.key); let value = assign_pat_prop .value .as_ref() - .map(|value| serialize_expr(ctx, value, child_pos)); + .map_or(NodeRef(0), |value| serialize_expr(ctx, value)); - ctx.write_ref(key_pos, ident); - ctx.write_maybe_ref(value_pos, value); - - child_pos + ctx.write_property( + &assign_pat_prop.span, + false, + false, + false, + "init", + ident, + value, + ) } ObjectPatProp::Rest(rest_pat) => { - serialize_pat(ctx, &Pat::Rest(rest_pat.clone()), parent) + serialize_pat(ctx, &Pat::Rest(rest_pat.clone())) } }) .collect::>(); - ctx.write_bool(opt_pos, node.optional); - ctx.write_maybe_ref(type_ann_pos, type_ann); - ctx.write_refs(props_pos, children); - - pos + ctx.write_obj_pat(&node.span, node.optional, type_ann, children) } Pat::Assign(node) => { - let raw = ctx.header(AstNode::AssignmentPattern, parent, &node.span); - let left_pos = ctx.ref_field(AstProp::Left); - let right_pos = ctx.ref_field(AstProp::Right); - let pos = ctx.commit_schema(raw); + let left = serialize_pat(ctx, &node.left); + let right = serialize_expr(ctx, &node.right); - let left = serialize_pat(ctx, &node.left, pos); - let right = serialize_expr(ctx, &node.right, pos); - - ctx.write_ref(left_pos, left); - ctx.write_ref(right_pos, right); - - pos + ctx.write_assign_pat(&node.span, left, right) } Pat::Invalid(_) => unreachable!(), - Pat::Expr(node) => serialize_expr(ctx, node, parent), + Pat::Expr(node) => serialize_expr(ctx, node), } } fn serialize_for_head( ctx: &mut TsEsTreeBuilder, for_head: &ForHead, - parent: NodeRef, ) -> NodeRef { match for_head { ForHead::VarDecl(var_decl) => { - serialize_decl(ctx, &Decl::Var(var_decl.clone()), parent) + serialize_decl(ctx, &Decl::Var(var_decl.clone())) } ForHead::UsingDecl(using_decl) => { - serialize_decl(ctx, &Decl::Using(using_decl.clone()), parent) + serialize_decl(ctx, &Decl::Using(using_decl.clone())) } - ForHead::Pat(pat) => serialize_pat(ctx, pat, parent), + ForHead::Pat(pat) => serialize_pat(ctx, pat), } } @@ -2468,471 +1841,634 @@ fn serialize_spread( ctx: &mut TsEsTreeBuilder, expr: &Expr, span: &Span, - parent: NodeRef, ) -> NodeRef { - let raw = ctx.header(AstNode::SpreadElement, parent, span); - let arg_pos = ctx.ref_field(AstProp::Argument); - let pos = ctx.commit_schema(raw); - - let expr_pos = serialize_expr(ctx, expr, parent); - ctx.write_ref(arg_pos, expr_pos); - - pos + let expr = serialize_expr(ctx, expr); + ctx.write_spread(span, expr) } fn serialize_ident_name( ctx: &mut TsEsTreeBuilder, ident_name: &IdentName, - parent: NodeRef, ) -> NodeRef { - let raw = ctx.header(AstNode::Identifier, parent, &ident_name.span); - let name_pos = ctx.str_field(AstProp::Name); - let pos = ctx.commit_schema(raw); - - ctx.write_str(name_pos, ident_name.sym.as_str()); - - pos + ctx.write_identifier(&ident_name.span, ident_name.sym.as_str(), false, None) } fn serialize_prop_name( ctx: &mut TsEsTreeBuilder, prop_name: &PropName, - parent: NodeRef, ) -> NodeRef { match prop_name { - PropName::Ident(ident_name) => { - serialize_ident_name(ctx, ident_name, parent) - } - PropName::Str(str_prop) => { - let raw = ctx.header(AstNode::StringLiteral, parent, &str_prop.span); - let value_pos = ctx.str_field(AstProp::Value); - ctx.write_str(value_pos, &str_prop.value); - ctx.commit_schema(raw) - } - PropName::Num(number) => { - serialize_lit(ctx, &Lit::Num(number.clone()), parent) - } - PropName::Computed(node) => serialize_expr(ctx, &node.expr, parent), + PropName::Ident(ident_name) => serialize_ident_name(ctx, ident_name), + PropName::Str(str_prop) => serialize_lit(ctx, &Lit::Str(str_prop.clone())), + PropName::Num(number) => serialize_lit(ctx, &Lit::Num(number.clone())), + PropName::Computed(node) => serialize_expr(ctx, &node.expr), PropName::BigInt(big_int) => { - serialize_lit(ctx, &Lit::BigInt(big_int.clone()), parent) + serialize_lit(ctx, &Lit::BigInt(big_int.clone())) } } } -fn serialize_lit( - ctx: &mut TsEsTreeBuilder, - lit: &Lit, - parent: NodeRef, -) -> NodeRef { +fn serialize_lit(ctx: &mut TsEsTreeBuilder, lit: &Lit) -> NodeRef { match lit { Lit::Str(node) => { - let raw = ctx.header(AstNode::StringLiteral, parent, &node.span); - let value_pos = ctx.str_field(AstProp::Value); - let pos = ctx.commit_schema(raw); + let raw_value = if let Some(v) = &node.raw { + v.to_string() + } else { + format!("{}", node.value).to_string() + }; - ctx.write_str(value_pos, &node.value); - - pos - } - Lit::Bool(lit_bool) => { - let raw = ctx.header(AstNode::Bool, parent, &lit_bool.span); - let value_pos = ctx.bool_field(AstProp::Value); - let pos = ctx.commit_schema(raw); - - ctx.write_bool(value_pos, lit_bool.value); - - pos - } - Lit::Null(node) => { - let raw = ctx.header(AstNode::Null, parent, &node.span); - ctx.commit_schema(raw) + ctx.write_str_lit(&node.span, &node.value, &raw_value) } + Lit::Bool(node) => ctx.write_bool_lit(&node.span, node.value), + Lit::Null(node) => ctx.write_null_lit(&node.span), Lit::Num(node) => { - let raw = ctx.header(AstNode::NumericLiteral, parent, &node.span); - let value_pos = ctx.str_field(AstProp::Value); - let pos = ctx.commit_schema(raw); + let raw_value = if let Some(v) = &node.raw { + v.to_string() + } else { + format!("{}", node.value).to_string() + }; let value = node.raw.as_ref().unwrap(); - ctx.write_str(value_pos, value); - - pos + ctx.write_num_lit(&node.span, value, &raw_value) } Lit::BigInt(node) => { - let raw = ctx.header(AstNode::BigIntLiteral, parent, &node.span); - let value_pos = ctx.str_field(AstProp::Value); - let pos = ctx.commit_schema(raw); + let raw_bigint_value = if let Some(v) = &node.raw { + let mut s = v.to_string(); + s.pop(); + s.to_string() + } else { + format!("{}", node.value).to_string() + }; - ctx.write_str(value_pos, &node.value.to_string()); + let raw_value = if let Some(v) = &node.raw { + v.to_string() + } else { + format!("{}", node.value).to_string() + }; - pos + ctx.write_bigint_lit( + &node.span, + &node.value.to_string(), + &raw_value, + &raw_bigint_value, + ) } Lit::Regex(node) => { - let raw = ctx.header(AstNode::RegExpLiteral, parent, &node.span); - let pattern_pos = ctx.str_field(AstProp::Pattern); - let flags_pos = ctx.str_field(AstProp::Flags); - let pos = ctx.commit_schema(raw); + let raw = format!("/{}/{}", node.exp.as_str(), node.flags.as_str()); - ctx.write_str(pattern_pos, node.exp.as_str()); - ctx.write_str(flags_pos, node.flags.as_str()); - - pos + ctx.write_regex_lit( + &node.span, + node.exp.as_str(), + node.flags.as_str(), + &raw, + &raw, + ) } - Lit::JSXText(jsxtext) => { - let raw = ctx.header(AstNode::JSXText, parent, &jsxtext.span); - ctx.commit_schema(raw) + Lit::JSXText(node) => { + ctx.write_jsx_text(&node.span, &node.raw, &node.value) } } } +fn serialize_class_member( + ctx: &mut TsEsTreeBuilder, + member: &ClassMember, +) -> Option { + match member { + ClassMember::Constructor(node) => { + let a11y = node.accessibility.as_ref().map(accessibility_to_str); + + let key = serialize_prop_name(ctx, &node.key); + let params = node + .params + .iter() + .map(|param| match param { + ParamOrTsParamProp::TsParamProp(prop) => { + let a11y = node.accessibility.as_ref().map(accessibility_to_str); + + let decorators = prop + .decorators + .iter() + .map(|deco| serialize_decorator(ctx, deco)) + .collect::>(); + + let paramter = match &prop.param { + TsParamPropParam::Ident(binding_ident) => { + serialize_binding_ident(ctx, binding_ident) + } + TsParamPropParam::Assign(assign_pat) => { + serialize_pat(ctx, &Pat::Assign(assign_pat.clone())) + } + }; + + ctx.write_ts_param_prop( + &prop.span, + prop.is_override, + prop.readonly, + a11y, + decorators, + paramter, + ) + } + ParamOrTsParamProp::Param(param) => serialize_pat(ctx, ¶m.pat), + }) + .collect::>(); + + let body = node + .body + .as_ref() + .map(|body| serialize_stmt(ctx, &Stmt::Block(body.clone()))); + + let value = ctx.write_fn_expr( + &node.span, false, false, None, None, params, None, body, + ); + + Some(ctx.write_class_method( + &node.span, + false, + false, + node.is_optional, + false, + false, + "constructor", + a11y, + key, + value, + )) + } + ClassMember::Method(node) => { + let key = serialize_prop_name(ctx, &node.key); + + Some(serialize_class_method( + ctx, + &node.span, + node.is_abstract, + node.is_override, + node.is_optional, + node.is_static, + node.accessibility, + &node.kind, + key, + &node.function, + )) + } + ClassMember::PrivateMethod(node) => { + let key = serialize_private_name(ctx, &node.key); + + Some(serialize_class_method( + ctx, + &node.span, + node.is_abstract, + node.is_override, + node.is_optional, + node.is_static, + node.accessibility, + &node.kind, + key, + &node.function, + )) + } + ClassMember::ClassProp(node) => { + let a11y = node.accessibility.as_ref().map(accessibility_to_str); + + let key = serialize_prop_name(ctx, &node.key); + let value = node.value.as_ref().map(|expr| serialize_expr(ctx, expr)); + + let decorators = node + .decorators + .iter() + .map(|deco| serialize_decorator(ctx, deco)) + .collect::>(); + + Some(ctx.write_class_prop( + &node.span, + node.declare, + false, + node.is_optional, + node.is_override, + node.readonly, + node.is_static, + a11y, + decorators, + key, + value, + )) + } + ClassMember::PrivateProp(node) => { + let a11y = node.accessibility.as_ref().map(accessibility_to_str); + + let decorators = node + .decorators + .iter() + .map(|deco| serialize_decorator(ctx, deco)) + .collect::>(); + + let key = serialize_private_name(ctx, &node.key); + + let value = node.value.as_ref().map(|expr| serialize_expr(ctx, expr)); + + Some(ctx.write_class_prop( + &node.span, + false, + false, + node.is_optional, + node.is_override, + node.readonly, + node.is_static, + a11y, + decorators, + key, + value, + )) + } + ClassMember::TsIndexSignature(node) => { + Some(serialize_ts_index_sig(ctx, node)) + } + ClassMember::Empty(_) => None, + ClassMember::StaticBlock(node) => { + let body = serialize_stmt(ctx, &Stmt::Block(node.body.clone())); + Some(ctx.write_static_block(&node.span, body)) + } + ClassMember::AutoAccessor(node) => { + let a11y = node.accessibility.as_ref().map(accessibility_to_str); + let decorators = node + .decorators + .iter() + .map(|deco| serialize_decorator(ctx, deco)) + .collect::>(); + + let key = match &node.key { + Key::Private(private_name) => serialize_private_name(ctx, private_name), + Key::Public(prop_name) => serialize_prop_name(ctx, prop_name), + }; + + let value = node.value.as_ref().map(|expr| serialize_expr(ctx, expr)); + + Some(ctx.write_accessor_property( + &node.span, + false, + false, + false, + node.is_override, + false, + node.is_static, + a11y, + decorators, + key, + value, + )) + } + } +} + +#[allow(clippy::too_many_arguments)] +fn serialize_class_method( + ctx: &mut TsEsTreeBuilder, + span: &Span, + is_abstract: bool, + is_override: bool, + is_optional: bool, + is_static: bool, + accessibility: Option, + method_kind: &MethodKind, + key: NodeRef, + function: &Function, +) -> NodeRef { + let kind = match method_kind { + MethodKind::Method => "method", + MethodKind::Getter => "getter", + MethodKind::Setter => "setter", + }; + + let type_params = + maybe_serialize_ts_type_param_decl(ctx, &function.type_params); + let params = function + .params + .iter() + .map(|param| serialize_pat(ctx, ¶m.pat)) + .collect::>(); + + let return_type = maybe_serialize_ts_type_ann(ctx, &function.return_type); + + let body = function + .body + .as_ref() + .map(|body| serialize_stmt(ctx, &Stmt::Block(body.clone()))); + + let value = if let Some(body) = body { + ctx.write_fn_expr( + &function.span, + function.is_async, + function.is_generator, + None, + type_params, + params, + return_type, + Some(body), + ) + } else { + ctx.write_ts_empty_body_fn_expr( + span, + false, + false, + function.is_async, + function.is_generator, + None, + type_params, + params, + return_type, + ) + }; + + let a11y = accessibility.as_ref().map(accessibility_to_str); + + if is_abstract { + ctx.write_ts_abstract_method_def( + span, + false, + is_optional, + is_override, + false, + a11y, + key, + value, + ) + } else { + ctx.write_class_method( + span, + false, + false, + is_optional, + is_override, + is_static, + kind, + a11y, + key, + value, + ) + } +} + +fn serialize_ts_expr_with_type_args( + ctx: &mut TsEsTreeBuilder, + node: &TsExprWithTypeArgs, +) -> NodeRef { + let expr = serialize_expr(ctx, &node.expr); + let type_args = node + .type_args + .as_ref() + .map(|arg| serialize_ts_param_inst(ctx, arg)); + + ctx.write_ts_class_implements(&node.span, expr, type_args) +} + +fn serialize_decorator(ctx: &mut TsEsTreeBuilder, node: &Decorator) -> NodeRef { + let expr = serialize_expr(ctx, &node.expr); + ctx.write_decorator(&node.span, expr) +} + +fn serialize_binding_ident( + ctx: &mut TsEsTreeBuilder, + node: &BindingIdent, +) -> NodeRef { + let type_ann = maybe_serialize_ts_type_ann(ctx, &node.type_ann); + ctx.write_identifier(&node.span, &node.sym, node.optional, type_ann) +} + fn serialize_ts_param_inst( ctx: &mut TsEsTreeBuilder, node: &TsTypeParamInstantiation, - parent: NodeRef, ) -> NodeRef { - let raw = - ctx.header(AstNode::TSTypeParameterInstantiation, parent, &node.span); - let params_pos = ctx.ref_vec_field(AstProp::Params, node.params.len()); - let pos = ctx.commit_schema(raw); - let params = node .params .iter() - .map(|param| serialize_ts_type(ctx, param, pos)) + .map(|param| serialize_ts_type(ctx, param)) .collect::>(); - ctx.write_refs(params_pos, params); - - pos + ctx.write_ts_type_param_inst(&node.span, params) } -fn serialize_ts_type( - ctx: &mut TsEsTreeBuilder, - node: &TsType, - parent: NodeRef, -) -> NodeRef { +fn serialize_ts_type(ctx: &mut TsEsTreeBuilder, node: &TsType) -> NodeRef { match node { TsType::TsKeywordType(node) => { let kind = match node.kind { - TsKeywordTypeKind::TsAnyKeyword => AstNode::TSAnyKeyword, - TsKeywordTypeKind::TsUnknownKeyword => AstNode::TSUnknownKeyword, - TsKeywordTypeKind::TsNumberKeyword => AstNode::TSNumberKeyword, - TsKeywordTypeKind::TsObjectKeyword => AstNode::TSObjectKeyword, - TsKeywordTypeKind::TsBooleanKeyword => AstNode::TSBooleanKeyword, - TsKeywordTypeKind::TsBigIntKeyword => AstNode::TSBigIntKeyword, - TsKeywordTypeKind::TsStringKeyword => AstNode::TSStringKeyword, - TsKeywordTypeKind::TsSymbolKeyword => AstNode::TSSymbolKeyword, - TsKeywordTypeKind::TsVoidKeyword => AstNode::TSVoidKeyword, - TsKeywordTypeKind::TsUndefinedKeyword => AstNode::TSUndefinedKeyword, - TsKeywordTypeKind::TsNullKeyword => AstNode::TSNullKeyword, - TsKeywordTypeKind::TsNeverKeyword => AstNode::TSNeverKeyword, - TsKeywordTypeKind::TsIntrinsicKeyword => AstNode::TSIntrinsicKeyword, + TsKeywordTypeKind::TsAnyKeyword => TsKeywordKind::Any, + TsKeywordTypeKind::TsUnknownKeyword => TsKeywordKind::Unknown, + TsKeywordTypeKind::TsNumberKeyword => TsKeywordKind::Number, + TsKeywordTypeKind::TsObjectKeyword => TsKeywordKind::Object, + TsKeywordTypeKind::TsBooleanKeyword => TsKeywordKind::Boolean, + TsKeywordTypeKind::TsBigIntKeyword => TsKeywordKind::BigInt, + TsKeywordTypeKind::TsStringKeyword => TsKeywordKind::String, + TsKeywordTypeKind::TsSymbolKeyword => TsKeywordKind::Symbol, + TsKeywordTypeKind::TsVoidKeyword => TsKeywordKind::Void, + TsKeywordTypeKind::TsUndefinedKeyword => TsKeywordKind::Undefined, + TsKeywordTypeKind::TsNullKeyword => TsKeywordKind::Null, + TsKeywordTypeKind::TsNeverKeyword => TsKeywordKind::Never, + TsKeywordTypeKind::TsIntrinsicKeyword => TsKeywordKind::Intrinsic, }; - let raw = ctx.header(kind, parent, &node.span); - ctx.commit_schema(raw) - } - TsType::TsThisType(node) => { - let raw = ctx.header(AstNode::TSThisType, parent, &node.span); - ctx.commit_schema(raw) + ctx.write_ts_keyword(kind, &node.span) } + TsType::TsThisType(node) => ctx.write_ts_this_type(&node.span), TsType::TsFnOrConstructorType(node) => match node { TsFnOrConstructorType::TsFnType(node) => { - let raw = ctx.header(AstNode::TSFunctionType, parent, &node.span); - let params_pos = ctx.ref_vec_field(AstProp::Params, node.params.len()); - let pos = ctx.commit_schema(raw); - let param_ids = node .params .iter() - .map(|param| serialize_ts_fn_param(ctx, param, pos)) + .map(|param| serialize_ts_fn_param(ctx, param)) .collect::>(); - ctx.write_refs(params_pos, param_ids); - - pos + ctx.write_ts_fn_type(&node.span, param_ids) } - TsFnOrConstructorType::TsConstructorType(_) => { - todo!() + TsFnOrConstructorType::TsConstructorType(node) => { + // interface Foo { new(arg1: any): any } + let type_params = node + .type_params + .as_ref() + .map(|param| serialize_ts_type_param_decl(ctx, param)); + + let params = node + .params + .iter() + .map(|param| serialize_ts_fn_param(ctx, param)) + .collect::>(); + + let return_type = serialize_ts_type_ann(ctx, node.type_ann.as_ref()); + + ctx.write_ts_construct_sig(&node.span, type_params, params, return_type) } }, TsType::TsTypeRef(node) => { - let raw = ctx.header(AstNode::TSTypeReference, parent, &node.span); - let name_pos = ctx.ref_field(AstProp::TypeName); - let type_args_pos = ctx.ref_field(AstProp::TypeArguments); - let pos = ctx.commit_schema(raw); - - let name = serialize_ts_entity_name(ctx, &node.type_name, pos); + let name = serialize_ts_entity_name(ctx, &node.type_name); let type_args = node .type_params .clone() - .map(|param| serialize_ts_param_inst(ctx, ¶m, pos)); + .map(|param| serialize_ts_param_inst(ctx, ¶m)); - ctx.write_ref(name_pos, name); - ctx.write_maybe_ref(type_args_pos, type_args); - - pos + ctx.write_ts_type_ref(&node.span, name, type_args) } TsType::TsTypeQuery(node) => { - let raw = ctx.header(AstNode::TSTypeQuery, parent, &node.span); - let name_pos = ctx.ref_field(AstProp::ExprName); - let type_args_pos = ctx.ref_field(AstProp::TypeArguments); - let pos = ctx.commit_schema(raw); - let expr_name = match &node.expr_name { TsTypeQueryExpr::TsEntityName(entity) => { - serialize_ts_entity_name(ctx, entity, pos) + serialize_ts_entity_name(ctx, entity) } TsTypeQueryExpr::Import(child) => { - serialize_ts_type(ctx, &TsType::TsImportType(child.clone()), pos) + serialize_ts_type(ctx, &TsType::TsImportType(child.clone())) } }; let type_args = node .type_args .clone() - .map(|param| serialize_ts_param_inst(ctx, ¶m, pos)); + .map(|param| serialize_ts_param_inst(ctx, ¶m)); - ctx.write_ref(name_pos, expr_name); - ctx.write_maybe_ref(type_args_pos, type_args); - - pos + ctx.write_ts_type_query(&node.span, expr_name, type_args) } - TsType::TsTypeLit(_) => { - // TODO: Not sure what this is - todo!() + TsType::TsTypeLit(node) => { + let members = node + .members + .iter() + .map(|member| serialize_ts_type_elem(ctx, member)) + .collect::>(); + + ctx.write_ts_type_lit(&node.span, members) } TsType::TsArrayType(node) => { - let raw = ctx.header(AstNode::TSArrayType, parent, &node.span); - let elem_pos = ctx.ref_field(AstProp::ElementType); - let pos = ctx.commit_schema(raw); - - let elem = serialize_ts_type(ctx, &node.elem_type, pos); - - ctx.write_ref(elem_pos, elem); - - pos + let elem = serialize_ts_type(ctx, &node.elem_type); + ctx.write_ts_array_type(&node.span, elem) } TsType::TsTupleType(node) => { - let raw = ctx.header(AstNode::TSTupleType, parent, &node.span); - let children_pos = - ctx.ref_vec_field(AstProp::ElementTypes, node.elem_types.len()); - let pos = ctx.commit_schema(raw); - let children = node .elem_types .iter() .map(|elem| { if let Some(label) = &elem.label { - let raw = ctx.header(AstNode::TSNamedTupleMember, pos, &elem.span); - let label_pos = ctx.ref_field(AstProp::Label); - let type_pos = ctx.ref_field(AstProp::ElementType); - let child_pos = ctx.commit_schema(raw); + let label = serialize_pat(ctx, label); + let type_id = serialize_ts_type(ctx, elem.ty.as_ref()); - let label_id = serialize_pat(ctx, label, child_pos); - let type_id = serialize_ts_type(ctx, elem.ty.as_ref(), child_pos); - - ctx.write_ref(label_pos, label_id); - ctx.write_ref(type_pos, type_id); - - child_pos + ctx.write_ts_named_tuple_member(&elem.span, label, type_id) } else { - serialize_ts_type(ctx, elem.ty.as_ref(), pos) + serialize_ts_type(ctx, elem.ty.as_ref()) } }) .collect::>(); - ctx.write_refs(children_pos, children); - - pos + ctx.write_ts_tuple_type(&node.span, children) + } + TsType::TsOptionalType(node) => { + let type_ann = serialize_ts_type(ctx, &node.type_ann); + ctx.write_ts_optional_type(&node.span, type_ann) } - TsType::TsOptionalType(_) => todo!(), TsType::TsRestType(node) => { - let raw = ctx.header(AstNode::TSRestType, parent, &node.span); - let type_ann_pos = ctx.ref_field(AstProp::TypeAnnotation); - let pos = ctx.commit_schema(raw); - - let type_ann = serialize_ts_type(ctx, &node.type_ann, pos); - - ctx.write_ref(type_ann_pos, type_ann); - - pos + let type_ann = serialize_ts_type(ctx, &node.type_ann); + ctx.write_ts_rest_type(&node.span, type_ann) } TsType::TsUnionOrIntersectionType(node) => match node { TsUnionOrIntersectionType::TsUnionType(node) => { - let raw = ctx.header(AstNode::TSUnionType, parent, &node.span); - let types_pos = ctx.ref_vec_field(AstProp::Types, node.types.len()); - let pos = ctx.commit_schema(raw); - let children = node .types .iter() - .map(|item| serialize_ts_type(ctx, item, pos)) + .map(|item| serialize_ts_type(ctx, item)) .collect::>(); - ctx.write_refs(types_pos, children); - - pos + ctx.write_ts_union_type(&node.span, children) } TsUnionOrIntersectionType::TsIntersectionType(node) => { - let raw = ctx.header(AstNode::TSIntersectionType, parent, &node.span); - let types_pos = ctx.ref_vec_field(AstProp::Types, node.types.len()); - let pos = ctx.commit_schema(raw); - let children = node .types .iter() - .map(|item| serialize_ts_type(ctx, item, pos)) + .map(|item| serialize_ts_type(ctx, item)) .collect::>(); - ctx.write_refs(types_pos, children); - - pos + ctx.write_ts_intersection_type(&node.span, children) } }, TsType::TsConditionalType(node) => { - let raw = ctx.header(AstNode::TSConditionalType, parent, &node.span); - let check_pos = ctx.ref_field(AstProp::CheckType); - let extends_pos = ctx.ref_field(AstProp::ExtendsType); - let true_pos = ctx.ref_field(AstProp::TrueType); - let false_pos = ctx.ref_field(AstProp::FalseType); - let pos = ctx.commit_schema(raw); + let check = serialize_ts_type(ctx, &node.check_type); + let extends = serialize_ts_type(ctx, &node.extends_type); + let v_true = serialize_ts_type(ctx, &node.true_type); + let v_false = serialize_ts_type(ctx, &node.false_type); - let check = serialize_ts_type(ctx, &node.check_type, pos); - let extends = serialize_ts_type(ctx, &node.extends_type, pos); - let v_true = serialize_ts_type(ctx, &node.true_type, pos); - let v_false = serialize_ts_type(ctx, &node.false_type, pos); - - ctx.write_ref(check_pos, check); - ctx.write_ref(extends_pos, extends); - ctx.write_ref(true_pos, v_true); - ctx.write_ref(false_pos, v_false); - - pos + ctx.write_ts_conditional_type(&node.span, check, extends, v_true, v_false) } TsType::TsInferType(node) => { - let raw = ctx.header(AstNode::TSInferType, parent, &node.span); - let param_pos = ctx.ref_field(AstProp::TypeParameter); - let pos = ctx.commit_schema(raw); - - let param = serialize_ts_type_param(ctx, &node.type_param, parent); - - ctx.write_ref(param_pos, param); - - pos + let param = serialize_ts_type_param(ctx, &node.type_param); + ctx.write_ts_infer_type(&node.span, param) + } + TsType::TsParenthesizedType(node) => { + // Not materialized in TSEstree + serialize_ts_type(ctx, &node.type_ann) } - TsType::TsParenthesizedType(_) => todo!(), TsType::TsTypeOperator(node) => { - let raw = ctx.header(AstNode::TSTypeOperator, parent, &node.span); - let operator_pos = ctx.str_field(AstProp::Operator); - let type_ann_pos = ctx.ref_field(AstProp::TypeAnnotation); - let pos = ctx.commit_schema(raw); + let type_ann = serialize_ts_type(ctx, &node.type_ann); - let type_ann = serialize_ts_type(ctx, &node.type_ann, pos); - - ctx.write_str( - operator_pos, - match node.op { - TsTypeOperatorOp::KeyOf => "keyof", - TsTypeOperatorOp::Unique => "unique", - TsTypeOperatorOp::ReadOnly => "readonly", - }, - ); - ctx.write_ref(type_ann_pos, type_ann); - - pos - } - TsType::TsIndexedAccessType(node) => { - let raw = ctx.header(AstNode::TSIndexedAccessType, parent, &node.span); - let index_type_pos = ctx.ref_field(AstProp::IndexType); - let obj_type_pos = ctx.ref_field(AstProp::ObjectType); - let pos = ctx.commit_schema(raw); - - let index = serialize_ts_type(ctx, &node.index_type, pos); - let obj = serialize_ts_type(ctx, &node.obj_type, pos); - - ctx.write_ref(index_type_pos, index); - ctx.write_ref(obj_type_pos, obj); - - pos - } - TsType::TsMappedType(node) => { - let raw = ctx.header(AstNode::TSMappedType, parent, &node.span); - let name_pos = ctx.ref_field(AstProp::NameType); - let type_ann_pos = ctx.ref_field(AstProp::TypeAnnotation); - let type_param_pos = ctx.ref_field(AstProp::TypeParameter); - let pos = ctx.commit_schema(raw); - - let opt_pos = - create_true_plus_minus_field(ctx, AstProp::Optional, node.optional); - let readonly_pos = - create_true_plus_minus_field(ctx, AstProp::Readonly, node.readonly); - - let name_id = maybe_serialize_ts_type(ctx, &node.name_type, pos); - let type_ann = maybe_serialize_ts_type(ctx, &node.type_ann, pos); - let type_param = serialize_ts_type_param(ctx, &node.type_param, pos); - - write_true_plus_minus(ctx, opt_pos, node.optional); - write_true_plus_minus(ctx, readonly_pos, node.readonly); - ctx.write_maybe_ref(name_pos, name_id); - ctx.write_maybe_ref(type_ann_pos, type_ann); - ctx.write_ref(type_param_pos, type_param); - - pos - } - TsType::TsLitType(node) => serialize_ts_lit_type(ctx, node, parent), - TsType::TsTypePredicate(node) => { - let raw = ctx.header(AstNode::TSTypePredicate, parent, &node.span); - let asserts_pos = ctx.bool_field(AstProp::Asserts); - let param_name_pos = ctx.ref_field(AstProp::ParameterName); - let type_ann_pos = ctx.ref_field(AstProp::TypeAnnotation); - let pos = ctx.commit_schema(raw); - - let param_name = match &node.param_name { - TsThisTypeOrIdent::TsThisType(ts_this_type) => { - let raw = ctx.header(AstNode::TSThisType, pos, &ts_this_type.span); - ctx.commit_schema(raw) - } - TsThisTypeOrIdent::Ident(ident) => serialize_ident(ctx, ident, pos), + let op = match node.op { + TsTypeOperatorOp::KeyOf => "keyof", + TsTypeOperatorOp::Unique => "unique", + TsTypeOperatorOp::ReadOnly => "readonly", }; - let type_ann = maybe_serialize_ts_type_ann(ctx, &node.type_ann, pos); + ctx.write_ts_type_op(&node.span, op, type_ann) + } + TsType::TsIndexedAccessType(node) => { + let index = serialize_ts_type(ctx, &node.index_type); + let obj = serialize_ts_type(ctx, &node.obj_type); - ctx.write_bool(asserts_pos, node.asserts); - ctx.write_ref(param_name_pos, param_name); - ctx.write_maybe_ref(type_ann_pos, type_ann); + ctx.write_ts_indexed_access_type(&node.span, index, obj) + } + TsType::TsMappedType(node) => { + let name = maybe_serialize_ts_type(ctx, &node.name_type); + let type_ann = maybe_serialize_ts_type(ctx, &node.type_ann); + let type_param = serialize_ts_type_param(ctx, &node.type_param); - pos + ctx.write_ts_mapped_type( + &node.span, + node.readonly, + node.optional, + name, + type_ann, + type_param, + ) + } + TsType::TsLitType(node) => serialize_ts_lit_type(ctx, node), + TsType::TsTypePredicate(node) => { + let param_name = match &node.param_name { + TsThisTypeOrIdent::TsThisType(node) => { + ctx.write_ts_this_type(&node.span) + } + TsThisTypeOrIdent::Ident(ident) => serialize_ident(ctx, ident, None), + }; + + let type_ann = maybe_serialize_ts_type_ann(ctx, &node.type_ann); + + ctx.write_ts_type_predicate( + &node.span, + node.asserts, + param_name, + type_ann, + ) } TsType::TsImportType(node) => { - let raw = ctx.header(AstNode::TSTypePredicate, parent, &node.span); - let arg_pos = ctx.ref_field(AstProp::Argument); - let type_args_pos = ctx.ref_field(AstProp::TypeArguments); - let qualifier_pos = ctx.ref_field(AstProp::Qualifier); - let pos = ctx.commit_schema(raw); - let arg = serialize_ts_lit_type( ctx, &TsLitType { lit: TsLit::Str(node.arg.clone()), span: node.arg.span, }, - pos, ); - let type_arg = node.type_args.clone().map(|param_node| { - serialize_ts_param_inst(ctx, param_node.as_ref(), pos) - }); + let type_arg = node + .type_args + .clone() + .map(|param_node| serialize_ts_param_inst(ctx, param_node.as_ref())); - let qualifier = node.qualifier.clone().map_or(NodeRef(0), |quali| { - serialize_ts_entity_name(ctx, &quali, pos) - }); + let qualifier = node + .qualifier + .clone() + .map(|quali| serialize_ts_entity_name(ctx, &quali)); - ctx.write_ref(arg_pos, arg); - ctx.write_ref(qualifier_pos, qualifier); - ctx.write_maybe_ref(type_args_pos, type_arg); - - pos + ctx.write_ts_import_type(&node.span, arg, qualifier, type_arg) } } } @@ -2940,80 +2476,47 @@ fn serialize_ts_type( fn serialize_ts_lit_type( ctx: &mut TsEsTreeBuilder, node: &TsLitType, - parent: NodeRef, ) -> NodeRef { - let raw = ctx.header(AstNode::TSLiteralType, parent, &node.span); - let lit_pos = ctx.ref_field(AstProp::Literal); - let pos = ctx.commit_schema(raw); - - let lit = match &node.lit { - TsLit::Number(lit) => serialize_lit(ctx, &Lit::Num(lit.clone()), pos), - TsLit::Str(lit) => serialize_lit(ctx, &Lit::Str(lit.clone()), pos), - TsLit::Bool(lit) => serialize_lit(ctx, &Lit::Bool(*lit), pos), - TsLit::BigInt(lit) => serialize_lit(ctx, &Lit::BigInt(lit.clone()), pos), - TsLit::Tpl(lit) => serialize_expr( - ctx, - &Expr::Tpl(Tpl { - span: lit.span, - exprs: vec![], - quasis: lit.quasis.clone(), - }), - pos, - ), - }; - - ctx.write_ref(lit_pos, lit); - - pos -} - -fn create_true_plus_minus_field( - ctx: &mut TsEsTreeBuilder, - prop: AstProp, - value: Option, -) -> NodePos { - if let Some(v) = value { - match v { - TruePlusMinus::True => NodePos::Bool(ctx.bool_field(prop)), - TruePlusMinus::Plus | TruePlusMinus::Minus => { - NodePos::Str(ctx.str_field(prop)) - } + match &node.lit { + TsLit::Number(lit) => { + let lit = serialize_lit(ctx, &Lit::Num(lit.clone())); + ctx.write_ts_lit_type(&node.span, lit) } - } else { - NodePos::Undef(ctx.undefined_field(prop)) - } -} + TsLit::Str(lit) => { + let lit = serialize_lit(ctx, &Lit::Str(lit.clone())); + ctx.write_ts_lit_type(&node.span, lit) + } + TsLit::Bool(lit) => { + let lit = serialize_lit(ctx, &Lit::Bool(*lit)); + ctx.write_ts_lit_type(&node.span, lit) + } + TsLit::BigInt(lit) => { + let lit = serialize_lit(ctx, &Lit::BigInt(lit.clone())); + ctx.write_ts_lit_type(&node.span, lit) + } + TsLit::Tpl(lit) => { + let quasis = lit + .quasis + .iter() + .map(|quasi| { + ctx.write_template_elem( + &quasi.span, + quasi.tail, + &quasi.raw, + &quasi + .cooked + .as_ref() + .map_or("".to_string(), |v| v.to_string()), + ) + }) + .collect::>(); + let types = lit + .types + .iter() + .map(|ts_type| serialize_ts_type(ctx, ts_type)) + .collect::>(); -fn extract_pos(pos: NodePos) -> usize { - match pos { - NodePos::Bool(bool_pos) => bool_pos.0, - NodePos::Field(field_pos) => field_pos.0, - NodePos::FieldArr(field_arr_pos) => field_arr_pos.0, - NodePos::Str(str_pos) => str_pos.0, - NodePos::Undef(undef_pos) => undef_pos.0, - NodePos::Null(null_pos) => null_pos.0, - } -} - -fn write_true_plus_minus( - ctx: &mut TsEsTreeBuilder, - pos: NodePos, - value: Option, -) { - if let Some(v) = value { - match v { - TruePlusMinus::True => { - let bool_pos = BoolPos(extract_pos(pos)); - ctx.write_bool(bool_pos, true); - } - TruePlusMinus::Plus => { - let str_pos = StrPos(extract_pos(pos)); - ctx.write_str(str_pos, "+") - } - TruePlusMinus::Minus => { - let str_pos = StrPos(extract_pos(pos)); - ctx.write_str(str_pos, "-") - } + ctx.write_ts_tpl_lit(&node.span, quasis, types) } } } @@ -3021,114 +2524,91 @@ fn write_true_plus_minus( fn serialize_ts_entity_name( ctx: &mut TsEsTreeBuilder, node: &TsEntityName, - parent: NodeRef, ) -> NodeRef { match &node { - TsEntityName::TsQualifiedName(_) => todo!(), - TsEntityName::Ident(ident) => serialize_ident(ctx, ident, parent), + TsEntityName::TsQualifiedName(node) => { + let left = serialize_ts_entity_name(ctx, &node.left); + let right = serialize_ident_name(ctx, &node.right); + + ctx.write_ts_qualified_name(&node.span, left, right) + } + TsEntityName::Ident(ident) => serialize_ident(ctx, ident, None), } } fn maybe_serialize_ts_type_ann( ctx: &mut TsEsTreeBuilder, node: &Option>, - parent: NodeRef, ) -> Option { node .as_ref() - .map(|type_ann| serialize_ts_type_ann(ctx, type_ann, parent)) + .map(|type_ann| serialize_ts_type_ann(ctx, type_ann)) } fn serialize_ts_type_ann( ctx: &mut TsEsTreeBuilder, node: &TsTypeAnn, - parent: NodeRef, ) -> NodeRef { - let raw = ctx.header(AstNode::TSTypeAnnotation, parent, &node.span); - let type_pos = ctx.ref_field(AstProp::TypeAnnotation); - let pos = ctx.commit_schema(raw); - - let v_type = serialize_ts_type(ctx, &node.type_ann, pos); - - ctx.write_ref(type_pos, v_type); - - pos + let v_type = serialize_ts_type(ctx, &node.type_ann); + ctx.write_ts_type_ann(&node.span, v_type) } fn maybe_serialize_ts_type( ctx: &mut TsEsTreeBuilder, node: &Option>, - parent: NodeRef, ) -> Option { - node - .as_ref() - .map(|item| serialize_ts_type(ctx, item, parent)) + node.as_ref().map(|item| serialize_ts_type(ctx, item)) } fn serialize_ts_type_param( ctx: &mut TsEsTreeBuilder, node: &TsTypeParam, - parent: NodeRef, ) -> NodeRef { - let raw = ctx.header(AstNode::TSTypeParameter, parent, &node.span); - let name_pos = ctx.ref_field(AstProp::Name); - let constraint_pos = ctx.ref_field(AstProp::Constraint); - let default_pos = ctx.ref_field(AstProp::Default); - let const_pos = ctx.bool_field(AstProp::Const); - let in_pos = ctx.bool_field(AstProp::In); - let out_pos = ctx.bool_field(AstProp::Out); - let pos = ctx.commit_schema(raw); + let name = serialize_ident(ctx, &node.name, None); + let constraint = maybe_serialize_ts_type(ctx, &node.constraint); + let default = maybe_serialize_ts_type(ctx, &node.default); - let name = serialize_ident(ctx, &node.name, pos); - let constraint = maybe_serialize_ts_type(ctx, &node.constraint, pos); - let default = maybe_serialize_ts_type(ctx, &node.default, pos); - - ctx.write_bool(const_pos, node.is_const); - ctx.write_bool(in_pos, node.is_in); - ctx.write_bool(out_pos, node.is_out); - ctx.write_ref(name_pos, name); - ctx.write_maybe_ref(constraint_pos, constraint); - ctx.write_maybe_ref(default_pos, default); - - pos + ctx.write_ts_type_param( + &node.span, + node.is_in, + node.is_out, + node.is_const, + name, + constraint, + default, + ) } -fn maybe_serialize_ts_type_param( +fn maybe_serialize_ts_type_param_decl( ctx: &mut TsEsTreeBuilder, node: &Option>, - parent: NodeRef, ) -> Option { - node.as_ref().map(|node| { - let raw = - ctx.header(AstNode::TSTypeParameterDeclaration, parent, &node.span); - let params_pos = ctx.ref_vec_field(AstProp::Params, node.params.len()); - let pos = ctx.commit_schema(raw); + node + .as_ref() + .map(|node| serialize_ts_type_param_decl(ctx, node)) +} - let params = node - .params - .iter() - .map(|param| serialize_ts_type_param(ctx, param, pos)) - .collect::>(); +fn serialize_ts_type_param_decl( + ctx: &mut TsEsTreeBuilder, + node: &TsTypeParamDecl, +) -> NodeRef { + let params = node + .params + .iter() + .map(|param| serialize_ts_type_param(ctx, param)) + .collect::>(); - ctx.write_refs(params_pos, params); - - pos - }) + ctx.write_ts_type_param_decl(&node.span, params) } fn serialize_ts_fn_param( ctx: &mut TsEsTreeBuilder, node: &TsFnParam, - parent: NodeRef, ) -> NodeRef { match node { - TsFnParam::Ident(ident) => serialize_ident(ctx, ident, parent), - TsFnParam::Array(pat) => { - serialize_pat(ctx, &Pat::Array(pat.clone()), parent) - } - TsFnParam::Rest(pat) => serialize_pat(ctx, &Pat::Rest(pat.clone()), parent), - TsFnParam::Object(pat) => { - serialize_pat(ctx, &Pat::Object(pat.clone()), parent) - } + TsFnParam::Ident(ident) => serialize_binding_ident(ctx, ident), + TsFnParam::Array(pat) => serialize_pat(ctx, &Pat::Array(pat.clone())), + TsFnParam::Rest(pat) => serialize_pat(ctx, &Pat::Rest(pat.clone())), + TsFnParam::Object(pat) => serialize_pat(ctx, &Pat::Object(pat.clone())), } } diff --git a/cli/tools/lint/ast_buffer/ts_estree.rs b/cli/tools/lint/ast_buffer/ts_estree.rs index 29bdb0d378..340f9f3225 100644 --- a/cli/tools/lint/ast_buffer/ts_estree.rs +++ b/cli/tools/lint/ast_buffer/ts_estree.rs @@ -1,26 +1,21 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::fmt; use std::fmt::Debug; use std::fmt::Display; use deno_ast::swc::common::Span; +use deno_ast::view::TruePlusMinus; use super::buffer::AstBufSerializer; -use super::buffer::BoolPos; -use super::buffer::FieldArrPos; -use super::buffer::FieldPos; use super::buffer::NodeRef; -use super::buffer::NullPos; -use super::buffer::PendingNodeRef; use super::buffer::SerializeCtx; -use super::buffer::StrPos; -use super::buffer::UndefPos; #[derive(Debug, Clone, PartialEq)] pub enum AstNode { // First node must always be the empty/invalid node Invalid, + RefArray, // Typically the Program, @@ -29,17 +24,27 @@ pub enum AstNode { ExportDefaultDeclaration, ExportNamedDeclaration, ImportDeclaration, - TsExportAssignment, - TsImportEquals, - TsNamespaceExport, + ImportSpecifier, + ImportAttribute, + ImportDefaultSpecifier, + ImportNamespaceSpecifier, + TSExportAssignment, + TSImportEqualss, + TSNamespaceExport, + TSNamespaceExportDeclaration, + TSImportEqualsDeclaration, + TSExternalModuleReference, + TSModuleDeclaration, + TSModuleBlock, // Decls ClassDeclaration, FunctionDeclaration, TSEnumDeclaration, TSInterface, - TsModule, - TsTypeAlias, + TSInterfaceDeclaration, + TSModule, + TSTypeAliasDeclaration, Using, VariableDeclaration, @@ -74,12 +79,13 @@ pub enum AstNode { ChainExpression, ClassExpression, ConditionalExpression, + EmptyExpr, FunctionExpression, Identifier, ImportExpression, LogicalExpression, MemberExpression, - MetaProp, + MetaProperty, NewExpression, ObjectExpression, PrivateIdentifier, @@ -89,8 +95,6 @@ pub enum AstNode { TemplateLiteral, ThisExpression, TSAsExpression, - TsConstAssertion, - TsInstantiation, TSNonNullExpression, TSSatisfiesExpression, TSTypeAssertion, @@ -98,16 +102,8 @@ pub enum AstNode { UpdateExpression, YieldExpression, - // TODO: TSEsTree uses a single literal node - // Literals - StringLiteral, - Bool, - Null, - NumericLiteral, - BigIntLiteral, - RegExpLiteral, - - EmptyExpr, + // Other + Literal, SpreadElement, Property, VariableDeclarator, @@ -117,6 +113,10 @@ pub enum AstNode { TemplateElement, MethodDefinition, ClassBody, + PropertyDefinition, + Decorator, + StaticBlock, + AccessorProperty, // Patterns ArrayPattern, @@ -150,6 +150,7 @@ pub enum AstNode { TSTypeReference, TSThisType, TSLiteralType, + TSTypeLiteral, TSInferType, TSConditionalType, TSUnionType, @@ -159,7 +160,7 @@ pub enum AstNode { TSTupleType, TSNamedTupleMember, TSFunctionType, - TsCallSignatureDeclaration, + TSCallSignatureDeclaration, TSPropertySignature, TSMethodSignature, TSIndexSignature, @@ -170,6 +171,13 @@ pub enum AstNode { TSRestType, TSArrayType, TSClassImplements, + TSAbstractMethodDefinition, + TSEmptyBodyFunctionExpression, + TSParameterProperty, + TSConstructSignatureDeclaration, + TSQualifiedName, + TSOptionalType, + TSTemplateLiteralType, TSAnyKeyword, TSBigIntKeyword, @@ -219,6 +227,7 @@ pub enum AstProp { Async, Attributes, Await, + BigInt, Block, Body, Callee, @@ -235,6 +244,7 @@ pub enum AstProp { Declaration, Declarations, Declare, + Decorators, Default, Definite, Delegate, @@ -246,12 +256,14 @@ pub enum AstProp { Expression, Expressions, Exported, + ExportKind, Extends, ExtendsType, FalseType, Finalizer, Flags, Generator, + Global, Handler, Id, In, @@ -259,6 +271,8 @@ pub enum AstProp { Init, Initializer, Implements, + Imported, + ImportKind, Key, Kind, Label, @@ -268,6 +282,7 @@ pub enum AstProp { Members, Meta, Method, + ModuleReference, Name, Namespace, NameType, @@ -277,8 +292,12 @@ pub enum AstProp { OpeningFragment, Operator, Optional, + Options, Out, + Override, Param, + Parameter, + Parameters, ParameterName, Params, Pattern, @@ -290,6 +309,7 @@ pub enum AstProp { Quasis, Raw, Readonly, + Regex, ReturnType, Right, SelfClosing, @@ -314,8 +334,6 @@ pub enum AstProp { Value, // Last value is used for max value } -// TODO: Feels like there should be an easier way to iterater over an -// enum in Rust and lowercase the first letter. impl Display for AstProp { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = match self { @@ -333,6 +351,7 @@ impl Display for AstProp { AstProp::Async => "async", AstProp::Attributes => "attributes", AstProp::Await => "await", + AstProp::BigInt => "bigint", AstProp::Block => "block", AstProp::Body => "body", AstProp::Callee => "callee", @@ -349,6 +368,7 @@ impl Display for AstProp { AstProp::Declaration => "declaration", AstProp::Declarations => "declarations", AstProp::Declare => "declare", + AstProp::Decorators => "decorators", AstProp::Default => "default", AstProp::Definite => "definite", AstProp::Delegate => "delegate", @@ -359,6 +379,7 @@ impl Display for AstProp { AstProp::ExprName => "exprName", AstProp::Expression => "expression", AstProp::Expressions => "expressions", + AstProp::ExportKind => "exportKind", AstProp::Exported => "exported", AstProp::Extends => "extends", AstProp::ExtendsType => "extendsType", @@ -366,6 +387,7 @@ impl Display for AstProp { AstProp::Finalizer => "finalizer", AstProp::Flags => "flags", AstProp::Generator => "generator", + AstProp::Global => "global", AstProp::Handler => "handler", AstProp::Id => "id", AstProp::In => "in", @@ -373,6 +395,8 @@ impl Display for AstProp { AstProp::Init => "init", AstProp::Initializer => "initializer", AstProp::Implements => "implements", + AstProp::Imported => "imported", + AstProp::ImportKind => "importKind", AstProp::Key => "key", AstProp::Kind => "kind", AstProp::Label => "label", @@ -382,6 +406,7 @@ impl Display for AstProp { AstProp::Members => "members", AstProp::Meta => "meta", AstProp::Method => "method", + AstProp::ModuleReference => "moduleReference", AstProp::Name => "name", AstProp::Namespace => "namespace", AstProp::NameType => "nameType", @@ -391,8 +416,12 @@ impl Display for AstProp { AstProp::OpeningFragment => "openingFragment", AstProp::Operator => "operator", AstProp::Optional => "optional", + AstProp::Options => "options", AstProp::Out => "out", + AstProp::Override => "override", AstProp::Param => "param", + AstProp::Parameter => "parameter", + AstProp::Parameters => "parameters", AstProp::ParameterName => "parameterName", AstProp::Params => "params", AstProp::Pattern => "pattern", @@ -404,6 +433,7 @@ impl Display for AstProp { AstProp::Quasis => "quasis", AstProp::Raw => "raw", AstProp::Readonly => "readonly", + AstProp::Regex => "regex", AstProp::ReturnType => "returnType", AstProp::Right => "right", AstProp::SelfClosing => "selfClosing", @@ -442,79 +472,2277 @@ pub struct TsEsTreeBuilder { ctx: SerializeCtx, } -// TODO: Add a builder API to make it easier to convert from different source -// ast formats. +impl AstBufSerializer for TsEsTreeBuilder { + fn serialize(&mut self) -> Vec { + self.ctx.serialize() + } +} + impl TsEsTreeBuilder { pub fn new() -> Self { // Max values - // TODO: Maybe there is a rust macro to grab the last enum value? let kind_max_count: u8 = u8::from(AstNode::TSEnumBody) + 1; let prop_max_count: u8 = u8::from(AstProp::Value) + 1; Self { ctx: SerializeCtx::new(kind_max_count, prop_max_count), } } -} -impl AstBufSerializer for TsEsTreeBuilder { - fn header( + pub fn write_program( &mut self, - kind: AstNode, - parent: NodeRef, span: &Span, - ) -> PendingNodeRef { - self.ctx.header(kind, parent, span) + source_kind: &str, + body: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::Program, span); + + self.ctx.write_str(AstProp::SourceType, source_kind); + self.ctx.write_ref_vec(AstProp::Body, &id, body); + + self.ctx.set_root_idx(id.0); + + self.ctx.commit_node(id) } - fn commit_schema(&mut self, offset: PendingNodeRef) -> NodeRef { - self.ctx.commit_schema(offset) + pub fn write_import_decl( + &mut self, + span: &Span, + type_only: bool, + source: NodeRef, + specifiers: Vec, + attributes: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::ImportDeclaration, span); + + let kind = if type_only { "type" } else { "value" }; + self.ctx.write_str(AstProp::ImportKind, kind); + self.ctx.write_ref(AstProp::Source, &id, source); + self.ctx.write_ref_vec(AstProp::Specifiers, &id, specifiers); + self.ctx.write_ref_vec(AstProp::Attributes, &id, attributes); + + self.ctx.commit_node(id) } - fn ref_field(&mut self, prop: AstProp) -> FieldPos { - FieldPos(self.ctx.ref_field(prop)) + pub fn write_import_spec( + &mut self, + span: &Span, + type_only: bool, + local: NodeRef, + imported: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::ImportSpecifier, span); + + let kind = if type_only { "type" } else { "value" }; + self.ctx.write_str(AstProp::ImportKind, kind); + + self.ctx.write_ref(AstProp::Imported, &id, imported); + self.ctx.write_ref(AstProp::Local, &id, local); + + self.ctx.commit_node(id) } - fn ref_vec_field(&mut self, prop: AstProp, len: usize) -> FieldArrPos { - FieldArrPos(self.ctx.ref_vec_field(prop, len)) + pub fn write_import_attr( + &mut self, + span: &Span, + key: NodeRef, + value: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::ImportAttribute, span); + + self.ctx.write_ref(AstProp::Key, &id, key); + self.ctx.write_ref(AstProp::Value, &id, value); + + self.ctx.commit_node(id) } - fn str_field(&mut self, prop: AstProp) -> StrPos { - StrPos(self.ctx.str_field(prop)) + pub fn write_import_default_spec( + &mut self, + span: &Span, + local: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::ImportDefaultSpecifier, span); + self.ctx.write_ref(AstProp::Local, &id, local); + self.ctx.commit_node(id) } - fn bool_field(&mut self, prop: AstProp) -> BoolPos { - BoolPos(self.ctx.bool_field(prop)) + pub fn write_import_ns_spec( + &mut self, + span: &Span, + local: NodeRef, + ) -> NodeRef { + let id = self + .ctx + .append_node(AstNode::ImportNamespaceSpecifier, span); + self.ctx.write_ref(AstProp::Local, &id, local); + self.ctx.commit_node(id) } - fn undefined_field(&mut self, prop: AstProp) -> UndefPos { - UndefPos(self.ctx.undefined_field(prop)) + pub fn write_export_decl(&mut self, span: &Span, decl: NodeRef) -> NodeRef { + let id = self.ctx.append_node(AstNode::ExportNamedDeclaration, span); + self.ctx.write_ref(AstProp::Declaration, &id, decl); + self.ctx.commit_node(id) } - fn null_field(&mut self, prop: AstProp) -> NullPos { - NullPos(self.ctx.null_field(prop)) + pub fn write_export_all_decl( + &mut self, + span: &Span, + is_type_only: bool, + source: NodeRef, + exported: Option, + attributes: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::ExportAllDeclaration, span); + + let value = if is_type_only { "type" } else { "value" }; + self.ctx.write_str(AstProp::ExportKind, value); + + self.ctx.write_maybe_ref(AstProp::Exported, &id, exported); + self.ctx.write_ref(AstProp::Source, &id, source); + self.ctx.write_ref_vec(AstProp::Attributes, &id, attributes); + self.ctx.commit_node(id) } - fn write_ref(&mut self, pos: FieldPos, value: NodeRef) { - self.ctx.write_ref(pos.0, value); + pub fn write_export_default_decl( + &mut self, + span: &Span, + is_type_only: bool, + decl: NodeRef, + ) -> NodeRef { + let id = self + .ctx + .append_node(AstNode::ExportDefaultDeclaration, span); + + let value = if is_type_only { "type" } else { "value" }; + self.ctx.write_str(AstProp::ExportKind, value); + self.ctx.write_ref(AstProp::Declaration, &id, decl); + self.ctx.commit_node(id) } - fn write_maybe_ref(&mut self, pos: FieldPos, value: Option) { - self.ctx.write_maybe_ref(pos.0, value); + pub fn write_export_named_decl( + &mut self, + span: &Span, + specifiers: Vec, + source: Option, + attributes: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::ExportNamedDeclaration, span); + + self.ctx.write_ref_vec(AstProp::Specifiers, &id, specifiers); + self.ctx.write_maybe_ref(AstProp::Source, &id, source); + self.ctx.write_ref_vec(AstProp::Attributes, &id, attributes); + + self.ctx.commit_node(id) } - fn write_refs(&mut self, pos: FieldArrPos, value: Vec) { - self.ctx.write_refs(pos.0, value); + pub fn write_export_ts_namespace( + &mut self, + span: &Span, + ident: NodeRef, + ) -> NodeRef { + let id = self + .ctx + .append_node(AstNode::TSNamespaceExportDeclaration, span); + self.ctx.write_ref(AstProp::Id, &id, ident); + self.ctx.commit_node(id) } - fn write_str(&mut self, pos: StrPos, value: &str) { - self.ctx.write_str(pos.0, value); + pub fn write_export_ts_import_equals( + &mut self, + span: &Span, + is_type_only: bool, + ident: NodeRef, + reference: NodeRef, + ) -> NodeRef { + let id = self + .ctx + .append_node(AstNode::TSImportEqualsDeclaration, span); + + let value = if is_type_only { "type" } else { "value" }; + self.ctx.write_str(AstProp::ImportKind, value); + self.ctx.write_ref(AstProp::Id, &id, ident); + self.ctx.write_ref(AstProp::ModuleReference, &id, reference); + + self.ctx.commit_node(id) } - fn write_bool(&mut self, pos: BoolPos, value: bool) { - self.ctx.write_bool(pos.0, value); + pub fn write_ts_external_mod_ref( + &mut self, + span: &Span, + expr: NodeRef, + ) -> NodeRef { + let id = self + .ctx + .append_node(AstNode::TSExternalModuleReference, span); + self.ctx.write_ref(AstProp::Expression, &id, expr); + self.ctx.commit_node(id) } - fn serialize(&mut self) -> Vec { - self.ctx.serialize() + pub fn write_export_spec( + &mut self, + span: &Span, + type_only: bool, + local: NodeRef, + exported: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::ExportSpecifier, span); + + let kind = if type_only { "type" } else { "value" }; + self.ctx.write_str(AstProp::ExportKind, kind); + + self.ctx.write_ref(AstProp::Exported, &id, exported); + self.ctx.write_ref(AstProp::Local, &id, local); + + self.ctx.commit_node(id) + } + + pub fn write_var_decl( + &mut self, + span: &Span, + declare: bool, + kind: &str, + decls: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::VariableDeclaration, span); + + self.ctx.write_bool(AstProp::Declare, declare); + self.ctx.write_str(AstProp::Kind, kind); + self.ctx.write_ref_vec(AstProp::Declarations, &id, decls); + + self.ctx.commit_node(id) + } + + pub fn write_var_declarator( + &mut self, + span: &Span, + ident: NodeRef, + init: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::VariableDeclarator, span); + + self.ctx.write_ref(AstProp::Id, &id, ident); + self.ctx.write_maybe_ref(AstProp::Init, &id, init); + + self.ctx.commit_node(id) + } + + #[allow(clippy::too_many_arguments)] + pub fn write_fn_decl( + &mut self, + span: &Span, + is_declare: bool, + is_async: bool, + is_generator: bool, + // Ident is required in most cases, but optional as default export + // declaration. TsEstree is weird... + ident: Option, + type_param: Option, + return_type: Option, + body: Option, + params: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::FunctionDeclaration, span); + + self.ctx.write_bool(AstProp::Declare, is_declare); + self.ctx.write_bool(AstProp::Async, is_async); + self.ctx.write_bool(AstProp::Generator, is_generator); + self.ctx.write_maybe_ref(AstProp::Id, &id, ident); + self + .ctx + .write_maybe_ref(AstProp::TypeParameters, &id, type_param); + self + .ctx + .write_maybe_ref(AstProp::ReturnType, &id, return_type); + self.ctx.write_maybe_ref(AstProp::Body, &id, body); + self.ctx.write_ref_vec(AstProp::Params, &id, params); + + self.ctx.commit_node(id) + } + + pub fn write_decorator(&mut self, span: &Span, expr: NodeRef) -> NodeRef { + let id = self.ctx.append_node(AstNode::Decorator, span); + self.ctx.write_ref(AstProp::Expression, &id, expr); + self.ctx.commit_node(id) + } + + #[allow(clippy::too_many_arguments)] + pub fn write_class_decl( + &mut self, + span: &Span, + is_declare: bool, + is_abstract: bool, + // Ident is required in most cases, but optional as default export + // declaration. TsEstree is weird... + ident: Option, + super_class: Option, + implements: Vec, + body: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::ClassDeclaration, span); + self.ctx.write_bool(AstProp::Declare, is_declare); + self.ctx.write_bool(AstProp::Abstract, is_abstract); + self.ctx.write_maybe_ref(AstProp::Id, &id, ident); + self + .ctx + .write_maybe_ref(AstProp::SuperClass, &id, super_class); + self.ctx.write_ref_vec(AstProp::Implements, &id, implements); + self.ctx.write_ref(AstProp::Body, &id, body); + + self.ctx.commit_node(id) + } + + #[allow(clippy::too_many_arguments)] + pub fn write_class_expr( + &mut self, + span: &Span, + is_declare: bool, + is_abstract: bool, + ident: Option, + super_class: Option, + implements: Vec, + body: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::ClassExpression, span); + self.ctx.write_bool(AstProp::Declare, is_declare); + self.ctx.write_bool(AstProp::Abstract, is_abstract); + self.ctx.write_maybe_ref(AstProp::Id, &id, ident); + self + .ctx + .write_maybe_ref(AstProp::SuperClass, &id, super_class); + self.ctx.write_ref_vec(AstProp::Implements, &id, implements); + self.ctx.write_ref(AstProp::Body, &id, body); + + self.ctx.commit_node(id) + } + + pub fn write_class_body( + &mut self, + span: &Span, + body: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::ClassBody, span); + self.ctx.write_ref_vec(AstProp::Body, &id, body); + self.ctx.commit_node(id) + } + + pub fn write_static_block(&mut self, span: &Span, body: NodeRef) -> NodeRef { + let id = self.ctx.append_node(AstNode::StaticBlock, span); + self.ctx.write_ref(AstProp::Body, &id, body); + self.ctx.commit_node(id) + } + + #[allow(clippy::too_many_arguments)] + pub fn write_accessor_property( + &mut self, + span: &Span, + is_declare: bool, + is_computed: bool, + is_optional: bool, + is_override: bool, + is_readonly: bool, + is_static: bool, + accessibility: Option, + decorators: Vec, + key: NodeRef, + value: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::AccessorProperty, span); + + self.ctx.write_bool(AstProp::Declare, is_declare); + self.ctx.write_bool(AstProp::Computed, is_computed); + self.ctx.write_bool(AstProp::Optional, is_optional); + self.ctx.write_bool(AstProp::Override, is_override); + self.ctx.write_bool(AstProp::Readonly, is_readonly); + self.ctx.write_bool(AstProp::Static, is_static); + self.write_accessibility(accessibility); + self.ctx.write_ref_vec(AstProp::Decorators, &id, decorators); + self.ctx.write_ref(AstProp::Key, &id, key); + self.ctx.write_maybe_ref(AstProp::Value, &id, value); + + self.ctx.commit_node(id) + } + + #[allow(clippy::too_many_arguments)] + pub fn write_class_prop( + &mut self, + span: &Span, + is_declare: bool, + is_computed: bool, + is_optional: bool, + is_override: bool, + is_readonly: bool, + is_static: bool, + accessibility: Option, + decorators: Vec, + key: NodeRef, + value: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::PropertyDefinition, span); + + self.ctx.write_bool(AstProp::Declare, is_declare); + self.ctx.write_bool(AstProp::Computed, is_computed); + self.ctx.write_bool(AstProp::Optional, is_optional); + self.ctx.write_bool(AstProp::Override, is_override); + self.ctx.write_bool(AstProp::Readonly, is_readonly); + self.ctx.write_bool(AstProp::Static, is_static); + + self.write_accessibility(accessibility); + self.ctx.write_ref_vec(AstProp::Decorators, &id, decorators); + + self.ctx.write_ref(AstProp::Key, &id, key); + self.ctx.write_maybe_ref(AstProp::Value, &id, value); + + self.ctx.commit_node(id) + } + + #[allow(clippy::too_many_arguments)] + pub fn write_class_method( + &mut self, + span: &Span, + is_declare: bool, + is_computed: bool, + is_optional: bool, + is_override: bool, + is_static: bool, + kind: &str, + accessibility: Option, + key: NodeRef, + value: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::MethodDefinition, span); + + self.ctx.write_bool(AstProp::Declare, is_declare); + self.ctx.write_bool(AstProp::Computed, is_computed); + self.ctx.write_bool(AstProp::Optional, is_optional); + self.ctx.write_bool(AstProp::Override, is_override); + self.ctx.write_bool(AstProp::Static, is_static); + self.ctx.write_str(AstProp::Kind, kind); + self.write_accessibility(accessibility); + self.ctx.write_ref(AstProp::Key, &id, key); + self.ctx.write_ref(AstProp::Value, &id, value); + + self.ctx.commit_node(id) + } + + pub fn write_block_stmt( + &mut self, + span: &Span, + body: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::BlockStatement, span); + self.ctx.write_ref_vec(AstProp::Body, &id, body); + self.ctx.commit_node(id) + } + + pub fn write_debugger_stmt(&mut self, span: &Span) -> NodeRef { + let id = self.ctx.append_node(AstNode::DebuggerStatement, span); + self.ctx.commit_node(id) + } + + pub fn write_with_stmt( + &mut self, + span: &Span, + obj: NodeRef, + body: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::WithStatement, span); + + self.ctx.write_ref(AstProp::Object, &id, obj); + self.ctx.write_ref(AstProp::Body, &id, body); + + self.ctx.commit_node(id) + } + + pub fn write_return_stmt( + &mut self, + span: &Span, + arg: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::ReturnStatement, span); + self.ctx.write_maybe_ref(AstProp::Argument, &id, arg); + self.ctx.commit_node(id) + } + + pub fn write_labeled_stmt( + &mut self, + span: &Span, + label: NodeRef, + body: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::LabeledStatement, span); + + self.ctx.write_ref(AstProp::Label, &id, label); + self.ctx.write_ref(AstProp::Body, &id, body); + + self.ctx.commit_node(id) + } + + pub fn write_break_stmt( + &mut self, + span: &Span, + label: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::BreakStatement, span); + self.ctx.write_maybe_ref(AstProp::Label, &id, label); + self.ctx.commit_node(id) + } + + pub fn write_continue_stmt( + &mut self, + span: &Span, + label: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::ContinueStatement, span); + self.ctx.write_maybe_ref(AstProp::Label, &id, label); + self.ctx.commit_node(id) + } + + pub fn write_if_stmt( + &mut self, + span: &Span, + test: NodeRef, + consequent: NodeRef, + alternate: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::IfStatement, span); + + self.ctx.write_ref(AstProp::Test, &id, test); + self.ctx.write_ref(AstProp::Consequent, &id, consequent); + self.ctx.write_maybe_ref(AstProp::Alternate, &id, alternate); + + self.ctx.commit_node(id) + } + + pub fn write_switch_stmt( + &mut self, + span: &Span, + discriminant: NodeRef, + cases: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::SwitchStatement, span); + + self.ctx.write_ref(AstProp::Discriminant, &id, discriminant); + self.ctx.write_ref_vec(AstProp::Cases, &id, cases); + + self.ctx.commit_node(id) + } + + pub fn write_switch_case( + &mut self, + span: &Span, + test: Option, + consequent: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::SwitchCase, span); + + self.ctx.write_maybe_ref(AstProp::Test, &id, test); + self.ctx.write_ref_vec(AstProp::Consequent, &id, consequent); + + self.ctx.commit_node(id) + } + + pub fn write_throw_stmt(&mut self, span: &Span, arg: NodeRef) -> NodeRef { + let id = self.ctx.append_node(AstNode::ThrowStatement, span); + self.ctx.write_ref(AstProp::Argument, &id, arg); + self.ctx.commit_node(id) + } + + pub fn write_while_stmt( + &mut self, + span: &Span, + test: NodeRef, + body: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::WhileStatement, span); + + self.ctx.write_ref(AstProp::Test, &id, test); + self.ctx.write_ref(AstProp::Body, &id, body); + + self.ctx.commit_node(id) + } + + pub fn write_do_while_stmt( + &mut self, + span: &Span, + test: NodeRef, + body: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::DoWhileStatement, span); + + self.ctx.write_ref(AstProp::Test, &id, test); + self.ctx.write_ref(AstProp::Body, &id, body); + + self.ctx.commit_node(id) + } + + pub fn write_for_stmt( + &mut self, + span: &Span, + init: Option, + test: Option, + update: Option, + body: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::ForStatement, span); + + self.ctx.write_maybe_ref(AstProp::Init, &id, init); + self.ctx.write_maybe_ref(AstProp::Test, &id, test); + self.ctx.write_maybe_ref(AstProp::Update, &id, update); + self.ctx.write_ref(AstProp::Body, &id, body); + + self.ctx.commit_node(id) + } + + pub fn write_for_in_stmt( + &mut self, + span: &Span, + left: NodeRef, + right: NodeRef, + body: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::ForInStatement, span); + + self.ctx.write_ref(AstProp::Left, &id, left); + self.ctx.write_ref(AstProp::Right, &id, right); + self.ctx.write_ref(AstProp::Body, &id, body); + + self.ctx.commit_node(id) + } + + pub fn write_for_of_stmt( + &mut self, + span: &Span, + is_await: bool, + left: NodeRef, + right: NodeRef, + body: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::ForOfStatement, span); + + self.ctx.write_bool(AstProp::Await, is_await); + self.ctx.write_ref(AstProp::Left, &id, left); + self.ctx.write_ref(AstProp::Right, &id, right); + self.ctx.write_ref(AstProp::Body, &id, body); + + self.ctx.commit_node(id) + } + + pub fn write_expr_stmt(&mut self, span: &Span, expr: NodeRef) -> NodeRef { + let id = self.ctx.append_node(AstNode::ExpressionStatement, span); + self.ctx.write_ref(AstProp::Expression, &id, expr); + self.ctx.commit_node(id) + } + + pub fn write_try_stmt( + &mut self, + span: &Span, + block: NodeRef, + handler: Option, + finalizer: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TryStatement, span); + + self.ctx.write_ref(AstProp::Block, &id, block); + self.ctx.write_maybe_ref(AstProp::Handler, &id, handler); + self.ctx.write_maybe_ref(AstProp::Finalizer, &id, finalizer); + + self.ctx.commit_node(id) + } + + pub fn write_catch_clause( + &mut self, + span: &Span, + param: Option, + body: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::CatchClause, span); + + self.ctx.write_maybe_ref(AstProp::Param, &id, param); + self.ctx.write_ref(AstProp::Body, &id, body); + + self.ctx.commit_node(id) + } + + pub fn write_arr_expr( + &mut self, + span: &Span, + elems: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::ArrayExpression, span); + self.ctx.write_ref_vec(AstProp::Elements, &id, elems); + self.ctx.commit_node(id) + } + + pub fn write_obj_expr( + &mut self, + span: &Span, + props: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::ObjectExpression, span); + self.ctx.write_ref_vec(AstProp::Properties, &id, props); + self.ctx.commit_node(id) + } + + pub fn write_bin_expr( + &mut self, + span: &Span, + operator: &str, + left: NodeRef, + right: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::BinaryExpression, span); + + self.ctx.write_str(AstProp::Operator, operator); + self.ctx.write_ref(AstProp::Left, &id, left); + self.ctx.write_ref(AstProp::Right, &id, right); + + self.ctx.commit_node(id) + } + + pub fn write_logical_expr( + &mut self, + span: &Span, + operator: &str, + left: NodeRef, + right: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::LogicalExpression, span); + + self.ctx.write_str(AstProp::Operator, operator); + self.ctx.write_ref(AstProp::Left, &id, left); + self.ctx.write_ref(AstProp::Right, &id, right); + + self.ctx.commit_node(id) + } + + #[allow(clippy::too_many_arguments)] + pub fn write_fn_expr( + &mut self, + span: &Span, + is_async: bool, + is_generator: bool, + ident: Option, + type_params: Option, + params: Vec, + return_type: Option, + body: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::FunctionExpression, span); + + self.ctx.write_bool(AstProp::Async, is_async); + self.ctx.write_bool(AstProp::Generator, is_generator); + self.ctx.write_maybe_ref(AstProp::Id, &id, ident); + self + .ctx + .write_maybe_ref(AstProp::TypeParameters, &id, type_params); + self.ctx.write_ref_vec(AstProp::Params, &id, params); + self + .ctx + .write_maybe_ref(AstProp::ReturnType, &id, return_type); + self.ctx.write_maybe_ref(AstProp::Body, &id, body); + + self.ctx.commit_node(id) + } + + #[allow(clippy::too_many_arguments)] + pub fn write_arrow_fn_expr( + &mut self, + span: &Span, + is_async: bool, + is_generator: bool, + type_params: Option, + params: Vec, + return_type: Option, + body: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::ArrowFunctionExpression, span); + + self.ctx.write_bool(AstProp::Async, is_async); + self.ctx.write_bool(AstProp::Generator, is_generator); + self + .ctx + .write_maybe_ref(AstProp::TypeParameters, &id, type_params); + self.ctx.write_ref_vec(AstProp::Params, &id, params); + self + .ctx + .write_maybe_ref(AstProp::ReturnType, &id, return_type); + self.ctx.write_ref(AstProp::Body, &id, body); + + self.ctx.commit_node(id) + } + + pub fn write_this_expr(&mut self, span: &Span) -> NodeRef { + let id = self.ctx.append_node(AstNode::ThisExpression, span); + self.ctx.commit_node(id) + } + + pub fn write_super(&mut self, span: &Span) -> NodeRef { + let id = self.ctx.append_node(AstNode::Super, span); + self.ctx.commit_node(id) + } + + pub fn write_unary_expr( + &mut self, + span: &Span, + operator: &str, + arg: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::UnaryExpression, span); + + self.ctx.write_str(AstProp::Operator, operator); + self.ctx.write_ref(AstProp::Argument, &id, arg); + + self.ctx.commit_node(id) + } + + pub fn write_new_expr( + &mut self, + span: &Span, + callee: NodeRef, + type_args: Option, + args: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::NewExpression, span); + + self.ctx.write_ref(AstProp::Callee, &id, callee); + self + .ctx + .write_maybe_ref(AstProp::TypeArguments, &id, type_args); + self.ctx.write_ref_vec(AstProp::Arguments, &id, args); + + self.ctx.commit_node(id) + } + + pub fn write_import_expr( + &mut self, + span: &Span, + source: NodeRef, + options: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::ImportExpression, span); + + self.ctx.write_ref(AstProp::Source, &id, source); + self.ctx.write_ref(AstProp::Options, &id, options); + + self.ctx.commit_node(id) + } + + pub fn write_call_expr( + &mut self, + span: &Span, + optional: bool, + callee: NodeRef, + type_args: Option, + args: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::CallExpression, span); + + self.ctx.write_bool(AstProp::Optional, optional); + self.ctx.write_ref(AstProp::Callee, &id, callee); + self + .ctx + .write_maybe_ref(AstProp::TypeArguments, &id, type_args); + self.ctx.write_ref_vec(AstProp::Arguments, &id, args); + + self.ctx.commit_node(id) + } + + pub fn write_update_expr( + &mut self, + span: &Span, + prefix: bool, + operator: &str, + arg: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::UpdateExpression, span); + + self.ctx.write_bool(AstProp::Prefix, prefix); + self.ctx.write_str(AstProp::Operator, operator); + self.ctx.write_ref(AstProp::Argument, &id, arg); + + self.ctx.commit_node(id) + } + + pub fn write_assignment_expr( + &mut self, + span: &Span, + operator: &str, + left: NodeRef, + right: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::AssignmentExpression, span); + + self.ctx.write_str(AstProp::Operator, operator); + self.ctx.write_ref(AstProp::Left, &id, left); + self.ctx.write_ref(AstProp::Right, &id, right); + + self.ctx.commit_node(id) + } + + pub fn write_conditional_expr( + &mut self, + span: &Span, + test: NodeRef, + consequent: NodeRef, + alternate: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::ConditionalExpression, span); + + self.ctx.write_ref(AstProp::Test, &id, test); + self.ctx.write_ref(AstProp::Consequent, &id, consequent); + self.ctx.write_ref(AstProp::Alternate, &id, alternate); + + self.ctx.commit_node(id) + } + + pub fn write_member_expr( + &mut self, + span: &Span, + optional: bool, + computed: bool, + obj: NodeRef, + prop: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::MemberExpression, span); + + self.ctx.write_bool(AstProp::Optional, optional); + self.ctx.write_bool(AstProp::Computed, computed); + self.ctx.write_ref(AstProp::Object, &id, obj); + self.ctx.write_ref(AstProp::Property, &id, prop); + + self.ctx.commit_node(id) + } + + pub fn write_chain_expr(&mut self, span: &Span, expr: NodeRef) -> NodeRef { + let id = self.ctx.append_node(AstNode::ChainExpression, span); + self.ctx.write_ref(AstProp::Expression, &id, expr); + self.ctx.commit_node(id) + } + + pub fn write_sequence_expr( + &mut self, + span: &Span, + exprs: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::SequenceExpression, span); + self.ctx.write_ref_vec(AstProp::Expressions, &id, exprs); + self.ctx.commit_node(id) + } + + pub fn write_template_lit( + &mut self, + span: &Span, + quasis: Vec, + exprs: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TemplateLiteral, span); + + self.ctx.write_ref_vec(AstProp::Quasis, &id, quasis); + self.ctx.write_ref_vec(AstProp::Expressions, &id, exprs); + + self.ctx.commit_node(id) + } + + pub fn write_template_elem( + &mut self, + span: &Span, + tail: bool, + raw: &str, + cooked: &str, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TemplateElement, span); + + self.ctx.write_bool(AstProp::Tail, tail); + self.ctx.write_str(AstProp::Raw, raw); + self.ctx.write_str(AstProp::Cooked, cooked); + + self.ctx.commit_node(id) + } + + pub fn write_tagged_template_expr( + &mut self, + span: &Span, + tag: NodeRef, + type_args: Option, + quasi: NodeRef, + ) -> NodeRef { + let id = self + .ctx + .append_node(AstNode::TaggedTemplateExpression, span); + + self.ctx.write_ref(AstProp::Tag, &id, tag); + self + .ctx + .write_maybe_ref(AstProp::TypeArguments, &id, type_args); + self.ctx.write_ref(AstProp::Quasi, &id, quasi); + + self.ctx.commit_node(id) + } + + pub fn write_yield_expr( + &mut self, + span: &Span, + delegate: bool, + arg: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::YieldExpression, span); + + self.ctx.write_bool(AstProp::Delegate, delegate); + self.ctx.write_maybe_ref(AstProp::Argument, &id, arg); + + self.ctx.commit_node(id) + } + + pub fn write_await_expr(&mut self, span: &Span, arg: NodeRef) -> NodeRef { + let id = self.ctx.append_node(AstNode::AwaitExpression, span); + self.ctx.write_ref(AstProp::Argument, &id, arg); + self.ctx.commit_node(id) + } + + pub fn write_meta_prop(&mut self, span: &Span, prop: NodeRef) -> NodeRef { + let id = self.ctx.append_node(AstNode::MetaProperty, span); + self.ctx.write_ref(AstProp::Property, &id, prop); + self.ctx.commit_node(id) + } + + pub fn write_identifier( + &mut self, + span: &Span, + name: &str, + optional: bool, + type_annotation: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::Identifier, span); + + self.ctx.write_str(AstProp::Name, name); + self.ctx.write_bool(AstProp::Optional, optional); + self + .ctx + .write_maybe_ref(AstProp::TypeAnnotation, &id, type_annotation); + + self.ctx.commit_node(id) + } + + pub fn write_private_identifier( + &mut self, + span: &Span, + name: &str, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::PrivateIdentifier, span); + self.ctx.write_str(AstProp::Name, name); + self.ctx.commit_node(id) + } + + pub fn write_assign_pat( + &mut self, + span: &Span, + left: NodeRef, + right: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::AssignmentPattern, span); + + self.ctx.write_ref(AstProp::Left, &id, left); + self.ctx.write_ref(AstProp::Right, &id, right); + + self.ctx.commit_node(id) + } + + pub fn write_arr_pat( + &mut self, + span: &Span, + optional: bool, + type_ann: Option, + elems: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::ArrayPattern, span); + + self.ctx.write_bool(AstProp::Optional, optional); + self + .ctx + .write_maybe_ref(AstProp::TypeAnnotation, &id, type_ann); + self.ctx.write_ref_vec(AstProp::Elements, &id, elems); + + self.ctx.commit_node(id) + } + + pub fn write_obj_pat( + &mut self, + span: &Span, + optional: bool, + type_ann: Option, + props: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::ObjectPattern, span); + + self.ctx.write_bool(AstProp::Optional, optional); + self + .ctx + .write_maybe_ref(AstProp::TypeAnnotation, &id, type_ann); + self.ctx.write_ref_vec(AstProp::Properties, &id, props); + + self.ctx.commit_node(id) + } + + pub fn write_rest_elem( + &mut self, + span: &Span, + type_ann: Option, + arg: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::RestElement, span); + + self + .ctx + .write_maybe_ref(AstProp::TypeAnnotation, &id, type_ann); + self.ctx.write_ref(AstProp::Argument, &id, arg); + + self.ctx.commit_node(id) + } + + pub fn write_spread(&mut self, span: &Span, arg: NodeRef) -> NodeRef { + let id = self.ctx.append_node(AstNode::SpreadElement, span); + self.ctx.write_ref(AstProp::Argument, &id, arg); + self.ctx.commit_node(id) + } + + #[allow(clippy::too_many_arguments)] + pub fn write_property( + &mut self, + span: &Span, + shorthand: bool, + computed: bool, + method: bool, + kind: &str, + key: NodeRef, + value: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::Property, span); + + self.ctx.write_bool(AstProp::Shorthand, shorthand); + self.ctx.write_bool(AstProp::Computed, computed); + self.ctx.write_bool(AstProp::Method, method); + self.ctx.write_str(AstProp::Kind, kind); + self.ctx.write_ref(AstProp::Key, &id, key); + self.ctx.write_ref(AstProp::Value, &id, value); + + self.ctx.commit_node(id) + } + + pub fn write_str_lit( + &mut self, + span: &Span, + value: &str, + raw: &str, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::Literal, span); + + self.ctx.write_str(AstProp::Value, value); + self.ctx.write_str(AstProp::Raw, raw); + + self.ctx.commit_node(id) + } + + pub fn write_bool_lit(&mut self, span: &Span, value: bool) -> NodeRef { + let id = self.ctx.append_node(AstNode::Literal, span); + + let raw = &format!("{}", value); + self.ctx.write_str(AstProp::Raw, raw); + self.ctx.write_bool(AstProp::Value, value); + + self.ctx.commit_node(id) + } + + pub fn write_null_lit(&mut self, span: &Span) -> NodeRef { + let id = self.ctx.append_node(AstNode::Literal, span); + + self.ctx.write_null(AstProp::Value); + self.ctx.write_str(AstProp::Raw, "null"); + + self.ctx.commit_node(id) + } + + pub fn write_num_lit( + &mut self, + span: &Span, + value: &str, + raw: &str, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::Literal, span); + + self.ctx.write_num(AstProp::Value, value); + self.ctx.write_str(AstProp::Raw, raw); + + self.ctx.commit_node(id) + } + + pub fn write_bigint_lit( + &mut self, + span: &Span, + value: &str, + raw: &str, + bigint_value: &str, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::Literal, span); + + self.ctx.write_bigint(AstProp::Value, value); + self.ctx.write_str(AstProp::Raw, raw); + self.ctx.write_str(AstProp::BigInt, bigint_value); + + self.ctx.commit_node(id) + } + + pub fn write_regex_lit( + &mut self, + span: &Span, + pattern: &str, + flags: &str, + value: &str, + raw: &str, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::Literal, span); + + self.ctx.write_regex(AstProp::Value, value); + self.ctx.write_str(AstProp::Raw, raw); + self.ctx.open_obj(); + self.ctx.write_str(AstProp::Flags, flags); + self.ctx.write_str(AstProp::Pattern, pattern); + self.ctx.commit_obj(AstProp::Regex); + + self.ctx.commit_node(id) + } + + pub fn write_jsx_identifier(&mut self, span: &Span, name: &str) -> NodeRef { + let id = self.ctx.append_node(AstNode::JSXIdentifier, span); + self.ctx.write_str(AstProp::Name, name); + self.ctx.commit_node(id) + } + + pub fn write_jsx_namespaced_name( + &mut self, + span: &Span, + namespace: NodeRef, + name: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::JSXNamespacedName, span); + + self.ctx.write_ref(AstProp::Namespace, &id, namespace); + self.ctx.write_ref(AstProp::Name, &id, name); + + self.ctx.commit_node(id) + } + + pub fn write_jsx_empty_expr(&mut self, span: &Span) -> NodeRef { + let id = self.ctx.append_node(AstNode::JSXEmptyExpression, span); + self.ctx.commit_node(id) + } + + pub fn write_jsx_elem( + &mut self, + span: &Span, + opening: NodeRef, + closing: Option, + children: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::JSXElement, span); + + self.ctx.write_ref(AstProp::OpeningElement, &id, opening); + self + .ctx + .write_maybe_ref(AstProp::ClosingElement, &id, closing); + self.ctx.write_ref_vec(AstProp::Children, &id, children); + + self.ctx.commit_node(id) + } + + pub fn write_jsx_opening_elem( + &mut self, + span: &Span, + self_closing: bool, + name: NodeRef, + attrs: Vec, + type_args: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::JSXOpeningElement, span); + + self.ctx.write_bool(AstProp::SelfClosing, self_closing); + self.ctx.write_ref(AstProp::Name, &id, name); + self.ctx.write_ref_vec(AstProp::Attributes, &id, attrs); + self + .ctx + .write_maybe_ref(AstProp::TypeArguments, &id, type_args); + + self.ctx.commit_node(id) + } + + pub fn write_jsx_attr( + &mut self, + span: &Span, + name: NodeRef, + value: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::JSXAttribute, span); + + self.ctx.write_ref(AstProp::Name, &id, name); + self.ctx.write_maybe_ref(AstProp::Value, &id, value); + + self.ctx.commit_node(id) + } + + pub fn write_jsx_spread_attr( + &mut self, + span: &Span, + arg: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::JSXSpreadAttribute, span); + self.ctx.write_ref(AstProp::Argument, &id, arg); + self.ctx.commit_node(id) + } + + pub fn write_jsx_closing_elem( + &mut self, + span: &Span, + name: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::JSXClosingElement, span); + self.ctx.write_ref(AstProp::Name, &id, name); + self.ctx.commit_node(id) + } + + pub fn write_jsx_frag( + &mut self, + span: &Span, + opening: NodeRef, + closing: NodeRef, + children: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::JSXFragment, span); + + self.ctx.write_ref(AstProp::OpeningFragment, &id, opening); + self.ctx.write_ref(AstProp::ClosingFragment, &id, closing); + self.ctx.write_ref_vec(AstProp::Children, &id, children); + + self.ctx.commit_node(id) + } + + pub fn write_jsx_opening_frag(&mut self, span: &Span) -> NodeRef { + let id = self.ctx.append_node(AstNode::JSXOpeningFragment, span); + self.ctx.commit_node(id) + } + + pub fn write_jsx_closing_frag(&mut self, span: &Span) -> NodeRef { + let id = self.ctx.append_node(AstNode::JSXClosingFragment, span); + self.ctx.commit_node(id) + } + + pub fn write_jsx_expr_container( + &mut self, + span: &Span, + expr: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::JSXExpressionContainer, span); + self.ctx.write_ref(AstProp::Expression, &id, expr); + self.ctx.commit_node(id) + } + + pub fn write_jsx_text( + &mut self, + span: &Span, + raw: &str, + value: &str, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::JSXText, span); + + self.ctx.write_str(AstProp::Raw, raw); + self.ctx.write_str(AstProp::Value, value); + + self.ctx.commit_node(id) + } + + pub fn write_jsx_member_expr( + &mut self, + span: &Span, + obj: NodeRef, + prop: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::JSXMemberExpression, span); + + self.ctx.write_ref(AstProp::Object, &id, obj); + self.ctx.write_ref(AstProp::Property, &id, prop); + + self.ctx.commit_node(id) + } + + pub fn write_ts_module_decl( + &mut self, + span: &Span, + is_declare: bool, + is_global: bool, + ident: NodeRef, + body: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSModuleDeclaration, span); + + self.ctx.write_bool(AstProp::Declare, is_declare); + self.ctx.write_bool(AstProp::Global, is_global); + self.ctx.write_ref(AstProp::Id, &id, ident); + self.ctx.write_maybe_ref(AstProp::Body, &id, body); + self.ctx.commit_node(id) + } + + pub fn write_ts_module_block( + &mut self, + span: &Span, + body: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSModuleBlock, span); + self.ctx.write_ref_vec(AstProp::Body, &id, body); + self.ctx.commit_node(id) + } + + pub fn write_ts_class_implements( + &mut self, + span: &Span, + expr: NodeRef, + type_args: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSClassImplements, span); + + self.ctx.write_ref(AstProp::Expression, &id, expr); + self + .ctx + .write_maybe_ref(AstProp::TypeArguments, &id, type_args); + + self.ctx.commit_node(id) + } + + #[allow(clippy::too_many_arguments)] + pub fn write_ts_abstract_method_def( + &mut self, + span: &Span, + is_computed: bool, + is_optional: bool, + is_override: bool, + is_static: bool, + accessibility: Option, + key: NodeRef, + value: NodeRef, + ) -> NodeRef { + let id = self + .ctx + .append_node(AstNode::TSAbstractMethodDefinition, span); + + self.ctx.write_bool(AstProp::Computed, is_computed); + self.ctx.write_bool(AstProp::Optional, is_optional); + self.ctx.write_bool(AstProp::Override, is_override); + self.ctx.write_bool(AstProp::Static, is_static); + + self.write_accessibility(accessibility); + + self.ctx.write_str(AstProp::Kind, "method"); + self.ctx.write_ref(AstProp::Key, &id, key); + self.ctx.write_ref(AstProp::Key, &id, value); + + self.ctx.commit_node(id) + } + + #[allow(clippy::too_many_arguments)] + pub fn write_ts_empty_body_fn_expr( + &mut self, + span: &Span, + is_declare: bool, + is_expression: bool, + is_async: bool, + is_generator: bool, + ident: Option, + type_params: Option, + params: Vec, + return_type: Option, + ) -> NodeRef { + let id = self + .ctx + .append_node(AstNode::TSEmptyBodyFunctionExpression, span); + + self.ctx.write_bool(AstProp::Declare, is_declare); + self.ctx.write_bool(AstProp::Expression, is_expression); + self.ctx.write_bool(AstProp::Async, is_async); + self.ctx.write_bool(AstProp::Generator, is_generator); + self.ctx.write_maybe_ref(AstProp::Id, &id, ident); + self + .ctx + .write_maybe_ref(AstProp::TypeParameters, &id, type_params); + self.ctx.write_ref_vec(AstProp::Params, &id, params); + self + .ctx + .write_maybe_ref(AstProp::ReturnType, &id, return_type); + + self.ctx.commit_node(id) + } + + pub fn write_ts_param_prop( + &mut self, + span: &Span, + is_override: bool, + is_readonly: bool, + accessibility: Option, + decorators: Vec, + param: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSParameterProperty, span); + + self.ctx.write_bool(AstProp::Override, is_override); + self.ctx.write_bool(AstProp::Readonly, is_readonly); + self.ctx.write_bool(AstProp::Static, false); + self.write_accessibility(accessibility); + self.ctx.write_ref_vec(AstProp::Decorators, &id, decorators); + self.ctx.write_ref(AstProp::Parameter, &id, param); + + self.ctx.commit_node(id) + } + + pub fn write_ts_call_sig_decl( + &mut self, + span: &Span, + type_ann: Option, + params: Vec, + return_type: Option, + ) -> NodeRef { + let id = self + .ctx + .append_node(AstNode::TSCallSignatureDeclaration, span); + + self + .ctx + .write_maybe_ref(AstProp::TypeAnnotation, &id, type_ann); + self.ctx.write_ref_vec(AstProp::Params, &id, params); + self + .ctx + .write_maybe_ref(AstProp::ReturnType, &id, return_type); + + self.ctx.commit_node(id) + } + + pub fn write_ts_property_sig( + &mut self, + span: &Span, + computed: bool, + optional: bool, + readonly: bool, + key: NodeRef, + type_ann: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSPropertySignature, span); + + self.ctx.write_bool(AstProp::Computed, computed); + self.ctx.write_bool(AstProp::Optional, optional); + self.ctx.write_bool(AstProp::Readonly, readonly); + // TODO(@marvinhagemeister) not sure where this is coming from + self.ctx.write_bool(AstProp::Static, false); + + self.ctx.write_ref(AstProp::Key, &id, key); + self + .ctx + .write_maybe_ref(AstProp::TypeAnnotation, &id, type_ann); + + self.ctx.commit_node(id) + } + + pub fn write_ts_enum( + &mut self, + span: &Span, + declare: bool, + is_const: bool, + ident: NodeRef, + body: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSEnumDeclaration, span); + + self.ctx.write_bool(AstProp::Declare, declare); + self.ctx.write_bool(AstProp::Const, is_const); + self.ctx.write_ref(AstProp::Id, &id, ident); + self.ctx.write_ref(AstProp::Body, &id, body); + + self.ctx.commit_node(id) + } + + pub fn write_ts_enum_body( + &mut self, + span: &Span, + members: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSEnumBody, span); + self.ctx.write_ref_vec(AstProp::Members, &id, members); + self.ctx.commit_node(id) + } + + pub fn write_ts_enum_member( + &mut self, + span: &Span, + ident: NodeRef, + init: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSEnumMember, span); + + self.ctx.write_ref(AstProp::Id, &id, ident); + self.ctx.write_maybe_ref(AstProp::Initializer, &id, init); + + self.ctx.commit_node(id) + } + + pub fn write_ts_type_assertion( + &mut self, + span: &Span, + expr: NodeRef, + type_ann: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSTypeAssertion, span); + + self.ctx.write_ref(AstProp::Expression, &id, expr); + self.ctx.write_ref(AstProp::TypeAnnotation, &id, type_ann); + + self.ctx.commit_node(id) + } + + pub fn write_ts_type_param_inst( + &mut self, + span: &Span, + params: Vec, + ) -> NodeRef { + let id = self + .ctx + .append_node(AstNode::TSTypeParameterInstantiation, span); + + self.ctx.write_ref_vec(AstProp::Params, &id, params); + + self.ctx.commit_node(id) + } + + pub fn write_ts_type_alias( + &mut self, + span: &Span, + declare: bool, + ident: NodeRef, + type_param: Option, + type_ann: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSTypeAliasDeclaration, span); + + self.ctx.write_bool(AstProp::Declare, declare); + self.ctx.write_ref(AstProp::Id, &id, ident); + self + .ctx + .write_maybe_ref(AstProp::TypeParameters, &id, type_param); + self.ctx.write_ref(AstProp::TypeAnnotation, &id, type_ann); + + self.ctx.commit_node(id) + } + + pub fn write_ts_satisfies_expr( + &mut self, + span: &Span, + expr: NodeRef, + type_ann: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSSatisfiesExpression, span); + + self.ctx.write_ref(AstProp::Expression, &id, expr); + self.ctx.write_ref(AstProp::TypeAnnotation, &id, type_ann); + + self.ctx.commit_node(id) + } + + pub fn write_ts_as_expr( + &mut self, + span: &Span, + expr: NodeRef, + type_ann: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSAsExpression, span); + + self.ctx.write_ref(AstProp::Expression, &id, expr); + self.ctx.write_ref(AstProp::TypeAnnotation, &id, type_ann); + + self.ctx.commit_node(id) + } + + pub fn write_ts_non_null(&mut self, span: &Span, expr: NodeRef) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSNonNullExpression, span); + self.ctx.write_ref(AstProp::Expression, &id, expr); + self.ctx.commit_node(id) + } + + pub fn write_ts_this_type(&mut self, span: &Span) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSThisType, span); + self.ctx.commit_node(id) + } + + pub fn write_ts_interface( + &mut self, + span: &Span, + declare: bool, + ident: NodeRef, + type_param: Option, + extends: Vec, + body: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSInterface, span); + + self.ctx.write_bool(AstProp::Declare, declare); + self.ctx.write_ref(AstProp::Id, &id, ident); + self.ctx.write_maybe_ref(AstProp::Extends, &id, type_param); + self + .ctx + .write_ref_vec(AstProp::TypeParameters, &id, extends); + self.ctx.write_ref(AstProp::Body, &id, body); + + self.ctx.commit_node(id) + } + + pub fn write_ts_interface_decl( + &mut self, + span: &Span, + declare: bool, + ident: NodeRef, + type_param: Option, + extends: Vec, + body: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSInterfaceDeclaration, span); + + self.ctx.write_bool(AstProp::Declare, declare); + self.ctx.write_ref(AstProp::Id, &id, ident); + self.ctx.write_maybe_ref(AstProp::Extends, &id, type_param); + self + .ctx + .write_ref_vec(AstProp::TypeParameters, &id, extends); + self.ctx.write_ref(AstProp::Body, &id, body); + + self.ctx.commit_node(id) + } + + pub fn write_ts_interface_body( + &mut self, + span: &Span, + body: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSInterfaceBody, span); + self.ctx.write_ref_vec(AstProp::Body, &id, body); + self.ctx.commit_node(id) + } + + pub fn write_ts_construct_sig( + &mut self, + span: &Span, + type_params: Option, + params: Vec, + return_type: NodeRef, + ) -> NodeRef { + let id = self + .ctx + .append_node(AstNode::TSConstructSignatureDeclaration, span); + self + .ctx + .write_maybe_ref(AstProp::TypeParameters, &id, type_params); + self.ctx.write_ref_vec(AstProp::Params, &id, params); + self.ctx.write_ref(AstProp::ReturnType, &id, return_type); + self.ctx.commit_node(id) + } + + pub fn write_ts_getter_sig( + &mut self, + span: &Span, + key: NodeRef, + return_type: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSMethodSignature, span); + + self.ctx.write_bool(AstProp::Computed, false); + self.ctx.write_bool(AstProp::Optional, false); + self.ctx.write_bool(AstProp::Readonly, false); + self.ctx.write_bool(AstProp::Static, false); + self.ctx.write_str(AstProp::Kind, "getter"); + self.ctx.write_ref(AstProp::Key, &id, key); + self + .ctx + .write_maybe_ref(AstProp::ReturnType, &id, return_type); + + self.ctx.commit_node(id) + } + + pub fn write_ts_setter_sig( + &mut self, + span: &Span, + key: NodeRef, + param: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSMethodSignature, span); + + self.ctx.write_bool(AstProp::Computed, false); + self.ctx.write_bool(AstProp::Optional, false); + self.ctx.write_bool(AstProp::Readonly, false); + self.ctx.write_bool(AstProp::Static, false); + self.ctx.write_str(AstProp::Kind, "setter"); + self.ctx.write_ref(AstProp::Key, &id, key); + self.ctx.write_ref_vec(AstProp::Params, &id, vec![param]); + + self.ctx.commit_node(id) + } + + #[allow(clippy::too_many_arguments)] + pub fn write_ts_method_sig( + &mut self, + span: &Span, + is_computed: bool, + is_optional: bool, + key: NodeRef, + type_params: Option, + params: Vec, + return_type: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSMethodSignature, span); + + self.ctx.write_bool(AstProp::Computed, is_computed); + self.ctx.write_bool(AstProp::Optional, is_optional); + self.ctx.write_bool(AstProp::Readonly, false); + self.ctx.write_bool(AstProp::Static, false); + self.ctx.write_str(AstProp::Kind, "method"); + self.ctx.write_ref(AstProp::Key, &id, key); + self + .ctx + .write_maybe_ref(AstProp::TypeParameters, &id, type_params); + self.ctx.write_ref_vec(AstProp::Params, &id, params); + self + .ctx + .write_maybe_ref(AstProp::ReturnType, &id, return_type); + + self.ctx.commit_node(id) + } + + pub fn write_ts_interface_heritage( + &mut self, + span: &Span, + expr: NodeRef, + type_args: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSInterfaceHeritage, span); + + self.ctx.write_ref(AstProp::Expression, &id, expr); + self + .ctx + .write_maybe_ref(AstProp::TypeArguments, &id, type_args); + + self.ctx.commit_node(id) + } + + pub fn write_ts_index_sig( + &mut self, + span: &Span, + is_readonly: bool, + params: Vec, + type_ann: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSIndexSignature, span); + + self.ctx.write_bool(AstProp::Readonly, is_readonly); + self.ctx.write_ref_vec(AstProp::Parameters, &id, params); + self + .ctx + .write_maybe_ref(AstProp::TypeAnnotation, &id, type_ann); + + self.ctx.commit_node(id) + } + + pub fn write_ts_union_type( + &mut self, + span: &Span, + types: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSUnionType, span); + self.ctx.write_ref_vec(AstProp::Types, &id, types); + self.ctx.commit_node(id) + } + + pub fn write_ts_intersection_type( + &mut self, + span: &Span, + types: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSIntersectionType, span); + self.ctx.write_ref_vec(AstProp::Types, &id, types); + self.ctx.commit_node(id) + } + + pub fn write_ts_infer_type( + &mut self, + span: &Span, + type_param: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSInferType, span); + self.ctx.write_ref(AstProp::TypeParameter, &id, type_param); + self.ctx.commit_node(id) + } + + pub fn write_ts_type_op( + &mut self, + span: &Span, + op: &str, + type_ann: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSTypeOperator, span); + + self.ctx.write_str(AstProp::Operator, op); + self.ctx.write_ref(AstProp::TypeAnnotation, &id, type_ann); + + self.ctx.commit_node(id) + } + + pub fn write_ts_indexed_access_type( + &mut self, + span: &Span, + index: NodeRef, + obj: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSIndexedAccessType, span); + + self.ctx.write_ref(AstProp::IndexType, &id, index); + self.ctx.write_ref(AstProp::ObjectType, &id, obj); + + self.ctx.commit_node(id) + } + + pub fn write_ts_keyword( + &mut self, + kind: TsKeywordKind, + span: &Span, + ) -> NodeRef { + let kind = match kind { + TsKeywordKind::Any => AstNode::TSAnyKeyword, + TsKeywordKind::Unknown => AstNode::TSUnknownKeyword, + TsKeywordKind::Number => AstNode::TSNumberKeyword, + TsKeywordKind::Object => AstNode::TSObjectKeyword, + TsKeywordKind::Boolean => AstNode::TSBooleanKeyword, + TsKeywordKind::BigInt => AstNode::TSBigIntKeyword, + TsKeywordKind::String => AstNode::TSStringKeyword, + TsKeywordKind::Symbol => AstNode::TSSymbolKeyword, + TsKeywordKind::Void => AstNode::TSVoidKeyword, + TsKeywordKind::Undefined => AstNode::TSUndefinedKeyword, + TsKeywordKind::Null => AstNode::TSNullKeyword, + TsKeywordKind::Never => AstNode::TSNeverKeyword, + TsKeywordKind::Intrinsic => AstNode::TSIntrinsicKeyword, + }; + + let id = self.ctx.append_node(kind, span); + self.ctx.commit_node(id) + } + + pub fn write_ts_rest_type( + &mut self, + span: &Span, + type_ann: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSRestType, span); + self.ctx.write_ref(AstProp::TypeAnnotation, &id, type_ann); + self.ctx.commit_node(id) + } + + pub fn write_ts_conditional_type( + &mut self, + span: &Span, + check: NodeRef, + extends: NodeRef, + true_type: NodeRef, + false_type: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSConditionalType, span); + + self.ctx.write_ref(AstProp::CheckType, &id, check); + self.ctx.write_ref(AstProp::ExtendsType, &id, extends); + self.ctx.write_ref(AstProp::TrueType, &id, true_type); + self.ctx.write_ref(AstProp::FalseType, &id, false_type); + + self.ctx.commit_node(id) + } + + pub fn write_ts_mapped_type( + &mut self, + span: &Span, + readonly: Option, + optional: Option, + name: Option, + type_ann: Option, + type_param: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSMappedType, span); + + self.write_plus_minus_true(AstProp::Readonly, readonly); + self.write_plus_minus_true(AstProp::Optional, optional); + self.ctx.write_maybe_ref(AstProp::NameType, &id, name); + self + .ctx + .write_maybe_ref(AstProp::TypeAnnotation, &id, type_ann); + self.ctx.write_ref(AstProp::TypeParameter, &id, type_param); + + self.ctx.commit_node(id) + } + + pub fn write_ts_lit_type(&mut self, span: &Span, lit: NodeRef) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSLiteralType, span); + self.ctx.write_ref(AstProp::Literal, &id, lit); + self.ctx.commit_node(id) + } + + pub fn write_ts_tpl_lit( + &mut self, + span: &Span, + quasis: Vec, + types: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSTemplateLiteralType, span); + + self.ctx.write_ref_vec(AstProp::Quasis, &id, quasis); + self.ctx.write_ref_vec(AstProp::Types, &id, types); + + self.ctx.commit_node(id) + } + + pub fn write_ts_type_lit( + &mut self, + span: &Span, + members: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSTypeLiteral, span); + self.ctx.write_ref_vec(AstProp::Members, &id, members); + self.ctx.commit_node(id) + } + + pub fn write_ts_optional_type( + &mut self, + span: &Span, + type_ann: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSOptionalType, span); + self.ctx.write_ref(AstProp::TypeAnnotation, &id, type_ann); + self.ctx.commit_node(id) + } + + pub fn write_ts_type_ann( + &mut self, + span: &Span, + type_ann: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSTypeAnnotation, span); + self.ctx.write_ref(AstProp::TypeAnnotation, &id, type_ann); + self.ctx.commit_node(id) + } + + pub fn write_ts_array_type( + &mut self, + span: &Span, + elem_type: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSArrayType, span); + self.ctx.write_ref(AstProp::ElementType, &id, elem_type); + self.ctx.commit_node(id) + } + + pub fn write_ts_type_query( + &mut self, + span: &Span, + expr_name: NodeRef, + type_arg: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSTypeQuery, span); + + self.ctx.write_ref(AstProp::ExprName, &id, expr_name); + self + .ctx + .write_maybe_ref(AstProp::TypeArguments, &id, type_arg); + + self.ctx.commit_node(id) + } + + pub fn write_ts_type_ref( + &mut self, + span: &Span, + type_name: NodeRef, + type_arg: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSTypeReference, span); + + self.ctx.write_ref(AstProp::TypeName, &id, type_name); + self + .ctx + .write_maybe_ref(AstProp::TypeArguments, &id, type_arg); + + self.ctx.commit_node(id) + } + + pub fn write_ts_type_predicate( + &mut self, + span: &Span, + asserts: bool, + param_name: NodeRef, + type_ann: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSTypePredicate, span); + + self.ctx.write_bool(AstProp::Asserts, asserts); + self.ctx.write_ref(AstProp::ParameterName, &id, param_name); + self + .ctx + .write_maybe_ref(AstProp::TypeAnnotation, &id, type_ann); + + self.ctx.commit_node(id) + } + + pub fn write_ts_tuple_type( + &mut self, + span: &Span, + elem_types: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSTupleType, span); + + self + .ctx + .write_ref_vec(AstProp::ElementTypes, &id, elem_types); + + self.ctx.commit_node(id) + } + + pub fn write_ts_named_tuple_member( + &mut self, + span: &Span, + label: NodeRef, + elem_type: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSNamedTupleMember, span); + + self.ctx.write_ref(AstProp::Label, &id, label); + self.ctx.write_ref(AstProp::ElementType, &id, elem_type); + + self.ctx.commit_node(id) + } + + pub fn write_ts_type_param_decl( + &mut self, + span: &Span, + params: Vec, + ) -> NodeRef { + let id = self + .ctx + .append_node(AstNode::TSTypeParameterDeclaration, span); + + self.ctx.write_ref_vec(AstProp::Params, &id, params); + + self.ctx.commit_node(id) + } + + #[allow(clippy::too_many_arguments)] + pub fn write_ts_type_param( + &mut self, + span: &Span, + is_in: bool, + is_out: bool, + is_const: bool, + name: NodeRef, + constraint: Option, + default: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSTypeParameter, span); + + self.ctx.write_bool(AstProp::In, is_in); + self.ctx.write_bool(AstProp::Out, is_out); + self.ctx.write_bool(AstProp::Const, is_const); + self.ctx.write_ref(AstProp::Name, &id, name); + self + .ctx + .write_maybe_ref(AstProp::Constraint, &id, constraint); + self.ctx.write_maybe_ref(AstProp::Default, &id, default); + + self.ctx.commit_node(id) + } + + pub fn write_ts_import_type( + &mut self, + span: &Span, + arg: NodeRef, + qualifier: Option, + type_args: Option, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSImportType, span); + + self.ctx.write_ref(AstProp::Argument, &id, arg); + self.ctx.write_maybe_ref(AstProp::Qualifier, &id, qualifier); + self + .ctx + .write_maybe_ref(AstProp::TypeArguments, &id, type_args); + + self.ctx.commit_node(id) + } + + pub fn write_export_assign(&mut self, span: &Span, expr: NodeRef) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSExportAssignment, span); + self.ctx.write_ref(AstProp::Expression, &id, expr); + self.ctx.commit_node(id) + } + + pub fn write_ts_fn_type( + &mut self, + span: &Span, + params: Vec, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSFunctionType, span); + self.ctx.write_ref_vec(AstProp::Params, &id, params); + self.ctx.commit_node(id) + } + + pub fn write_ts_qualified_name( + &mut self, + span: &Span, + left: NodeRef, + right: NodeRef, + ) -> NodeRef { + let id = self.ctx.append_node(AstNode::TSQualifiedName, span); + + self.ctx.write_ref(AstProp::Left, &id, left); + self.ctx.write_ref(AstProp::Right, &id, right); + + self.ctx.commit_node(id) + } + + fn write_accessibility(&mut self, accessibility: Option) { + if let Some(value) = accessibility { + self.ctx.write_str(AstProp::Accessibility, &value); + } else { + self.ctx.write_undefined(AstProp::Accessibility); + } + } + + fn write_plus_minus_true( + &mut self, + prop: AstProp, + value: Option, + ) { + match value { + Some(TruePlusMinus::Plus) => self.ctx.write_str(prop, "+"), + Some(TruePlusMinus::Minus) => self.ctx.write_str(prop, "-"), + Some(TruePlusMinus::True) => self.ctx.write_bool(prop, true), + _ => self.ctx.write_undefined(prop), + } } } + +#[derive(Debug)] +pub enum TsKeywordKind { + Any, + Unknown, + Number, + Object, + Boolean, + BigInt, + String, + Symbol, + Void, + Undefined, + Null, + Never, + Intrinsic, +} diff --git a/cli/tools/lint/linter.rs b/cli/tools/lint/linter.rs index 6bb3c628fa..5d6f845274 100644 --- a/cli/tools/lint/linter.rs +++ b/cli/tools/lint/linter.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashSet; use std::path::Path; @@ -17,12 +17,11 @@ use deno_lint::linter::Linter as DenoLintLinter; use deno_lint::linter::LinterOptions; use deno_path_util::fs::atomic_write_file_with_retries; -use crate::sys::CliSys; -use crate::util::fs::specifier_from_file_path; - use super::rules::FileOrPackageLintRule; use super::rules::PackageLintRule; use super::ConfiguredRules; +use crate::sys::CliSys; +use crate::util::fs::specifier_from_file_path; pub struct CliLinterOptions { pub configured_rules: ConfiguredRules, diff --git a/cli/tools/lint/mod.rs b/cli/tools/lint/mod.rs index 6d3997ac3b..36ba85f613 100644 --- a/cli/tools/lint/mod.rs +++ b/cli/tools/lint/mod.rs @@ -1,8 +1,16 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. //! This module provides file linting utilities using //! [`deno_lint`](https://github.com/denoland/deno_lint). +use std::collections::HashSet; +use std::fs; +use std::io::stdin; +use std::io::Read; +use std::path::PathBuf; +use std::rc::Rc; +use std::sync::Arc; + use deno_ast::ModuleSpecifier; use deno_ast::ParsedSource; use deno_config::deno_json::LintRulesConfig; @@ -10,7 +18,6 @@ use deno_config::glob::FileCollector; use deno_config::glob::FilePatterns; use deno_config::workspace::WorkspaceDirectory; use deno_core::anyhow::anyhow; -use deno_core::error::generic_error; use deno_core::error::AnyError; use deno_core::futures::future::LocalBoxFuture; use deno_core::futures::FutureExt; @@ -25,19 +32,13 @@ use log::debug; use reporters::create_reporter; use reporters::LintReporter; use serde::Serialize; -use std::collections::HashSet; -use std::fs; -use std::io::stdin; -use std::io::Read; -use std::path::PathBuf; -use std::rc::Rc; -use std::sync::Arc; use crate::args::CliOptions; use crate::args::Flags; use crate::args::LintFlags; use crate::args::LintOptions; use crate::args::WorkspaceLintOptions; +use crate::cache::CacheDBHash; use crate::cache::Caches; use crate::cache::IncrementalCache; use crate::colors; @@ -75,9 +76,7 @@ pub async fn lint( ) -> Result<(), AnyError> { if lint_flags.watch.is_some() { if lint_flags.is_stdin() { - return Err(generic_error( - "Lint watch on standard input is not supported.", - )); + return Err(anyhow!("Lint watch on standard input is not supported.",)); } return lint_with_watch(flags, lint_flags).await; @@ -221,7 +220,7 @@ fn resolve_paths_with_options_batches( let mut paths_with_options_batches = Vec::with_capacity(members_lint_options.len()); for (dir, lint_options) in members_lint_options { - let files = collect_lint_files(cli_options, lint_options.files.clone())?; + let files = collect_lint_files(cli_options, lint_options.files.clone()); if !files.is_empty() { paths_with_options_batches.push(PathsWithOptions { dir, @@ -231,7 +230,7 @@ fn resolve_paths_with_options_batches( } } if paths_with_options_batches.is_empty() { - return Err(generic_error("No target files found.")); + return Err(anyhow!("No target files found.")); } Ok(paths_with_options_batches) } @@ -290,7 +289,7 @@ impl WorkspaceLinter { lint_rules.incremental_cache_state().map(|state| { Arc::new(IncrementalCache::new( self.caches.lint_incremental_cache_db(), - &state, + CacheDBHash::from_hashable(&state), &paths, )) }); @@ -444,7 +443,7 @@ impl WorkspaceLinter { fn collect_lint_files( cli_options: &CliOptions, files: FilePatterns, -) -> Result, AnyError> { +) -> Vec { FileCollector::new(|e| { is_script_ext(e.path) || (e.path.extension().is_none() && cli_options.ext_flag().is_some()) @@ -532,7 +531,7 @@ fn lint_stdin( } let mut source_code = String::new(); if stdin().read_to_string(&mut source_code).is_err() { - return Err(generic_error("Failed to read from stdin")); + return Err(anyhow!("Failed to read from stdin")); } let linter = CliLinter::new(CliLinterOptions { @@ -596,11 +595,12 @@ struct LintError { #[cfg(test)] mod tests { - use super::*; use pretty_assertions::assert_eq; use serde::Deserialize; use test_util as util; + use super::*; + #[derive(Serialize, Deserialize)] struct RulesSchema { #[serde(rename = "$schema")] diff --git a/cli/tools/lint/reporters.rs b/cli/tools/lint/reporters.rs index 18bc1216a6..24e04e840f 100644 --- a/cli/tools/lint/reporters.rs +++ b/cli/tools/lint/reporters.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_ast::diagnostics::Diagnostic; use deno_core::error::AnyError; @@ -8,9 +8,8 @@ use deno_runtime::colors; use log::info; use serde::Serialize; -use crate::args::LintReporterKind; - use super::LintError; +use crate::args::LintReporterKind; const JSON_SCHEMA_VERSION: u8 = 1; diff --git a/cli/tools/lint/rules/mod.rs b/cli/tools/lint/rules/mod.rs index dd723ad159..e7be12d56d 100644 --- a/cli/tools/lint/rules/mod.rs +++ b/cli/tools/lint/rules/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::collections::HashSet; diff --git a/cli/tools/lint/rules/no_sloppy_imports.rs b/cli/tools/lint/rules/no_sloppy_imports.rs index 1bf7eddf6e..825835f3b5 100644 --- a/cli/tools/lint/rules/no_sloppy_imports.rs +++ b/cli/tools/lint/rules/no_sloppy_imports.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::cell::RefCell; @@ -7,7 +7,7 @@ use std::sync::Arc; use deno_ast::SourceRange; use deno_config::workspace::WorkspaceResolver; -use deno_core::anyhow::anyhow; +use deno_error::JsErrorBox; use deno_graph::source::ResolutionKind; use deno_graph::source::ResolveError; use deno_graph::Range; @@ -20,11 +20,10 @@ use deno_resolver::sloppy_imports::SloppyImportsResolution; use deno_resolver::sloppy_imports::SloppyImportsResolutionKind; use text_lines::LineAndColumnIndex; +use super::ExtendedLintRule; use crate::graph_util::CliJsrUrlProvider; use crate::resolver::CliSloppyImportsResolver; -use super::ExtendedLintRule; - #[derive(Debug)] pub struct NoSloppyImportsRule { sloppy_imports_resolver: Option>, @@ -188,7 +187,7 @@ impl<'a> deno_graph::source::Resolver for SloppyImportCaptureResolver<'a> { let resolution = self .workspace_resolver .resolve(specifier_text, &referrer_range.specifier) - .map_err(|err| ResolveError::Other(err.into()))?; + .map_err(|err| ResolveError::Other(JsErrorBox::from_err(err)))?; match resolution { deno_config::workspace::MappedResolution::Normal { @@ -221,7 +220,7 @@ impl<'a> deno_graph::source::Resolver for SloppyImportCaptureResolver<'a> { } | deno_config::workspace::MappedResolution::PackageJson { .. } => { // this error is ignored - Err(ResolveError::Other(anyhow!(""))) + Err(ResolveError::Other(JsErrorBox::generic(""))) } } } diff --git a/cli/tools/lint/rules/no_slow_types.rs b/cli/tools/lint/rules/no_slow_types.rs index bc3f835b17..a792c38612 100644 --- a/cli/tools/lint/rules/no_slow_types.rs +++ b/cli/tools/lint/rules/no_slow_types.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; diff --git a/cli/tools/mod.rs b/cli/tools/mod.rs index a458da9f1b..35de8ab9fa 100644 --- a/cli/tools/mod.rs +++ b/cli/tools/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. pub mod bench; pub mod check; diff --git a/cli/tools/registry/api.rs b/cli/tools/registry/api.rs index 2f27cb2fea..c2d34442a1 100644 --- a/cli/tools/registry/api.rs +++ b/cli/tools/registry/api.rs @@ -1,12 +1,12 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::http_util; use deno_core::error::AnyError; use deno_core::serde_json; use deno_core::url::Url; use deno_runtime::deno_fetch; use serde::de::DeserializeOwned; +use crate::http_util; use crate::http_util::HttpClient; #[derive(serde::Deserialize)] diff --git a/cli/tools/registry/auth.rs b/cli/tools/registry/auth.rs index 820d3b6b60..3665990905 100644 --- a/cli/tools/registry/auth.rs +++ b/cli/tools/registry/auth.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::io::IsTerminal; diff --git a/cli/tools/registry/diagnostics.rs b/cli/tools/registry/diagnostics.rs index 9c32b8e36d..27753167f3 100644 --- a/cli/tools/registry/diagnostics.rs +++ b/cli/tools/registry/diagnostics.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::path::PathBuf; diff --git a/cli/tools/registry/graph.rs b/cli/tools/registry/graph.rs index 21962d009e..7152675ff8 100644 --- a/cli/tools/registry/graph.rs +++ b/cli/tools/registry/graph.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashSet; use std::sync::Arc; @@ -16,10 +16,9 @@ use deno_graph::WalkOptions; use deno_semver::jsr::JsrPackageReqReference; use deno_semver::npm::NpmPackageReqReference; -use crate::cache::ParsedSourceCache; - use super::diagnostics::PublishDiagnostic; use super::diagnostics::PublishDiagnosticsCollector; +use crate::cache::ParsedSourceCache; pub struct GraphDiagnosticsCollector { parsed_source_cache: Arc, diff --git a/cli/tools/registry/mod.rs b/cli/tools/registry/mod.rs index 45a040d236..ea457f8a71 100644 --- a/cli/tools/registry/mod.rs +++ b/cli/tools/registry/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashMap; use std::collections::HashSet; @@ -73,11 +73,10 @@ pub use pm::AddRmPackageReq; use publish_order::PublishOrderGraph; use unfurl::SpecifierUnfurler; -use super::check::TypeChecker; - use self::graph::GraphDiagnosticsCollector; use self::paths::CollectedPublishPath; use self::tar::PublishableTarball; +use super::check::TypeChecker; pub async fn publish( flags: Arc, @@ -1281,14 +1280,14 @@ fn ring_bell() { #[cfg(test)] mod tests { - use deno_ast::ModuleSpecifier; + use std::collections::HashMap; - use crate::tools::registry::has_license_file; + use deno_ast::ModuleSpecifier; use super::tar::PublishableTarball; use super::tar::PublishableTarballFile; use super::verify_version_manifest; - use std::collections::HashMap; + use crate::tools::registry::has_license_file; #[test] fn test_verify_version_manifest() { diff --git a/cli/tools/registry/paths.rs b/cli/tools/registry/paths.rs index 1c675982df..563b841280 100644 --- a/cli/tools/registry/paths.rs +++ b/cli/tools/registry/paths.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Validation logic in this file is shared with registry/api/src/ids.rs @@ -6,7 +6,6 @@ use std::collections::HashSet; use std::path::Path; use std::path::PathBuf; -use crate::sys::CliSys; use deno_ast::MediaType; use deno_ast::ModuleSpecifier; use deno_config::glob::FileCollector; @@ -14,10 +13,10 @@ use deno_config::glob::FilePatterns; use deno_core::error::AnyError; use thiserror::Error; -use crate::args::CliOptions; - use super::diagnostics::PublishDiagnostic; use super::diagnostics::PublishDiagnosticsCollector; +use crate::args::CliOptions; +use crate::sys::CliSys; /// A package path, like '/foo' or '/foo/bar'. The path is prefixed with a slash /// and does not end with a slash. @@ -234,7 +233,7 @@ pub fn collect_publish_paths( ) -> Result, AnyError> { let diagnostics_collector = opts.diagnostics_collector; let publish_paths = - collect_paths(opts.cli_options, diagnostics_collector, opts.file_patterns)?; + collect_paths(opts.cli_options, diagnostics_collector, opts.file_patterns); let publish_paths_set = publish_paths.iter().cloned().collect::>(); let capacity = publish_paths.len() + opts.force_include_paths.len(); let mut paths = HashSet::with_capacity(capacity); @@ -322,7 +321,7 @@ fn collect_paths( cli_options: &CliOptions, diagnostics_collector: &PublishDiagnosticsCollector, file_patterns: FilePatterns, -) -> Result, AnyError> { +) -> Vec { FileCollector::new(|e| { if !e.metadata.file_type().is_file() { if let Ok(specifier) = ModuleSpecifier::from_file_path(e.path) { diff --git a/cli/tools/registry/pm.rs b/cli/tools/registry/pm.rs index ab4d92762f..0b27b1a3e3 100644 --- a/cli/tools/registry/pm.rs +++ b/cli/tools/registry/pm.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::path::Path; use std::path::PathBuf; @@ -861,10 +861,8 @@ async fn npm_install_after_modification( // make a new CliFactory to pick up the updated config file let cli_factory = CliFactory::from_flags(flags); // surface any errors in the package.json - let npm_resolver = cli_factory.npm_resolver().await?; - if let Some(npm_resolver) = npm_resolver.as_managed() { - npm_resolver.ensure_no_pkg_json_dep_errors()?; - } + let npm_installer = cli_factory.npm_installer()?; + npm_installer.ensure_no_pkg_json_dep_errors()?; // npm install cache_deps::cache_top_level_deps(&cli_factory, jsr_resolver).await?; diff --git a/cli/tools/registry/pm/cache_deps.rs b/cli/tools/registry/pm/cache_deps.rs index 814c76cb27..5683a30cc8 100644 --- a/cli/tools/registry/pm/cache_deps.rs +++ b/cli/tools/registry/pm/cache_deps.rs @@ -1,26 +1,30 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::sync::Arc; +use deno_core::error::AnyError; +use deno_core::futures::stream::FuturesUnordered; +use deno_core::futures::StreamExt; +use deno_semver::jsr::JsrPackageReqReference; + use crate::factory::CliFactory; use crate::graph_container::ModuleGraphContainer; use crate::graph_container::ModuleGraphUpdatePermit; use crate::graph_util::CreateGraphOptions; -use deno_core::error::AnyError; -use deno_core::futures::stream::FuturesUnordered; -use deno_core::futures::StreamExt; -use deno_semver::jsr::JsrPackageReqReference; +use crate::npm::installer::PackageCaching; pub async fn cache_top_level_deps( // todo(dsherret): don't pass the factory into this function. Instead use ctor deps factory: &CliFactory, jsr_resolver: Option>, ) -> Result<(), AnyError> { - let npm_resolver = factory.npm_resolver().await?; + let npm_installer = factory.npm_installer_if_managed()?; let cli_options = factory.cli_options()?; - if let Some(npm_resolver) = npm_resolver.as_managed() { - npm_resolver.ensure_top_level_package_json_install().await?; + if let Some(npm_installer) = &npm_installer { + npm_installer + .ensure_top_level_package_json_install() + .await?; if let Some(lockfile) = cli_options.maybe_lockfile() { lockfile.error_if_changed()?; } @@ -137,10 +141,8 @@ pub async fn cache_top_level_deps( maybe_graph_error = graph_builder.graph_roots_valid(graph, &roots); } - if let Some(npm_resolver) = npm_resolver.as_managed() { - npm_resolver - .cache_packages(crate::npm::PackageCaching::All) - .await?; + if let Some(npm_installer) = &npm_installer { + npm_installer.cache_packages(PackageCaching::All).await?; } maybe_graph_error?; diff --git a/cli/tools/registry/pm/deps.rs b/cli/tools/registry/pm/deps.rs index ffa53417e9..621dd4693d 100644 --- a/cli/tools/registry/pm/deps.rs +++ b/cli/tools/registry/pm/deps.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::collections::HashMap; @@ -35,18 +35,18 @@ use import_map::ImportMapWithDiagnostics; use import_map::SpecifierMapEntry; use tokio::sync::Semaphore; +use super::ConfigUpdater; 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::installer::NpmInstaller; use crate::npm::CliNpmResolver; use crate::npm::NpmFetchResolver; use crate::util::sync::AtomicFlag; -use super::ConfigUpdater; - #[derive(Clone, Debug, PartialEq, Eq)] pub enum ImportMapKind { Inline, @@ -451,7 +451,8 @@ pub struct DepManager { // TODO(nathanwhit): probably shouldn't be pub pub(crate) jsr_fetch_resolver: Arc, pub(crate) npm_fetch_resolver: Arc, - npm_resolver: Arc, + npm_resolver: CliNpmResolver, + npm_installer: Arc, permissions_container: PermissionsContainer, main_module_graph_container: Arc, lockfile: Option>, @@ -461,7 +462,8 @@ pub struct DepManagerArgs { pub module_load_preparer: Arc, pub jsr_fetch_resolver: Arc, pub npm_fetch_resolver: Arc, - pub npm_resolver: Arc, + pub npm_installer: Arc, + pub npm_resolver: CliNpmResolver, pub permissions_container: PermissionsContainer, pub main_module_graph_container: Arc, pub lockfile: Option>, @@ -478,6 +480,7 @@ impl DepManager { module_load_preparer, jsr_fetch_resolver, npm_fetch_resolver, + npm_installer, npm_resolver, permissions_container, main_module_graph_container, @@ -491,6 +494,7 @@ impl DepManager { dependencies_resolved: AtomicFlag::lowered(), module_load_preparer, npm_fetch_resolver, + npm_installer, npm_resolver, permissions_container, main_module_graph_container, @@ -547,9 +551,10 @@ impl DepManager { 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::Npm => npm_resolver + .resolution() + .resolve_pkg_id_from_pkg_req(&dep.req) + .is_ok(), DepKind::Jsr => graph.packages.mappings().contains_key(&dep.req), }) { self.dependencies_resolved.raise(); @@ -557,7 +562,10 @@ impl DepManager { return Ok(()); } - npm_resolver.ensure_top_level_package_json_install().await?; + self + .npm_installer + .ensure_top_level_package_json_install() + .await?; let mut roots = Vec::new(); let mut info_futures = FuturesUnordered::new(); for dep in &self.deps { @@ -623,7 +631,12 @@ impl DepManager { 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 snapshot = self + .npm_resolver + .as_managed() + .unwrap() + .resolution() + .snapshot(); let resolved_npm = snapshot.package_reqs(); let resolved_jsr = graph.packages.mappings(); for dep in &self.deps { @@ -670,10 +683,21 @@ impl DepManager { .and_then(|info| { let latest_tag = info.dist_tags.get("latest")?; let lower_bound = &semver_compatible.as_ref()?.version; - if latest_tag > lower_bound { + if latest_tag >= lower_bound { Some(latest_tag.clone()) } else { - latest_version(Some(latest_tag), info.versions.keys()) + latest_version( + Some(latest_tag), + info.versions.iter().filter_map( + |(version, version_info)| { + if version_info.deprecated.is_none() { + Some(version) + } else { + None + } + }, + ), + ) } }) .map(|version| PackageNv { diff --git a/cli/tools/registry/pm/outdated.rs b/cli/tools/registry/pm/outdated.rs index bb4c60fde8..610ad48c1d 100644 --- a/cli/tools/registry/pm/outdated.rs +++ b/cli/tools/registry/pm/outdated.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashSet; use std::sync::Arc; @@ -12,6 +12,10 @@ use deno_semver::StackString; use deno_semver::VersionReq; use deno_terminal::colors; +use super::deps::Dep; +use super::deps::DepManager; +use super::deps::DepManagerArgs; +use super::deps::PackageLatestVersion; use crate::args::CliOptions; use crate::args::Flags; use crate::args::OutdatedFlags; @@ -21,11 +25,6 @@ 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, @@ -281,9 +280,15 @@ fn choose_new_version_req( if preferred.version <= resolved?.version { return None; } + let exact = if let Some(range) = dep.req.version_req.range() { + range.0[0].start == range.0[0].end + } else { + false + }; Some( VersionReq::parse_from_specifier( - format!("^{}", preferred.version).as_str(), + format!("{}{}", if exact { "" } else { "^" }, preferred.version) + .as_str(), ) .unwrap(), ) @@ -446,6 +451,7 @@ async fn dep_manager_args( jsr_fetch_resolver, npm_fetch_resolver, npm_resolver: factory.npm_resolver().await?.clone(), + npm_installer: factory.npm_installer()?.clone(), permissions_container: factory.root_permissions_container()?.clone(), main_module_graph_container: factory .main_module_graph_container() diff --git a/cli/tools/registry/provenance.rs b/cli/tools/registry/provenance.rs index 47169f2132..bd5249b5cd 100644 --- a/cli/tools/registry/provenance.rs +++ b/cli/tools/registry/provenance.rs @@ -1,11 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::http_util; -use crate::http_util::HttpClient; +use std::collections::HashMap; +use std::env; -use super::api::OidcTokenResponse; -use super::auth::gha_oidc_token; -use super::auth::is_gha; use base64::engine::general_purpose::STANDARD_NO_PAD; use base64::prelude::BASE64_STANDARD; use base64::Engine as _; @@ -27,8 +24,12 @@ use sha2::Digest; use spki::der::asn1; use spki::der::pem::LineEnding; use spki::der::EncodePem; -use std::collections::HashMap; -use std::env; + +use super::api::OidcTokenResponse; +use super::auth::gha_oidc_token; +use super::auth::is_gha; +use crate::http_util; +use crate::http_util::HttpClient; const PAE_PREFIX: &str = "DSSEv1"; @@ -706,10 +707,11 @@ async fn testify( #[cfg(test)] mod tests { + use std::env; + use super::ProvenanceAttestation; use super::Subject; use super::SubjectDigest; - use std::env; #[test] fn slsa_github_actions() { diff --git a/cli/tools/registry/publish_order.rs b/cli/tools/registry/publish_order.rs index ad77a56bb1..577627f348 100644 --- a/cli/tools/registry/publish_order.rs +++ b/cli/tools/registry/publish_order.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashMap; use std::collections::HashSet; diff --git a/cli/tools/registry/tar.rs b/cli/tools/registry/tar.rs index 6d1801ce69..2d6f53b5af 100644 --- a/cli/tools/registry/tar.rs +++ b/cli/tools/registry/tar.rs @@ -1,4 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::fmt::Write as FmtWrite; +use std::io::Write; +use std::path::Path; use bytes::Bytes; use deno_ast::MediaType; @@ -6,17 +10,13 @@ use deno_core::anyhow::Context; use deno_core::error::AnyError; use deno_core::url::Url; use sha2::Digest; -use std::fmt::Write as FmtWrite; -use std::io::Write; -use std::path::Path; use tar::Header; -use crate::cache::LazyGraphSourceParser; - use super::diagnostics::PublishDiagnostic; use super::diagnostics::PublishDiagnosticsCollector; use super::paths::CollectedPublishPath; use super::unfurl::SpecifierUnfurler; +use crate::cache::LazyGraphSourceParser; #[derive(Debug, Clone, PartialEq)] pub struct PublishableTarballFile { diff --git a/cli/tools/registry/unfurl.rs b/cli/tools/registry/unfurl.rs index 989a6e1ed4..e3fd4e715b 100644 --- a/cli/tools/registry/unfurl.rs +++ b/cli/tools/registry/unfurl.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::sync::Arc; @@ -655,15 +655,12 @@ fn to_range( mod tests { use std::sync::Arc; - use crate::resolver::SloppyImportsCachedFs; - - use super::*; - use crate::sys::CliSys; use deno_ast::MediaType; use deno_ast::ModuleSpecifier; use deno_config::workspace::ResolverWorkspaceJsrPackage; use deno_core::serde_json::json; use deno_core::url::Url; + use deno_resolver::sloppy_imports::SloppyImportsCachedFs; use deno_runtime::deno_node::PackageJson; use deno_semver::Version; use import_map::ImportMapWithDiagnostics; @@ -671,6 +668,9 @@ mod tests { use pretty_assertions::assert_eq; use test_util::testdata_path; + use super::*; + use crate::sys::CliSys; + fn parse_ast(specifier: &Url, source_code: &str) -> ParsedSource { let media_type = MediaType::from_specifier(specifier); deno_ast::parse_module(deno_ast::ParseParams { diff --git a/cli/tools/repl/channel.rs b/cli/tools/repl/channel.rs index 823a13d288..dbafacebc9 100644 --- a/cli/tools/repl/channel.rs +++ b/cli/tools/repl/channel.rs @@ -1,10 +1,13 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::cell::RefCell; use deno_core::anyhow::anyhow; use deno_core::error::AnyError; +use deno_core::error::CoreError; use deno_core::serde_json; use deno_core::serde_json::Value; -use std::cell::RefCell; +use deno_error::JsErrorBox; use tokio::sync::mpsc::channel; use tokio::sync::mpsc::unbounded_channel; use tokio::sync::mpsc::Receiver; @@ -46,7 +49,7 @@ pub enum RustylineSyncMessage { } pub enum RustylineSyncResponse { - PostMessage(Result), + PostMessage(Result), LspCompletions(Vec), } @@ -60,7 +63,7 @@ impl RustylineSyncMessageSender { &self, method: &str, params: Option, - ) -> Result { + ) -> Result { if let Err(err) = self .message_tx @@ -68,10 +71,11 @@ impl RustylineSyncMessageSender { method: method.to_string(), params: params .map(|params| serde_json::to_value(params)) - .transpose()?, + .transpose() + .map_err(JsErrorBox::from_err)?, }) { - Err(anyhow!("{}", err)) + Err(JsErrorBox::from_err(err).into()) } else { match self.response_rx.borrow_mut().blocking_recv().unwrap() { RustylineSyncResponse::PostMessage(result) => result, diff --git a/cli/tools/repl/editor.rs b/cli/tools/repl/editor.rs index dbc9bce703..27d726255c 100644 --- a/cli/tools/repl/editor.rs +++ b/cli/tools/repl/editor.rs @@ -1,7 +1,11 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::borrow::Cow; +use std::path::PathBuf; +use std::sync::atomic::AtomicBool; +use std::sync::atomic::Ordering::Relaxed; +use std::sync::Arc; -use crate::cdp; -use crate::colors; use deno_ast::swc::parser::error::SyntaxError; use deno_ast::swc::parser::token::BinOpToken; use deno_ast::swc::parser::token::Token; @@ -32,14 +36,11 @@ use rustyline::Modifiers; use rustyline::RepeatCount; use rustyline_derive::Helper; use rustyline_derive::Hinter; -use std::borrow::Cow; -use std::path::PathBuf; -use std::sync::atomic::AtomicBool; -use std::sync::atomic::Ordering::Relaxed; -use std::sync::Arc; use super::channel::RustylineSyncMessageSender; use super::session::REPL_INTERNALS_NAME; +use crate::cdp; +use crate::colors; // Provides helpers to the editor like validation for multi-line edits, completion candidates for // tab completion. diff --git a/cli/tools/repl/mod.rs b/cli/tools/repl/mod.rs index 9fb4624fa4..05e2f320eb 100644 --- a/cli/tools/repl/mod.rs +++ b/cli/tools/repl/mod.rs @@ -1,10 +1,16 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::io; use std::io::Write; - use std::sync::Arc; +use deno_core::error::AnyError; +use deno_core::futures::StreamExt; +use deno_core::serde_json; +use deno_core::unsync::spawn_blocking; +use deno_runtime::WorkerExecutionMode; +use rustyline::error::ReadlineError; + use crate::args::CliOptions; use crate::args::Flags; use crate::args::ReplFlags; @@ -13,12 +19,6 @@ use crate::colors; use crate::factory::CliFactory; use crate::file_fetcher::CliFileFetcher; use crate::file_fetcher::TextDecodedFile; -use deno_core::error::AnyError; -use deno_core::futures::StreamExt; -use deno_core::serde_json; -use deno_core::unsync::spawn_blocking; -use deno_runtime::WorkerExecutionMode; -use rustyline::error::ReadlineError; mod channel; mod editor; @@ -164,7 +164,7 @@ pub async fn run( let cli_options = factory.cli_options()?; let main_module = cli_options.resolve_main_module()?; let permissions = factory.root_permissions_container()?; - let npm_resolver = factory.npm_resolver().await?.clone(); + let npm_installer = factory.npm_installer_if_managed()?.cloned(); let resolver = factory.resolver().await?.clone(); let file_fetcher = factory.file_fetcher()?; let worker_factory = factory.create_cli_main_worker_factory().await?; @@ -187,7 +187,7 @@ pub async fn run( let worker = worker.into_main_worker(); let session = ReplSession::initialize( cli_options, - npm_resolver, + npm_installer, resolver, worker, main_module.clone(), diff --git a/cli/tools/repl/session.rs b/cli/tools/repl/session.rs index 02594f1519..5ea4523c48 100644 --- a/cli/tools/repl/session.rs +++ b/cli/tools/repl/session.rs @@ -1,23 +1,7 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::sync::Arc; -use crate::args::CliOptions; -use crate::cdp; -use crate::colors; -use crate::lsp::ReplLanguageServer; -use crate::npm::CliNpmResolver; -use crate::resolver::CliResolver; -use crate::tools::test::report_tests; -use crate::tools::test::reporters::PrettyTestReporter; -use crate::tools::test::reporters::TestReporter; -use crate::tools::test::run_tests_for_worker; -use crate::tools::test::send_test_event; -use crate::tools::test::worker_has_tests; -use crate::tools::test::TestEvent; -use crate::tools::test::TestEventReceiver; -use crate::tools::test::TestFailureFormatOptions; - use deno_ast::diagnostics::Diagnostic; use deno_ast::swc::ast as swc_ast; use deno_ast::swc::common::comments::CommentKind; @@ -32,8 +16,9 @@ use deno_ast::ParsedSource; use deno_ast::SourcePos; use deno_ast::SourceRangedForSpanned; use deno_ast::SourceTextInfo; -use deno_core::error::generic_error; +use deno_core::anyhow::anyhow; use deno_core::error::AnyError; +use deno_core::error::CoreError; use deno_core::futures::channel::mpsc::UnboundedReceiver; use deno_core::futures::FutureExt; use deno_core::futures::StreamExt; @@ -43,6 +28,7 @@ use deno_core::unsync::spawn; use deno_core::url::Url; use deno_core::LocalInspectorSession; use deno_core::PollEventLoopOptions; +use deno_error::JsErrorBox; use deno_graph::Position; use deno_graph::PositionRange; use deno_graph::SpecifierWithRange; @@ -55,6 +41,22 @@ use regex::Match; use regex::Regex; use tokio::sync::Mutex; +use crate::args::CliOptions; +use crate::cdp; +use crate::colors; +use crate::lsp::ReplLanguageServer; +use crate::npm::installer::NpmInstaller; +use crate::resolver::CliResolver; +use crate::tools::test::report_tests; +use crate::tools::test::reporters::PrettyTestReporter; +use crate::tools::test::reporters::TestReporter; +use crate::tools::test::run_tests_for_worker; +use crate::tools::test::send_test_event; +use crate::tools::test::worker_has_tests; +use crate::tools::test::TestEvent; +use crate::tools::test::TestEventReceiver; +use crate::tools::test::TestFailureFormatOptions; + fn comment_source_to_position_range( comment_start: SourcePos, m: &Match, @@ -179,7 +181,7 @@ struct ReplJsxState { } pub struct ReplSession { - npm_resolver: Arc, + npm_installer: Option>, resolver: Arc, pub worker: MainWorker, session: LocalInspectorSession, @@ -198,7 +200,7 @@ pub struct ReplSession { impl ReplSession { pub async fn initialize( cli_options: &CliOptions, - npm_resolver: Arc, + npm_installer: Option>, resolver: Arc, mut worker: MainWorker, main_module: ModuleSpecifier, @@ -250,10 +252,10 @@ impl ReplSession { let cwd_url = Url::from_directory_path(cli_options.initial_cwd()).map_err(|_| { - generic_error(format!( + anyhow!( "Unable to construct URL from the path of cwd: {}", cli_options.initial_cwd().to_string_lossy(), - )) + ) })?; let ts_config_for_emit = cli_options .resolve_ts_config_for_emit(deno_config::deno_json::TsConfigType::Emit)?; @@ -263,7 +265,7 @@ impl ReplSession { )?; let experimental_decorators = transpile_options.use_ts_decorators; let mut repl_session = ReplSession { - npm_resolver, + npm_installer, resolver, worker, session, @@ -322,7 +324,7 @@ impl ReplSession { &mut self, method: &str, params: Option, - ) -> Result { + ) -> Result { self .worker .js_runtime @@ -339,7 +341,7 @@ impl ReplSession { .await } - pub async fn run_event_loop(&mut self) -> Result<(), AnyError> { + pub async fn run_event_loop(&mut self) -> Result<(), CoreError> { self.worker.run_event_loop(true).await } @@ -400,21 +402,29 @@ impl ReplSession { } Err(err) => { // handle a parsing diagnostic - match err.downcast_ref::() { + match crate::util::result::any_and_jserrorbox_downcast_ref::< + deno_ast::ParseDiagnostic, + >(&err) + { Some(diagnostic) => { Ok(EvaluationOutput::Error(format_diagnostic(diagnostic))) } - None => match err.downcast_ref::() { - Some(diagnostics) => Ok(EvaluationOutput::Error( - diagnostics - .0 - .iter() - .map(format_diagnostic) - .collect::>() - .join("\n\n"), - )), - None => Err(err), - }, + None => { + match crate::util::result::any_and_jserrorbox_downcast_ref::< + ParseDiagnosticsError, + >(&err) + { + Some(diagnostics) => Ok(EvaluationOutput::Error( + diagnostics + .0 + .iter() + .map(format_diagnostic) + .collect::>() + .join("\n\n"), + )), + None => Err(err), + } + } } } } @@ -694,8 +704,8 @@ impl ReplSession { &mut self, program: &swc_ast::Program, ) -> Result<(), AnyError> { - let Some(npm_resolver) = self.npm_resolver.as_managed() else { - return Ok(()); // don't auto-install for byonm + let Some(npm_installer) = &self.npm_installer else { + return Ok(()); }; let mut collector = ImportCollector::new(); @@ -727,13 +737,13 @@ impl ReplSession { let has_node_specifier = resolved_imports.iter().any(|url| url.scheme() == "node"); if !npm_imports.is_empty() || has_node_specifier { - npm_resolver + npm_installer .add_and_cache_package_reqs(&npm_imports) .await?; // prevent messages in the repl about @types/node not being cached if has_node_specifier { - npm_resolver.inject_synthetic_types_node_package().await?; + npm_installer.inject_synthetic_types_node_package().await?; } } Ok(()) @@ -742,7 +752,7 @@ impl ReplSession { async fn evaluate_expression( &mut self, expression: &str, - ) -> Result { + ) -> Result { self .post_message_with_event_loop( "Runtime.evaluate", @@ -765,7 +775,9 @@ impl ReplSession { }), ) .await - .and_then(|res| serde_json::from_value(res).map_err(|e| e.into())) + .and_then(|res| { + serde_json::from_value(res).map_err(|e| JsErrorBox::from_err(e).into()) + }) } } diff --git a/cli/tools/run/hmr.rs b/cli/tools/run/hmr.rs index 373c207d69..913e119689 100644 --- a/cli/tools/run/hmr.rs +++ b/cli/tools/run/hmr.rs @@ -1,16 +1,16 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashMap; use std::path::PathBuf; use std::sync::Arc; -use deno_core::error::generic_error; -use deno_core::error::AnyError; +use deno_core::error::CoreError; use deno_core::futures::StreamExt; use deno_core::serde_json::json; use deno_core::serde_json::{self}; use deno_core::url::Url; use deno_core::LocalInspectorSession; +use deno_error::JsErrorBox; use deno_terminal::colors; use tokio::select; @@ -66,19 +66,19 @@ pub struct HmrRunner { #[async_trait::async_trait(?Send)] impl crate::worker::HmrRunner for HmrRunner { // TODO(bartlomieju): this code is duplicated in `cli/tools/coverage/mod.rs` - async fn start(&mut self) -> Result<(), AnyError> { + async fn start(&mut self) -> Result<(), CoreError> { self.enable_debugger().await } // TODO(bartlomieju): this code is duplicated in `cli/tools/coverage/mod.rs` - async fn stop(&mut self) -> Result<(), AnyError> { + async fn stop(&mut self) -> Result<(), CoreError> { self .watcher_communicator .change_restart_mode(WatcherRestartMode::Automatic); self.disable_debugger().await } - async fn run(&mut self) -> Result<(), AnyError> { + async fn run(&mut self) -> Result<(), CoreError> { self .watcher_communicator .change_restart_mode(WatcherRestartMode::Manual); @@ -87,13 +87,13 @@ impl crate::worker::HmrRunner for HmrRunner { select! { biased; Some(notification) = session_rx.next() => { - let notification = serde_json::from_value::(notification)?; + let notification = serde_json::from_value::(notification).map_err(JsErrorBox::from_err)?; if notification.method == "Runtime.exceptionThrown" { - let exception_thrown = serde_json::from_value::(notification.params)?; + let exception_thrown = serde_json::from_value::(notification.params).map_err(JsErrorBox::from_err)?; let (message, description) = exception_thrown.exception_details.get_message_and_description(); - break Err(generic_error(format!("{} {}", message, description))); + break Err(JsErrorBox::generic(format!("{} {}", message, description)).into()); } else if notification.method == "Debugger.scriptParsed" { - let params = serde_json::from_value::(notification.params)?; + let params = serde_json::from_value::(notification.params).map_err(JsErrorBox::from_err)?; if params.url.starts_with("file://") { let file_url = Url::parse(¶ms.url).unwrap(); let file_path = file_url.to_file_path().unwrap(); @@ -105,7 +105,7 @@ impl crate::worker::HmrRunner for HmrRunner { } } changed_paths = self.watcher_communicator.watch_for_changed_paths() => { - let changed_paths = changed_paths?; + let changed_paths = changed_paths.map_err(JsErrorBox::from_err)?; let Some(changed_paths) = changed_paths else { let _ = self.watcher_communicator.force_restart(); @@ -187,7 +187,7 @@ impl HmrRunner { } // TODO(bartlomieju): this code is duplicated in `cli/tools/coverage/mod.rs` - async fn enable_debugger(&mut self) -> Result<(), AnyError> { + async fn enable_debugger(&mut self) -> Result<(), CoreError> { self .session .post_message::<()>("Debugger.enable", None) @@ -200,7 +200,7 @@ impl HmrRunner { } // TODO(bartlomieju): this code is duplicated in `cli/tools/coverage/mod.rs` - async fn disable_debugger(&mut self) -> Result<(), AnyError> { + async fn disable_debugger(&mut self) -> Result<(), CoreError> { self .session .post_message::<()>("Debugger.disable", None) @@ -216,7 +216,7 @@ impl HmrRunner { &mut self, script_id: &str, source: &str, - ) -> Result { + ) -> Result { let result = self .session .post_message( @@ -229,15 +229,16 @@ impl HmrRunner { ) .await?; - Ok(serde_json::from_value::( - result, - )?) + Ok( + serde_json::from_value::(result) + .map_err(JsErrorBox::from_err)?, + ) } async fn dispatch_hmr_event( &mut self, script_id: &str, - ) -> Result<(), AnyError> { + ) -> Result<(), CoreError> { let expr = format!( "dispatchEvent(new CustomEvent(\"hmr\", {{ detail: {{ path: \"{}\" }} }}));", script_id diff --git a/cli/tools/run/mod.rs b/cli/tools/run/mod.rs index cd7d1dd6c4..ecf1bd52f3 100644 --- a/cli/tools/run/mod.rs +++ b/cli/tools/run/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::io::Read; use std::sync::Arc; @@ -12,6 +12,7 @@ use crate::args::EvalFlags; use crate::args::Flags; use crate::args::WatchFlagsWithPaths; use crate::factory::CliFactory; +use crate::npm::installer::PackageCaching; use crate::util; use crate::util::file_watcher::WatcherRestartMode; @@ -202,18 +203,17 @@ pub async fn maybe_npm_install(factory: &CliFactory) -> Result<(), AnyError> { // ensure an "npm install" is done if the user has explicitly // opted into using a managed node_modules directory if cli_options.node_modules_dir()? == Some(NodeModulesDirMode::Auto) { - if let Some(npm_resolver) = factory.npm_resolver().await?.as_managed() { - let already_done = - npm_resolver.ensure_top_level_package_json_install().await?; + if let Some(npm_installer) = factory.npm_installer_if_managed()? { + let already_done = npm_installer + .ensure_top_level_package_json_install() + .await?; if !already_done && matches!( cli_options.default_npm_caching_strategy(), crate::graph_util::NpmCachingStrategy::Eager ) { - npm_resolver - .cache_packages(crate::npm::PackageCaching::All) - .await?; + npm_installer.cache_packages(PackageCaching::All).await?; } } } diff --git a/cli/tools/serve.rs b/cli/tools/serve.rs index d7989140ae..2143eb33bb 100644 --- a/cli/tools/serve.rs +++ b/cli/tools/serve.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::sync::Arc; @@ -43,7 +43,8 @@ pub async fn serve( maybe_npm_install(&factory).await?; - let worker_factory = factory.create_cli_main_worker_factory().await?; + let worker_factory = + Arc::new(factory.create_cli_main_worker_factory().await?); let hmr = serve_flags .watch .map(|watch_flags| watch_flags.hmr) @@ -58,7 +59,7 @@ pub async fn serve( } async fn do_serve( - worker_factory: CliMainWorkerFactory, + worker_factory: Arc, main_module: ModuleSpecifier, worker_count: Option, hmr: bool, @@ -73,7 +74,7 @@ async fn do_serve( ) .await?; let worker_count = match worker_count { - None | Some(1) => return worker.run().await, + None | Some(1) => return worker.run().await.map_err(Into::into), Some(c) => c, }; @@ -116,7 +117,7 @@ async fn do_serve( async fn run_worker( worker_count: usize, - worker_factory: CliMainWorkerFactory, + worker_factory: Arc, main_module: ModuleSpecifier, hmr: bool, ) -> Result { @@ -133,7 +134,7 @@ async fn run_worker( worker.run_for_watcher().await?; Ok(0) } else { - worker.run().await + worker.run().await.map_err(Into::into) } } @@ -164,7 +165,8 @@ async fn serve_with_watch( maybe_npm_install(&factory).await?; let _ = watcher_communicator.watch_paths(cli_options.watch_paths()); - let worker_factory = factory.create_cli_main_worker_factory().await?; + let worker_factory = + Arc::new(factory.create_cli_main_worker_factory().await?); do_serve(worker_factory, main_module.clone(), worker_count, hmr) .await?; diff --git a/cli/tools/task.rs b/cli/tools/task.rs index 4d83cc98fd..329195ab46 100644 --- a/cli/tools/task.rs +++ b/cli/tools/task.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashMap; use std::collections::HashSet; @@ -36,6 +36,8 @@ use crate::args::TaskFlags; use crate::colors; use crate::factory::CliFactory; use crate::node::CliNodeResolver; +use crate::npm::installer::NpmInstaller; +use crate::npm::installer::PackageCaching; use crate::npm::CliNpmResolver; use crate::task_runner; use crate::task_runner::run_future_forwarding_signals; @@ -203,6 +205,7 @@ pub async fn execute_script( }] }; + let npm_installer = factory.npm_installer_if_managed()?; let npm_resolver = factory.npm_resolver().await?; let node_resolver = factory.node_resolver().await?; let env_vars = task_runner::real_env_vars(); @@ -216,7 +219,8 @@ pub async fn execute_script( let task_runner = TaskRunner { task_flags: &task_flags, - npm_resolver: npm_resolver.as_ref(), + npm_installer: npm_installer.map(|n| n.as_ref()), + npm_resolver, node_resolver: node_resolver.as_ref(), env_vars, cli_options, @@ -266,7 +270,8 @@ struct RunSingleOptions<'a> { struct TaskRunner<'a> { task_flags: &'a TaskFlags, - npm_resolver: &'a dyn CliNpmResolver, + npm_installer: Option<&'a NpmInstaller>, + npm_resolver: &'a CliNpmResolver, node_resolver: &'a CliNodeResolver, env_vars: HashMap, cli_options: &'a CliOptions, @@ -458,11 +463,11 @@ impl<'a> TaskRunner<'a> { return Ok(0); }; - if let Some(npm_resolver) = self.npm_resolver.as_managed() { - npm_resolver.ensure_top_level_package_json_install().await?; - npm_resolver - .cache_packages(crate::npm::PackageCaching::All) + if let Some(npm_installer) = self.npm_installer { + npm_installer + .ensure_top_level_package_json_install() .await?; + npm_installer.cache_packages(PackageCaching::All).await?; } let cwd = match &self.task_flags.cwd { @@ -497,11 +502,11 @@ impl<'a> TaskRunner<'a> { argv: &[String], ) -> Result { // ensure the npm packages are installed if using a managed resolver - if let Some(npm_resolver) = self.npm_resolver.as_managed() { - npm_resolver.ensure_top_level_package_json_install().await?; - npm_resolver - .cache_packages(crate::npm::PackageCaching::All) + if let Some(npm_installer) = self.npm_installer { + npm_installer + .ensure_top_level_package_json_install() .await?; + npm_installer.cache_packages(PackageCaching::All).await?; } let cwd = match &self.task_flags.cwd { diff --git a/cli/tools/test/channel.rs b/cli/tools/test/channel.rs index 9a003f2d5d..68633b17e6 100644 --- a/cli/tools/test/channel.rs +++ b/cli/tools/test/channel.rs @@ -1,15 +1,5 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use super::TestEvent; -use deno_core::futures::future::poll_fn; -use deno_core::parking_lot; -use deno_core::parking_lot::lock_api::RawMutex; -use deno_core::parking_lot::lock_api::RawMutexTimed; -use deno_runtime::deno_io::pipe; -use deno_runtime::deno_io::AsyncPipeRead; -use deno_runtime::deno_io::PipeRead; -use deno_runtime::deno_io::PipeWrite; -use memmem::Searcher; use std::fmt::Display; use std::future::Future; use std::io::Write; @@ -19,6 +9,16 @@ use std::sync::atomic::Ordering; use std::task::ready; use std::task::Poll; use std::time::Duration; + +use deno_core::futures::future::poll_fn; +use deno_core::parking_lot; +use deno_core::parking_lot::lock_api::RawMutex; +use deno_core::parking_lot::lock_api::RawMutexTimed; +use deno_runtime::deno_io::pipe; +use deno_runtime::deno_io::AsyncPipeRead; +use deno_runtime::deno_io::PipeRead; +use deno_runtime::deno_io::PipeWrite; +use memmem::Searcher; use tokio::io::AsyncRead; use tokio::io::AsyncReadExt; use tokio::io::ReadBuf; @@ -27,6 +27,8 @@ use tokio::sync::mpsc::UnboundedReceiver; use tokio::sync::mpsc::UnboundedSender; use tokio::sync::mpsc::WeakUnboundedSender; +use super::TestEvent; + /// 8-byte sync marker that is unlikely to appear in normal output. Equivalent /// to the string `"\u{200B}\0\u{200B}\0"`. const SYNC_MARKER: &[u8; 8] = &[226, 128, 139, 0, 226, 128, 139, 0]; @@ -35,7 +37,8 @@ const HALF_SYNC_MARKER: &[u8; 4] = &[226, 128, 139, 0]; const BUFFER_SIZE: usize = 4096; /// The test channel has been closed and cannot be used to send further messages. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, deno_error::JsError)] +#[class(generic)] pub struct ChannelClosedError; impl std::error::Error for ChannelClosedError {} @@ -437,11 +440,12 @@ impl TestEventSender { #[allow(clippy::print_stderr)] #[cfg(test)] mod tests { - use super::*; - use crate::tools::test::TestResult; use deno_core::unsync::spawn; use deno_core::unsync::spawn_blocking; + use super::*; + use crate::tools::test::TestResult; + /// Test that output is correctly interleaved with messages. #[tokio::test] async fn spawn_worker() { diff --git a/cli/tools/test/fmt.rs b/cli/tools/test/fmt.rs index 0f6a9ed2b4..e5b40b874b 100644 --- a/cli/tools/test/fmt.rs +++ b/cli/tools/test/fmt.rs @@ -1,16 +1,16 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::borrow::Cow; +use std::ops::AddAssign; use deno_core::stats::RuntimeActivity; use deno_core::stats::RuntimeActivityDiff; use deno_core::stats::RuntimeActivityTrace; use deno_core::stats::RuntimeActivityType; use phf::phf_map; -use std::borrow::Cow; -use std::ops::AddAssign; - -use crate::util::path::to_percent_decoded_str; use super::*; +use crate::util::path::to_percent_decoded_str; pub fn to_relative_path_or_remote_url(cwd: &Url, path_or_url: &str) -> String { let Ok(url) = Url::parse(path_or_url) else { diff --git a/cli/tools/test/mod.rs b/cli/tools/test/mod.rs index 3745d7c7ec..21ee7e152d 100644 --- a/cli/tools/test/mod.rs +++ b/cli/tools/test/mod.rs @@ -1,4 +1,72 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::borrow::Cow; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::collections::BTreeSet; +use std::collections::HashMap; +use std::collections::HashSet; +use std::env; +use std::fmt::Write as _; +use std::future::poll_fn; +use std::io::Write; +use std::num::NonZeroUsize; +use std::path::Path; +use std::sync::atomic::AtomicBool; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; +use std::sync::Arc; +use std::task::Poll; +use std::time::Duration; +use std::time::Instant; + +use deno_ast::MediaType; +use deno_cache_dir::file_fetcher::File; +use deno_config::glob::FilePatterns; +use deno_config::glob::WalkEntry; +use deno_core::anyhow; +use deno_core::anyhow::anyhow; +use deno_core::error::AnyError; +use deno_core::error::CoreError; +use deno_core::error::JsError; +use deno_core::futures::future; +use deno_core::futures::stream; +use deno_core::futures::FutureExt; +use deno_core::futures::StreamExt; +use deno_core::located_script_name; +use deno_core::serde_v8; +use deno_core::stats::RuntimeActivity; +use deno_core::stats::RuntimeActivityDiff; +use deno_core::stats::RuntimeActivityStats; +use deno_core::stats::RuntimeActivityStatsFactory; +use deno_core::stats::RuntimeActivityStatsFilter; +use deno_core::stats::RuntimeActivityType; +use deno_core::unsync::spawn; +use deno_core::unsync::spawn_blocking; +use deno_core::url::Url; +use deno_core::v8; +use deno_core::ModuleSpecifier; +use deno_core::OpState; +use deno_core::PollEventLoopOptions; +use deno_error::JsErrorBox; +use deno_runtime::deno_io::Stdio; +use deno_runtime::deno_io::StdioPipe; +use deno_runtime::deno_permissions::Permissions; +use deno_runtime::deno_permissions::PermissionsContainer; +use deno_runtime::fmt_errors::format_js_error; +use deno_runtime::permissions::RuntimePermissionDescriptorParser; +use deno_runtime::tokio_util::create_and_run_current_thread; +use deno_runtime::worker::MainWorker; +use deno_runtime::WorkerExecutionMode; +use indexmap::IndexMap; +use indexmap::IndexSet; +use log::Level; +use rand::rngs::SmallRng; +use rand::seq::SliceRandom; +use rand::SeedableRng; +use regex::Regex; +use serde::Deserialize; +use tokio::signal; use crate::args::CliOptions; use crate::args::Flags; @@ -20,73 +88,6 @@ use crate::util::path::matches_pattern_or_exact_path; use crate::worker::CliMainWorkerFactory; use crate::worker::CoverageCollector; -use deno_ast::MediaType; -use deno_cache_dir::file_fetcher::File; -use deno_config::glob::FilePatterns; -use deno_config::glob::WalkEntry; -use deno_core::anyhow; -use deno_core::anyhow::bail; -use deno_core::anyhow::Context as _; -use deno_core::error::generic_error; -use deno_core::error::AnyError; -use deno_core::error::JsError; -use deno_core::futures::future; -use deno_core::futures::stream; -use deno_core::futures::FutureExt; -use deno_core::futures::StreamExt; -use deno_core::located_script_name; -use deno_core::serde_v8; -use deno_core::stats::RuntimeActivity; -use deno_core::stats::RuntimeActivityDiff; -use deno_core::stats::RuntimeActivityStats; -use deno_core::stats::RuntimeActivityStatsFactory; -use deno_core::stats::RuntimeActivityStatsFilter; -use deno_core::stats::RuntimeActivityType; -use deno_core::unsync::spawn; -use deno_core::unsync::spawn_blocking; -use deno_core::url::Url; -use deno_core::v8; -use deno_core::ModuleSpecifier; -use deno_core::OpState; -use deno_core::PollEventLoopOptions; -use deno_runtime::deno_io::Stdio; -use deno_runtime::deno_io::StdioPipe; -use deno_runtime::deno_permissions::Permissions; -use deno_runtime::deno_permissions::PermissionsContainer; -use deno_runtime::fmt_errors::format_js_error; -use deno_runtime::permissions::RuntimePermissionDescriptorParser; -use deno_runtime::tokio_util::create_and_run_current_thread; -use deno_runtime::worker::MainWorker; -use deno_runtime::WorkerExecutionMode; -use indexmap::IndexMap; -use indexmap::IndexSet; -use log::Level; -use rand::rngs::SmallRng; -use rand::seq::SliceRandom; -use rand::SeedableRng; -use regex::Regex; -use serde::Deserialize; -use std::borrow::Cow; -use std::cell::RefCell; -use std::collections::BTreeMap; -use std::collections::BTreeSet; -use std::collections::HashMap; -use std::collections::HashSet; -use std::env; -use std::fmt::Write as _; -use std::future::poll_fn; -use std::io::Write; -use std::num::NonZeroUsize; -use std::path::Path; -use std::sync::atomic::AtomicBool; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering; -use std::sync::Arc; -use std::task::Poll; -use std::time::Duration; -use std::time::Instant; -use tokio::signal; - mod channel; pub mod fmt; pub mod reporters; @@ -105,6 +106,8 @@ use reporters::PrettyTestReporter; use reporters::TapTestReporter; use reporters::TestReporter; +use crate::tools::test::channel::ChannelClosedError; + /// How many times we're allowed to spin the event loop before considering something a leak. const MAX_SANITIZER_LOOP_SPINS: usize = 16; @@ -611,7 +614,7 @@ async fn configure_main_worker( permissions_container: PermissionsContainer, worker_sender: TestEventWorkerSender, options: &TestSpecifierOptions, -) -> Result<(Option>, MainWorker), anyhow::Error> { +) -> Result<(Option>, MainWorker), CoreError> { let mut worker = worker_factory .create_custom_worker( WorkerExecutionMode::Test, @@ -639,21 +642,15 @@ async fn configure_main_worker( let mut worker = worker.into_main_worker(); match res { Ok(()) => Ok(()), - Err(error) => { - // TODO(mmastrac): It would be nice to avoid having this error pattern repeated - if error.is::() { - send_test_event( - &worker.js_runtime.op_state(), - TestEvent::UncaughtError( - specifier.to_string(), - Box::new(error.downcast::().unwrap()), - ), - )?; - Ok(()) - } else { - Err(error) - } + Err(CoreError::Js(err)) => { + send_test_event( + &worker.js_runtime.op_state(), + TestEvent::UncaughtError(specifier.to_string(), Box::new(err)), + ) + .map_err(JsErrorBox::from_err)?; + Ok(()) } + Err(err) => Err(err), }?; Ok((coverage_collector, worker)) } @@ -690,21 +687,14 @@ pub async fn test_specifier( .await { Ok(()) => Ok(()), - Err(error) => { - // TODO(mmastrac): It would be nice to avoid having this error pattern repeated - if error.is::() { - send_test_event( - &worker.js_runtime.op_state(), - TestEvent::UncaughtError( - specifier.to_string(), - Box::new(error.downcast::().unwrap()), - ), - )?; - Ok(()) - } else { - Err(error) - } + Err(CoreError::Js(err)) => { + send_test_event( + &worker.js_runtime.op_state(), + TestEvent::UncaughtError(specifier.to_string(), Box::new(err)), + )?; + Ok(()) } + Err(e) => Err(e.into()), } } @@ -717,7 +707,7 @@ async fn test_specifier_inner( specifier: ModuleSpecifier, fail_fast_tracker: FailFastTracker, options: TestSpecifierOptions, -) -> Result<(), AnyError> { +) -> Result<(), CoreError> { // Ensure that there are no pending exceptions before we start running tests worker.run_up_to_duration(Duration::from_millis(0)).await?; @@ -764,7 +754,7 @@ pub fn worker_has_tests(worker: &mut MainWorker) -> bool { /// Yields to tokio to allow async work to process, and then polls /// the event loop once. #[must_use = "The event loop result should be checked"] -pub async fn poll_event_loop(worker: &mut MainWorker) -> Result<(), AnyError> { +pub async fn poll_event_loop(worker: &mut MainWorker) -> Result<(), CoreError> { // Allow any ops that to do work in the tokio event loop to do so tokio::task::yield_now().await; // Spin the event loop once @@ -783,13 +773,11 @@ pub async fn poll_event_loop(worker: &mut MainWorker) -> Result<(), AnyError> { pub fn send_test_event( op_state: &RefCell, event: TestEvent, -) -> Result<(), AnyError> { - Ok( - op_state - .borrow_mut() - .borrow_mut::() - .send(event)?, - ) +) -> Result<(), ChannelClosedError> { + op_state + .borrow_mut() + .borrow_mut::() + .send(event) } pub async fn run_tests_for_worker( @@ -985,13 +973,10 @@ async fn run_tests_for_worker_inner( let result = match result { Ok(r) => r, Err(error) => { - if error.is::() { + if let CoreError::Js(js_error) = error { send_test_event( &state_rc, - TestEvent::UncaughtError( - specifier.to_string(), - Box::new(error.downcast::().unwrap()), - ), + TestEvent::UncaughtError(specifier.to_string(), Box::new(js_error)), )?; fail_fast_tracker.add_failure(); send_test_event( @@ -1001,7 +986,7 @@ async fn run_tests_for_worker_inner( had_uncaught_error = true; continue; } else { - return Err(error); + return Err(error.into()); } } }; @@ -1373,25 +1358,20 @@ pub async fn report_tests( reporter.report_summary(&elapsed, &tests, &test_steps); if let Err(err) = reporter.flush_report(&elapsed, &tests, &test_steps) { return ( - Err(generic_error(format!( - "Test reporter failed to flush: {}", - err - ))), + Err(anyhow!("Test reporter failed to flush: {}", err)), receiver, ); } if used_only { return ( - Err(generic_error( - "Test failed because the \"only\" option was used", - )), + Err(anyhow!("Test failed because the \"only\" option was used",)), receiver, ); } if failed { - return (Err(generic_error("Test failed")), receiver); + return (Err(anyhow!("Test failed")), receiver); } (Ok(()), receiver) @@ -1574,7 +1554,7 @@ pub async fn run_tests( if !workspace_test_options.permit_no_files && specifiers_with_mode.is_empty() { - return Err(generic_error("No test modules found")); + return Err(anyhow!("No test modules found")); } let doc_tests = get_doc_tests(&specifiers_with_mode, file_fetcher).await?; @@ -1610,10 +1590,10 @@ pub async fn run_tests( TestSpecifiersOptions { cwd: Url::from_directory_path(cli_options.initial_cwd()).map_err( |_| { - generic_error(format!( + anyhow!( "Unable to construct URL from the path of cwd: {}", cli_options.initial_cwd().to_string_lossy(), - )) + ) }, )?, concurrent_jobs: workspace_test_options.concurrent_jobs, @@ -1792,10 +1772,10 @@ pub async fn run_tests_with_watch( TestSpecifiersOptions { cwd: Url::from_directory_path(cli_options.initial_cwd()).map_err( |_| { - generic_error(format!( + anyhow!( "Unable to construct URL from the path of cwd: {}", cli_options.initial_cwd().to_string_lossy(), - )) + ) }, )?, concurrent_jobs: workspace_test_options.concurrent_jobs, diff --git a/cli/tools/test/reporters/common.rs b/cli/tools/test/reporters/common.rs index 7ca83db809..2db6a36464 100644 --- a/cli/tools/test/reporters/common.rs +++ b/cli/tools/test/reporters/common.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use super::fmt::format_test_error; use super::fmt::to_relative_path_or_remote_url; diff --git a/cli/tools/test/reporters/compound.rs b/cli/tools/test/reporters/compound.rs index 3ab7297db5..3c4409ecaa 100644 --- a/cli/tools/test/reporters/compound.rs +++ b/cli/tools/test/reporters/compound.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use super::*; @@ -129,7 +129,7 @@ impl TestReporter for CompoundTestReporter { if errors.is_empty() { Ok(()) } else { - bail!( + anyhow::bail!( "error in one or more wrapped reporters:\n{}", errors .iter() diff --git a/cli/tools/test/reporters/dot.rs b/cli/tools/test/reporters/dot.rs index 169c4b0e72..0912858431 100644 --- a/cli/tools/test/reporters/dot.rs +++ b/cli/tools/test/reporters/dot.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use super::common; use super::fmt::to_relative_path_or_remote_url; diff --git a/cli/tools/test/reporters/junit.rs b/cli/tools/test/reporters/junit.rs index 3998bee40d..9418ac9fb2 100644 --- a/cli/tools/test/reporters/junit.rs +++ b/cli/tools/test/reporters/junit.rs @@ -1,8 +1,10 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::VecDeque; use std::path::PathBuf; +use deno_core::anyhow::Context; + use super::fmt::to_relative_path_or_remote_url; use super::*; diff --git a/cli/tools/test/reporters/mod.rs b/cli/tools/test/reporters/mod.rs index 07351e9c3b..ef2b00b776 100644 --- a/cli/tools/test/reporters/mod.rs +++ b/cli/tools/test/reporters/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use super::*; diff --git a/cli/tools/test/reporters/pretty.rs b/cli/tools/test/reporters/pretty.rs index 4120bbfb54..3419fdea59 100644 --- a/cli/tools/test/reporters/pretty.rs +++ b/cli/tools/test/reporters/pretty.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use super::common; use super::fmt::to_relative_path_or_remote_url; diff --git a/cli/tools/test/reporters/tap.rs b/cli/tools/test/reporters/tap.rs index ea68ddd43a..c36df25756 100644 --- a/cli/tools/test/reporters/tap.rs +++ b/cli/tools/test/reporters/tap.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::serde_json::json; use deno_core::serde_json::{self}; diff --git a/cli/tools/upgrade.rs b/cli/tools/upgrade.rs index b3d7618be9..521c3217fe 100644 --- a/cli/tools/upgrade.rs +++ b/cli/tools/upgrade.rs @@ -1,7 +1,28 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. //! This module provides feature to upgrade deno executable +use std::borrow::Cow; +use std::env; +use std::fs; +use std::io::IsTerminal; +use std::ops::Sub; +use std::path::Path; +use std::path::PathBuf; +use std::process::Command; +use std::sync::Arc; +use std::time::Duration; + +use async_trait::async_trait; +use deno_core::anyhow::bail; +use deno_core::anyhow::Context; +use deno_core::error::AnyError; +use deno_core::unsync::spawn; +use deno_core::url::Url; +use deno_semver::SmallStackString; +use deno_semver::Version; +use once_cell::sync::Lazy; + use crate::args::Flags; use crate::args::UpgradeFlags; use crate::args::UPGRADE_USAGE; @@ -15,26 +36,6 @@ use crate::util::progress_bar::ProgressBar; use crate::util::progress_bar::ProgressBarStyle; use crate::version; -use async_trait::async_trait; -use deno_core::anyhow::bail; -use deno_core::anyhow::Context; -use deno_core::error::AnyError; -use deno_core::unsync::spawn; -use deno_core::url::Url; -use deno_semver::SmallStackString; -use deno_semver::Version; -use once_cell::sync::Lazy; -use std::borrow::Cow; -use std::env; -use std::fs; -use std::io::IsTerminal; -use std::ops::Sub; -use std::path::Path; -use std::path::PathBuf; -use std::process::Command; -use std::sync::Arc; -use std::time::Duration; - const RELEASE_URL: &str = "https://github.com/denoland/deno/releases"; const CANARY_URL: &str = "https://dl.deno.land/canary"; const DL_RELEASE_URL: &str = "https://dl.deno.land/release"; diff --git a/cli/tsc/99_main_compiler.js b/cli/tsc/99_main_compiler.js index f7862c95e4..65319211fb 100644 --- a/cli/tsc/99_main_compiler.js +++ b/cli/tsc/99_main_compiler.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// @@ -409,9 +409,20 @@ delete Object.prototype.__proto__; messageText = formatMessage(msgText, ri.code); } if (start !== undefined && length !== undefined && file) { - const startPos = file.getLineAndCharacterOfPosition(start); - const sourceLine = file.getFullText().split("\n")[startPos.line]; - const fileName = file.fileName; + let startPos = file.getLineAndCharacterOfPosition(start); + let sourceLine = file.getFullText().split("\n")[startPos.line]; + const originalFileName = file.fileName; + const fileName = ops.op_remap_specifier + ? (ops.op_remap_specifier(file.fileName) ?? file.fileName) + : file.fileName; + // Bit of a hack to detect when we have a .wasm file and want to hide + // the .d.ts text. This is not perfect, but will work in most scenarios + if ( + fileName.endsWith(".wasm") && originalFileName.endsWith(".wasm.d.mts") + ) { + startPos = { line: 0, character: 0 }; + sourceLine = undefined; + } return { start: startPos, end: file.getLineAndCharacterOfPosition(start + length), @@ -475,6 +486,9 @@ delete Object.prototype.__proto__; 2792, // TS2307: Cannot find module '{0}' or its corresponding type declarations. 2307, + // Relative import errors to add an extension + 2834, + 2835, // TS5009: Cannot find the common subdirectory path for the input files. 5009, // TS5055: Cannot write file @@ -486,6 +500,8 @@ delete Object.prototype.__proto__; // Microsoft/TypeScript#26825 but that doesn't seem to be working here, // so we will ignore complaints about this compiler setting. 5070, + // TS6053: File '{0}' not found. + 6053, // TS7016: Could not find a declaration file for module '...'. '...' // implicitly has an 'any' type. This is due to `allowJs` being off by // default but importing of a JavaScript module. @@ -691,15 +707,14 @@ delete Object.prototype.__proto__; resolveTypeReferenceDirectiveReferences( typeDirectiveReferences, containingFilePath, - redirectedReference, + _redirectedReference, options, containingSourceFile, _reusedNames, ) { const isCjs = containingSourceFile?.impliedNodeFormat === ts.ModuleKind.CommonJS; - /** @type {Array} */ - const result = typeDirectiveReferences.map((arg) => { + const toResolve = typeDirectiveReferences.map((arg) => { /** @type {ts.FileReference} */ const fileReference = typeof arg === "string" ? { @@ -708,46 +723,50 @@ delete Object.prototype.__proto__; fileName: arg, } : arg; - if (fileReference.fileName.startsWith("npm:")) { - /** @type {[string, ts.Extension] | undefined} */ - const resolved = ops.op_resolve( - containingFilePath, - [ - [ - fileReference.resolutionMode == null - ? isCjs - : fileReference.resolutionMode === ts.ModuleKind.CommonJS, - fileReference.fileName, - ], - ], - )?.[0]; - if (resolved) { - return { - resolvedTypeReferenceDirective: { - primary: true, - resolvedFileName: resolved[0], - // todo(dsherret): we should probably be setting this - isExternalLibraryImport: undefined, - }, - }; - } else { - return { - resolvedTypeReferenceDirective: undefined, - }; - } + return [ + fileReference.resolutionMode == null + ? isCjs + : fileReference.resolutionMode === ts.ModuleKind.CommonJS, + fileReference.fileName, + ]; + }); + + /** @type {Array<[string, ts.Extension | null] | undefined>} */ + const resolved = ops.op_resolve( + containingFilePath, + toResolve, + ); + + /** @type {Array} */ + const result = resolved.map((item) => { + if (item && item[1]) { + const [resolvedFileName, extension] = item; + return { + resolvedTypeReferenceDirective: { + primary: true, + resolvedFileName, + extension, + isExternalLibraryImport: false, + }, + }; } else { - return ts.resolveTypeReferenceDirective( - fileReference.fileName, - containingFilePath, - options, - host, - redirectedReference, - undefined, - containingSourceFile?.impliedNodeFormat ?? - fileReference.resolutionMode, - ); + return { + resolvedTypeReferenceDirective: undefined, + }; } }); + + if (logDebug) { + debug( + "resolveTypeReferenceDirectiveReferences ", + typeDirectiveReferences, + containingFilePath, + options, + containingSourceFile?.fileName, + " => ", + result, + ); + } return result; }, resolveModuleNameLiterals( @@ -771,7 +790,7 @@ delete Object.prototype.__proto__; debug(` base: ${base}`); debug(` specifiers: ${specifiers.map((s) => s[1]).join(", ")}`); } - /** @type {Array<[string, ts.Extension] | undefined>} */ + /** @type {Array<[string, ts.Extension | null] | undefined>} */ const resolved = ops.op_resolve( base, specifiers, @@ -779,7 +798,7 @@ delete Object.prototype.__proto__; if (resolved) { /** @type {Array} */ const result = resolved.map((item) => { - if (item) { + if (item && item[1]) { const [resolvedFileName, extension] = item; return { resolvedModule: { @@ -1037,24 +1056,27 @@ delete Object.prototype.__proto__; configFileParsingDiagnostics, }); - const checkFiles = localOnly - ? rootNames - .filter((n) => !n.startsWith("http")) - .map((checkName) => { - const sourceFile = program.getSourceFile(checkName); - if (sourceFile == null) { - throw new Error("Could not find source file for: " + checkName); - } - return sourceFile; - }) - : undefined; + let checkFiles = undefined; + + if (localOnly) { + const checkFileNames = new Set(); + checkFiles = []; + + for (const checkName of rootNames) { + if (checkName.startsWith("http")) { + continue; + } + const sourceFile = program.getSourceFile(checkName); + if (sourceFile != null) { + checkFiles.push(sourceFile); + } + checkFileNames.add(checkName); + } - if (checkFiles != null) { // When calling program.getSemanticDiagnostics(...) with a source file, we // need to call this code first in order to get it to invalidate cached // diagnostics correctly. This is what program.getSemanticDiagnostics() // does internally when calling without any arguments. - const checkFileNames = new Set(checkFiles.map((f) => f.fileName)); while ( program.getSemanticDiagnosticsOfNextAffectedFile( undefined, @@ -1099,6 +1121,36 @@ delete Object.prototype.__proto__; if (IGNORED_DIAGNOSTICS.includes(diagnostic.code)) { return false; } + + // ignore diagnostics resulting from the `ImportMeta` declaration in deno merging with + // the one in @types/node. the types of the filename and dirname properties are different, + // which causes tsc to error. + const importMetaFilenameDirnameModifiersRe = + /^All declarations of '(filename|dirname)'/; + const importMetaFilenameDirnameTypesRe = + /^Subsequent property declarations must have the same type.\s+Property '(filename|dirname)'/; + // Declarations of X must have identical modifiers. + if (diagnostic.code === 2687) { + if ( + typeof diagnostic.messageText === "string" && + (importMetaFilenameDirnameModifiersRe.test(diagnostic.messageText)) && + (diagnostic.file?.fileName.startsWith("asset:///") || + diagnostic.file?.fileName?.includes("@types/node")) + ) { + return false; + } + } + // Subsequent property declarations must have the same type. + if (diagnostic.code === 2717) { + if ( + typeof diagnostic.messageText === "string" && + (importMetaFilenameDirnameTypesRe.test(diagnostic.messageText)) && + (diagnostic.file?.fileName.startsWith("asset:///") || + diagnostic.file?.fileName?.includes("@types/node")) + ) { + return false; + } + } // make the diagnostic for using an `export =` in an es module a warning if (diagnostic.code === 1203) { diagnostic.category = ts.DiagnosticCategory.Warning; @@ -1393,7 +1445,6 @@ delete Object.prototype.__proto__; "ErrorConstructor", "gc", "Global", - "ImportMeta", "localStorage", "queueMicrotask", "RequestInit", diff --git a/cli/tsc/_analyze_types_node.ts b/cli/tsc/_analyze_types_node.ts index 10af00ee83..1a77b6c547 100755 --- a/cli/tsc/_analyze_types_node.ts +++ b/cli/tsc/_analyze_types_node.ts @@ -1,5 +1,5 @@ #!/usr/bin/env -S deno run --allow-env --allow-read --allow-write=. -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { ModuleDeclarationKind, Node, diff --git a/cli/tsc/compiler.d.ts b/cli/tsc/compiler.d.ts index 428e4d1ed8..0389527f5b 100644 --- a/cli/tsc/compiler.d.ts +++ b/cli/tsc/compiler.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Contains types that can be used to validate and check `99_main_compiler.js` diff --git a/cli/tsc/diagnostics.rs b/cli/tsc/diagnostics.rs index e4cc80723f..3780f65e77 100644 --- a/cli/tsc/diagnostics.rs +++ b/cli/tsc/diagnostics.rs @@ -1,16 +1,16 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::error::Error; +use std::fmt; use deno_ast::ModuleSpecifier; -use deno_graph::ModuleGraph; -use deno_terminal::colors; - use deno_core::serde::Deserialize; use deno_core::serde::Deserializer; use deno_core::serde::Serialize; use deno_core::serde::Serializer; use deno_core::sourcemap::SourceMap; -use std::error::Error; -use std::fmt; +use deno_graph::ModuleGraph; +use deno_terminal::colors; const MAX_SOURCE_LINE_LENGTH: usize = 150; @@ -90,9 +90,9 @@ impl DiagnosticMessageChain { s.push_str(&" ".repeat(level * 2)); s.push_str(&self.message_text); if let Some(next) = &self.next { - s.push('\n'); let arr = next.clone(); for dm in arr { + s.push('\n'); s.push_str(&dm.format_message(level + 1)); } } @@ -110,6 +110,15 @@ pub struct Position { pub character: u64, } +impl Position { + pub fn from_deno_graph(deno_graph_position: deno_graph::Position) -> Self { + Self { + line: deno_graph_position.line as u64, + character: deno_graph_position.character as u64, + } + } +} + #[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Diagnostic { @@ -142,6 +151,38 @@ pub struct Diagnostic { } impl Diagnostic { + pub fn from_missing_error( + specifier: &ModuleSpecifier, + maybe_range: Option<&deno_graph::Range>, + additional_message: Option, + ) -> Self { + Self { + category: DiagnosticCategory::Error, + code: 2307, + start: maybe_range.map(|r| Position::from_deno_graph(r.range.start)), + end: maybe_range.map(|r| Position::from_deno_graph(r.range.end)), + original_source_start: None, // will be applied later + message_text: Some(format!( + "Cannot find module '{}'.{}{}", + specifier, + if additional_message.is_none() { + "" + } else { + " " + }, + additional_message.unwrap_or_default() + )), + message_chain: None, + source: None, + source_line: None, + file_name: maybe_range.map(|r| r.specifier.to_string()), + related_information: None, + reports_deprecated: None, + reports_unnecessary: None, + other: Default::default(), + } + } + /// If this diagnostic should be included when it comes from a remote module. pub fn include_when_remote(&self) -> bool { /// TS6133: value is declared but its value is never read (noUnusedParameters and noUnusedLocals) @@ -279,7 +320,8 @@ impl fmt::Display for Diagnostic { } } -#[derive(Clone, Debug, Default, Eq, PartialEq)] +#[derive(Clone, Debug, Default, Eq, PartialEq, deno_error::JsError)] +#[class(generic)] pub struct Diagnostics(Vec); impl Diagnostics { @@ -299,6 +341,14 @@ impl Diagnostics { }); } + pub fn push(&mut self, diagnostic: Diagnostic) { + self.0.push(diagnostic); + } + + pub fn extend(&mut self, diagnostic: Diagnostics) { + self.0.extend(diagnostic.0); + } + /// Return a set of diagnostics where only the values where the predicate /// returns `true` are included. pub fn filter

(self, predicate: P) -> Self @@ -401,11 +451,12 @@ impl Error for Diagnostics {} #[cfg(test)] mod tests { - use super::*; use deno_core::serde_json; use deno_core::serde_json::json; use test_util::strip_ansi_codes; + use super::*; + #[test] fn test_de_diagnostics() { let value = json!([ diff --git a/cli/tsc/dts/lib.deno.ns.d.ts b/cli/tsc/dts/lib.deno.ns.d.ts index d9f66f11a7..e98f68ea38 100644 --- a/cli/tsc/dts/lib.deno.ns.d.ts +++ b/cli/tsc/dts/lib.deno.ns.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// /// diff --git a/cli/tsc/dts/lib.deno.shared_globals.d.ts b/cli/tsc/dts/lib.deno.shared_globals.d.ts index 96790fb665..a469525270 100644 --- a/cli/tsc/dts/lib.deno.shared_globals.d.ts +++ b/cli/tsc/dts/lib.deno.shared_globals.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Documentation partially adapted from [MDN](https://developer.mozilla.org/), // by Mozilla Contributors, which is licensed under CC-BY-SA 2.5. diff --git a/cli/tsc/dts/lib.deno.unstable.d.ts b/cli/tsc/dts/lib.deno.unstable.d.ts index 6759856e6a..bd32845a6a 100644 --- a/cli/tsc/dts/lib.deno.unstable.d.ts +++ b/cli/tsc/dts/lib.deno.unstable.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// /// @@ -293,7 +293,8 @@ declare namespace Deno { * executions. Each element in the array represents the number of milliseconds * to wait before retrying the execution. For example, `[1000, 5000, 10000]` * means that a failed execution will be retried at most 3 times, with 1 - * second, 5 seconds, and 10 seconds delay between each retry. + * second, 5 seconds, and 10 seconds delay between each retry. There is a + * limit of 5 retries and a maximum interval of 1 hour (3600000 milliseconds). * * @category Cloud * @experimental @@ -1267,16 +1268,15 @@ declare namespace Deno { * OpenTelemetry API. This is done using the official OpenTelemetry package * for JavaScript: * [`npm:@opentelemetry/api`](https://opentelemetry.io/docs/languages/js/). - * Deno integrates with this package to provide trace context propagation - * between native Deno APIs (like `Deno.serve` or `fetch`) and custom user - * code. Deno also provides APIs that allow exporting custom telemetry data - * via the same OTLP channel used by the Deno runtime. This is done using the - * [`jsr:@deno/otel`](https://jsr.io/@deno/otel) package. + * Deno integrates with this package to provide tracing, metrics, and trace + * context propagation between native Deno APIs (like `Deno.serve` or `fetch`) + * and custom user code. Deno automatically registers the providers with the + * OpenTelemetry API, so users can start creating custom traces, metrics, and + * logs without any additional setup. * * @example Using OpenTelemetry API to create custom traces * ```ts,ignore * import { trace } from "npm:@opentelemetry/api@1"; - * import "jsr:@deno/otel@0.0.2/register"; * * const tracer = trace.getTracer("example-tracer"); * @@ -1300,20 +1300,43 @@ declare namespace Deno { */ export namespace telemetry { /** - * A SpanExporter compatible with OpenTelemetry.js - * https://open-telemetry.github.io/opentelemetry-js/interfaces/_opentelemetry_sdk_trace_base.SpanExporter.html + * A TracerProvider compatible with OpenTelemetry.js + * https://open-telemetry.github.io/opentelemetry-js/interfaces/_opentelemetry_api.TracerProvider.html + * + * This is a singleton object that implements the OpenTelemetry + * TracerProvider interface. + * * @category Telemetry * @experimental */ - export class SpanExporter {} + // deno-lint-ignore no-explicit-any + export const tracerProvider: any; /** * A ContextManager compatible with OpenTelemetry.js * https://open-telemetry.github.io/opentelemetry-js/interfaces/_opentelemetry_api.ContextManager.html + * + * This is a singleton object that implements the OpenTelemetry + * ContextManager interface. + * * @category Telemetry * @experimental */ - export class ContextManager {} + // deno-lint-ignore no-explicit-any + export const contextManager: any; + + /** + * A MeterProvider compatible with OpenTelemetry.js + * https://open-telemetry.github.io/opentelemetry-js/interfaces/_opentelemetry_api.MeterProvider.html + * + * This is a singleton object that implements the OpenTelemetry + * MeterProvider interface. + * + * @category Telemetry + * @experimental + */ + // deno-lint-ignore no-explicit-any + export const meterProvider: any; export {}; // only export exports } diff --git a/cli/tsc/dts/lib.deno.window.d.ts b/cli/tsc/dts/lib.deno.window.d.ts index 636e2b0fd0..698b39c5df 100644 --- a/cli/tsc/dts/lib.deno.window.d.ts +++ b/cli/tsc/dts/lib.deno.window.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// /// @@ -83,8 +83,30 @@ declare var window: Window & typeof globalThis; declare var self: Window & typeof globalThis; /** @category Platform */ declare var closed: boolean; -/** @category Platform */ + +/** + * Exits the current Deno process. + * + * This function terminates the process by signaling the runtime to exit. + * Similar to exit(0) in posix. Its behavior is similar to the `window.close()` + * method in the browser, but specific to the Deno runtime. + * + * Note: Use this function cautiously, as it will stop the execution of the + * entire Deno program immediately. + * + * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/close + * + * @example + * ```ts + * console.log("About to close the Deno process."); + * close(); // The process will terminate here. + * console.log("This will not be logged."); // This line will never execute. + * ``` + * + * @category Platform + */ declare function close(): void; + /** @category Events */ declare var onerror: ((this: Window, ev: ErrorEvent) => any) | null; /** @category Events */ @@ -97,9 +119,86 @@ declare var onunload: ((this: Window, ev: Event) => any) | null; declare var onunhandledrejection: | ((this: Window, ev: PromiseRejectionEvent) => any) | null; -/** @category Storage */ +/** + * Deno's `localStorage` API provides a way to store key-value pairs in a + * web-like environment, similar to the Web Storage API found in browsers. + * It allows developers to persist data across sessions in a Deno application. + * This API is particularly useful for applications that require a simple + * and effective way to store data locally. + * + * - Key-Value Storage: Stores data as key-value pairs. + * - Persistent: Data is retained even after the application is closed. + * - Synchronous API: Operations are performed synchronously. + * + * `localStorage` is similar to {@linkcode sessionStorage}, and shares the same + * API methods, visible in the {@linkcode Storage} type. + * + * When using the `--location` flag, the origin for the location is used to + * uniquely store the data. That means a location of http://example.com/a.ts + * and http://example.com/b.ts and http://example.com:80/ would all share the + * same storage, but https://example.com/ would be different. + * + * For more information, see the reference guide for + * [Web Storage](https://docs.deno.com/runtime/reference/web_platform_apis/#web-storage) + * and using + * [the `--location` flag](https://docs.deno.com/runtime/reference/web_platform_apis/#location-flag). + * + * @example + * ```ts + * // Set a value in localStorage + * localStorage.setItem("key", "value"); + * + * // Get a value from localStorage + * const value = localStorage.getItem("key"); + * console.log(value); // Output: "value" + * + * // Remove a value from localStorage + * localStorage.removeItem("key"); + * + * // Clear all values from localStorage + * localStorage.clear(); + * ``` + * + * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage + * @category Storage */ declare var localStorage: Storage; -/** @category Storage */ + +/** + * Deno's `sessionStorage` API operates similarly to the {@linkcode localStorage} API, + * but it is intended for storing data temporarily for the duration of a session. + * Data stored in sessionStorage is cleared when the application session or + * process ends. This makes it suitable for temporary data that you do not need + * to persist across user sessions. + * + * - Key-Value Storage: Stores data as key-value pairs. + * - Session-Based: Data is only available for the duration of the page session. + * - Synchronous API: Operations are performed synchronously. + * + * `sessionStorage` is similar to {@linkcode localStorage}, and shares the same API + * methods, visible in the {@linkcode Storage} type. + * + * For more information, see the reference guide for + * [Web Storage](https://docs.deno.com/runtime/reference/web_platform_apis/#web-storage) + * + * @example + * ```ts + * // Set a value in sessionStorage + * sessionStorage.setItem("key", "value"); + * + * // Get a value from sessionStorage + * const value = sessionStorage.getItem("key"); + * console.log(value); // Output: "value" + * + * // Remove a value from sessionStorage + * sessionStorage.removeItem("key"); + * + * // Clear all the values from sessionStorage + * sessionStorage.clear(); + * ``` + * + * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage + * @category Storage + */ declare var sessionStorage: Storage; /** @category Cache */ declare var caches: CacheStorage; @@ -127,6 +226,12 @@ declare var navigator: Navigator; * * If the stdin is not interactive, it does nothing. * + * @example + * ```ts + * // Displays the message "Acknowledge me! [Enter]" and waits for the enter key to be pressed before continuing. + * alert("Acknowledge me!"); + * ``` + * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/alert * @category Platform * * @param message @@ -140,6 +245,15 @@ declare function alert(message?: string): void; * * If the stdin is not interactive, it returns false. * + * @example + * ```ts + * const shouldProceed = confirm("Do you want to proceed?"); + * + * // If the user presses 'y' or 'Y', the result will be true + * // If the user presses 'n' or 'N', the result will be false + * console.log("Should proceed?", shouldProceed); + * ``` + * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm * @category Platform * * @param message @@ -157,6 +271,15 @@ declare function confirm(message?: string): boolean; * * If the stdin is not interactive, it returns null. * + * @example + * ```ts + * const pet = prompt("Cats or dogs?", "It's fine to love both!"); + * + * // Displays the user's input or the default value of "It's fine to love both!" + * console.log("Best pet:", pet); + * ``` + * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt + * * @category Platform * * @param message diff --git a/cli/tsc/dts/lib.deno.worker.d.ts b/cli/tsc/dts/lib.deno.worker.d.ts index fa69cc57d6..c309417031 100644 --- a/cli/tsc/dts/lib.deno.worker.d.ts +++ b/cli/tsc/dts/lib.deno.worker.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// /// diff --git a/cli/tsc/dts/lib.deno_webgpu.d.ts b/cli/tsc/dts/lib.deno_webgpu.d.ts index 2deb63abc7..6dbfc57768 100644 --- a/cli/tsc/dts/lib.deno_webgpu.d.ts +++ b/cli/tsc/dts/lib.deno_webgpu.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-explicit-any no-empty-interface diff --git a/cli/tsc/dts/lib.dom.extras.d.ts b/cli/tsc/dts/lib.dom.extras.d.ts index a6de789f56..3a1667a99c 100644 --- a/cli/tsc/dts/lib.dom.extras.d.ts +++ b/cli/tsc/dts/lib.dom.extras.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /* * This library contains DOM standards that are not currently included in the diff --git a/cli/tsc/mod.rs b/cli/tsc/mod.rs index 4c84050b5e..1b76b640d3 100644 --- a/cli/tsc/mod.rs +++ b/cli/tsc/mod.rs @@ -1,19 +1,12 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::args::TsConfig; -use crate::args::TypeCheckMode; -use crate::cache::FastInsecureHasher; -use crate::cache::ModuleInfoCache; -use crate::node::CliNodeResolver; -use crate::npm::CliNpmResolver; -use crate::resolver::CjsTracker; -use crate::sys::CliSys; -use crate::util::checksum; -use crate::util::path::mapped_specifier_for_tsc; -use crate::worker::create_isolate_create_params; +use std::borrow::Cow; +use std::collections::HashMap; +use std::fmt; +use std::path::PathBuf; +use std::sync::Arc; use deno_ast::MediaType; -use deno_core::anyhow::anyhow; use deno_core::anyhow::Context; use deno_core::ascii_str; use deno_core::error::AnyError; @@ -35,6 +28,9 @@ use deno_graph::GraphKind; use deno_graph::Module; use deno_graph::ModuleGraph; use deno_graph::ResolutionResolved; +use deno_lib::util::checksum; +use deno_lib::worker::create_isolate_create_params; +use deno_resolver::npm::managed::ResolvePkgFolderFromDenoModuleError; use deno_resolver::npm::ResolvePkgFolderFromDenoReqError; use deno_semver::npm::NpmPackageReqReference; use node_resolver::errors::NodeJsErrorCode; @@ -44,14 +40,18 @@ use node_resolver::resolve_specifier_into_node_modules; use node_resolver::NodeResolutionKind; use node_resolver::ResolutionMode; use once_cell::sync::Lazy; -use std::borrow::Cow; -use std::collections::HashMap; -use std::fmt; -use std::path::Path; -use std::path::PathBuf; -use std::sync::Arc; use thiserror::Error; +use crate::args::TsConfig; +use crate::args::TypeCheckMode; +use crate::cache::FastInsecureHasher; +use crate::cache::ModuleInfoCache; +use crate::node::CliNodeResolver; +use crate::npm::CliNpmResolver; +use crate::resolver::CliCjsTracker; +use crate::sys::CliSys; +use crate::util::path::mapped_specifier_for_tsc; + mod diagnostics; pub use self::diagnostics::Diagnostic; @@ -128,6 +128,7 @@ fn get_asset_texts_from_new_runtime() -> Result, AnyError> { op_emit, op_is_node_file, op_load, + op_remap_specifier, op_resolve, op_respond, ] @@ -274,30 +275,6 @@ fn hash_url(specifier: &ModuleSpecifier, media_type: MediaType) -> String { ) } -/// If the provided URLs derivable tsc media type doesn't match the media type, -/// we will add an extension to the output. This is to avoid issues with -/// specifiers that don't have extensions, that tsc refuses to emit because they -/// think a `.js` version exists, when it doesn't. -fn maybe_remap_specifier( - specifier: &ModuleSpecifier, - media_type: MediaType, -) -> Option { - let path = if specifier.scheme() == "file" { - if let Ok(path) = specifier.to_file_path() { - path - } else { - PathBuf::from(specifier.path()) - } - } else { - PathBuf::from(specifier.path()) - }; - if path.extension().is_none() { - Some(format!("{}{}", specifier, media_type.as_ts_extension())) - } else { - None - } -} - #[derive(Debug, Clone, Default, Eq, PartialEq)] pub struct EmittedFile { pub data: String, @@ -315,7 +292,7 @@ pub fn into_specifier_and_media_type( (specifier, media_type) } None => ( - Url::parse("internal:///missing_dependency.d.ts").unwrap(), + Url::parse(MISSING_DEPENDENCY_SPECIFIER).unwrap(), MediaType::Dts, ), } @@ -323,13 +300,13 @@ pub fn into_specifier_and_media_type( #[derive(Debug)] pub struct TypeCheckingCjsTracker { - cjs_tracker: Arc, + cjs_tracker: Arc, module_info_cache: Arc, } impl TypeCheckingCjsTracker { pub fn new( - cjs_tracker: Arc, + cjs_tracker: Arc, module_info_cache: Arc, ) -> Self { Self { @@ -381,7 +358,7 @@ impl TypeCheckingCjsTracker { pub struct RequestNpmState { pub cjs_tracker: Arc, pub node_resolver: Arc, - pub npm_resolver: Arc, + pub npm_resolver: CliNpmResolver, } /// A structure representing a request to be sent to the tsc runtime. @@ -421,6 +398,8 @@ struct State { maybe_tsbuildinfo: Option, maybe_response: Option, maybe_npm: Option, + // todo(dsherret): it looks like the remapped_specifiers and + // root_map could be combined... what is the point of the separation? remapped_specifiers: HashMap, root_map: HashMap, current_dir: PathBuf, @@ -462,13 +441,16 @@ impl State { current_dir, } } -} -fn normalize_specifier( - specifier: &str, - current_dir: &Path, -) -> Result { - resolve_url_or_path(specifier, current_dir).map_err(|err| err.into()) + pub fn maybe_remapped_specifier( + &self, + specifier: &str, + ) -> Option<&ModuleSpecifier> { + self + .remapped_specifiers + .get(specifier) + .or_else(|| self.root_map.get(specifier)) + } } #[op2] @@ -541,6 +523,21 @@ pub fn as_ts_script_kind(media_type: MediaType) -> i32 { pub const MISSING_DEPENDENCY_SPECIFIER: &str = "internal:///missing_dependency.d.ts"; +#[derive(Debug, Error, deno_error::JsError)] +pub enum LoadError { + #[class(generic)] + #[error("Unable to load {path}: {error}")] + LoadFromNodeModule { path: String, error: std::io::Error }, + #[class(inherit)] + #[error( + "Error converting a string module specifier for \"op_resolve\": {0}" + )] + ModuleResolution(#[from] deno_core::ModuleResolutionError), + #[class(inherit)] + #[error("{0}")] + ClosestPkgJson(#[from] node_resolver::errors::ClosestPkgJsonError), +} + #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] struct LoadResponse { @@ -555,24 +552,28 @@ struct LoadResponse { fn op_load( state: &mut OpState, #[string] load_specifier: &str, -) -> Result, AnyError> { +) -> Result, LoadError> { op_load_inner(state, load_specifier) } fn op_load_inner( state: &mut OpState, load_specifier: &str, -) -> Result, AnyError> { +) -> Result, LoadError> { fn load_from_node_modules( specifier: &ModuleSpecifier, npm_state: Option<&RequestNpmState>, media_type: &mut MediaType, is_cjs: &mut bool, - ) -> Result { + ) -> Result { *media_type = MediaType::from_specifier(specifier); let file_path = specifier.to_file_path().unwrap(); - let code = std::fs::read_to_string(&file_path) - .with_context(|| format!("Unable to load {}", file_path.display()))?; + let code = std::fs::read_to_string(&file_path).map_err(|err| { + LoadError::LoadFromNodeModule { + path: file_path.display().to_string(), + error: err, + } + })?; let code: Arc = code.into(); *is_cjs = npm_state .map(|npm_state| { @@ -585,8 +586,7 @@ fn op_load_inner( let state = state.borrow_mut::(); - let specifier = normalize_specifier(load_specifier, &state.current_dir) - .context("Error converting a string module specifier for \"op_load\".")?; + let specifier = resolve_url_or_path(load_specifier, &state.current_dir)?; let mut hash: Option = None; let mut media_type = MediaType::Unknown; @@ -606,10 +606,7 @@ fn op_load_inner( maybe_source.map(Cow::Borrowed) } else { let specifier = if let Some(remapped_specifier) = - state.remapped_specifiers.get(load_specifier) - { - remapped_specifier - } else if let Some(remapped_specifier) = state.root_map.get(load_specifier) + state.maybe_remapped_specifier(load_specifier) { remapped_specifier } else { @@ -701,6 +698,24 @@ fn op_load_inner( })) } +#[derive(Debug, Error, deno_error::JsError)] +pub enum ResolveError { + #[class(inherit)] + #[error( + "Error converting a string module specifier for \"op_resolve\": {0}" + )] + ModuleResolution(#[from] deno_core::ModuleResolutionError), + #[class(inherit)] + #[error("{0}")] + PackageSubpathResolve(PackageSubpathResolveError), + #[class(inherit)] + #[error("{0}")] + ResolvePkgFolderFromDenoModule(#[from] ResolvePkgFolderFromDenoModuleError), + #[class(inherit)] + #[error("{0}")] + ResolveNonGraphSpecifierTypes(#[from] ResolveNonGraphSpecifierTypesError), +} + #[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct ResolveArgs { @@ -712,13 +727,25 @@ pub struct ResolveArgs { pub specifiers: Vec<(bool, String)>, } +#[op2] +#[string] +fn op_remap_specifier( + state: &mut OpState, + #[string] specifier: &str, +) -> Option { + let state = state.borrow::(); + state + .maybe_remapped_specifier(specifier) + .map(|url| url.to_string()) +} + #[op2] #[serde] fn op_resolve( state: &mut OpState, #[string] base: String, #[serde] specifiers: Vec<(bool, String)>, -) -> Result, AnyError> { +) -> Result)>, ResolveError> { op_resolve_inner(state, ResolveArgs { base, specifiers }) } @@ -726,40 +753,40 @@ fn op_resolve( fn op_resolve_inner( state: &mut OpState, args: ResolveArgs, -) -> Result, AnyError> { +) -> Result)>, ResolveError> { let state = state.borrow_mut::(); - let mut resolved: Vec<(String, &'static str)> = + let mut resolved: Vec<(String, Option<&'static str>)> = Vec::with_capacity(args.specifiers.len()); let referrer = if let Some(remapped_specifier) = - state.remapped_specifiers.get(&args.base) + state.maybe_remapped_specifier(&args.base) { remapped_specifier.clone() - } else if let Some(remapped_base) = state.root_map.get(&args.base) { - remapped_base.clone() } else { - normalize_specifier(&args.base, &state.current_dir).context( - "Error converting a string module specifier for \"op_resolve\".", - )? + resolve_url_or_path(&args.base, &state.current_dir)? }; let referrer_module = state.graph.get(&referrer); for (is_cjs, specifier) in args.specifiers { if specifier.starts_with("node:") { resolved.push(( MISSING_DEPENDENCY_SPECIFIER.to_string(), - MediaType::Dts.as_ts_extension(), + Some(MediaType::Dts.as_ts_extension()), )); continue; } if specifier.starts_with("asset:///") { let ext = MediaType::from_str(&specifier).as_ts_extension(); - resolved.push((specifier, ext)); + resolved.push((specifier, Some(ext))); continue; } let resolved_dep = referrer_module - .and_then(|m| m.js()) - .and_then(|m| m.dependencies_prefer_fast_check().get(&specifier)) + .and_then(|m| match m { + Module::Js(m) => m.dependencies_prefer_fast_check().get(&specifier), + Module::Json(_) => None, + Module::Wasm(m) => m.dependencies.get(&specifier), + Module::Npm(_) | Module::Node(_) | Module::External(_) => None, + }) .and_then(|d| d.maybe_type.ok().or_else(|| d.maybe_code.ok())); let resolution_mode = if is_cjs { ResolutionMode::Require @@ -815,7 +842,7 @@ fn op_resolve_inner( } _ => { if let Some(specifier_str) = - maybe_remap_specifier(&specifier, media_type) + mapped_specifier_for_tsc(&specifier, media_type) { state .remapped_specifiers @@ -829,17 +856,18 @@ fn op_resolve_inner( ( specifier_str, match media_type { - MediaType::Css => ".js", // surface these as .js for typescript - media_type => media_type.as_ts_extension(), + MediaType::Css => Some(".js"), // surface these as .js for typescript + MediaType::Unknown => None, + media_type => Some(media_type.as_ts_extension()), }, ) } None => ( MISSING_DEPENDENCY_SPECIFIER.to_string(), - MediaType::Dts.as_ts_extension(), + Some(MediaType::Dts.as_ts_extension()), ), }; - log::debug!("Resolved {} to {:?}", specifier, result); + log::debug!("Resolved {} from {} to {:?}", specifier, referrer, result); resolved.push(result); } @@ -851,7 +879,7 @@ fn resolve_graph_specifier_types( referrer: &ModuleSpecifier, resolution_mode: ResolutionMode, state: &State, -) -> Result, AnyError> { +) -> Result, ResolveError> { let graph = &state.graph; let maybe_module = match graph.try_get(specifier) { Ok(Some(module)) => Some(module), @@ -913,7 +941,7 @@ fn resolve_graph_specifier_types( Err(err) => match err.code() { NodeJsErrorCode::ERR_TYPES_NOT_FOUND | NodeJsErrorCode::ERR_MODULE_NOT_FOUND => None, - _ => return Err(err.into()), + _ => return Err(ResolveError::PackageSubpathResolve(err)), }, }; Ok(Some(into_specifier_and_media_type(maybe_url))) @@ -935,10 +963,12 @@ fn resolve_graph_specifier_types( } } -#[derive(Debug, Error)] -enum ResolveNonGraphSpecifierTypesError { +#[derive(Debug, Error, deno_error::JsError)] +pub enum ResolveNonGraphSpecifierTypesError { + #[class(inherit)] #[error(transparent)] ResolvePkgFolderFromDenoReq(#[from] ResolvePkgFolderFromDenoReqError), + #[class(inherit)] #[error(transparent)] PackageSubpathResolve(#[from] PackageSubpathResolveError), } @@ -1035,10 +1065,20 @@ fn op_respond_inner(state: &mut OpState, args: RespondArgs) { state.maybe_response = Some(args); } +#[derive(Debug, Error, deno_error::JsError)] +pub enum ExecError { + #[class(generic)] + #[error("The response for the exec request was not set.")] + ResponseNotSet, + #[class(inherit)] + #[error(transparent)] + Core(deno_core::error::CoreError), +} + /// Execute a request on the supplied snapshot, returning a response which /// contains information, like any emitted files, diagnostics, statistics and /// optionally an updated TypeScript build info. -pub fn exec(request: Request) -> Result { +pub fn exec(request: Request) -> Result { // tsc cannot handle root specifiers that don't have one of the "acceptable" // extensions. Therefore, we have to check the root modules against their // extensions and remap any that are unacceptable to tsc and add them to the @@ -1071,6 +1111,7 @@ pub fn exec(request: Request) -> Result { op_emit, op_is_node_file, op_load, + op_remap_specifier, op_resolve, op_respond, ], @@ -1113,7 +1154,9 @@ pub fn exec(request: Request) -> Result { ..Default::default() }); - runtime.execute_script(located_script_name!(), exec_source)?; + runtime + .execute_script(located_script_name!(), exec_source) + .map_err(ExecError::Core)?; let op_state = runtime.op_state(); let mut op_state = op_state.borrow_mut(); @@ -1130,22 +1173,24 @@ pub fn exec(request: Request) -> Result { stats, }) } else { - Err(anyhow!("The response for the exec request was not set.")) + Err(ExecError::ResponseNotSet) } } #[cfg(test)] mod tests { + use deno_core::futures::future; + use deno_core::serde_json; + use deno_core::OpState; + use deno_error::JsErrorBox; + use deno_graph::GraphKind; + use deno_graph::ModuleGraph; + use test_util::PathRef; + use super::Diagnostic; use super::DiagnosticCategory; use super::*; use crate::args::TsConfig; - use deno_core::futures::future; - use deno_core::serde_json; - use deno_core::OpState; - use deno_graph::GraphKind; - use deno_graph::ModuleGraph; - use test_util::PathRef; #[derive(Debug, Default)] pub struct MockLoader { @@ -1164,13 +1209,20 @@ mod tests { .replace("://", "_") .replace('/', "-"); let source_path = self.fixtures.join(specifier_text); - let response = source_path.read_to_bytes_if_exists().map(|c| { - Some(deno_graph::source::LoadResponse::Module { - specifier: specifier.clone(), - maybe_headers: None, - content: c.into(), + let response = source_path + .read_to_bytes_if_exists() + .map(|c| { + Some(deno_graph::source::LoadResponse::Module { + specifier: specifier.clone(), + maybe_headers: None, + content: c.into(), + }) }) - }); + .map_err(|e| { + deno_graph::source::LoadError::Other(Arc::new(JsErrorBox::generic( + e.to_string(), + ))) + }); Box::pin(future::ready(response)) } } @@ -1207,7 +1259,7 @@ mod tests { async fn test_exec( specifier: &ModuleSpecifier, - ) -> Result { + ) -> Result { let hash_data = 123; // something random let fixtures = test_util::testdata_path().join("tsc2"); let loader = MockLoader { fixtures }; @@ -1389,7 +1441,10 @@ mod tests { }, ) .expect("should have invoked op"); - assert_eq!(actual, vec![("https://deno.land/x/b.ts".into(), ".ts")]); + assert_eq!( + actual, + vec![("https://deno.land/x/b.ts".into(), Some(".ts"))] + ); } #[tokio::test] @@ -1408,7 +1463,10 @@ mod tests { }, ) .expect("should have not errored"); - assert_eq!(actual, vec![(MISSING_DEPENDENCY_SPECIFIER.into(), ".d.ts")]); + assert_eq!( + actual, + vec![(MISSING_DEPENDENCY_SPECIFIER.into(), Some(".d.ts"))] + ); } #[tokio::test] diff --git a/cli/util/archive.rs b/cli/util/archive.rs index e2183d57ab..e3efd69adb 100644 --- a/cli/util/archive.rs +++ b/cli/util/archive.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::fs; use std::path::Path; diff --git a/cli/util/console.rs b/cli/util/console.rs index 74e6928a28..d22d41f5ea 100644 --- a/cli/util/console.rs +++ b/cli/util/console.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_runtime::ops::tty::ConsoleSize; diff --git a/cli/util/diff.rs b/cli/util/diff.rs index 14ece0c44c..a42da3a89a 100644 --- a/cli/util/diff.rs +++ b/cli/util/diff.rs @@ -1,9 +1,11 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::fmt::Write as _; -use crate::colors; use dissimilar::diff as difference; use dissimilar::Chunk; -use std::fmt::Write as _; + +use crate::colors; /// Print diff of the same file_path, before and after formatting. /// diff --git a/cli/util/display.rs b/cli/util/display.rs index 8795d3db68..dff08f31fa 100644 --- a/cli/util/display.rs +++ b/cli/util/display.rs @@ -1,9 +1,10 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::io::Write; use deno_core::error::AnyError; use deno_core::serde_json; use deno_runtime::colors; -use std::io::Write; /// A function that converts a float to a string the represents a human /// readable version of that number. diff --git a/cli/util/draw_thread.rs b/cli/util/draw_thread.rs index 164a8fc713..a2d7681425 100644 --- a/cli/util/draw_thread.rs +++ b/cli/util/draw_thread.rs @@ -1,13 +1,14 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::io::IsTerminal; +use std::sync::Arc; +use std::time::Duration; use console_static_text::ConsoleStaticText; use deno_core::parking_lot::Mutex; use deno_core::unsync::spawn_blocking; use deno_runtime::ops::tty::ConsoleSize; use once_cell::sync::Lazy; -use std::io::IsTerminal; -use std::sync::Arc; -use std::time::Duration; use crate::util::console::console_size; diff --git a/cli/util/extract.rs b/cli/util/extract.rs index c4562060d8..825e81bb4b 100644 --- a/cli/util/extract.rs +++ b/cli/util/extract.rs @@ -1,4 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::collections::BTreeSet; +use std::fmt::Write as _; +use std::sync::Arc; use deno_ast::swc::ast; use deno_ast::swc::atoms::Atom; @@ -17,9 +21,6 @@ use deno_cache_dir::file_fetcher::File; use deno_core::error::AnyError; use deno_core::ModuleSpecifier; use regex::Regex; -use std::collections::BTreeSet; -use std::fmt::Write as _; -use std::sync::Arc; use crate::file_fetcher::TextDecodedFile; use crate::util::path::mapped_specifier_for_tsc; @@ -808,11 +809,12 @@ fn wrap_in_deno_test(stmts: Vec, test_name: Atom) -> ast::Stmt { #[cfg(test)] mod tests { - use super::*; - use crate::file_fetcher::TextDecodedFile; use deno_ast::swc::atoms::Atom; use pretty_assertions::assert_eq; + use super::*; + use crate::file_fetcher::TextDecodedFile; + #[test] fn test_extract_doc_tests() { struct Input { diff --git a/cli/util/file_watcher.rs b/cli/util/file_watcher.rs index b9318a6e4b..d3ff1bae77 100644 --- a/cli/util/file_watcher.rs +++ b/cli/util/file_watcher.rs @@ -1,12 +1,16 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::args::Flags; -use crate::colors; -use crate::util::fs::canonicalize_path; +use std::cell::RefCell; +use std::collections::HashSet; +use std::io::IsTerminal; +use std::path::PathBuf; +use std::rc::Rc; +use std::sync::Arc; +use std::time::Duration; use deno_config::glob::PathOrPatternSet; use deno_core::error::AnyError; -use deno_core::error::JsError; +use deno_core::error::CoreError; use deno_core::futures::Future; use deno_core::futures::FutureExt; use deno_core::parking_lot::Mutex; @@ -18,18 +22,17 @@ use notify::Error as NotifyError; use notify::RecommendedWatcher; use notify::RecursiveMode; use notify::Watcher; -use std::cell::RefCell; -use std::collections::HashSet; -use std::io::IsTerminal; -use std::path::PathBuf; -use std::rc::Rc; -use std::sync::Arc; -use std::time::Duration; use tokio::select; +use tokio::sync::broadcast::error::RecvError; use tokio::sync::mpsc; +use tokio::sync::mpsc::error::SendError; use tokio::sync::mpsc::UnboundedReceiver; use tokio::time::sleep; +use crate::args::Flags; +use crate::colors; +use crate::util::fs::canonicalize_path; + const CLEAR_SCREEN: &str = "\x1B[H\x1B[2J\x1B[3J"; const DEBOUNCE_INTERVAL: Duration = Duration::from_millis(200); @@ -79,10 +82,13 @@ where { let result = watch_future.await; if let Err(err) = result { - let error_string = match err.downcast_ref::() { - Some(e) => format_js_error(e), - None => format!("{err:?}"), - }; + let error_string = + match crate::util::result::any_and_jserrorbox_downcast_ref::( + &err, + ) { + Some(CoreError::Js(e)) => format_js_error(e), + _ => format!("{err:?}"), + }; log::error!( "{}: {}", colors::red_bold("error"), @@ -136,49 +142,89 @@ fn create_print_after_restart_fn(clear_screen: bool) -> impl Fn() { } } +#[derive(Debug)] +pub struct WatcherCommunicatorOptions { + /// Send a list of paths that should be watched for changes. + pub paths_to_watch_tx: tokio::sync::mpsc::UnboundedSender>, + /// Listen for a list of paths that were changed. + pub changed_paths_rx: tokio::sync::broadcast::Receiver>>, + pub changed_paths_tx: tokio::sync::broadcast::Sender>>, + /// Send a message to force a restart. + pub restart_tx: tokio::sync::mpsc::UnboundedSender<()>, + pub restart_mode: WatcherRestartMode, + pub banner: String, +} + /// An interface to interact with Deno's CLI file watcher. #[derive(Debug)] pub struct WatcherCommunicator { /// Send a list of paths that should be watched for changes. paths_to_watch_tx: tokio::sync::mpsc::UnboundedSender>, - /// Listen for a list of paths that were changed. changed_paths_rx: tokio::sync::broadcast::Receiver>>, - + changed_paths_tx: tokio::sync::broadcast::Sender>>, /// Send a message to force a restart. restart_tx: tokio::sync::mpsc::UnboundedSender<()>, - restart_mode: Mutex, - banner: String, } impl WatcherCommunicator { - pub fn watch_paths(&self, paths: Vec) -> Result<(), AnyError> { + pub fn new(options: WatcherCommunicatorOptions) -> Self { + Self { + paths_to_watch_tx: options.paths_to_watch_tx, + changed_paths_rx: options.changed_paths_rx, + changed_paths_tx: options.changed_paths_tx, + restart_tx: options.restart_tx, + restart_mode: Mutex::new(options.restart_mode), + banner: options.banner, + } + } + + pub fn watch_paths( + &self, + paths: Vec, + ) -> Result<(), SendError>> { if paths.is_empty() { return Ok(()); } - self.paths_to_watch_tx.send(paths).map_err(AnyError::from) + self.paths_to_watch_tx.send(paths) } - pub fn force_restart(&self) -> Result<(), AnyError> { + pub fn force_restart(&self) -> Result<(), SendError<()>> { // Change back to automatic mode, so that HMR can set up watching // from scratch. *self.restart_mode.lock() = WatcherRestartMode::Automatic; - self.restart_tx.send(()).map_err(AnyError::from) + self.restart_tx.send(()) } pub async fn watch_for_changed_paths( &self, - ) -> Result>, AnyError> { + ) -> Result>, RecvError> { let mut rx = self.changed_paths_rx.resubscribe(); - rx.recv().await.map_err(AnyError::from) + rx.recv().await } pub fn change_restart_mode(&self, restart_mode: WatcherRestartMode) { *self.restart_mode.lock() = restart_mode; } + pub fn send( + &self, + paths: Option>, + ) -> Result<(), SendError>>> { + match *self.restart_mode.lock() { + WatcherRestartMode::Automatic => { + self.restart_tx.send(()).map_err(|_| SendError(None)) + } + WatcherRestartMode::Manual => self + .changed_paths_tx + .send(paths) + .map(|_| ()) + .map_err(|e| SendError(e.0)), + } + } + pub fn print(&self, msg: String) { log::info!("{} {}", self.banner, colors::gray(msg)); } @@ -267,13 +313,15 @@ where } = print_config; let print_after_restart = create_print_after_restart_fn(clear_screen); - let watcher_communicator = Arc::new(WatcherCommunicator { - paths_to_watch_tx: paths_to_watch_tx.clone(), - changed_paths_rx: changed_paths_rx.resubscribe(), - restart_tx: restart_tx.clone(), - restart_mode: Mutex::new(restart_mode), - banner: colors::intense_blue(banner).to_string(), - }); + let watcher_communicator = + Arc::new(WatcherCommunicator::new(WatcherCommunicatorOptions { + paths_to_watch_tx: paths_to_watch_tx.clone(), + changed_paths_rx: changed_paths_rx.resubscribe(), + changed_paths_tx, + restart_tx: restart_tx.clone(), + restart_mode, + banner: colors::intense_blue(banner).to_string(), + })); info!("{} {} started.", colors::intense_blue(banner), job_name); let changed_paths = Rc::new(RefCell::new(None)); @@ -287,15 +335,8 @@ where .borrow_mut() .clone_from(&received_changed_paths); - match *watcher_.restart_mode.lock() { - WatcherRestartMode::Automatic => { - let _ = restart_tx.send(()); - } - WatcherRestartMode::Manual => { - // TODO(bartlomieju): should we fail on sending changed paths? - let _ = changed_paths_tx.send(received_changed_paths); - } - } + // TODO(bartlomieju): should we fail on sending changed paths? + let _ = watcher_.send(received_changed_paths); } }); diff --git a/cli/util/fs.rs b/cli/util/fs.rs index e0b9a6f4ee..d9cebe10d5 100644 --- a/cli/util/fs.rs +++ b/cli/util/fs.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::io::Error; use std::io::ErrorKind; @@ -13,10 +13,12 @@ use deno_config::glob::PathOrPattern; use deno_config::glob::PathOrPatternSet; use deno_config::glob::WalkEntry; use deno_core::anyhow::anyhow; -use deno_core::anyhow::Context; use deno_core::error::AnyError; use deno_core::unsync::spawn_blocking; use deno_core::ModuleSpecifier; +use sys_traits::FsCreateDirAll; +use sys_traits::FsDirEntry; +use sys_traits::FsSymlinkDir; use crate::sys::CliSys; use crate::util::progress_bar::ProgressBar; @@ -126,7 +128,7 @@ pub fn collect_specifiers( .ignore_git_folder() .ignore_node_modules() .set_vendor_folder(vendor_folder) - .collect_file_patterns(&CliSys::default(), files)?; + .collect_file_patterns(&CliSys::default(), files); let mut collected_files_as_urls = collected_files .iter() .map(|f| specifier_from_file_path(f).unwrap()) @@ -148,86 +150,123 @@ pub async fn remove_dir_all_if_exists(path: &Path) -> std::io::Result<()> { } } -mod clone_dir_imp { - - #[cfg(target_vendor = "apple")] - mod apple { - use super::super::copy_dir_recursive; - use deno_core::error::AnyError; - use std::os::unix::ffi::OsStrExt; - use std::path::Path; - fn clonefile(from: &Path, to: &Path) -> std::io::Result<()> { - let from = std::ffi::CString::new(from.as_os_str().as_bytes())?; - let to = std::ffi::CString::new(to.as_os_str().as_bytes())?; - // SAFETY: `from` and `to` are valid C strings. - let ret = unsafe { libc::clonefile(from.as_ptr(), to.as_ptr(), 0) }; - if ret != 0 { - return Err(std::io::Error::last_os_error()); - } - Ok(()) - } - - pub fn clone_dir_recursive(from: &Path, to: &Path) -> Result<(), AnyError> { - if let Some(parent) = to.parent() { - std::fs::create_dir_all(parent)?; - } - // Try to clone the whole directory - if let Err(err) = clonefile(from, to) { - if err.kind() != std::io::ErrorKind::AlreadyExists { - log::warn!( - "Failed to clone dir {:?} to {:?} via clonefile: {}", - from, - to, - err - ); - } - // clonefile won't overwrite existing files, so if the dir exists - // we need to handle it recursively. - copy_dir_recursive(from, to)?; - } - - Ok(()) - } - } - - #[cfg(target_vendor = "apple")] - pub(super) use apple::clone_dir_recursive; - - #[cfg(not(target_vendor = "apple"))] - pub(super) fn clone_dir_recursive( - from: &std::path::Path, - to: &std::path::Path, - ) -> Result<(), deno_core::error::AnyError> { - use crate::sys::CliSys; - - if let Err(e) = - deno_npm_cache::hard_link_dir_recursive(&CliSys::default(), from, to) - { - log::debug!("Failed to hard link dir {:?} to {:?}: {}", from, to, e); - super::copy_dir_recursive(from, to)?; - } - - Ok(()) - } -} - /// Clones a directory to another directory. The exact method /// is not guaranteed - it may be a hardlink, copy, or other platform-specific /// operation. /// /// Note: Does not handle symlinks. -pub fn clone_dir_recursive(from: &Path, to: &Path) -> Result<(), AnyError> { - clone_dir_imp::clone_dir_recursive(from, to) +pub fn clone_dir_recursive< + TSys: sys_traits::FsCopy + + sys_traits::FsCloneFile + + sys_traits::FsCloneFile + + sys_traits::FsCreateDir + + sys_traits::FsHardLink + + sys_traits::FsReadDir + + sys_traits::FsRemoveFile + + sys_traits::ThreadSleep, +>( + sys: &TSys, + from: &Path, + to: &Path, +) -> Result<(), CopyDirRecursiveError> { + if cfg!(target_vendor = "apple") { + if let Some(parent) = to.parent() { + sys.fs_create_dir_all(parent)?; + } + // Try to clone the whole directory + if let Err(err) = sys.fs_clone_file(from, to) { + if !matches!( + err.kind(), + std::io::ErrorKind::AlreadyExists | std::io::ErrorKind::Unsupported + ) { + log::warn!( + "Failed to clone dir {:?} to {:?} via clonefile: {}", + from, + to, + err + ); + } + // clonefile won't overwrite existing files, so if the dir exists + // we need to handle it recursively. + copy_dir_recursive(sys, from, to)?; + } + } else if let Err(e) = deno_npm_cache::hard_link_dir_recursive(sys, from, to) + { + log::debug!("Failed to hard link dir {:?} to {:?}: {}", from, to, e); + copy_dir_recursive(sys, from, to)?; + } + + Ok(()) +} + +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum CopyDirRecursiveError { + #[class(inherit)] + #[error("Creating {path}")] + Creating { + path: PathBuf, + #[source] + #[inherit] + source: Error, + }, + #[class(inherit)] + #[error("Creating {path}")] + Reading { + path: PathBuf, + #[source] + #[inherit] + source: Error, + }, + #[class(inherit)] + #[error("Dir {from} to {to}")] + Dir { + from: PathBuf, + to: PathBuf, + #[source] + #[inherit] + source: Box, + }, + #[class(inherit)] + #[error("Copying {from} to {to}")] + Copying { + from: PathBuf, + to: PathBuf, + #[source] + #[inherit] + source: Error, + }, + #[class(inherit)] + #[error(transparent)] + Other(#[from] Error), } /// Copies a directory to another directory. /// /// Note: Does not handle symlinks. -pub fn copy_dir_recursive(from: &Path, to: &Path) -> Result<(), AnyError> { - std::fs::create_dir_all(to) - .with_context(|| format!("Creating {}", to.display()))?; - let read_dir = std::fs::read_dir(from) - .with_context(|| format!("Reading {}", from.display()))?; +pub fn copy_dir_recursive< + TSys: sys_traits::FsCopy + + sys_traits::FsCloneFile + + sys_traits::FsCreateDir + + sys_traits::FsHardLink + + sys_traits::FsReadDir, +>( + sys: &TSys, + from: &Path, + to: &Path, +) -> Result<(), CopyDirRecursiveError> { + sys.fs_create_dir_all(to).map_err(|source| { + CopyDirRecursiveError::Creating { + path: to.to_path_buf(), + source, + } + })?; + let read_dir = + sys + .fs_read_dir(from) + .map_err(|source| CopyDirRecursiveError::Reading { + path: from.to_path_buf(), + source, + })?; for entry in read_dir { let entry = entry?; @@ -236,12 +275,20 @@ pub fn copy_dir_recursive(from: &Path, to: &Path) -> Result<(), AnyError> { let new_to = to.join(entry.file_name()); if file_type.is_dir() { - copy_dir_recursive(&new_from, &new_to).with_context(|| { - format!("Dir {} to {}", new_from.display(), new_to.display()) + copy_dir_recursive(sys, &new_from, &new_to).map_err(|source| { + CopyDirRecursiveError::Dir { + from: new_from.to_path_buf(), + to: new_to.to_path_buf(), + source: Box::new(source), + } })?; } else if file_type.is_file() { - std::fs::copy(&new_from, &new_to).with_context(|| { - format!("Copying {} to {}", new_from.display(), new_to.display()) + sys.fs_copy(&new_from, &new_to).map_err(|source| { + CopyDirRecursiveError::Copying { + from: new_from.to_path_buf(), + to: new_to.to_path_buf(), + source, + } })?; } } @@ -249,7 +296,11 @@ pub fn copy_dir_recursive(from: &Path, to: &Path) -> Result<(), AnyError> { Ok(()) } -pub fn symlink_dir(oldpath: &Path, newpath: &Path) -> Result<(), Error> { +pub fn symlink_dir( + sys: &TSys, + oldpath: &Path, + newpath: &Path, +) -> Result<(), Error> { let err_mapper = |err: Error, kind: Option| { Error::new( kind.unwrap_or_else(|| err.kind()), @@ -261,26 +312,18 @@ pub fn symlink_dir(oldpath: &Path, newpath: &Path) -> Result<(), Error> { ), ) }; - #[cfg(unix)] - { - use std::os::unix::fs::symlink; - symlink(oldpath, newpath).map_err(|e| err_mapper(e, None))?; - } - #[cfg(not(unix))] - { - use std::os::windows::fs::symlink_dir; - symlink_dir(oldpath, newpath).map_err(|err| { - if let Some(code) = err.raw_os_error() { - if code as u32 == winapi::shared::winerror::ERROR_PRIVILEGE_NOT_HELD - || code as u32 == winapi::shared::winerror::ERROR_INVALID_FUNCTION - { - return err_mapper(err, Some(ErrorKind::PermissionDenied)); - } + + sys.fs_symlink_dir(oldpath, newpath).map_err(|err| { + #[cfg(windows)] + if let Some(code) = err.raw_os_error() { + if code as u32 == winapi::shared::winerror::ERROR_PRIVILEGE_NOT_HELD + || code as u32 == winapi::shared::winerror::ERROR_INVALID_FUNCTION + { + return err_mapper(err, Some(ErrorKind::PermissionDenied)); } - err_mapper(err, None) - })?; - } - Ok(()) + } + err_mapper(err, None) + }) } /// Gets the total size (in bytes) of a directory. @@ -462,7 +505,6 @@ pub fn specifier_from_file_path( #[cfg(test)] mod tests { - use super::*; use deno_core::futures; use deno_core::parking_lot::Mutex; use deno_path_util::normalize_path; @@ -471,6 +513,8 @@ mod tests { use test_util::TempDir; use tokio::sync::Notify; + use super::*; + #[test] fn test_normalize_path() { assert_eq!(normalize_path(Path::new("a/../b")), PathBuf::from("b")); diff --git a/cli/util/logger.rs b/cli/util/logger.rs index 783f8a5f68..2bd4760ebd 100644 --- a/cli/util/logger.rs +++ b/cli/util/logger.rs @@ -1,9 +1,11 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::io::Write; -use super::draw_thread::DrawThread; use deno_telemetry::OtelConfig; use deno_telemetry::OtelConsoleConfig; -use std::io::Write; + +use super::draw_thread::DrawThread; struct CliLogger { otel_console_config: OtelConsoleConfig, diff --git a/cli/util/mod.rs b/cli/util/mod.rs index f81a74c449..702e5673c9 100644 --- a/cli/util/mod.rs +++ b/cli/util/mod.rs @@ -1,8 +1,7 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Note: Only add code in this folder that has no application specific logic pub mod archive; -pub mod checksum; pub mod console; pub mod diff; pub mod display; diff --git a/cli/util/path.rs b/cli/util/path.rs index 539e1235a8..90b2df6a3c 100644 --- a/cli/util/path.rs +++ b/cli/util/path.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::path::Path; diff --git a/cli/util/progress_bar/mod.rs b/cli/util/progress_bar/mod.rs index 85be056d84..3b5bb20e55 100644 --- a/cli/util/progress_bar/mod.rs +++ b/cli/util/progress_bar/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::sync::atomic::AtomicU64; use std::sync::atomic::Ordering; @@ -8,15 +8,13 @@ use std::time::Instant; use deno_core::parking_lot::Mutex; use deno_runtime::ops::tty::ConsoleSize; -use crate::colors; - use self::renderer::ProgressBarRenderer; use self::renderer::ProgressData; use self::renderer::ProgressDataDisplayEntry; - use super::draw_thread::DrawThread; use super::draw_thread::DrawThreadGuard; use super::draw_thread::DrawThreadRenderer; +use crate::colors; mod renderer; diff --git a/cli/util/progress_bar/renderer.rs b/cli/util/progress_bar/renderer.rs index db3d37140f..3498c7ae0f 100644 --- a/cli/util/progress_bar/renderer.rs +++ b/cli/util/progress_bar/renderer.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::fmt::Write; use std::sync::atomic::AtomicUsize; @@ -7,9 +7,8 @@ use std::time::Duration; use deno_terminal::colors; -use crate::util::display::human_download_size; - use super::ProgressMessagePrompt; +use crate::util::display::human_download_size; #[derive(Clone)] pub struct ProgressDataDisplayEntry { @@ -224,11 +223,13 @@ fn get_elapsed_text(elapsed: Duration) -> String { #[cfg(test)] mod test { - use super::*; - use pretty_assertions::assert_eq; use std::time::Duration; + + use pretty_assertions::assert_eq; use test_util::assert_contains; + use super::*; + #[test] fn should_get_elapsed_text() { assert_eq!(get_elapsed_text(Duration::from_secs(1)), "[00:01]"); diff --git a/cli/util/result.rs b/cli/util/result.rs index 3203d04eb7..0c1a75b1ce 100644 --- a/cli/util/result.rs +++ b/cli/util/result.rs @@ -1,6 +1,13 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::convert::Infallible; +use std::fmt::Debug; +use std::fmt::Display; + +use deno_core::error::AnyError; +use deno_core::error::CoreError; +use deno_error::JsErrorBox; +use deno_error::JsErrorClass; pub trait InfallibleResultExt { fn unwrap_infallible(self) -> T; @@ -14,3 +21,23 @@ impl InfallibleResultExt for Result { } } } + +pub fn any_and_jserrorbox_downcast_ref< + E: Display + Debug + Send + Sync + 'static, +>( + err: &AnyError, +) -> Option<&E> { + err + .downcast_ref::() + .or_else(|| { + err + .downcast_ref::() + .and_then(|e| e.as_any().downcast_ref::()) + }) + .or_else(|| { + err.downcast_ref::().and_then(|e| match e { + CoreError::JsNative(e) => e.as_any().downcast_ref::(), + _ => None, + }) + }) +} diff --git a/cli/util/retry.rs b/cli/util/retry.rs index a8febe60de..ac36a380ed 100644 --- a/cli/util/retry.rs +++ b/cli/util/retry.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::future::Future; use std::time::Duration; diff --git a/cli/util/sync/async_flag.rs b/cli/util/sync/async_flag.rs index 2bdff63c04..a9ca46002d 100644 --- a/cli/util/sync/async_flag.rs +++ b/cli/util/sync/async_flag.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use tokio_util::sync::CancellationToken; diff --git a/cli/util/sync/mod.rs b/cli/util/sync/mod.rs index c3b2a315b0..717dcd768a 100644 --- a/cli/util/sync/mod.rs +++ b/cli/util/sync/mod.rs @@ -1,11 +1,9 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. mod async_flag; -mod sync_read_async_write_lock; mod task_queue; pub use async_flag::AsyncFlag; pub use deno_core::unsync::sync::AtomicFlag; -pub use sync_read_async_write_lock::SyncReadAsyncWriteLock; pub use task_queue::TaskQueue; pub use task_queue::TaskQueuePermit; diff --git a/cli/util/sync/sync_read_async_write_lock.rs b/cli/util/sync/sync_read_async_write_lock.rs deleted file mode 100644 index 8bd211aa72..0000000000 --- a/cli/util/sync/sync_read_async_write_lock.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. - -use deno_core::parking_lot::RwLock; -use deno_core::parking_lot::RwLockReadGuard; -use deno_core::parking_lot::RwLockWriteGuard; - -use super::TaskQueue; -use super::TaskQueuePermit; - -/// A lock that can be read synchronously at any time (including when -/// being written to), but must write asynchronously. -pub struct SyncReadAsyncWriteLockWriteGuard<'a, T: Send + Sync> { - _update_permit: TaskQueuePermit<'a>, - data: &'a RwLock, -} - -impl<'a, T: Send + Sync> SyncReadAsyncWriteLockWriteGuard<'a, T> { - pub fn read(&self) -> RwLockReadGuard<'_, T> { - self.data.read() - } - - /// Warning: Only `write()` with data you created within this - /// write this `SyncReadAsyncWriteLockWriteGuard`. - /// - /// ```rs - /// let mut data = lock.write().await; - /// - /// let mut data = data.read().clone(); - /// data.value = 2; - /// *data.write() = data; - /// ``` - pub fn write(&self) -> RwLockWriteGuard<'_, T> { - self.data.write() - } -} - -/// A lock that can only be -pub struct SyncReadAsyncWriteLock { - data: RwLock, - update_queue: TaskQueue, -} - -impl SyncReadAsyncWriteLock { - pub fn new(data: T) -> Self { - Self { - data: RwLock::new(data), - update_queue: TaskQueue::default(), - } - } - - pub fn read(&self) -> RwLockReadGuard<'_, T> { - self.data.read() - } - - pub async fn acquire(&self) -> SyncReadAsyncWriteLockWriteGuard<'_, T> { - let update_permit = self.update_queue.acquire().await; - SyncReadAsyncWriteLockWriteGuard { - _update_permit: update_permit, - data: &self.data, - } - } -} diff --git a/cli/util/sync/task_queue.rs b/cli/util/sync/task_queue.rs index 6ef747e1ae..4c5abfab3b 100644 --- a/cli/util/sync/task_queue.rs +++ b/cli/util/sync/task_queue.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::LinkedList; use std::sync::Arc; @@ -146,9 +146,10 @@ impl<'a> Future for TaskQueuePermitAcquireFuture<'a> { #[cfg(test)] mod test { + use std::sync::Arc; + use deno_core::futures; use deno_core::parking_lot::Mutex; - use std::sync::Arc; use super::*; diff --git a/cli/util/text_encoding.rs b/cli/util/text_encoding.rs index 107b78a213..b5a288be7b 100644 --- a/cli/util/text_encoding.rs +++ b/cli/util/text_encoding.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::ops::Range; diff --git a/cli/util/unix.rs b/cli/util/unix.rs index 2c76a54c38..4b6ac1f320 100644 --- a/cli/util/unix.rs +++ b/cli/util/unix.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// Raise soft file descriptor limit to hard file descriptor limit. /// This is the difference between `ulimit -n` and `ulimit -n -H`. diff --git a/cli/util/v8.rs b/cli/util/v8.rs index 6e690e6f30..403d1955a5 100644 --- a/cli/util/v8.rs +++ b/cli/util/v8.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. pub mod convert; diff --git a/cli/util/v8/convert.rs b/cli/util/v8/convert.rs index 28107d9010..4d0cb732a8 100644 --- a/cli/util/v8/convert.rs +++ b/cli/util/v8/convert.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::v8; use deno_core::FromV8; diff --git a/cli/util/windows.rs b/cli/util/windows.rs index 37e78a5d08..7f516efbeb 100644 --- a/cli/util/windows.rs +++ b/cli/util/windows.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// Ensures that stdin, stdout, and stderr are open and have valid HANDLEs /// associated with them. There are many places where a `std::fs::File` is @@ -8,6 +8,7 @@ pub fn ensure_stdio_open() { // SAFETY: winapi calls unsafe { use std::mem::size_of; + use winapi::shared::minwindef::DWORD; use winapi::shared::minwindef::FALSE; use winapi::shared::minwindef::TRUE; diff --git a/cli/version.rs b/cli/version.rs index 0cdb32102a..fb0fe98b29 100644 --- a/cli/version.rs +++ b/cli/version.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use once_cell::sync::Lazy; diff --git a/cli/worker.rs b/cli/worker.rs index ef519c7278..cf301de83e 100644 --- a/cli/worker.rs +++ b/cli/worker.rs @@ -1,88 +1,44 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::path::Path; -use std::path::PathBuf; -use std::rc::Rc; use std::sync::Arc; use deno_ast::ModuleSpecifier; use deno_core::anyhow::bail; use deno_core::error::AnyError; +use deno_core::error::CoreError; use deno_core::futures::FutureExt; -use deno_core::url::Url; use deno_core::v8; -use deno_core::CompiledWasmModuleStore; use deno_core::Extension; -use deno_core::FeatureChecker; -use deno_core::ModuleLoader; use deno_core::PollEventLoopOptions; -use deno_core::SharedArrayBufferStore; +use deno_error::JsErrorBox; +use deno_lib::worker::LibMainWorker; +use deno_lib::worker::LibMainWorkerFactory; use deno_runtime::code_cache; -use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel; -use deno_runtime::deno_fs; -use deno_runtime::deno_node::NodeExtInitServices; -use deno_runtime::deno_node::NodeRequireLoader; -use deno_runtime::deno_node::NodeRequireLoaderRc; use deno_runtime::deno_permissions::PermissionsContainer; -use deno_runtime::deno_tls::RootCertStoreProvider; -use deno_runtime::deno_web::BlobStore; -use deno_runtime::fmt_errors::format_js_error; -use deno_runtime::inspector_server::InspectorServer; -use deno_runtime::ops::process::NpmProcessStateProviderRc; -use deno_runtime::ops::worker_host::CreateWebWorkerCb; -use deno_runtime::web_worker::WebWorker; -use deno_runtime::web_worker::WebWorkerOptions; -use deno_runtime::web_worker::WebWorkerServiceOptions; use deno_runtime::worker::MainWorker; -use deno_runtime::worker::WorkerOptions; -use deno_runtime::worker::WorkerServiceOptions; -use deno_runtime::BootstrapOptions; use deno_runtime::WorkerExecutionMode; -use deno_runtime::WorkerLogLevel; use deno_semver::npm::NpmPackageReqReference; -use deno_telemetry::OtelConfig; -use deno_terminal::colors; use node_resolver::NodeResolutionKind; use node_resolver::ResolutionMode; +use sys_traits::EnvCurrentDir; use tokio::select; use crate::args::CliLockfile; -use crate::args::DenoSubcommand; use crate::args::NpmCachingStrategy; -use crate::args::StorageKeyResolver; -use crate::errors; use crate::node::CliNodeResolver; -use crate::node::CliPackageJsonResolver; +use crate::npm::installer::NpmInstaller; +use crate::npm::installer::PackageCaching; use crate::npm::CliNpmResolver; use crate::sys::CliSys; -use crate::util::checksum; use crate::util::file_watcher::WatcherCommunicator; use crate::util::file_watcher::WatcherRestartMode; -use crate::version; - -pub struct CreateModuleLoaderResult { - pub module_loader: Rc, - pub node_require_loader: Rc, -} - -pub trait ModuleLoaderFactory: Send + Sync { - fn create_for_main( - &self, - root_permissions: PermissionsContainer, - ) -> CreateModuleLoaderResult; - - fn create_for_worker( - &self, - parent_permissions: PermissionsContainer, - permissions: PermissionsContainer, - ) -> CreateModuleLoaderResult; -} #[async_trait::async_trait(?Send)] pub trait HmrRunner: Send + Sync { - async fn start(&mut self) -> Result<(), AnyError>; - async fn stop(&mut self) -> Result<(), AnyError>; - async fn run(&mut self) -> Result<(), AnyError>; + async fn start(&mut self) -> Result<(), CoreError>; + async fn stop(&mut self) -> Result<(), CoreError>; + async fn run(&mut self) -> Result<(), CoreError>; } pub trait CliCodeCache: code_cache::CodeCache { @@ -111,83 +67,28 @@ pub type CreateCoverageCollectorCb = Box< >; pub struct CliMainWorkerOptions { - pub argv: Vec, - pub log_level: WorkerLogLevel, - pub enable_op_summary_metrics: bool, - pub enable_testing_features: bool, - pub has_node_modules_dir: bool, - pub hmr: bool, - pub inspect_brk: bool, - pub inspect_wait: bool, - pub strace_ops: Option>, - pub is_inspecting: bool, - pub location: Option, - pub argv0: Option, - pub node_debug: Option, - pub origin_data_folder_path: Option, - pub seed: Option, - pub unsafely_ignore_certificate_errors: Option>, - pub skip_op_registration: bool, pub create_hmr_runner: Option, pub create_coverage_collector: Option, - pub node_ipc: Option, - pub serve_port: Option, - pub serve_host: Option, + pub default_npm_caching_strategy: NpmCachingStrategy, + pub needs_test_modules: bool, } -struct SharedWorkerState { - blob_store: Arc, - broadcast_channel: InMemoryBroadcastChannel, - code_cache: Option>, - compiled_wasm_module_store: CompiledWasmModuleStore, - feature_checker: Arc, - fs: Arc, - maybe_file_watcher_communicator: Option>, - maybe_inspector_server: Option>, - maybe_lockfile: Option>, - module_loader_factory: Box, - node_resolver: Arc, - npm_resolver: Arc, - pkg_json_resolver: Arc, - root_cert_store_provider: Arc, - root_permissions: PermissionsContainer, - shared_array_buffer_store: SharedArrayBufferStore, - storage_key_resolver: StorageKeyResolver, - sys: CliSys, - options: CliMainWorkerOptions, - subcommand: DenoSubcommand, - otel_config: OtelConfig, - default_npm_caching_strategy: NpmCachingStrategy, -} - -impl SharedWorkerState { - pub fn create_node_init_services( - &self, - node_require_loader: NodeRequireLoaderRc, - ) -> NodeExtInitServices { - NodeExtInitServices { - node_require_loader, - node_resolver: self.node_resolver.clone(), - npm_resolver: self.npm_resolver.clone().into_npm_pkg_folder_resolver(), - pkg_json_resolver: self.pkg_json_resolver.clone(), - sys: self.sys.clone(), - } - } - - pub fn npm_process_state_provider(&self) -> NpmProcessStateProviderRc { - self.npm_resolver.clone().into_process_state_provider() - } +/// Data shared between the factory and workers. +struct SharedState { + pub create_hmr_runner: Option, + pub create_coverage_collector: Option, + pub maybe_file_watcher_communicator: Option>, } pub struct CliMainWorker { - main_module: ModuleSpecifier, - worker: MainWorker, - shared: Arc, + worker: LibMainWorker, + shared: Arc, } impl CliMainWorker { + #[inline] pub fn into_main_worker(self) -> MainWorker { - self.worker + self.worker.into_main_worker() } pub async fn setup_repl(&mut self) -> Result<(), AnyError> { @@ -195,35 +96,36 @@ impl CliMainWorker { Ok(()) } - pub async fn run(&mut self) -> Result { + pub async fn run(&mut self) -> Result { let mut maybe_coverage_collector = self.maybe_setup_coverage_collector().await?; let mut maybe_hmr_runner = self.maybe_setup_hmr_runner().await?; - log::debug!("main_module {}", self.main_module); + log::debug!("main_module {}", self.worker.main_module()); self.execute_main_module().await?; self.worker.dispatch_load_event()?; loop { if let Some(hmr_runner) = maybe_hmr_runner.as_mut() { - let watcher_communicator = - self.shared.maybe_file_watcher_communicator.clone().unwrap(); - let hmr_future = hmr_runner.run().boxed_local(); let event_loop_future = self.worker.run_event_loop(false).boxed_local(); let result; select! { hmr_result = hmr_future => { - result = hmr_result; + result = hmr_result.map_err(Into::into); }, event_loop_result = event_loop_future => { result = event_loop_result; } } if let Err(e) = result { - watcher_communicator + self + .shared + .maybe_file_watcher_communicator + .as_ref() + .unwrap() .change_restart_mode(WatcherRestartMode::Automatic); return Err(e); } @@ -249,7 +151,7 @@ impl CliMainWorker { if let Some(coverage_collector) = maybe_coverage_collector.as_mut() { self .worker - .js_runtime + .js_runtime() .with_event_loop_future( coverage_collector.stop_collecting().boxed_local(), PollEventLoopOptions::default(), @@ -259,7 +161,7 @@ impl CliMainWorker { if let Some(hmr_runner) = maybe_hmr_runner.as_mut() { self .worker - .js_runtime + .js_runtime() .with_event_loop_future( hmr_runner.stop().boxed_local(), PollEventLoopOptions::default(), @@ -331,24 +233,20 @@ impl CliMainWorker { executor.execute().await } - pub async fn execute_main_module(&mut self) -> Result<(), AnyError> { - let id = self.worker.preload_main_module(&self.main_module).await?; - self.worker.evaluate_module(id).await + #[inline] + pub async fn execute_main_module(&mut self) -> Result<(), CoreError> { + self.worker.execute_main_module().await } - pub async fn execute_side_module(&mut self) -> Result<(), AnyError> { - let id = self.worker.preload_side_module(&self.main_module).await?; - self.worker.evaluate_module(id).await + #[inline] + pub async fn execute_side_module(&mut self) -> Result<(), CoreError> { + self.worker.execute_side_module().await } pub async fn maybe_setup_hmr_runner( &mut self, ) -> Result>, AnyError> { - if !self.shared.options.hmr { - return Ok(None); - } - let Some(setup_hmr_runner) = self.shared.options.create_hmr_runner.as_ref() - else { + let Some(setup_hmr_runner) = self.shared.create_hmr_runner.as_ref() else { return Ok(None); }; @@ -358,7 +256,7 @@ impl CliMainWorker { self .worker - .js_runtime + .js_runtime() .with_event_loop_future( hmr_runner.start().boxed_local(), PollEventLoopOptions::default(), @@ -371,7 +269,7 @@ impl CliMainWorker { &mut self, ) -> Result>, AnyError> { let Some(create_coverage_collector) = - self.shared.options.create_coverage_collector.as_ref() + self.shared.create_coverage_collector.as_ref() else { return Ok(None); }; @@ -380,7 +278,7 @@ impl CliMainWorker { let mut coverage_collector = create_coverage_collector(session); self .worker - .js_runtime + .js_runtime() .with_event_loop_future( coverage_collector.start_collecting().boxed_local(), PollEventLoopOptions::default(), @@ -393,71 +291,52 @@ impl CliMainWorker { &mut self, name: &'static str, source_code: &'static str, - ) -> Result, AnyError> { - self.worker.js_runtime.execute_script(name, source_code) + ) -> Result, CoreError> { + self.worker.js_runtime().execute_script(name, source_code) } } -// TODO(bartlomieju): this should be moved to some other place, added to avoid string -// duplication between worker setups and `deno info` output. -pub fn get_cache_storage_dir() -> PathBuf { - // Note: we currently use temp_dir() to avoid managing storage size. - std::env::temp_dir().join("deno_cache") -} - -#[derive(Clone)] pub struct CliMainWorkerFactory { - shared: Arc, + lib_main_worker_factory: LibMainWorkerFactory, + maybe_lockfile: Option>, + node_resolver: Arc, + npm_installer: Option>, + npm_resolver: CliNpmResolver, + root_permissions: PermissionsContainer, + shared: Arc, + sys: CliSys, + default_npm_caching_strategy: NpmCachingStrategy, + needs_test_modules: bool, } impl CliMainWorkerFactory { #[allow(clippy::too_many_arguments)] pub fn new( - blob_store: Arc, - code_cache: Option>, - feature_checker: Arc, - fs: Arc, + lib_main_worker_factory: LibMainWorkerFactory, maybe_file_watcher_communicator: Option>, - maybe_inspector_server: Option>, maybe_lockfile: Option>, - module_loader_factory: Box, node_resolver: Arc, - npm_resolver: Arc, - pkg_json_resolver: Arc, - root_cert_store_provider: Arc, - root_permissions: PermissionsContainer, - storage_key_resolver: StorageKeyResolver, + npm_installer: Option>, + npm_resolver: CliNpmResolver, sys: CliSys, - subcommand: DenoSubcommand, options: CliMainWorkerOptions, - otel_config: OtelConfig, - default_npm_caching_strategy: NpmCachingStrategy, + root_permissions: PermissionsContainer, ) -> Self { Self { - shared: Arc::new(SharedWorkerState { - blob_store, - broadcast_channel: Default::default(), - code_cache, - compiled_wasm_module_store: Default::default(), - feature_checker, - fs, + lib_main_worker_factory, + maybe_lockfile, + node_resolver, + npm_installer, + npm_resolver, + root_permissions, + sys, + shared: Arc::new(SharedState { + create_hmr_runner: options.create_hmr_runner, + create_coverage_collector: options.create_coverage_collector, maybe_file_watcher_communicator, - maybe_inspector_server, - maybe_lockfile, - module_loader_factory, - node_resolver, - npm_resolver, - pkg_json_resolver, - root_cert_store_provider, - root_permissions, - shared_array_buffer_store: Default::default(), - storage_key_resolver, - sys, - options, - subcommand, - otel_config, - default_npm_caching_strategy, }), + default_npm_caching_strategy: options.default_npm_caching_strategy, + needs_test_modules: options.needs_test_modules, } } @@ -465,12 +344,12 @@ impl CliMainWorkerFactory { &self, mode: WorkerExecutionMode, main_module: ModuleSpecifier, - ) -> Result { + ) -> Result { self .create_custom_worker( mode, main_module, - self.shared.root_permissions.clone(), + self.root_permissions.clone(), vec![], Default::default(), ) @@ -484,49 +363,41 @@ impl CliMainWorkerFactory { permissions: PermissionsContainer, custom_extensions: Vec, stdio: deno_runtime::deno_io::Stdio, - ) -> Result { - let shared = &self.shared; - let CreateModuleLoaderResult { - module_loader, - node_require_loader, - } = shared - .module_loader_factory - .create_for_main(permissions.clone()); + ) -> Result { let main_module = if let Ok(package_ref) = NpmPackageReqReference::from_specifier(&main_module) { - if let Some(npm_resolver) = shared.npm_resolver.as_managed() { + if let Some(npm_installer) = &self.npm_installer { let reqs = &[package_ref.req().clone()]; - npm_resolver + npm_installer .add_package_reqs( reqs, if matches!( - shared.default_npm_caching_strategy, + self.default_npm_caching_strategy, NpmCachingStrategy::Lazy ) { - crate::npm::PackageCaching::Only(reqs.into()) + PackageCaching::Only(reqs.into()) } else { - crate::npm::PackageCaching::All + PackageCaching::All }, ) .await?; } // use a fake referrer that can be used to discover the package.json if necessary - let referrer = - ModuleSpecifier::from_directory_path(self.shared.fs.cwd()?) - .unwrap() - .join("package.json")?; - let package_folder = shared + let referrer = ModuleSpecifier::from_directory_path( + self.sys.env_current_dir().map_err(JsErrorBox::from_err)?, + ) + .unwrap() + .join("package.json")?; + let package_folder = self .npm_resolver - .resolve_pkg_folder_from_deno_module_req( - package_ref.req(), - &referrer, - )?; + .resolve_pkg_folder_from_deno_module_req(package_ref.req(), &referrer) + .map_err(JsErrorBox::from_err)?; let main_module = self .resolve_binary_entrypoint(&package_folder, package_ref.sub_path())?; - if let Some(lockfile) = &shared.maybe_lockfile { + if let Some(lockfile) = &self.maybe_lockfile { // For npm binary commands, ensure that the lockfile gets updated // so that we can re-use the npm resolution the next time it runs // for better performance @@ -538,120 +409,18 @@ impl CliMainWorkerFactory { main_module }; - let maybe_inspector_server = shared.maybe_inspector_server.clone(); - - let create_web_worker_cb = - create_web_worker_callback(shared.clone(), stdio.clone()); - - let maybe_storage_key = shared - .storage_key_resolver - .resolve_storage_key(&main_module); - let origin_storage_dir = maybe_storage_key.as_ref().map(|key| { - shared - .options - .origin_data_folder_path - .as_ref() - .unwrap() // must be set if storage key resolver returns a value - .join(checksum::gen(&[key.as_bytes()])) - }); - let cache_storage_dir = maybe_storage_key.map(|key| { - // TODO(@satyarohith): storage quota management - get_cache_storage_dir().join(checksum::gen(&[key.as_bytes()])) - }); - - // TODO(bartlomieju): this is cruft, update FeatureChecker to spit out - // list of enabled features. - let feature_checker = shared.feature_checker.clone(); - let mut unstable_features = - Vec::with_capacity(crate::UNSTABLE_GRANULAR_FLAGS.len()); - for granular_flag in crate::UNSTABLE_GRANULAR_FLAGS { - if feature_checker.check(granular_flag.name) { - unstable_features.push(granular_flag.id); - } - } - - let services = WorkerServiceOptions { - root_cert_store_provider: Some(shared.root_cert_store_provider.clone()), - module_loader, - fs: shared.fs.clone(), - node_services: Some( - shared.create_node_init_services(node_require_loader), - ), - npm_process_state_provider: Some(shared.npm_process_state_provider()), - blob_store: shared.blob_store.clone(), - broadcast_channel: shared.broadcast_channel.clone(), - fetch_dns_resolver: Default::default(), - shared_array_buffer_store: Some(shared.shared_array_buffer_store.clone()), - compiled_wasm_module_store: Some( - shared.compiled_wasm_module_store.clone(), - ), - feature_checker, + let mut worker = self.lib_main_worker_factory.create_custom_worker( + mode, + main_module, permissions, - v8_code_cache: shared.code_cache.clone().map(|c| c.as_code_cache()), - }; - - let options = WorkerOptions { - bootstrap: BootstrapOptions { - deno_version: crate::version::DENO_VERSION_INFO.deno.to_string(), - args: shared.options.argv.clone(), - cpu_count: std::thread::available_parallelism() - .map(|p| p.get()) - .unwrap_or(1), - log_level: shared.options.log_level, - enable_op_summary_metrics: shared.options.enable_op_summary_metrics, - enable_testing_features: shared.options.enable_testing_features, - locale: deno_core::v8::icu::get_language_tag(), - location: shared.options.location.clone(), - no_color: !colors::use_color(), - is_stdout_tty: deno_terminal::is_stdout_tty(), - is_stderr_tty: deno_terminal::is_stderr_tty(), - color_level: colors::get_color_level(), - unstable_features, - user_agent: version::DENO_VERSION_INFO.user_agent.to_string(), - inspect: shared.options.is_inspecting, - has_node_modules_dir: shared.options.has_node_modules_dir, - argv0: shared.options.argv0.clone(), - node_debug: shared.options.node_debug.clone(), - node_ipc_fd: shared.options.node_ipc, - mode, - serve_port: shared.options.serve_port, - serve_host: shared.options.serve_host.clone(), - otel_config: shared.otel_config.clone(), - close_on_idle: true, - }, - extensions: custom_extensions, - startup_snapshot: crate::js::deno_isolate_init(), - create_params: create_isolate_create_params(), - unsafely_ignore_certificate_errors: shared - .options - .unsafely_ignore_certificate_errors - .clone(), - seed: shared.options.seed, - format_js_error_fn: Some(Arc::new(format_js_error)), - create_web_worker_cb, - maybe_inspector_server, - should_break_on_first_statement: shared.options.inspect_brk, - should_wait_for_inspector_session: shared.options.inspect_wait, - strace_ops: shared.options.strace_ops.clone(), - get_error_class_fn: Some(&errors::get_error_class_name), - cache_storage_dir, - origin_storage_dir, + custom_extensions, stdio, - skip_op_registration: shared.options.skip_op_registration, - enable_stack_trace_arg_in_ops: crate::args::has_trace_permissions_enabled( - ), - }; + )?; - let mut worker = MainWorker::bootstrap_from_options( - main_module.clone(), - services, - options, - ); - - if self.shared.subcommand.needs_test() { + if self.needs_test_modules { macro_rules! test_file { ($($file:literal),*) => { - $(worker.js_runtime.lazy_load_es_module_with_code( + $(worker.js_runtime().lazy_load_es_module_with_code( concat!("ext:cli/", $file), deno_core::ascii_str_include!(concat!("js/", $file)), )?;)* @@ -669,9 +438,8 @@ impl CliMainWorkerFactory { } Ok(CliMainWorker { - main_module, worker, - shared: shared.clone(), + shared: self.shared.clone(), }) } @@ -681,7 +449,6 @@ impl CliMainWorkerFactory { sub_path: Option<&str>, ) -> Result { match self - .shared .node_resolver .resolve_binary_export(package_folder, sub_path) { @@ -716,7 +483,6 @@ impl CliMainWorkerFactory { } let specifier = self - .shared .node_resolver .resolve_package_subpath_from_deno_module( package_folder, @@ -737,138 +503,22 @@ impl CliMainWorkerFactory { } } -fn create_web_worker_callback( - shared: Arc, - stdio: deno_runtime::deno_io::Stdio, -) -> Arc { - Arc::new(move |args| { - let maybe_inspector_server = shared.maybe_inspector_server.clone(); - - let CreateModuleLoaderResult { - module_loader, - node_require_loader, - } = shared.module_loader_factory.create_for_worker( - args.parent_permissions.clone(), - args.permissions.clone(), - ); - let create_web_worker_cb = - create_web_worker_callback(shared.clone(), stdio.clone()); - - let maybe_storage_key = shared - .storage_key_resolver - .resolve_storage_key(&args.main_module); - let cache_storage_dir = maybe_storage_key.map(|key| { - // TODO(@satyarohith): storage quota management - get_cache_storage_dir().join(checksum::gen(&[key.as_bytes()])) - }); - - // TODO(bartlomieju): this is cruft, update FeatureChecker to spit out - // list of enabled features. - let feature_checker = shared.feature_checker.clone(); - let mut unstable_features = - Vec::with_capacity(crate::UNSTABLE_GRANULAR_FLAGS.len()); - for granular_flag in crate::UNSTABLE_GRANULAR_FLAGS { - if feature_checker.check(granular_flag.name) { - unstable_features.push(granular_flag.id); - } - } - - let services = WebWorkerServiceOptions { - root_cert_store_provider: Some(shared.root_cert_store_provider.clone()), - module_loader, - fs: shared.fs.clone(), - node_services: Some( - shared.create_node_init_services(node_require_loader), - ), - blob_store: shared.blob_store.clone(), - broadcast_channel: shared.broadcast_channel.clone(), - shared_array_buffer_store: Some(shared.shared_array_buffer_store.clone()), - compiled_wasm_module_store: Some( - shared.compiled_wasm_module_store.clone(), - ), - maybe_inspector_server, - feature_checker, - npm_process_state_provider: Some(shared.npm_process_state_provider()), - permissions: args.permissions, - }; - let options = WebWorkerOptions { - name: args.name, - main_module: args.main_module.clone(), - worker_id: args.worker_id, - bootstrap: BootstrapOptions { - deno_version: crate::version::DENO_VERSION_INFO.deno.to_string(), - args: shared.options.argv.clone(), - cpu_count: std::thread::available_parallelism() - .map(|p| p.get()) - .unwrap_or(1), - log_level: shared.options.log_level, - enable_op_summary_metrics: shared.options.enable_op_summary_metrics, - enable_testing_features: shared.options.enable_testing_features, - locale: deno_core::v8::icu::get_language_tag(), - location: Some(args.main_module), - no_color: !colors::use_color(), - color_level: colors::get_color_level(), - is_stdout_tty: deno_terminal::is_stdout_tty(), - is_stderr_tty: deno_terminal::is_stderr_tty(), - unstable_features, - user_agent: version::DENO_VERSION_INFO.user_agent.to_string(), - inspect: shared.options.is_inspecting, - has_node_modules_dir: shared.options.has_node_modules_dir, - argv0: shared.options.argv0.clone(), - node_debug: shared.options.node_debug.clone(), - node_ipc_fd: None, - mode: WorkerExecutionMode::Worker, - serve_port: shared.options.serve_port, - serve_host: shared.options.serve_host.clone(), - otel_config: shared.otel_config.clone(), - close_on_idle: args.close_on_idle, - }, - extensions: vec![], - startup_snapshot: crate::js::deno_isolate_init(), - create_params: create_isolate_create_params(), - unsafely_ignore_certificate_errors: shared - .options - .unsafely_ignore_certificate_errors - .clone(), - seed: shared.options.seed, - create_web_worker_cb, - format_js_error_fn: Some(Arc::new(format_js_error)), - worker_type: args.worker_type, - get_error_class_fn: Some(&errors::get_error_class_name), - stdio: stdio.clone(), - cache_storage_dir, - strace_ops: shared.options.strace_ops.clone(), - close_on_idle: args.close_on_idle, - maybe_worker_metadata: args.maybe_worker_metadata, - enable_stack_trace_arg_in_ops: crate::args::has_trace_permissions_enabled( - ), - }; - - WebWorker::bootstrap_from_options(services, options) - }) -} - -/// By default V8 uses 1.4Gb heap limit which is meant for browser tabs. -/// Instead probe for the total memory on the system and use it instead -/// as a default. -pub fn create_isolate_create_params() -> Option { - let maybe_mem_info = deno_runtime::sys_info::mem_info(); - maybe_mem_info.map(|mem_info| { - v8::CreateParams::default() - .heap_limits_from_system_memory(mem_info.total, 0) - }) -} - #[allow(clippy::print_stdout)] #[allow(clippy::print_stderr)] #[cfg(test)] mod tests { - use super::*; + use std::rc::Rc; + use deno_core::resolve_path; use deno_core::FsModuleLoader; - use deno_fs::RealFs; + use deno_resolver::npm::DenoInNpmPackageChecker; + use deno_runtime::deno_fs::RealFs; use deno_runtime::deno_permissions::Permissions; use deno_runtime::permissions::RuntimePermissionDescriptorParser; + use deno_runtime::worker::WorkerOptions; + use deno_runtime::worker::WorkerServiceOptions; + + use super::*; fn create_test_worker() -> MainWorker { let main_module = @@ -882,8 +532,12 @@ mod tests { ..Default::default() }; - MainWorker::bootstrap_from_options::( - main_module, + MainWorker::bootstrap_from_options::< + DenoInNpmPackageChecker, + CliNpmResolver, + CliSys, + >( + &main_module, WorkerServiceOptions { module_loader: Rc::new(FsModuleLoader), permissions: PermissionsContainer::new( diff --git a/ext/broadcast_channel/01_broadcast_channel.js b/ext/broadcast_channel/01_broadcast_channel.js index 1a4bb36474..a71ae465cf 100644 --- a/ext/broadcast_channel/01_broadcast_channel.js +++ b/ext/broadcast_channel/01_broadcast_channel.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// diff --git a/ext/broadcast_channel/Cargo.toml b/ext/broadcast_channel/Cargo.toml index 4dea8f21e1..ff0034f0a8 100644 --- a/ext/broadcast_channel/Cargo.toml +++ b/ext/broadcast_channel/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_broadcast_channel" -version = "0.178.0" +version = "0.180.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -16,6 +16,7 @@ path = "lib.rs" [dependencies] async-trait.workspace = true deno_core.workspace = true +deno_error.workspace = true thiserror.workspace = true tokio.workspace = true uuid.workspace = true diff --git a/ext/broadcast_channel/in_memory_broadcast_channel.rs b/ext/broadcast_channel/in_memory_broadcast_channel.rs index 61dc68e17d..33803c74f4 100644 --- a/ext/broadcast_channel/in_memory_broadcast_channel.rs +++ b/ext/broadcast_channel/in_memory_broadcast_channel.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::sync::Arc; diff --git a/ext/broadcast_channel/lib.deno_broadcast_channel.d.ts b/ext/broadcast_channel/lib.deno_broadcast_channel.d.ts index 339765ec9c..a43f8609b9 100644 --- a/ext/broadcast_channel/lib.deno_broadcast_channel.d.ts +++ b/ext/broadcast_channel/lib.deno_broadcast_channel.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-explicit-any no-var diff --git a/ext/broadcast_channel/lib.rs b/ext/broadcast_channel/lib.rs index c1de118a36..ae709c674c 100644 --- a/ext/broadcast_channel/lib.rs +++ b/ext/broadcast_channel/lib.rs @@ -1,10 +1,7 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. mod in_memory_broadcast_channel; -pub use in_memory_broadcast_channel::InMemoryBroadcastChannel; -pub use in_memory_broadcast_channel::InMemoryBroadcastChannelResource; - use std::cell::RefCell; use std::path::PathBuf; use std::rc::Rc; @@ -15,23 +12,34 @@ use deno_core::JsBuffer; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; +use deno_error::JsErrorBox; +pub use in_memory_broadcast_channel::InMemoryBroadcastChannel; +pub use in_memory_broadcast_channel::InMemoryBroadcastChannelResource; use tokio::sync::broadcast::error::SendError as BroadcastSendError; use tokio::sync::mpsc::error::SendError as MpscSendError; pub const UNSTABLE_FEATURE_NAME: &str = "broadcast-channel"; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum BroadcastChannelError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource( + #[from] + #[inherit] + deno_core::error::ResourceError, + ), + #[class(generic)] #[error(transparent)] MPSCSendError(MpscSendError>), + #[class(generic)] #[error(transparent)] BroadcastSendError( BroadcastSendError>, ), + #[class(inherit)] #[error(transparent)] - Other(deno_core::error::AnyError), + Other(#[inherit] JsErrorBox), } impl From> @@ -101,10 +109,7 @@ pub fn op_broadcast_unsubscribe( where BC: BroadcastChannel + 'static, { - let resource = state - .resource_table - .get::(rid) - .map_err(BroadcastChannelError::Resource)?; + let resource = state.resource_table.get::(rid)?; let bc = state.borrow::(); bc.unsubscribe(&resource) } @@ -119,11 +124,7 @@ pub async fn op_broadcast_send( where BC: BroadcastChannel + 'static, { - let resource = state - .borrow() - .resource_table - .get::(rid) - .map_err(BroadcastChannelError::Resource)?; + let resource = state.borrow().resource_table.get::(rid)?; let bc = state.borrow().borrow::().clone(); bc.send(&resource, name, buf.to_vec()).await } @@ -137,11 +138,7 @@ pub async fn op_broadcast_recv( where BC: BroadcastChannel + 'static, { - let resource = state - .borrow() - .resource_table - .get::(rid) - .map_err(BroadcastChannelError::Resource)?; + let resource = state.borrow().resource_table.get::(rid)?; let bc = state.borrow().borrow::().clone(); bc.recv(&resource).await } diff --git a/ext/cache/01_cache.js b/ext/cache/01_cache.js index 269261f401..55aac3a4d8 100644 --- a/ext/cache/01_cache.js +++ b/ext/cache/01_cache.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { primordials } from "ext:core/mod.js"; import { op_cache_delete, diff --git a/ext/cache/Cargo.toml b/ext/cache/Cargo.toml index 96aec27576..4d15c8861b 100644 --- a/ext/cache/Cargo.toml +++ b/ext/cache/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_cache" -version = "0.116.0" +version = "0.118.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -16,6 +16,7 @@ path = "lib.rs" [dependencies] async-trait.workspace = true deno_core.workspace = true +deno_error.workspace = true rusqlite.workspace = true serde.workspace = true sha2.workspace = true diff --git a/ext/cache/lib.deno_cache.d.ts b/ext/cache/lib.deno_cache.d.ts index f9e1818482..9995af7f66 100644 --- a/ext/cache/lib.deno_cache.d.ts +++ b/ext/cache/lib.deno_cache.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-var diff --git a/ext/cache/lib.rs b/ext/cache/lib.rs index 524d4cea05..d3bfe23def 100644 --- a/ext/cache/lib.rs +++ b/ext/cache/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::cell::RefCell; use std::path::PathBuf; @@ -6,7 +6,6 @@ use std::rc::Rc; use std::sync::Arc; use async_trait::async_trait; -use deno_core::error::type_error; use deno_core::op2; use deno_core::serde::Deserialize; use deno_core::serde::Serialize; @@ -14,22 +13,38 @@ use deno_core::ByteString; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; +use deno_error::JsErrorBox; mod sqlite; pub use sqlite::SqliteBackedCache; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum CacheError { + #[class(type)] + #[error("CacheStorage is not available in this context")] + ContextUnsupported, + #[class(generic)] #[error(transparent)] Sqlite(#[from] rusqlite::Error), + #[class(generic)] #[error(transparent)] JoinError(#[from] tokio::task::JoinError), + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] deno_core::error::ResourceError), + #[class(inherit)] #[error(transparent)] - Other(deno_core::error::AnyError), + Other(JsErrorBox), + #[class(inherit)] #[error("{0}")] Io(#[from] std::io::Error), + #[class(generic)] + #[error("Failed to create cache storage directory {}", .dir.display())] + CacheStorageDirectory { + dir: PathBuf, + #[source] + source: std::io::Error, + }, } #[derive(Clone)] @@ -237,9 +252,7 @@ where state.put(cache); Ok(state.borrow::().clone()) } else { - Err(CacheError::Other(type_error( - "CacheStorage is not available in this context", - ))) + Err(CacheError::ContextUnsupported) } } diff --git a/ext/cache/sqlite.rs b/ext/cache/sqlite.rs index 469e3e51d6..6587a52bac 100644 --- a/ext/cache/sqlite.rs +++ b/ext/cache/sqlite.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::path::PathBuf; use std::pin::Pin; @@ -8,8 +8,6 @@ use std::time::SystemTime; use std::time::UNIX_EPOCH; use async_trait::async_trait; -use deno_core::anyhow::Context; -use deno_core::error::AnyError; use deno_core::futures::future::poll_fn; use deno_core::parking_lot::Mutex; use deno_core::unsync::spawn_blocking; @@ -45,14 +43,12 @@ pub struct SqliteBackedCache { impl SqliteBackedCache { pub fn new(cache_storage_dir: PathBuf) -> Result { { - std::fs::create_dir_all(&cache_storage_dir) - .with_context(|| { - format!( - "Failed to create cache storage directory {}", - cache_storage_dir.display() - ) - }) - .map_err(CacheError::Other)?; + std::fs::create_dir_all(&cache_storage_dir).map_err(|source| { + CacheError::CacheStorageDirectory { + dir: cache_storage_dir.clone(), + source, + } + })?; let path = cache_storage_dir.join("cache_metadata.db"); let connection = rusqlite::Connection::open(&path).unwrap_or_else(|_| { panic!("failed to open cache db at {}", path.display()) @@ -385,7 +381,10 @@ impl CacheResponseResource { } } - async fn read(self: Rc, data: &mut [u8]) -> Result { + async fn read( + self: Rc, + data: &mut [u8], + ) -> Result { let resource = deno_core::RcRef::map(&self, |r| &r.file); let mut file = resource.borrow_mut().await; let nread = file.read(data).await?; diff --git a/ext/canvas/01_image.js b/ext/canvas/01_image.js index 3ea72db6ac..4b39c041b4 100644 --- a/ext/canvas/01_image.js +++ b/ext/canvas/01_image.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { internals, primordials } from "ext:core/mod.js"; import { op_image_decode_png, op_image_process } from "ext:core/ops"; diff --git a/ext/canvas/Cargo.toml b/ext/canvas/Cargo.toml index 7c7cc49b7c..0b89842f09 100644 --- a/ext/canvas/Cargo.toml +++ b/ext/canvas/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_canvas" -version = "0.53.0" +version = "0.55.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -15,6 +15,7 @@ path = "lib.rs" [dependencies] deno_core.workspace = true +deno_error.workspace = true deno_webgpu.workspace = true image = { version = "0.24.7", default-features = false, features = ["png"] } serde = { workspace = true, features = ["derive"] } diff --git a/ext/canvas/lib.deno_canvas.d.ts b/ext/canvas/lib.deno_canvas.d.ts index c695ba5cd8..84d3cbdd42 100644 --- a/ext/canvas/lib.deno_canvas.d.ts +++ b/ext/canvas/lib.deno_canvas.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-var diff --git a/ext/canvas/lib.rs b/ext/canvas/lib.rs index defb288ac9..91b4e44afe 100644 --- a/ext/canvas/lib.rs +++ b/ext/canvas/lib.rs @@ -1,4 +1,6 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::path::PathBuf; use deno_core::op2; use deno_core::ToJsBuffer; @@ -9,12 +11,13 @@ use image::Pixel; use image::RgbaImage; use serde::Deserialize; use serde::Serialize; -use std::path::PathBuf; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum CanvasError { + #[class(type)] #[error("Color type '{0:?}' not supported")] UnsupportedColorType(ColorType), + #[class(generic)] #[error(transparent)] Image(#[from] image::ImageError), } diff --git a/ext/console/01_console.js b/ext/console/01_console.js index 3803492b90..09441a56a3 100644 --- a/ext/console/01_console.js +++ b/ext/console/01_console.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// @@ -216,7 +216,7 @@ const styles = { regexp: "red", module: "underline", internalError: "red", - temporal: "magenta", + temporal: "cyan", }; const defaultFG = 39; diff --git a/ext/console/Cargo.toml b/ext/console/Cargo.toml index f68dd7d198..87ab697e36 100644 --- a/ext/console/Cargo.toml +++ b/ext/console/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_console" -version = "0.184.0" +version = "0.186.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/console/internal.d.ts b/ext/console/internal.d.ts index 5f9627cf56..e90c9b6f11 100644 --- a/ext/console/internal.d.ts +++ b/ext/console/internal.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// /// diff --git a/ext/console/lib.deno_console.d.ts b/ext/console/lib.deno_console.d.ts index 0c73972d36..1f6c3fe682 100644 --- a/ext/console/lib.deno_console.d.ts +++ b/ext/console/lib.deno_console.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-explicit-any @@ -6,33 +6,251 @@ /// /** @category I/O */ +/** + * The Console interface provides methods for logging information to the console, + * as well as other utility methods for debugging and inspecting code. + * @see https://developer.mozilla.org/en-US/docs/Web/API/console + */ +/** Interface representing the console object that provides methods for logging, debugging, and timing */ interface Console { + /** + * Tests that an expression is true. If not, logs an error message + * @param condition The expression to test for truthiness + * @param data Additional arguments to be printed if the assertion fails + * @example + * ```ts + * console.assert(1 === 1, "This won't show"); + * console.assert(1 === 2, "This will show an error"); + * ``` + */ assert(condition?: boolean, ...data: any[]): void; + + /** + * Clears the console if the environment allows it + * @example + * ```ts + * console.clear(); + * ``` + */ clear(): void; + + /** + * Maintains an internal counter for a given label, incrementing it each time the method is called + * @param label The label to count. Defaults to 'default' + * @example + * ```ts + * console.count('myCounter'); + * console.count('myCounter'); // Will show: myCounter: 2 + * ``` + */ count(label?: string): void; + + /** + * Resets the counter for a given label + * @param label The label to reset. Defaults to 'default' + * @example + * ```ts + * console.count('myCounter'); + * console.countReset('myCounter'); // Resets to 0 + * ``` + */ countReset(label?: string): void; + + /** + * Outputs a debugging message to the console + * @param data Values to be printed to the console + * @example + * ```ts + * console.debug('Debug message', { detail: 'some data' }); + * ``` + */ debug(...data: any[]): void; + + /** + * Displays a list of the properties of a specified object + * @param item Object to display + * @param options Formatting options + * @example + * ```ts + * console.dir({ name: 'object', value: 42 }, { depth: 1 }); + * ``` + */ dir(item?: any, options?: any): void; + + /** + * @ignore + */ dirxml(...data: any[]): void; + + /** + * Outputs an error message to the console. + * This method routes the output to stderr, + * unlike other console methods that route to stdout. + * @param data Values to be printed to the console + * @example + * ```ts + * console.error('Error occurred:', new Error('Something went wrong')); + * ``` + */ error(...data: any[]): void; + + /** + * Creates a new inline group in the console, indenting subsequent console messages + * @param data Labels for the group + * @example + * ```ts + * console.group('Group 1'); + * console.log('Inside group 1'); + * console.groupEnd(); + * ``` + */ group(...data: any[]): void; + + /** + * Creates a new inline group in the console that is initially collapsed + * @param data Labels for the group + * @example + * ```ts + * console.groupCollapsed('Details'); + * console.log('Hidden until expanded'); + * console.groupEnd(); + * ``` + */ groupCollapsed(...data: any[]): void; + + /** + * Exits the current inline group in the console + * @example + * ```ts + * console.group('Group'); + * console.log('Grouped message'); + * console.groupEnd(); + * ``` + */ groupEnd(): void; + + /** + * Outputs an informational message to the console + * @param data Values to be printed to the console + * @example + * ```ts + * console.info('Application started', { version: '1.0.0' }); + * ``` + */ info(...data: any[]): void; + + /** + * Outputs a message to the console + * @param data Values to be printed to the console + * @example + * ```ts + * console.log('Hello', 'World', 123); + * ``` + */ log(...data: any[]): void; + + /** + * Displays tabular data as a table + * @param tabularData Data to be displayed in table format + * @param properties Array of property names to be displayed + * @example + * ```ts + * console.table([ + * { name: 'John', age: 30 }, + * { name: 'Jane', age: 25 } + * ]); + * ``` + */ table(tabularData?: any, properties?: string[]): void; + + /** + * Starts a timer you can use to track how long an operation takes + * @param label Timer label. Defaults to 'default' + * @example + * ```ts + * console.time('operation'); + * // ... some code + * console.timeEnd('operation'); + * ``` + */ time(label?: string): void; + + /** + * Stops a timer that was previously started + * @param label Timer label to stop. Defaults to 'default' + * @example + * ```ts + * console.time('operation'); + * // ... some code + * console.timeEnd('operation'); // Prints: operation: 1234ms + * ``` + */ timeEnd(label?: string): void; + + /** + * Logs the current value of a timer that was previously started + * @param label Timer label + * @param data Additional data to log + * @example + * ```ts + * console.time('process'); + * // ... some code + * console.timeLog('process', 'Checkpoint A'); + * ``` + */ timeLog(label?: string, ...data: any[]): void; + + /** + * Outputs a stack trace to the console + * @param data Values to be printed to the console + * @example + * ```ts + * console.trace('Trace message'); + * ``` + */ trace(...data: any[]): void; + + /** + * Outputs a warning message to the console + * @param data Values to be printed to the console + * @example + * ```ts + * console.warn('Deprecated feature used'); + * ``` + */ warn(...data: any[]): void; - /** This method is a noop, unless used in inspector */ + /** + * Adds a marker to the DevTools Performance panel + * @param label Label for the timestamp + * @example + * ```ts + * console.timeStamp('Navigation Start'); + * ``` + */ timeStamp(label?: string): void; - /** This method is a noop, unless used in inspector */ + /** + * Starts recording a performance profile + * @param label Profile label + * @example + * ```ts + * console.profile('Performance Profile'); + * // ... code to profile + * console.profileEnd('Performance Profile'); + * ``` + */ profile(label?: string): void; - /** This method is a noop, unless used in inspector */ + /** + * Stops recording a performance profile + * @param label Profile label to stop + * @example + * ```ts + * console.profile('Performance Profile'); + * // ... code to profile + * console.profileEnd('Performance Profile'); + * ``` + */ profileEnd(label?: string): void; } diff --git a/ext/console/lib.rs b/ext/console/lib.rs index 87fc8327da..48a75329af 100644 --- a/ext/console/lib.rs +++ b/ext/console/lib.rs @@ -1,7 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. +use std::path::PathBuf; + use deno_core::op2; use deno_core::v8; -use std::path::PathBuf; deno_core::extension!( deno_console, diff --git a/ext/cron/01_cron.ts b/ext/cron/01_cron.ts index b5c556a677..db193053d8 100644 --- a/ext/cron/01_cron.ts +++ b/ext/cron/01_cron.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, internals, primordials } from "ext:core/mod.js"; const { diff --git a/ext/cron/Cargo.toml b/ext/cron/Cargo.toml index 022a8418cf..7a5af4fc02 100644 --- a/ext/cron/Cargo.toml +++ b/ext/cron/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_cron" -version = "0.64.0" +version = "0.66.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -18,6 +18,7 @@ anyhow.workspace = true async-trait.workspace = true chrono = { workspace = true, features = ["now"] } deno_core.workspace = true +deno_error.workspace = true saffron.workspace = true thiserror.workspace = true tokio.workspace = true diff --git a/ext/cron/interface.rs b/ext/cron/interface.rs index a19525cc4e..f92d601796 100644 --- a/ext/cron/interface.rs +++ b/ext/cron/interface.rs @@ -1,7 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use async_trait::async_trait; use crate::CronError; -use async_trait::async_trait; pub trait CronHandler { type EH: CronHandle + 'static; diff --git a/ext/cron/lib.rs b/ext/cron/lib.rs index feffb5e511..b4f4938b5e 100644 --- a/ext/cron/lib.rs +++ b/ext/cron/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. mod interface; pub mod local; @@ -7,12 +7,14 @@ use std::borrow::Cow; use std::cell::RefCell; use std::rc::Rc; -pub use crate::interface::*; -use deno_core::error::get_custom_error_class; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; +use deno_error::JsErrorBox; +use deno_error::JsErrorClass; + +pub use crate::interface::*; pub const UNSTABLE_FEATURE_NAME: &str = "cron"; @@ -46,26 +48,35 @@ impl Resource for CronResource { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum CronError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] deno_core::error::ResourceError), + #[class(type)] #[error("Cron name cannot exceed 64 characters: current length {0}")] NameExceeded(usize), + #[class(type)] #[error("Invalid cron name: only alphanumeric characters, whitespace, hyphens, and underscores are allowed")] NameInvalid, + #[class(type)] #[error("Cron with this name already exists")] AlreadyExists, + #[class(type)] #[error("Too many crons")] TooManyCrons, + #[class(type)] #[error("Invalid cron schedule")] InvalidCron, + #[class(type)] #[error("Invalid backoff schedule")] InvalidBackoff, + #[class(generic)] #[error(transparent)] AcquireError(#[from] tokio::sync::AcquireError), + #[class(inherit)] #[error(transparent)] - Other(deno_core::error::AnyError), + Other(JsErrorBox), } #[op2] @@ -118,7 +129,7 @@ where let resource = match state.resource_table.get::>(rid) { Ok(resource) => resource, Err(err) => { - if get_custom_error_class(&err) == Some("BadResource") { + if err.get_class() == "BadResource" { return Ok(false); } else { return Err(CronError::Resource(err)); diff --git a/ext/cron/local.rs b/ext/cron/local.rs index 1110baadb8..d6213a7e36 100644 --- a/ext/cron/local.rs +++ b/ext/cron/local.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::cell::OnceCell; use std::cell::RefCell; diff --git a/ext/crypto/00_crypto.js b/ext/crypto/00_crypto.js index 63b1905145..5a9f32cb00 100644 --- a/ext/crypto/00_crypto.js +++ b/ext/crypto/00_crypto.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/crypto/Cargo.toml b/ext/crypto/Cargo.toml index c283cc9277..b1c0e8a24b 100644 --- a/ext/crypto/Cargo.toml +++ b/ext/crypto/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_crypto" -version = "0.198.0" +version = "0.200.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -23,6 +23,7 @@ const-oid = "0.9.0" ctr = "0.9.1" curve25519-dalek = "4.1.3" deno_core.workspace = true +deno_error.workspace = true deno_web.workspace = true ed448-goldilocks = { version = "0.8.3", features = ["zeroize"] } elliptic-curve = { version = "0.13.1", features = ["std", "pem"] } diff --git a/ext/crypto/decrypt.rs b/ext/crypto/decrypt.rs index 1140475183..766f62d16f 100644 --- a/ext/crypto/decrypt.rs +++ b/ext/crypto/decrypt.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use aes::cipher::block_padding::Pkcs7; use aes::cipher::BlockDecryptMut; @@ -70,26 +70,40 @@ pub enum DecryptAlgorithm { }, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum DecryptError { + #[class(inherit)] #[error(transparent)] - General(#[from] SharedError), + General( + #[from] + #[inherit] + SharedError, + ), + #[class(generic)] #[error(transparent)] Pkcs1(#[from] rsa::pkcs1::Error), + #[class("DOMExceptionOperationError")] #[error("Decryption failed")] Failed, + #[class(type)] #[error("invalid length")] InvalidLength, + #[class(type)] #[error("invalid counter length. Currently supported 32/64/128 bits")] InvalidCounterLength, + #[class(type)] #[error("tag length not equal to 128")] InvalidTagLength, + #[class("DOMExceptionOperationError")] #[error("invalid key or iv")] InvalidKeyOrIv, + #[class("DOMExceptionOperationError")] #[error("tried to decrypt too much data")] TooMuchData, + #[class(type)] #[error("iv length not equal to 12 or 16")] InvalidIvLength, + #[class("DOMExceptionOperationError")] #[error("{0}")] Rsa(rsa::Error), } diff --git a/ext/crypto/ed25519.rs b/ext/crypto/ed25519.rs index da34b7d25d..c56fdc7c62 100644 --- a/ext/crypto/ed25519.rs +++ b/ext/crypto/ed25519.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use base64::prelude::BASE64_URL_SAFE_NO_PAD; use base64::Engine; @@ -13,12 +13,15 @@ use spki::der::asn1::BitString; use spki::der::Decode; use spki::der::Encode; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum Ed25519Error { + #[class("DOMExceptionOperationError")] #[error("Failed to export key")] FailedExport, + #[class(generic)] #[error(transparent)] Der(#[from] rsa::pkcs1::der::Error), + #[class(generic)] #[error(transparent)] KeyRejected(#[from] ring::error::KeyRejected), } diff --git a/ext/crypto/encrypt.rs b/ext/crypto/encrypt.rs index 66b27657f8..d94eb97cfd 100644 --- a/ext/crypto/encrypt.rs +++ b/ext/crypto/encrypt.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use aes::cipher::block_padding::Pkcs7; use aes::cipher::BlockEncryptMut; @@ -71,20 +71,31 @@ pub enum EncryptAlgorithm { }, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum EncryptError { + #[class(inherit)] #[error(transparent)] - General(#[from] SharedError), + General( + #[from] + #[inherit] + SharedError, + ), + #[class(type)] #[error("invalid length")] InvalidLength, + #[class("DOMExceptionOperationError")] #[error("invalid key or iv")] InvalidKeyOrIv, + #[class(type)] #[error("iv length not equal to 12 or 16")] InvalidIvLength, + #[class(type)] #[error("invalid counter length. Currently supported 32/64/128 bits")] InvalidCounterLength, + #[class("DOMExceptionOperationError")] #[error("tried to encrypt too much data")] TooMuchData, + #[class("DOMExceptionOperationError")] #[error("Encryption failed")] Failed, } diff --git a/ext/crypto/export_key.rs b/ext/crypto/export_key.rs index edf0d7239c..c7d59e3cc5 100644 --- a/ext/crypto/export_key.rs +++ b/ext/crypto/export_key.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use base64::prelude::BASE64_URL_SAFE_NO_PAD; use base64::Engine; @@ -20,12 +20,19 @@ use spki::AlgorithmIdentifierOwned; use crate::shared::*; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum ExportKeyError { + #[class(inherit)] #[error(transparent)] - General(#[from] SharedError), + General( + #[from] + #[inherit] + SharedError, + ), + #[class(generic)] #[error(transparent)] Der(#[from] spki::der::Error), + #[class("DOMExceptionNotSupportedError")] #[error("Unsupported named curve")] UnsupportedNamedCurve, } diff --git a/ext/crypto/generate_key.rs b/ext/crypto/generate_key.rs index 3c0bd77c22..211084af17 100644 --- a/ext/crypto/generate_key.rs +++ b/ext/crypto/generate_key.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::op2; use deno_core::unsync::spawn_blocking; @@ -15,10 +15,16 @@ use serde::Deserialize; use crate::shared::*; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class("DOMExceptionOperationError")] pub enum GenerateKeyError { + #[class(inherit)] #[error(transparent)] - General(#[from] SharedError), + General( + #[from] + #[inherit] + SharedError, + ), #[error("Bad public exponent")] BadPublicExponent, #[error("Invalid HMAC key length")] diff --git a/ext/crypto/import_key.rs b/ext/crypto/import_key.rs index 3463ca2beb..e9059bbdc6 100644 --- a/ext/crypto/import_key.rs +++ b/ext/crypto/import_key.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use base64::Engine; use deno_core::op2; @@ -14,10 +14,16 @@ use spki::der::Decode; use crate::shared::*; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class("DOMExceptionDataError")] pub enum ImportKeyError { + #[class(inherit)] #[error(transparent)] - General(#[from] SharedError), + General( + #[from] + #[inherit] + SharedError, + ), #[error("invalid modulus")] InvalidModulus, #[error("invalid public exponent")] diff --git a/ext/crypto/key.rs b/ext/crypto/key.rs index 6b3bf26f43..52a035ef01 100644 --- a/ext/crypto/key.rs +++ b/ext/crypto/key.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use ring::agreement::Algorithm as RingAlgorithm; use ring::digest; diff --git a/ext/crypto/lib.deno_crypto.d.ts b/ext/crypto/lib.deno_crypto.d.ts index 827c0224ce..3f4edb9245 100644 --- a/ext/crypto/lib.deno_crypto.d.ts +++ b/ext/crypto/lib.deno_crypto.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-var diff --git a/ext/crypto/lib.rs b/ext/crypto/lib.rs index 69dcd1413a..0d6eecb911 100644 --- a/ext/crypto/lib.rs +++ b/ext/crypto/lib.rs @@ -1,22 +1,22 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::num::NonZeroU32; +use std::path::PathBuf; use aes_kw::KekAes128; use aes_kw::KekAes192; use aes_kw::KekAes256; - use base64::prelude::BASE64_URL_SAFE_NO_PAD; use base64::Engine; -use deno_core::error::not_supported; use deno_core::op2; -use deno_core::ToJsBuffer; - use deno_core::unsync::spawn_blocking; use deno_core::JsBuffer; use deno_core::OpState; -use serde::Deserialize; - +use deno_core::ToJsBuffer; +use deno_error::JsErrorBox; use p256::elliptic_curve::sec1::FromEncodedPoint; use p256::pkcs8::DecodePrivateKey; +pub use rand; use rand::rngs::OsRng; use rand::rngs::StdRng; use rand::thread_rng; @@ -41,15 +41,12 @@ use rsa::traits::SignatureScheme; use rsa::Pss; use rsa::RsaPrivateKey; use rsa::RsaPublicKey; +use serde::Deserialize; use sha1::Sha1; use sha2::Digest; use sha2::Sha256; use sha2::Sha384; -use sha2::Sha512; -use std::num::NonZeroU32; -use std::path::PathBuf; - -pub use rand; // Re-export rand +use sha2::Sha512; // Re-export rand mod decrypt; mod ed25519; @@ -132,63 +129,99 @@ deno_core::extension!(deno_crypto, }, ); -#[derive(Debug, thiserror::Error)] -pub enum Error { +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum CryptoError { + #[class(inherit)] #[error(transparent)] - General(#[from] SharedError), + General( + #[from] + #[inherit] + SharedError, + ), + #[class(inherit)] #[error(transparent)] - JoinError(#[from] tokio::task::JoinError), + JoinError( + #[from] + #[inherit] + tokio::task::JoinError, + ), + #[class(generic)] #[error(transparent)] Der(#[from] rsa::pkcs1::der::Error), + #[class(type)] #[error("Missing argument hash")] MissingArgumentHash, + #[class(type)] #[error("Missing argument saltLength")] MissingArgumentSaltLength, + #[class(type)] #[error("unsupported algorithm")] UnsupportedAlgorithm, + #[class(generic)] #[error(transparent)] KeyRejected(#[from] ring::error::KeyRejected), + #[class(generic)] #[error(transparent)] RSA(#[from] rsa::Error), + #[class(generic)] #[error(transparent)] Pkcs1(#[from] rsa::pkcs1::Error), + #[class(generic)] #[error(transparent)] Unspecified(#[from] ring::error::Unspecified), + #[class(type)] #[error("Invalid key format")] InvalidKeyFormat, + #[class(generic)] #[error(transparent)] P256Ecdsa(#[from] p256::ecdsa::Error), + #[class(type)] #[error("Unexpected error decoding private key")] DecodePrivateKey, + #[class(type)] #[error("Missing argument publicKey")] MissingArgumentPublicKey, + #[class(type)] #[error("Missing argument namedCurve")] MissingArgumentNamedCurve, + #[class(type)] #[error("Missing argument info")] MissingArgumentInfo, + #[class("DOMExceptionOperationError")] #[error("The length provided for HKDF is too large")] HKDFLengthTooLarge, + #[class(generic)] #[error(transparent)] Base64Decode(#[from] base64::DecodeError), + #[class(type)] #[error("Data must be multiple of 8 bytes")] DataInvalidSize, + #[class(type)] #[error("Invalid key length")] InvalidKeyLength, + #[class("DOMExceptionOperationError")] #[error("encryption error")] EncryptionError, + #[class("DOMExceptionOperationError")] #[error("decryption error - integrity check failed")] DecryptionError, + #[class("DOMExceptionQuotaExceededError")] #[error("The ArrayBufferView's byte length ({0}) exceeds the number of bytes of entropy available via this API (65536)")] ArrayBufferViewLengthExceeded(usize), + #[class(inherit)] #[error(transparent)] - Other(deno_core::error::AnyError), + Other( + #[from] + #[inherit] + JsErrorBox, + ), } #[op2] #[serde] pub fn op_crypto_base64url_decode( #[string] data: String, -) -> Result { +) -> Result { let data: Vec = BASE64_URL_SAFE_NO_PAD.decode(data)?; Ok(data.into()) } @@ -204,9 +237,9 @@ pub fn op_crypto_base64url_encode(#[buffer] data: JsBuffer) -> String { pub fn op_crypto_get_random_values( state: &mut OpState, #[buffer] out: &mut [u8], -) -> Result<(), Error> { +) -> Result<(), CryptoError> { if out.len() > 65536 { - return Err(Error::ArrayBufferViewLengthExceeded(out.len())); + return Err(CryptoError::ArrayBufferViewLengthExceeded(out.len())); } let maybe_seeded_rng = state.try_borrow_mut::(); @@ -258,7 +291,7 @@ pub struct SignArg { pub async fn op_crypto_sign_key( #[serde] args: SignArg, #[buffer] zero_copy: JsBuffer, -) -> Result { +) -> Result { deno_core::unsync::spawn_blocking(move || { let data = &*zero_copy; let algorithm = args.algorithm; @@ -267,7 +300,7 @@ pub async fn op_crypto_sign_key( Algorithm::RsassaPkcs1v15 => { use rsa::pkcs1v15::SigningKey; let private_key = RsaPrivateKey::from_pkcs1_der(&args.key.data)?; - match args.hash.ok_or_else(|| Error::MissingArgumentHash)? { + match args.hash.ok_or_else(|| CryptoError::MissingArgumentHash)? { CryptoHash::Sha1 => { let signing_key = SigningKey::::new(private_key); signing_key.sign(data) @@ -292,11 +325,11 @@ pub async fn op_crypto_sign_key( let salt_len = args .salt_length - .ok_or_else(|| Error::MissingArgumentSaltLength)? + .ok_or_else(|| CryptoError::MissingArgumentSaltLength)? as usize; let mut rng = OsRng; - match args.hash.ok_or_else(|| Error::MissingArgumentHash)? { + match args.hash.ok_or_else(|| CryptoError::MissingArgumentHash)? { CryptoHash::Sha1 => { let signing_key = Pss::new_with_salt::(salt_len); let hashed = Sha1::digest(data); @@ -323,7 +356,7 @@ pub async fn op_crypto_sign_key( Algorithm::Ecdsa => { let curve: &EcdsaSigningAlgorithm = args .named_curve - .ok_or_else(|| Error::Other(not_supported()))? + .ok_or_else(JsErrorBox::not_supported)? .into(); let rng = RingRand::SystemRandom::new(); @@ -333,7 +366,7 @@ pub async fn op_crypto_sign_key( if let Some(hash) = args.hash { match hash { CryptoHash::Sha256 | CryptoHash::Sha384 => (), - _ => return Err(Error::UnsupportedAlgorithm), + _ => return Err(CryptoError::UnsupportedAlgorithm), } }; @@ -343,17 +376,15 @@ pub async fn op_crypto_sign_key( signature.as_ref().to_vec() } Algorithm::Hmac => { - let hash: HmacAlgorithm = args - .hash - .ok_or_else(|| Error::Other(not_supported()))? - .into(); + let hash: HmacAlgorithm = + args.hash.ok_or_else(JsErrorBox::not_supported)?.into(); let key = HmacKey::new(hash, &args.key.data); let signature = ring::hmac::sign(&key, data); signature.as_ref().to_vec() } - _ => return Err(Error::UnsupportedAlgorithm), + _ => return Err(CryptoError::UnsupportedAlgorithm), }; Ok(signature.into()) @@ -376,7 +407,7 @@ pub struct VerifyArg { pub async fn op_crypto_verify_key( #[serde] args: VerifyArg, #[buffer] zero_copy: JsBuffer, -) -> Result { +) -> Result { deno_core::unsync::spawn_blocking(move || { let data = &*zero_copy; let algorithm = args.algorithm; @@ -387,7 +418,7 @@ pub async fn op_crypto_verify_key( use rsa::pkcs1v15::VerifyingKey; let public_key = read_rsa_public_key(args.key)?; let signature: Signature = args.signature.as_ref().try_into()?; - match args.hash.ok_or_else(|| Error::MissingArgumentHash)? { + match args.hash.ok_or_else(|| CryptoError::MissingArgumentHash)? { CryptoHash::Sha1 => { let verifying_key = VerifyingKey::::new(public_key); verifying_key.verify(data, &signature).is_ok() @@ -412,10 +443,10 @@ pub async fn op_crypto_verify_key( let salt_len = args .salt_length - .ok_or_else(|| Error::MissingArgumentSaltLength)? + .ok_or_else(|| CryptoError::MissingArgumentSaltLength)? as usize; - match args.hash.ok_or_else(|| Error::MissingArgumentHash)? { + match args.hash.ok_or_else(|| CryptoError::MissingArgumentHash)? { CryptoHash::Sha1 => { let pss = Pss::new_with_salt::(salt_len); let hashed = Sha1::digest(data); @@ -439,21 +470,19 @@ pub async fn op_crypto_verify_key( } } Algorithm::Hmac => { - let hash: HmacAlgorithm = args - .hash - .ok_or_else(|| Error::Other(not_supported()))? - .into(); + let hash: HmacAlgorithm = + args.hash.ok_or_else(JsErrorBox::not_supported)?.into(); let key = HmacKey::new(hash, &args.key.data); ring::hmac::verify(&key, data, &args.signature).is_ok() } Algorithm::Ecdsa => { let signing_alg: &EcdsaSigningAlgorithm = args .named_curve - .ok_or_else(|| Error::Other(not_supported()))? + .ok_or_else(JsErrorBox::not_supported)? .into(); let verify_alg: &EcdsaVerificationAlgorithm = args .named_curve - .ok_or_else(|| Error::Other(not_supported()))? + .ok_or_else(JsErrorBox::not_supported)? .into(); let private_key; @@ -467,7 +496,7 @@ pub async fn op_crypto_verify_key( private_key.public_key().as_ref() } KeyType::Public => &*args.key.data, - _ => return Err(Error::InvalidKeyFormat), + _ => return Err(CryptoError::InvalidKeyFormat), }; let public_key = @@ -475,7 +504,7 @@ pub async fn op_crypto_verify_key( public_key.verify(data, &args.signature).is_ok() } - _ => return Err(Error::UnsupportedAlgorithm), + _ => return Err(CryptoError::UnsupportedAlgorithm), }; Ok(verification) @@ -503,31 +532,27 @@ pub struct DeriveKeyArg { pub async fn op_crypto_derive_bits( #[serde] args: DeriveKeyArg, #[buffer] zero_copy: Option, -) -> Result { +) -> Result { deno_core::unsync::spawn_blocking(move || { let algorithm = args.algorithm; match algorithm { Algorithm::Pbkdf2 => { - let zero_copy = - zero_copy.ok_or_else(|| Error::Other(not_supported()))?; + let zero_copy = zero_copy.ok_or_else(JsErrorBox::not_supported)?; let salt = &*zero_copy; // The caller must validate these cases. assert!(args.length > 0); assert!(args.length % 8 == 0); - let algorithm = - match args.hash.ok_or_else(|| Error::Other(not_supported()))? { - CryptoHash::Sha1 => pbkdf2::PBKDF2_HMAC_SHA1, - CryptoHash::Sha256 => pbkdf2::PBKDF2_HMAC_SHA256, - CryptoHash::Sha384 => pbkdf2::PBKDF2_HMAC_SHA384, - CryptoHash::Sha512 => pbkdf2::PBKDF2_HMAC_SHA512, - }; + let algorithm = match args.hash.ok_or_else(JsErrorBox::not_supported)? { + CryptoHash::Sha1 => pbkdf2::PBKDF2_HMAC_SHA1, + CryptoHash::Sha256 => pbkdf2::PBKDF2_HMAC_SHA256, + CryptoHash::Sha384 => pbkdf2::PBKDF2_HMAC_SHA384, + CryptoHash::Sha512 => pbkdf2::PBKDF2_HMAC_SHA512, + }; // This will never panic. We have already checked length earlier. let iterations = NonZeroU32::new( - args - .iterations - .ok_or_else(|| Error::Other(not_supported()))?, + args.iterations.ok_or_else(JsErrorBox::not_supported)?, ) .unwrap(); let secret = args.key.data; @@ -538,33 +563,33 @@ pub async fn op_crypto_derive_bits( Algorithm::Ecdh => { let named_curve = args .named_curve - .ok_or_else(|| Error::MissingArgumentNamedCurve)?; + .ok_or_else(|| CryptoError::MissingArgumentNamedCurve)?; let public_key = args .public_key - .ok_or_else(|| Error::MissingArgumentPublicKey)?; + .ok_or_else(|| CryptoError::MissingArgumentPublicKey)?; match named_curve { CryptoNamedCurve::P256 => { let secret_key = p256::SecretKey::from_pkcs8_der(&args.key.data) - .map_err(|_| Error::DecodePrivateKey)?; + .map_err(|_| CryptoError::DecodePrivateKey)?; let public_key = match public_key.r#type { KeyType::Private => { p256::SecretKey::from_pkcs8_der(&public_key.data) - .map_err(|_| Error::DecodePrivateKey)? + .map_err(|_| CryptoError::DecodePrivateKey)? .public_key() } KeyType::Public => { let point = p256::EncodedPoint::from_bytes(public_key.data) - .map_err(|_| Error::DecodePrivateKey)?; + .map_err(|_| CryptoError::DecodePrivateKey)?; let pk = p256::PublicKey::from_encoded_point(&point); // pk is a constant time Option. if pk.is_some().into() { pk.unwrap() } else { - return Err(Error::DecodePrivateKey); + return Err(CryptoError::DecodePrivateKey); } } _ => unreachable!(), @@ -580,24 +605,24 @@ pub async fn op_crypto_derive_bits( } CryptoNamedCurve::P384 => { let secret_key = p384::SecretKey::from_pkcs8_der(&args.key.data) - .map_err(|_| Error::DecodePrivateKey)?; + .map_err(|_| CryptoError::DecodePrivateKey)?; let public_key = match public_key.r#type { KeyType::Private => { p384::SecretKey::from_pkcs8_der(&public_key.data) - .map_err(|_| Error::DecodePrivateKey)? + .map_err(|_| CryptoError::DecodePrivateKey)? .public_key() } KeyType::Public => { let point = p384::EncodedPoint::from_bytes(public_key.data) - .map_err(|_| Error::DecodePrivateKey)?; + .map_err(|_| CryptoError::DecodePrivateKey)?; let pk = p384::PublicKey::from_encoded_point(&point); // pk is a constant time Option. if pk.is_some().into() { pk.unwrap() } else { - return Err(Error::DecodePrivateKey); + return Err(CryptoError::DecodePrivateKey); } } _ => unreachable!(), @@ -614,18 +639,16 @@ pub async fn op_crypto_derive_bits( } } Algorithm::Hkdf => { - let zero_copy = - zero_copy.ok_or_else(|| Error::Other(not_supported()))?; + let zero_copy = zero_copy.ok_or_else(JsErrorBox::not_supported)?; let salt = &*zero_copy; - let algorithm = - match args.hash.ok_or_else(|| Error::Other(not_supported()))? { - CryptoHash::Sha1 => hkdf::HKDF_SHA1_FOR_LEGACY_USE_ONLY, - CryptoHash::Sha256 => hkdf::HKDF_SHA256, - CryptoHash::Sha384 => hkdf::HKDF_SHA384, - CryptoHash::Sha512 => hkdf::HKDF_SHA512, - }; + let algorithm = match args.hash.ok_or_else(JsErrorBox::not_supported)? { + CryptoHash::Sha1 => hkdf::HKDF_SHA1_FOR_LEGACY_USE_ONLY, + CryptoHash::Sha256 => hkdf::HKDF_SHA256, + CryptoHash::Sha384 => hkdf::HKDF_SHA384, + CryptoHash::Sha512 => hkdf::HKDF_SHA512, + }; - let info = args.info.ok_or_else(|| Error::MissingArgumentInfo)?; + let info = args.info.ok_or(CryptoError::MissingArgumentInfo)?; // IKM let secret = args.key.data; // L @@ -636,18 +659,18 @@ pub async fn op_crypto_derive_bits( let info = &[&*info]; let okm = prk .expand(info, HkdfOutput(length)) - .map_err(|_e| Error::HKDFLengthTooLarge)?; + .map_err(|_e| CryptoError::HKDFLengthTooLarge)?; let mut r = vec![0u8; length]; okm.fill(&mut r)?; Ok(r.into()) } - _ => Err(Error::UnsupportedAlgorithm), + _ => Err(CryptoError::UnsupportedAlgorithm), } }) .await? } -fn read_rsa_public_key(key_data: KeyData) -> Result { +fn read_rsa_public_key(key_data: KeyData) -> Result { let public_key = match key_data.r#type { KeyType::Private => { RsaPrivateKey::from_pkcs1_der(&key_data.data)?.to_public_key() @@ -660,7 +683,9 @@ fn read_rsa_public_key(key_data: KeyData) -> Result { #[op2] #[string] -pub fn op_crypto_random_uuid(state: &mut OpState) -> Result { +pub fn op_crypto_random_uuid( + state: &mut OpState, +) -> Result { let maybe_seeded_rng = state.try_borrow_mut::(); let uuid = if let Some(seeded_rng) = maybe_seeded_rng { let mut bytes = [0u8; 16]; @@ -681,7 +706,7 @@ pub fn op_crypto_random_uuid(state: &mut OpState) -> Result { pub async fn op_crypto_subtle_digest( #[serde] algorithm: CryptoHash, #[buffer] data: JsBuffer, -) -> Result { +) -> Result { let output = spawn_blocking(move || { digest::digest(algorithm.into(), &data) .as_ref() @@ -705,7 +730,7 @@ pub struct WrapUnwrapKeyArg { pub fn op_crypto_wrap_key( #[serde] args: WrapUnwrapKeyArg, #[buffer] data: JsBuffer, -) -> Result { +) -> Result { let algorithm = args.algorithm; match algorithm { @@ -713,20 +738,20 @@ pub fn op_crypto_wrap_key( let key = args.key.as_secret_key()?; if data.len() % 8 != 0 { - return Err(Error::DataInvalidSize); + return Err(CryptoError::DataInvalidSize); } let wrapped_key = match key.len() { 16 => KekAes128::new(key.into()).wrap_vec(&data), 24 => KekAes192::new(key.into()).wrap_vec(&data), 32 => KekAes256::new(key.into()).wrap_vec(&data), - _ => return Err(Error::InvalidKeyLength), + _ => return Err(CryptoError::InvalidKeyLength), } - .map_err(|_| Error::EncryptionError)?; + .map_err(|_| CryptoError::EncryptionError)?; Ok(wrapped_key.into()) } - _ => Err(Error::UnsupportedAlgorithm), + _ => Err(CryptoError::UnsupportedAlgorithm), } } @@ -735,27 +760,27 @@ pub fn op_crypto_wrap_key( pub fn op_crypto_unwrap_key( #[serde] args: WrapUnwrapKeyArg, #[buffer] data: JsBuffer, -) -> Result { +) -> Result { let algorithm = args.algorithm; match algorithm { Algorithm::AesKw => { let key = args.key.as_secret_key()?; if data.len() % 8 != 0 { - return Err(Error::DataInvalidSize); + return Err(CryptoError::DataInvalidSize); } let unwrapped_key = match key.len() { 16 => KekAes128::new(key.into()).unwrap_vec(&data), 24 => KekAes192::new(key.into()).unwrap_vec(&data), 32 => KekAes256::new(key.into()).unwrap_vec(&data), - _ => return Err(Error::InvalidKeyLength), + _ => return Err(CryptoError::InvalidKeyLength), } - .map_err(|_| Error::DecryptionError)?; + .map_err(|_| CryptoError::DecryptionError)?; Ok(unwrapped_key.into()) } - _ => Err(Error::UnsupportedAlgorithm), + _ => Err(CryptoError::UnsupportedAlgorithm), } } diff --git a/ext/crypto/shared.rs b/ext/crypto/shared.rs index f70d32856c..1c28e0b87d 100644 --- a/ext/crypto/shared.rs +++ b/ext/crypto/shared.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; @@ -60,26 +60,36 @@ pub enum RustRawKeyData { Public(ToJsBuffer), } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum SharedError { + #[class(type)] #[error("expected valid private key")] ExpectedValidPrivateKey, + #[class(type)] #[error("expected valid public key")] ExpectedValidPublicKey, + #[class(type)] #[error("expected valid private EC key")] ExpectedValidPrivateECKey, + #[class(type)] #[error("expected valid public EC key")] ExpectedValidPublicECKey, + #[class(type)] #[error("expected private key")] ExpectedPrivateKey, + #[class(type)] #[error("expected public key")] ExpectedPublicKey, + #[class(type)] #[error("expected secret key")] ExpectedSecretKey, + #[class("DOMExceptionOperationError")] #[error("failed to decode private key")] FailedDecodePrivateKey, + #[class("DOMExceptionOperationError")] #[error("failed to decode public key")] FailedDecodePublicKey, + #[class("DOMExceptionNotSupportedError")] #[error("unsupported format")] UnsupportedFormat, } diff --git a/ext/crypto/x25519.rs b/ext/crypto/x25519.rs index d2c4d986b9..226ed89e40 100644 --- a/ext/crypto/x25519.rs +++ b/ext/crypto/x25519.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use curve25519_dalek::montgomery::MontgomeryPoint; use deno_core::op2; @@ -11,10 +11,12 @@ use spki::der::asn1::BitString; use spki::der::Decode; use spki::der::Encode; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum X25519Error { + #[class("DOMExceptionOperationError")] #[error("Failed to export key")] FailedExport, + #[class(generic)] #[error(transparent)] Der(#[from] spki::der::Error), } diff --git a/ext/crypto/x448.rs b/ext/crypto/x448.rs index 89bf48e28b..2086a8f048 100644 --- a/ext/crypto/x448.rs +++ b/ext/crypto/x448.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::op2; use deno_core::ToJsBuffer; @@ -12,10 +12,12 @@ use spki::der::asn1::BitString; use spki::der::Decode; use spki::der::Encode; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum X448Error { + #[class("DOMExceptionOperationError")] #[error("Failed to export key")] FailedExport, + #[class(generic)] #[error(transparent)] Der(#[from] spki::der::Error), } diff --git a/ext/fetch/20_headers.js b/ext/fetch/20_headers.js index e56a74c423..fb97adb13b 100644 --- a/ext/fetch/20_headers.js +++ b/ext/fetch/20_headers.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/fetch/21_formdata.js b/ext/fetch/21_formdata.js index 7d466b8e25..8b91a0fa47 100644 --- a/ext/fetch/21_formdata.js +++ b/ext/fetch/21_formdata.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/fetch/22_body.js b/ext/fetch/22_body.js index bb2bee77e2..f180bda18d 100644 --- a/ext/fetch/22_body.js +++ b/ext/fetch/22_body.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/fetch/22_http_client.js b/ext/fetch/22_http_client.js index 6a1243ee0b..b74979c4c6 100644 --- a/ext/fetch/22_http_client.js +++ b/ext/fetch/22_http_client.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/fetch/23_request.js b/ext/fetch/23_request.js index 61cac22d2e..9aa2f0fe5c 100644 --- a/ext/fetch/23_request.js +++ b/ext/fetch/23_request.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/fetch/23_response.js b/ext/fetch/23_response.js index 278dcb7dec..0a86e04310 100644 --- a/ext/fetch/23_response.js +++ b/ext/fetch/23_response.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/fetch/26_fetch.js b/ext/fetch/26_fetch.js index 12b9c4582b..7d5f5ea2f7 100644 --- a/ext/fetch/26_fetch.js +++ b/ext/fetch/26_fetch.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// @@ -59,10 +59,9 @@ import { } from "ext:deno_fetch/23_response.js"; import * as abortSignal from "ext:deno_web/03_abort_signal.js"; import { - endSpan, + builtinTracer, enterSpan, - exitSpan, - Span, + restoreContext, TRACING_ENABLED, } from "ext:deno_telemetry/telemetry.ts"; import { @@ -320,10 +319,10 @@ function httpRedirectFetch(request, response, terminator) { // Drop confidential headers when redirecting to a less secure protocol // or to a different domain that is not a superdomain if ( - locationURL.protocol !== currentURL.protocol && - locationURL.protocol !== "https:" || - locationURL.host !== currentURL.host && - !isSubdomain(locationURL.host, currentURL.host) + (locationURL.protocol !== currentURL.protocol && + locationURL.protocol !== "https:") || + (locationURL.host !== currentURL.host && + !isSubdomain(locationURL.host, currentURL.host)) ) { for (let i = 0; i < request.headerList.length; i++) { if ( @@ -352,10 +351,11 @@ function httpRedirectFetch(request, response, terminator) { */ function fetch(input, init = { __proto__: null }) { let span; + let context; try { if (TRACING_ENABLED) { - span = new Span("fetch", { kind: 2 }); - enterSpan(span); + span = builtinTracer().startSpan("fetch", { kind: 2 }); + context = enterSpan(span); } // There is an async dispatch later that causes a stack trace disconnect. @@ -454,9 +454,7 @@ function fetch(input, init = { __proto__: null }) { await opPromise; return result; } finally { - if (span) { - endSpan(span); - } + span?.end(); } })(); } @@ -469,19 +467,17 @@ function fetch(input, init = { __proto__: null }) { // XXX: This should always be true, otherwise `opPromise` would be present. if (op_fetch_promise_is_settled(result)) { // It's already settled. - endSpan(span); + span?.end(); } else { // Not settled yet, we can return a new wrapper promise. return SafePromisePrototypeFinally(result, () => { - endSpan(span); + span?.end(); }); } } return result; } finally { - if (span) { - exitSpan(span); - } + if (context) restoreContext(context); } } @@ -508,8 +504,11 @@ function abortFetch(request, responseObject, error) { */ function isSubdomain(subdomain, domain) { const dot = subdomain.length - domain.length - 1; - return dot > 0 && subdomain[dot] === "." && - StringPrototypeEndsWith(subdomain, domain); + return ( + dot > 0 && + subdomain[dot] === "." && + StringPrototypeEndsWith(subdomain, domain) + ); } /** diff --git a/ext/fetch/27_eventsource.js b/ext/fetch/27_eventsource.js index aadbb5fe71..99ea4073a5 100644 --- a/ext/fetch/27_eventsource.js +++ b/ext/fetch/27_eventsource.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// diff --git a/ext/fetch/Cargo.toml b/ext/fetch/Cargo.toml index e6e4ded4af..0b98358104 100644 --- a/ext/fetch/Cargo.toml +++ b/ext/fetch/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_fetch" -version = "0.208.0" +version = "0.210.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -18,6 +18,7 @@ base64.workspace = true bytes.workspace = true data-url.workspace = true deno_core.workspace = true +deno_error.workspace = true deno_path_util.workspace = true deno_permissions.workspace = true deno_tls.workspace = true diff --git a/ext/fetch/dns.rs b/ext/fetch/dns.rs index fdde4e17bb..e233021400 100644 --- a/ext/fetch/dns.rs +++ b/ext/fetch/dns.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::future::Future; use std::io; use std::net::SocketAddr; diff --git a/ext/fetch/fs_fetch_handler.rs b/ext/fetch/fs_fetch_handler.rs index c236dd9c67..8761eb2d65 100644 --- a/ext/fetch/fs_fetch_handler.rs +++ b/ext/fetch/fs_fetch_handler.rs @@ -1,8 +1,6 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::CancelHandle; -use crate::CancelableResponseFuture; -use crate::FetchHandler; +use std::rc::Rc; use deno_core::futures::FutureExt; use deno_core::futures::TryFutureExt; @@ -10,11 +8,15 @@ use deno_core::futures::TryStreamExt; use deno_core::url::Url; use deno_core::CancelFuture; use deno_core::OpState; +use deno_error::JsErrorBox; use http::StatusCode; use http_body_util::BodyExt; -use std::rc::Rc; use tokio_util::io::ReaderStream; +use crate::CancelHandle; +use crate::CancelableResponseFuture; +use crate::FetchHandler; + /// An implementation which tries to read file URLs from the file system via /// tokio::fs. #[derive(Clone)] @@ -33,7 +35,7 @@ impl FetchHandler for FsFetchHandler { let file = tokio::fs::File::open(path).map_err(|_| ()).await?; let stream = ReaderStream::new(file) .map_ok(hyper::body::Frame::data) - .map_err(Into::into); + .map_err(JsErrorBox::from_err); let body = http_body_util::StreamBody::new(stream).boxed(); let response = http::Response::builder() .status(StatusCode::OK) diff --git a/ext/fetch/internal.d.ts b/ext/fetch/internal.d.ts index 17565992f4..8ab38f9b62 100644 --- a/ext/fetch/internal.d.ts +++ b/ext/fetch/internal.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-explicit-any no-var diff --git a/ext/fetch/lib.deno_fetch.d.ts b/ext/fetch/lib.deno_fetch.d.ts index 8614dec899..2be844f0f8 100644 --- a/ext/fetch/lib.deno_fetch.d.ts +++ b/ext/fetch/lib.deno_fetch.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-explicit-any no-var diff --git a/ext/fetch/lib.rs b/ext/fetch/lib.rs index 103698b3bf..5af68695ef 100644 --- a/ext/fetch/lib.rs +++ b/ext/fetch/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. pub mod dns; mod fs_fetch_handler; @@ -19,6 +19,10 @@ use std::sync::Arc; use std::task::Context; use std::task::Poll; +use bytes::Bytes; +// Re-export data_url +pub use data_url; +use data_url::DataUrl; use deno_core::futures::stream::Peekable; use deno_core::futures::Future; use deno_core::futures::FutureExt; @@ -42,6 +46,7 @@ use deno_core::OpState; use deno_core::RcRef; use deno_core::Resource; use deno_core::ResourceId; +use deno_error::JsErrorBox; use deno_path_util::url_from_file_path; use deno_path_util::PathToUrlError; use deno_permissions::PermissionCheckError; @@ -51,9 +56,7 @@ use deno_tls::RootCertStoreProvider; use deno_tls::TlsKey; use deno_tls::TlsKeys; use deno_tls::TlsKeysHolder; - -use bytes::Bytes; -use data_url::DataUrl; +pub use fs_fetch_handler::FsFetchHandler; use http::header::HeaderName; use http::header::HeaderValue; use http::header::ACCEPT; @@ -75,18 +78,13 @@ use hyper_util::client::legacy::connect::HttpInfo; use hyper_util::client::legacy::Builder as HyperClientBuilder; use hyper_util::rt::TokioExecutor; use hyper_util::rt::TokioTimer; +pub use proxy::basic_auth; use serde::Deserialize; use serde::Serialize; use tower::retry; use tower::ServiceExt; use tower_http::decompression::Decompression; -// Re-export data_url -pub use data_url; -pub use proxy::basic_auth; - -pub use fs_fetch_handler::FsFetchHandler; - #[derive(Clone)] pub struct Options { pub user_agent: String, @@ -103,9 +101,8 @@ pub struct Options { /// For more info on what can be configured, see [`hyper_util::client::legacy::Builder`]. pub client_builder_hook: Option HyperClientBuilder>, #[allow(clippy::type_complexity)] - pub request_builder_hook: Option< - fn(&mut http::Request) -> Result<(), deno_core::error::AnyError>, - >, + pub request_builder_hook: + Option) -> Result<(), JsErrorBox>>, pub unsafely_ignore_certificate_errors: Option>, pub client_cert_chain_and_key: TlsKeys, pub file_fetch_handler: Rc, @@ -113,9 +110,7 @@ pub struct Options { } impl Options { - pub fn root_cert_store( - &self, - ) -> Result, deno_core::error::AnyError> { + pub fn root_cert_store(&self) -> Result, JsErrorBox> { Ok(match &self.root_cert_store_provider { Some(provider) => Some(provider.get_or_try_init()?.clone()), None => None, @@ -167,48 +162,71 @@ deno_core::extension!(deno_fetch, }, ); -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum FetchError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] deno_core::error::ResourceError), + #[class(inherit)] #[error(transparent)] Permission(#[from] PermissionCheckError), + #[class(type)] #[error("NetworkError when attempting to fetch resource")] NetworkError, + #[class(type)] #[error("Fetching files only supports the GET method: received {0}")] FsNotGet(Method), + #[class(inherit)] #[error(transparent)] PathToUrl(#[from] PathToUrlError), + #[class(type)] #[error("Invalid URL {0}")] InvalidUrl(Url), + #[class(type)] #[error(transparent)] InvalidHeaderName(#[from] http::header::InvalidHeaderName), + #[class(type)] #[error(transparent)] InvalidHeaderValue(#[from] http::header::InvalidHeaderValue), + #[class(type)] #[error("{0:?}")] DataUrl(data_url::DataUrlError), + #[class(type)] #[error("{0:?}")] Base64(data_url::forgiving_base64::InvalidBase64), + #[class(type)] #[error("Blob for the given URL not found.")] BlobNotFound, + #[class(type)] #[error("Url scheme '{0}' not supported")] SchemeNotSupported(String), + #[class(type)] #[error("Request was cancelled")] RequestCanceled, + #[class(generic)] #[error(transparent)] Http(#[from] http::Error), + #[class(inherit)] #[error(transparent)] ClientCreate(#[from] HttpClientCreateError), + #[class(inherit)] #[error(transparent)] Url(#[from] url::ParseError), + #[class(type)] #[error(transparent)] Method(#[from] http::method::InvalidMethod), + #[class(inherit)] #[error(transparent)] ClientSend(#[from] ClientSendError), + #[class(inherit)] #[error(transparent)] - RequestBuilderHook(deno_core::error::AnyError), + RequestBuilderHook(JsErrorBox), + #[class(inherit)] #[error(transparent)] Io(#[from] std::io::Error), + #[class(generic)] + #[error(transparent)] + Dns(hickory_resolver::ResolveError), } pub type CancelableResponseFuture = @@ -297,9 +315,7 @@ pub fn create_client_from_options( #[allow(clippy::type_complexity)] pub struct ResourceToBodyAdapter( Rc, - Option< - Pin>>>, - >, + Option>>>>, ); impl ResourceToBodyAdapter { @@ -315,7 +331,7 @@ unsafe impl Send for ResourceToBodyAdapter {} unsafe impl Sync for ResourceToBodyAdapter {} impl Stream for ResourceToBodyAdapter { - type Item = Result; + type Item = Result; fn poll_next( self: Pin<&mut Self>, @@ -345,7 +361,7 @@ impl Stream for ResourceToBodyAdapter { impl hyper::body::Body for ResourceToBodyAdapter { type Data = Bytes; - type Error = deno_core::error::AnyError; + type Error = JsErrorBox; fn poll_frame( self: Pin<&mut Self>, @@ -420,10 +436,7 @@ where FP: FetchPermissions + 'static, { let (client, allow_host) = if let Some(rid) = client_rid { - let r = state - .resource_table - .get::(rid) - .map_err(FetchError::Resource)?; + let r = state.resource_table.get::(rid)?; (r.client.clone(), r.allow_host) } else { (get_or_create_client_from_state(state)?, false) @@ -482,10 +495,7 @@ where ReqBody::full(data.to_vec().into()) } (_, Some(resource)) => { - let resource = state - .resource_table - .take_any(resource) - .map_err(FetchError::Resource)?; + let resource = state.resource_table.take_any(resource)?; match resource.size_hint() { (body_size, Some(n)) if body_size == n && body_size > 0 => { con_len = Some(body_size); @@ -627,8 +637,7 @@ pub async fn op_fetch_send( let request = state .borrow_mut() .resource_table - .take::(rid) - .map_err(FetchError::Resource)?; + .take::(rid)?; let request = Rc::try_unwrap(request) .ok() @@ -807,9 +816,7 @@ impl Resource for FetchResponseResource { // safely call `await` on it without creating a race condition. Some(_) => match reader.as_mut().next().await.unwrap() { Ok(chunk) => assert!(chunk.is_empty()), - Err(err) => { - break Err(deno_core::error::type_error(err.to_string())) - } + Err(err) => break Err(JsErrorBox::type_error(err.to_string())), }, None => break Ok(BufView::empty()), } @@ -817,7 +824,10 @@ impl Resource for FetchResponseResource { }; let cancel_handle = RcRef::map(self, |r| &r.cancel); - fut.try_or_cancel(cancel_handle).await + fut + .try_or_cancel(cancel_handle) + .await + .map_err(JsErrorBox::from_err) }) } @@ -900,9 +910,7 @@ where ca_certs, proxy: args.proxy, dns_resolver: if args.use_hickory_resolver { - dns::Resolver::hickory() - .map_err(deno_core::error::AnyError::new) - .map_err(FetchError::Resource)? + dns::Resolver::hickory().map_err(FetchError::Dns)? } else { dns::Resolver::default() }, @@ -966,7 +974,8 @@ impl Default for CreateHttpClientOptions { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(type)] pub enum HttpClientCreateError { #[error(transparent)] Tls(deno_tls::TlsError), @@ -976,8 +985,9 @@ pub enum HttpClientCreateError { InvalidProxyUrl, #[error("Cannot create Http Client: either `http1` or `http2` needs to be set to true")] HttpVersionSelectionInvalid, + #[class(inherit)] #[error(transparent)] - RootCertStore(deno_core::error::AnyError), + RootCertStore(JsErrorBox), } /// Create new instance of async Client. This client supports @@ -1100,7 +1110,8 @@ type Connector = proxy::ProxyConnector>; #[allow(clippy::declare_interior_mutable_const)] const STAR_STAR: HeaderValue = HeaderValue::from_static("*/*"); -#[derive(Debug)] +#[derive(Debug, deno_error::JsError)] +#[class(type)] pub struct ClientSendError { uri: Uri, pub source: hyper_util::client::legacy::Error, @@ -1175,7 +1186,7 @@ impl Client { .oneshot(req) .await .map_err(|e| ClientSendError { uri, source: e })?; - Ok(resp.map(|b| b.map_err(|e| deno_core::anyhow::anyhow!(e)).boxed())) + Ok(resp.map(|b| b.map_err(|e| JsErrorBox::generic(e.to_string())).boxed())) } } @@ -1183,10 +1194,10 @@ impl Client { pub enum ReqBody { Full(http_body_util::Full), Empty(http_body_util::Empty), - Streaming(BoxBody), + Streaming(BoxBody), } -pub type ResBody = BoxBody; +pub type ResBody = BoxBody; impl ReqBody { pub fn full(bytes: Bytes) -> Self { @@ -1199,7 +1210,7 @@ impl ReqBody { pub fn streaming(body: B) -> Self where - B: hyper::body::Body + B: hyper::body::Body + Send + Sync + 'static, @@ -1210,7 +1221,7 @@ impl ReqBody { impl hyper::body::Body for ReqBody { type Data = Bytes; - type Error = deno_core::error::AnyError; + type Error = JsErrorBox; fn poll_frame( mut self: Pin<&mut Self>, diff --git a/ext/fetch/proxy.rs b/ext/fetch/proxy.rs index 88fc211ecc..3b371a07b1 100644 --- a/ext/fetch/proxy.rs +++ b/ext/fetch/proxy.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. //! Parts of this module should be able to be replaced with other crates //! eventually, once generic versions appear in hyper-util, et al. @@ -13,7 +13,6 @@ use std::task::Poll; use deno_core::futures::TryFutureExt; use deno_tls::rustls::ClientConfig as TlsConfig; - use http::header::HeaderValue; use http::uri::Scheme; use http::Uri; @@ -108,9 +107,10 @@ pub(crate) fn from_env() -> Proxies { } pub fn basic_auth(user: &str, pass: Option<&str>) -> HeaderValue { + use std::io::Write; + use base64::prelude::BASE64_STANDARD; use base64::write::EncoderWriter; - use std::io::Write; let mut buf = b"Basic ".to_vec(); { diff --git a/ext/fetch/tests.rs b/ext/fetch/tests.rs index 243b80bd90..4e023be4fa 100644 --- a/ext/fetch/tests.rs +++ b/ext/fetch/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::net::SocketAddr; use std::sync::atomic::AtomicUsize; @@ -12,10 +12,9 @@ use http_body_util::BodyExt; use tokio::io::AsyncReadExt; use tokio::io::AsyncWriteExt; -use crate::dns; - use super::create_http_client; use super::CreateHttpClientOptions; +use crate::dns; static EXAMPLE_CRT: &[u8] = include_bytes!("../tls/testdata/example1_cert.der"); static EXAMPLE_KEY: &[u8] = diff --git a/ext/ffi/00_ffi.js b/ext/ffi/00_ffi.js index d3b07dc373..b8c12180c9 100644 --- a/ext/ffi/00_ffi.js +++ b/ext/ffi/00_ffi.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, primordials } from "ext:core/mod.js"; const { diff --git a/ext/ffi/Cargo.toml b/ext/ffi/Cargo.toml index 9cd5c77013..f41ee2d644 100644 --- a/ext/ffi/Cargo.toml +++ b/ext/ffi/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_ffi" -version = "0.171.0" +version = "0.173.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -15,6 +15,7 @@ path = "lib.rs" [dependencies] deno_core.workspace = true +deno_error.workspace = true deno_permissions.workspace = true dlopen2.workspace = true dynasmrt = "1.2.3" diff --git a/ext/ffi/call.rs b/ext/ffi/call.rs index c964071a09..4f9a057d01 100644 --- a/ext/ffi/call.rs +++ b/ext/ffi/call.rs @@ -1,12 +1,10 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::cell::RefCell; +use std::ffi::c_void; +use std::future::Future; +use std::rc::Rc; -use crate::callback::PtrSymbol; -use crate::dlfcn::DynamicLibraryResource; -use crate::ir::*; -use crate::symbol::NativeType; -use crate::symbol::Symbol; -use crate::FfiPermissions; -use crate::ForeignFunction; use deno_core::op2; use deno_core::serde_json::Value; use deno_core::serde_v8::BigInt as V8BigInt; @@ -18,23 +16,33 @@ use deno_core::ResourceId; use libffi::middle::Arg; use num_bigint::BigInt; use serde::Serialize; -use std::cell::RefCell; -use std::ffi::c_void; -use std::future::Future; -use std::rc::Rc; -#[derive(Debug, thiserror::Error)] +use crate::callback::PtrSymbol; +use crate::dlfcn::DynamicLibraryResource; +use crate::ir::*; +use crate::symbol::NativeType; +use crate::symbol::Symbol; +use crate::FfiPermissions; +use crate::ForeignFunction; + +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum CallError { + #[class(type)] #[error(transparent)] IR(#[from] IRError), + #[class(generic)] #[error("Nonblocking FFI call failed: {0}")] NonblockingCallFailure(#[source] tokio::task::JoinError), + #[class(type)] #[error("Invalid FFI symbol name: '{0}'")] InvalidSymbol(String), + #[class(inherit)] #[error(transparent)] Permission(#[from] deno_permissions::PermissionCheckError), + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] deno_core::error::ResourceError), + #[class(inherit)] #[error(transparent)] Callback(#[from] super::CallbackError), } @@ -344,10 +352,7 @@ pub fn op_ffi_call_nonblocking( ) -> Result>, CallError> { let symbol = { let state = state.borrow(); - let resource = state - .resource_table - .get::(rid) - .map_err(CallError::Resource)?; + let resource = state.resource_table.get::(rid)?; let symbols = &resource.symbols; *symbols .get(&symbol) diff --git a/ext/ffi/callback.rs b/ext/ffi/callback.rs index eff14503d1..a6c104ef42 100644 --- a/ext/ffi/callback.rs +++ b/ext/ffi/callback.rs @@ -1,19 +1,5 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::symbol::NativeType; -use crate::FfiPermissions; -use crate::ForeignFunction; -use deno_core::op2; -use deno_core::v8; -use deno_core::v8::TryCatch; -use deno_core::CancelFuture; -use deno_core::CancelHandle; -use deno_core::OpState; -use deno_core::Resource; -use deno_core::ResourceId; -use deno_core::V8CrossThreadTaskSpawner; -use libffi::middle::Cif; -use serde::Deserialize; use std::borrow::Cow; use std::cell::RefCell; use std::ffi::c_void; @@ -27,20 +13,39 @@ use std::sync::atomic; use std::sync::atomic::AtomicU32; use std::task::Poll; +use deno_core::op2; +use deno_core::v8; +use deno_core::v8::TryCatch; +use deno_core::CancelFuture; +use deno_core::CancelHandle; +use deno_core::OpState; +use deno_core::Resource; +use deno_core::ResourceId; +use deno_core::V8CrossThreadTaskSpawner; +use libffi::middle::Cif; +use serde::Deserialize; + +use crate::symbol::NativeType; +use crate::FfiPermissions; +use crate::ForeignFunction; + static THREAD_ID_COUNTER: AtomicU32 = AtomicU32::new(1); thread_local! { static LOCAL_THREAD_ID: RefCell = const { RefCell::new(0) }; } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum CallbackError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] deno_core::error::ResourceError), + #[class(inherit)] #[error(transparent)] Permission(#[from] deno_permissions::PermissionCheckError), + #[class(inherit)] #[error(transparent)] - Other(deno_core::error::AnyError), + Other(#[from] deno_error::JsErrorBox), } #[derive(Clone)] @@ -61,13 +66,8 @@ impl PtrSymbol { .clone() .into_iter() .map(libffi::middle::Type::try_from) - .collect::, _>>() - .map_err(CallbackError::Other)?, - def - .result - .clone() - .try_into() - .map_err(CallbackError::Other)?, + .collect::, _>>()?, + def.result.clone().try_into()?, ); Ok(Self { cif, ptr }) @@ -538,10 +538,8 @@ pub fn op_ffi_unsafe_callback_ref( #[smi] rid: ResourceId, ) -> Result, CallbackError> { let state = state.borrow(); - let callback_resource = state - .resource_table - .get::(rid) - .map_err(CallbackError::Resource)?; + let callback_resource = + state.resource_table.get::(rid)?; Ok(async move { let info: &mut CallbackInfo = @@ -608,10 +606,8 @@ where .parameters .into_iter() .map(libffi::middle::Type::try_from) - .collect::, _>>() - .map_err(CallbackError::Other)?, - libffi::middle::Type::try_from(args.result) - .map_err(CallbackError::Other)?, + .collect::, _>>()?, + libffi::middle::Type::try_from(args.result)?, ); // SAFETY: CallbackInfo is leaked, is not null and stays valid as long as the callback exists. @@ -647,10 +643,8 @@ pub fn op_ffi_unsafe_callback_close( // It is up to the user to know that it is safe to call the `close()` on the // UnsafeCallback instance. unsafe { - let callback_resource = state - .resource_table - .take::(rid) - .map_err(CallbackError::Resource)?; + let callback_resource = + state.resource_table.take::(rid)?; let info = Box::from_raw(callback_resource.info); let _ = v8::Global::from_raw(scope, info.callback); let _ = v8::Global::from_raw(scope, info.context); diff --git a/ext/ffi/dlfcn.rs b/ext/ffi/dlfcn.rs index e1bb121d8c..da5a85e7e3 100644 --- a/ext/ffi/dlfcn.rs +++ b/ext/ffi/dlfcn.rs @@ -1,4 +1,21 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::borrow::Cow; +use std::cell::RefCell; +use std::collections::HashMap; +use std::ffi::c_void; +use std::rc::Rc; + +use deno_core::op2; +use deno_core::v8; +use deno_core::GarbageCollected; +use deno_core::OpState; +use deno_core::Resource; +use deno_error::JsErrorBox; +use deno_error::JsErrorClass; +use dlopen2::raw::Library; +use serde::Deserialize; +use serde_value::ValueDeserializer; use crate::ir::out_buffer_as_ptr; use crate::symbol::NativeType; @@ -6,34 +23,35 @@ use crate::symbol::Symbol; use crate::turbocall; use crate::turbocall::Turbocall; use crate::FfiPermissions; -use deno_core::op2; -use deno_core::v8; -use deno_core::GarbageCollected; -use deno_core::OpState; -use deno_core::Resource; -use dlopen2::raw::Library; -use serde::Deserialize; -use serde_value::ValueDeserializer; -use std::borrow::Cow; -use std::cell::RefCell; -use std::collections::HashMap; -use std::ffi::c_void; -use std::rc::Rc; -#[derive(Debug, thiserror::Error)] +deno_error::js_error_wrapper!(dlopen2::Error, JsDlopen2Error, |err| { + match err { + dlopen2::Error::NullCharacter(_) => "InvalidData".into(), + dlopen2::Error::OpeningLibraryError(e) => e.get_class(), + dlopen2::Error::SymbolGettingError(e) => e.get_class(), + dlopen2::Error::AddrNotMatchingDll(e) => e.get_class(), + dlopen2::Error::NullSymbol => "NotFound".into(), + } +}); + +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum DlfcnError { + #[class(generic)] #[error("Failed to register symbol {symbol}: {error}")] RegisterSymbol { symbol: String, #[source] error: dlopen2::Error, }, + #[class(generic)] #[error(transparent)] Dlopen(#[from] dlopen2::Error), + #[class(inherit)] #[error(transparent)] Permission(#[from] deno_permissions::PermissionCheckError), + #[class(inherit)] #[error(transparent)] - Other(deno_core::error::AnyError), + Other(#[from] JsErrorBox), } pub struct DynamicLibraryResource { @@ -188,13 +206,8 @@ where .clone() .into_iter() .map(libffi::middle::Type::try_from) - .collect::, _>>() - .map_err(DlfcnError::Other)?, - foreign_fn - .result - .clone() - .try_into() - .map_err(DlfcnError::Other)?, + .collect::, _>>()?, + foreign_fn.result.clone().try_into()?, ); let func_key = v8::String::new(scope, &symbol_key).unwrap(); @@ -302,9 +315,7 @@ fn sync_fn_impl<'s>( unsafe { result.to_v8(scope, data.symbol.result_type.clone()) }; rv.set(result); } - Err(err) => { - deno_core::_ops::throw_type_error(scope, err.to_string()); - } + Err(err) => deno_core::error::throw_js_error_class(scope, &err), }; } @@ -324,6 +335,7 @@ pub(crate) fn format_error( // https://github.com/denoland/deno/issues/11632 dlopen2::Error::OpeningLibraryError(e) => { use std::os::windows::ffi::OsStrExt; + use winapi::shared::minwindef::DWORD; use winapi::shared::winerror::ERROR_INSUFFICIENT_BUFFER; use winapi::um::errhandlingapi::GetLastError; @@ -392,10 +404,11 @@ pub(crate) fn format_error( #[cfg(test)] mod tests { + use serde_json::json; + use super::ForeignFunction; use super::ForeignSymbol; use crate::symbol::NativeType; - use serde_json::json; #[cfg(target_os = "windows")] #[test] diff --git a/ext/ffi/ir.rs b/ext/ffi/ir.rs index 2e80842166..a1877b4a2b 100644 --- a/ext/ffi/ir.rs +++ b/ext/ffi/ir.rs @@ -1,12 +1,15 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::symbol::NativeType; -use deno_core::v8; -use libffi::middle::Arg; use std::ffi::c_void; use std::ptr; -#[derive(Debug, thiserror::Error)] +use deno_core::v8; +use libffi::middle::Arg; + +use crate::symbol::NativeType; + +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(type)] pub enum IRError { #[error("Invalid FFI u8 type, expected boolean")] InvalidU8ExpectedBoolean, diff --git a/ext/ffi/lib.rs b/ext/ffi/lib.rs index 73ec7757ab..7fed3c32aa 100644 --- a/ext/ffi/lib.rs +++ b/ext/ffi/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::mem::size_of; use std::os::raw::c_char; @@ -17,24 +17,23 @@ mod turbocall; use call::op_ffi_call_nonblocking; use call::op_ffi_call_ptr; use call::op_ffi_call_ptr_nonblocking; +pub use call::CallError; use callback::op_ffi_unsafe_callback_close; use callback::op_ffi_unsafe_callback_create; use callback::op_ffi_unsafe_callback_ref; +pub use callback::CallbackError; +use deno_permissions::PermissionCheckError; use dlfcn::op_ffi_load; +pub use dlfcn::DlfcnError; use dlfcn::ForeignFunction; +pub use ir::IRError; use r#static::op_ffi_get_static; +pub use r#static::StaticError; +pub use repr::ReprError; use repr::*; use symbol::NativeType; use symbol::Symbol; -pub use call::CallError; -pub use callback::CallbackError; -use deno_permissions::PermissionCheckError; -pub use dlfcn::DlfcnError; -pub use ir::IRError; -pub use r#static::StaticError; -pub use repr::ReprError; - #[cfg(not(target_pointer_width = "64"))] compile_error!("platform not supported"); diff --git a/ext/ffi/repr.rs b/ext/ffi/repr.rs index eea15f3e97..bcd80cbf03 100644 --- a/ext/ffi/repr.rs +++ b/ext/ffi/repr.rs @@ -1,15 +1,18 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::FfiPermissions; -use deno_core::op2; -use deno_core::v8; -use deno_core::OpState; use std::ffi::c_char; use std::ffi::c_void; use std::ffi::CStr; use std::ptr; -#[derive(Debug, thiserror::Error)] +use deno_core::op2; +use deno_core::v8; +use deno_core::OpState; + +use crate::FfiPermissions; + +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(type)] pub enum ReprError { #[error("Invalid pointer to offset, pointer is null")] InvalidOffset, @@ -45,6 +48,7 @@ pub enum ReprError { InvalidF64, #[error("Invalid pointer pointer, pointer is null")] InvalidPointer, + #[class(inherit)] #[error(transparent)] Permission(#[from] deno_permissions::PermissionCheckError), } diff --git a/ext/ffi/static.rs b/ext/ffi/static.rs index 61b4059336..6d999430e3 100644 --- a/ext/ffi/static.rs +++ b/ext/ffi/static.rs @@ -1,23 +1,29 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::ptr; -use crate::dlfcn::DynamicLibraryResource; -use crate::symbol::NativeType; use deno_core::op2; use deno_core::v8; use deno_core::OpState; use deno_core::ResourceId; -use std::ptr; -#[derive(Debug, thiserror::Error)] +use crate::dlfcn::DynamicLibraryResource; +use crate::symbol::NativeType; + +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum StaticError { + #[class(inherit)] #[error(transparent)] Dlfcn(super::DlfcnError), + #[class(type)] #[error("Invalid FFI static type 'void'")] InvalidTypeVoid, + #[class(type)] #[error("Invalid FFI static type 'struct'")] InvalidTypeStruct, + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] deno_core::error::ResourceError), } #[op2] @@ -29,10 +35,7 @@ pub fn op_ffi_get_static<'scope>( #[serde] static_type: NativeType, optional: bool, ) -> Result, StaticError> { - let resource = state - .resource_table - .get::(rid) - .map_err(StaticError::Resource)?; + let resource = state.resource_table.get::(rid)?; let data_ptr = match resource.get_static(name) { Ok(data_ptr) => data_ptr, diff --git a/ext/ffi/symbol.rs b/ext/ffi/symbol.rs index cee1c7d33e..5bca5be6d2 100644 --- a/ext/ffi/symbol.rs +++ b/ext/ffi/symbol.rs @@ -1,7 +1,6 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use deno_core::error::type_error; -use deno_core::error::AnyError; +use deno_error::JsErrorBox; /// Defines the accepted types that can be used as /// parameters and return values in FFI. @@ -29,7 +28,7 @@ pub enum NativeType { } impl TryFrom for libffi::middle::Type { - type Error = AnyError; + type Error = JsErrorBox; fn try_from(native_type: NativeType) -> Result { Ok(match native_type { @@ -56,7 +55,9 @@ impl TryFrom for libffi::middle::Type { .map(|field| field.clone().try_into()) .collect::, _>>()?, false => { - return Err(type_error("Struct must have at least one field")) + return Err(JsErrorBox::type_error( + "Struct must have at least one field", + )) } }) } diff --git a/ext/ffi/turbocall.rs b/ext/ffi/turbocall.rs index 38b4062ab7..499168dceb 100644 --- a/ext/ffi/turbocall.rs +++ b/ext/ffi/turbocall.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::cmp::max; use std::ffi::c_void; diff --git a/ext/fs/30_fs.js b/ext/fs/30_fs.js index 4e71acb1b2..74e3c87c17 100644 --- a/ext/fs/30_fs.js +++ b/ext/fs/30_fs.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, primordials } from "ext:core/mod.js"; const { diff --git a/ext/fs/Cargo.toml b/ext/fs/Cargo.toml index 1d0b623718..349c0a3be4 100644 --- a/ext/fs/Cargo.toml +++ b/ext/fs/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_fs" -version = "0.94.0" +version = "0.96.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -21,6 +21,7 @@ async-trait.workspace = true base32.workspace = true boxed_error.workspace = true deno_core.workspace = true +deno_error.workspace = true deno_io.workspace = true deno_path_util.workspace = true deno_permissions.workspace = true diff --git a/ext/fs/interface.rs b/ext/fs/interface.rs index 0e753d684c..0aae2b998f 100644 --- a/ext/fs/interface.rs +++ b/ext/fs/interface.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use core::str; use std::borrow::Cow; @@ -6,12 +6,11 @@ use std::path::Path; use std::path::PathBuf; use std::rc::Rc; -use serde::Deserialize; -use serde::Serialize; - use deno_io::fs::File; use deno_io::fs::FsResult; use deno_io::fs::FsStat; +use serde::Deserialize; +use serde::Serialize; use crate::sync::MaybeSend; use crate::sync::MaybeSync; diff --git a/ext/fs/lib.rs b/ext/fs/lib.rs index 360400df0d..89bd5bc09a 100644 --- a/ext/fs/lib.rs +++ b/ext/fs/lib.rs @@ -1,10 +1,17 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. mod interface; mod ops; mod std_fs; pub mod sync; +use std::borrow::Cow; +use std::path::Path; +use std::path::PathBuf; + +use deno_io::fs::FsError; +use deno_permissions::PermissionCheckError; + pub use crate::interface::AccessCheckCb; pub use crate::interface::AccessCheckFn; pub use crate::interface::FileSystem; @@ -15,18 +22,11 @@ pub use crate::interface::OpenOptions; pub use crate::ops::FsOpsError; pub use crate::ops::FsOpsErrorKind; pub use crate::ops::OperationError; +use crate::ops::*; pub use crate::std_fs::RealFs; pub use crate::sync::MaybeSend; pub use crate::sync::MaybeSync; -use crate::ops::*; - -use deno_io::fs::FsError; -use deno_permissions::PermissionCheckError; -use std::borrow::Cow; -use std::path::Path; -use std::path::PathBuf; - pub trait FsPermissions { fn check_open<'a>( &mut self, diff --git a/ext/fs/ops.rs b/ext/fs/ops.rs index ac0a8901d7..9f5f3c6e90 100644 --- a/ext/fs/ops.rs +++ b/ext/fs/ops.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::cell::RefCell; @@ -11,13 +11,8 @@ use std::path::PathBuf; use std::path::StripPrefixError; use std::rc::Rc; -use crate::interface::AccessCheckFn; -use crate::interface::FileSystemRc; -use crate::interface::FsDirEntry; -use crate::interface::FsFileType; -use crate::FsPermissions; -use crate::OpenOptions; use boxed_error::Boxed; +use deno_core::error::ResourceError; use deno_core::op2; use deno_core::CancelFuture; use deno_core::CancelHandle; @@ -26,6 +21,7 @@ use deno_core::JsBuffer; use deno_core::OpState; use deno_core::ResourceId; use deno_core::ToJsBuffer; +use deno_error::JsErrorBox; use deno_io::fs::FileResource; use deno_io::fs::FsError; use deno_io::fs::FsStat; @@ -35,34 +31,53 @@ use rand::thread_rng; use rand::Rng; use serde::Serialize; -#[derive(Debug, Boxed)] +use crate::interface::AccessCheckFn; +use crate::interface::FileSystemRc; +use crate::interface::FsDirEntry; +use crate::interface::FsFileType; +use crate::FsPermissions; +use crate::OpenOptions; + +#[derive(Debug, Boxed, deno_error::JsError)] pub struct FsOpsError(pub Box); -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum FsOpsErrorKind { + #[class(inherit)] #[error("{0}")] Io(#[source] std::io::Error), + #[class(inherit)] #[error("{0}")] OperationError(#[source] OperationError), + #[class(inherit)] #[error(transparent)] Permission(#[from] PermissionCheckError), + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] ResourceError), + #[class("InvalidData")] #[error("File name or path {0:?} is not valid UTF-8")] InvalidUtf8(std::ffi::OsString), + #[class(generic)] #[error("{0}")] StripPrefix(#[from] StripPrefixError), + #[class(inherit)] #[error("{0}")] Canceled(#[from] deno_core::Canceled), + #[class(type)] #[error("Invalid seek mode: {0}")] InvalidSeekMode(i32), + #[class(generic)] #[error("Invalid control character in prefix or suffix: {0:?}")] InvalidControlCharacter(String), + #[class(generic)] #[error("Invalid character in prefix or suffix: {0:?}")] InvalidCharacter(String), #[cfg(windows)] + #[class(generic)] #[error("Invalid trailing character in suffix")] InvalidTrailingCharacter, + #[class("NotCapable")] #[error("Requires {err} access to {path}, {}", print_not_capable_info(*.standalone, .err))] NotCapableAccess { // NotCapable @@ -70,21 +85,21 @@ pub enum FsOpsErrorKind { err: &'static str, path: String, }, + #[class("NotCapable")] #[error("permission denied: {0}")] - NotCapable(&'static str), // NotCapable + NotCapable(&'static str), + #[class(inherit)] #[error(transparent)] - Other(deno_core::error::AnyError), + Other(JsErrorBox), } impl From for FsOpsError { fn from(err: FsError) -> Self { match err { FsError::Io(err) => FsOpsErrorKind::Io(err), - FsError::FileBusy => { - FsOpsErrorKind::Other(deno_core::error::resource_unavailable()) - } + FsError::FileBusy => FsOpsErrorKind::Resource(ResourceError::Unavailable), FsError::NotSupported => { - FsOpsErrorKind::Other(deno_core::error::not_supported()) + FsOpsErrorKind::Other(JsErrorBox::not_supported()) } FsError::NotCapable(err) => FsOpsErrorKind::NotCapable(err), } @@ -1665,10 +1680,12 @@ pub async fn op_fs_futime_async( Ok(()) } -#[derive(Debug)] +#[derive(Debug, deno_error::JsError)] +#[class(inherit)] pub struct OperationError { operation: &'static str, kind: OperationErrorKind, + #[inherit] pub err: FsError, } diff --git a/ext/fs/std_fs.rs b/ext/fs/std_fs.rs index c28fe9f915..4845e9c7bc 100644 --- a/ext/fs/std_fs.rs +++ b/ext/fs/std_fs.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. #![allow(clippy::disallowed_methods)] @@ -503,6 +503,7 @@ fn remove(path: &Path, recursive: bool) -> FsResult<()> { #[cfg(not(unix))] { use std::os::windows::prelude::MetadataExt; + use winapi::um::winnt::FILE_ATTRIBUTE_DIRECTORY; if metadata.file_attributes() & FILE_ATTRIBUTE_DIRECTORY != 0 { fs::remove_dir(path) @@ -520,13 +521,14 @@ fn remove(path: &Path, recursive: bool) -> FsResult<()> { fn copy_file(from: &Path, to: &Path) -> FsResult<()> { #[cfg(target_os = "macos")] { - use libc::clonefile; - use libc::stat; - use libc::unlink; use std::ffi::CString; use std::os::unix::fs::OpenOptionsExt; use std::os::unix::fs::PermissionsExt; + use libc::clonefile; + use libc::stat; + use libc::unlink; + let from_str = CString::new(from.as_os_str().as_encoded_bytes()) .map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?; let to_str = CString::new(to.as_os_str().as_encoded_bytes()) @@ -670,11 +672,12 @@ fn cp(from: &Path, to: &Path) -> FsResult<()> { #[cfg(target_os = "macos")] { // Just clonefile() - use libc::clonefile; - use libc::unlink; use std::ffi::CString; use std::os::unix::ffi::OsStrExt; + use libc::clonefile; + use libc::unlink; + let from_str = CString::new(from.as_os_str().as_bytes()) .map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?; let to_str = CString::new(to.as_os_str().as_bytes()) @@ -762,6 +765,7 @@ fn stat(path: &Path) -> FsResult { #[cfg(windows)] fn stat(path: &Path) -> FsResult { use std::os::windows::fs::OpenOptionsExt; + use winapi::um::winbase::FILE_FLAG_BACKUP_SEMANTICS; let mut opts = fs::OpenOptions::new(); @@ -924,6 +928,7 @@ fn exists(path: &Path) -> bool { #[cfg(windows)] { use std::os::windows::ffi::OsStrExt; + use winapi::um::fileapi::GetFileAttributesW; use winapi::um::fileapi::INVALID_FILE_ATTRIBUTES; diff --git a/ext/fs/sync.rs b/ext/fs/sync.rs index 06694f1dc4..2c07ba42df 100644 --- a/ext/fs/sync.rs +++ b/ext/fs/sync.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. pub use inner::*; @@ -6,10 +6,9 @@ pub use inner::*; mod inner { #![allow(clippy::disallowed_types)] - pub use std::sync::Arc as MaybeArc; - pub use core::marker::Send as MaybeSend; pub use core::marker::Sync as MaybeSync; + pub use std::sync::Arc as MaybeArc; } #[cfg(not(feature = "sync_fs"))] diff --git a/ext/http/00_serve.ts b/ext/http/00_serve.ts index 446533e910..5ce0a4bf7f 100644 --- a/ext/http/00_serve.ts +++ b/ext/http/00_serve.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, internals, primordials } from "ext:core/mod.js"; const { @@ -43,10 +43,7 @@ const { Uint8Array, Promise, } = primordials; -const { - getAsyncContext, - setAsyncContext, -} = core; +const { getAsyncContext, setAsyncContext } = core; import { InnerBody } from "ext:deno_fetch/22_body.js"; import { Event } from "ext:deno_web/02_event.js"; @@ -90,9 +87,8 @@ import { import { hasTlsKeyPairOptions, listenTls } from "ext:deno_net/02_tls.js"; import { SymbolAsyncDispose } from "ext:deno_web/00_infra.js"; import { - endSpan, + builtinTracer, enterSpan, - Span, TRACING_ENABLED, } from "ext:deno_telemetry/telemetry.ts"; import { @@ -288,28 +284,28 @@ class InnerRequest { // * is valid for OPTIONS if (path === "*") { - return this.#urlValue = "*"; + return (this.#urlValue = "*"); } // If the path is empty, return the authority (valid for CONNECT) if (path == "") { - return this.#urlValue = this.#methodAndUri[1]; + return (this.#urlValue = this.#methodAndUri[1]); } // CONNECT requires an authority if (this.#methodAndUri[0] == "CONNECT") { - return this.#urlValue = this.#methodAndUri[1]; + return (this.#urlValue = this.#methodAndUri[1]); } const hostname = this.#methodAndUri[1]; if (hostname) { // Construct a URL from the scheme, the hostname, and the path - return this.#urlValue = this.#context.scheme + hostname + path; + return (this.#urlValue = this.#context.scheme + hostname + path); } // Construct a URL from the scheme, the fallback hostname, and the path - return this.#urlValue = this.#context.scheme + this.#context.fallbackHost + - path; + return (this.#urlValue = this.#context.scheme + this.#context.fallbackHost + + path); } get completed() { @@ -370,7 +366,25 @@ class InnerRequest { return null; } this.#streamRid = op_http_read_request_body(this.#external); - this.#body = new InnerBody(readableStreamForRid(this.#streamRid, false)); + this.#body = new InnerBody( + readableStreamForRid( + this.#streamRid, + false, + undefined, + (controller, error) => { + if (ObjectPrototypeIsPrototypeOf(BadResourcePrototype, error)) { + // TODO(kt3k): We would like to pass `error` as `cause` when BadResource supports it. + controller.error( + new error.constructor( + `Cannot read request body as underlying resource unavailable`, + ), + ); + } else { + controller.error(error); + } + }, + ), + ); return this.#body; } @@ -396,10 +410,7 @@ class InnerRequest { return; } - PromisePrototypeThen( - op_http_request_on_cancel(this.#external), - callback, - ); + PromisePrototypeThen(op_http_request_on_cancel(this.#external), callback); } } @@ -503,12 +514,7 @@ function fastSyncResponseOrStream( autoClose = true; } PromisePrototypeThen( - op_http_set_response_body_resource( - req, - rid, - autoClose, - status, - ), + op_http_set_response_body_resource(req, rid, autoClose, status), (success) => { innerRequest?.close(success); op_http_close_after_finish(req); @@ -538,10 +544,7 @@ function mapToCallback(context, callback, onError) { updateSpanFromRequest(span, request); } - response = await callback( - request, - new ServeHandlerInfo(innerRequest), - ); + response = await callback(request, new ServeHandlerInfo(innerRequest)); // Throwing Error if the handler return value is not a Response class if (!ObjectPrototypeIsPrototypeOf(ResponsePrototype, response)) { @@ -618,12 +621,12 @@ function mapToCallback(context, callback, onError) { mapped = function (req, _span) { const oldCtx = getAsyncContext(); setAsyncContext(context.asyncContext); - const span = new Span("deno.serve", { kind: 1 }); + const span = builtinTracer().startSpan("deno.serve", { kind: 1 }); try { enterSpan(span); return SafePromisePrototypeFinally( origMapped(req, span), - () => endSpan(span), + () => span.end(), ); } finally { // equiv to exitSpan. @@ -670,7 +673,7 @@ function formatHostName(hostname: string): string { // because browsers in Windows don't resolve "0.0.0.0". // See the discussion in https://github.com/denoland/deno_std/issues/1165 if ( - (Deno.build.os === "windows") && + Deno.build.os === "windows" && (hostname == "0.0.0.0" || hostname == "::") ) { return "localhost"; @@ -712,11 +715,12 @@ function serve(arg1, arg2) { const wantsHttps = hasTlsKeyPairOptions(options); const wantsUnix = ObjectHasOwn(options, "path"); const signal = options.signal; - const onError = options.onError ?? function (error) { - // deno-lint-ignore no-console - console.error(error); - return internalServerError(); - }; + const onError = options.onError ?? + function (error) { + // deno-lint-ignore no-console + console.error(error); + return internalServerError(); + }; if (wantsUnix) { const listener = listen({ @@ -825,10 +829,7 @@ function serveHttpOn(context, addr, callback) { const promiseErrorHandler = (error) => { // Abnormal exit // deno-lint-ignore no-console - console.error( - "Terminating Deno.serve loop due to unexpected error", - error, - ); + console.error("Terminating Deno.serve loop due to unexpected error", error); context.close(); }; @@ -946,7 +947,7 @@ function registerDeclarativeServer(exports) { port: servePort, hostname: serveHost, [kLoadBalanced]: (serveIsMain && serveWorkerCount > 1) || - (serveWorkerCount !== null), + serveWorkerCount !== null, onListen: ({ port, hostname }) => { if (serveIsMain) { const nThreads = serveWorkerCount > 1 diff --git a/ext/http/01_http.js b/ext/http/01_http.js index 9302bd8a0f..83983fa0ca 100644 --- a/ext/http/01_http.js +++ b/ext/http/01_http.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, primordials } from "ext:core/mod.js"; const { diff --git a/ext/http/02_websocket.ts b/ext/http/02_websocket.ts index 96af4d4822..4d37b04a1d 100644 --- a/ext/http/02_websocket.ts +++ b/ext/http/02_websocket.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { internals, primordials } from "ext:core/mod.js"; import { op_http_websocket_accept_header } from "ext:core/ops"; const { diff --git a/ext/http/Cargo.toml b/ext/http/Cargo.toml index e7aaad2fc0..103af9a27b 100644 --- a/ext/http/Cargo.toml +++ b/ext/http/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_http" -version = "0.182.0" +version = "0.184.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -28,6 +28,7 @@ brotli.workspace = true bytes.workspace = true cache_control.workspace = true deno_core.workspace = true +deno_error.workspace = true deno_net.workspace = true deno_websocket.workspace = true flate2.workspace = true diff --git a/ext/http/benches/compressible.rs b/ext/http/benches/compressible.rs index 5ac09cb8bb..96b21512ba 100644 --- a/ext/http/benches/compressible.rs +++ b/ext/http/benches/compressible.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use bencher::benchmark_group; use bencher::benchmark_main; use bencher::Bencher; diff --git a/ext/http/compressible.rs b/ext/http/compressible.rs index 6e96582e7e..5c499f957d 100644 --- a/ext/http/compressible.rs +++ b/ext/http/compressible.rs @@ -1,7 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::str::FromStr; use phf::phf_set; -use std::str::FromStr; // Data obtained from https://github.com/jshttp/mime-db/blob/fa5e4ef3cc8907ec3c5ec5b85af0c63d7059a5cd/db.json // Important! Keep this list sorted alphabetically. diff --git a/ext/http/fly_accept_encoding.rs b/ext/http/fly_accept_encoding.rs index 4d6fd2231e..1be864fd3b 100644 --- a/ext/http/fly_accept_encoding.rs +++ b/ext/http/fly_accept_encoding.rs @@ -1,5 +1,5 @@ // Copyright 2018 Yoshua Wuyts. All rights reserved. MIT license. -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Forked from https://github.com/superfly/accept-encoding/blob/1cded757ec7ff3916e5bfe7441db76cdc48170dc/ // Forked to support both http 0.3 and http 1.0 crates. @@ -124,11 +124,12 @@ fn encodings_iter_inner<'s>( #[cfg(test)] mod tests { - use super::*; use http_v02::header::ACCEPT_ENCODING; use http_v02::HeaderMap; use http_v02::HeaderValue; + use super::*; + fn encodings( headers: &HeaderMap, ) -> Result, f32)>, EncodingError> { diff --git a/ext/http/http_next.rs b/ext/http/http_next.rs index 7dbac6021a..82edf817bf 100644 --- a/ext/http/http_next.rs +++ b/ext/http/http_next.rs @@ -1,24 +1,13 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use crate::compressible::is_content_compressible; -use crate::extract_network_stream; -use crate::network_buffered_stream::NetworkStreamPrefixCheck; -use crate::request_body::HttpRequestBody; -use crate::request_properties::HttpConnectionProperties; -use crate::request_properties::HttpListenProperties; -use crate::request_properties::HttpPropertyExtractor; -use crate::response_body::Compression; -use crate::response_body::ResponseBytesInner; -use crate::service::handle_request; -use crate::service::http_general_trace; -use crate::service::http_trace; -use crate::service::HttpRecord; -use crate::service::HttpRecordResponse; -use crate::service::HttpRequestBodyAutocloser; -use crate::service::HttpServerState; -use crate::service::SignallingRc; -use crate::websocket_upgrade::WebSocketUpgrade; -use crate::LocalExecutor; -use crate::Options; +// Copyright 2018-2025 the Deno authors. MIT license. +use std::borrow::Cow; +use std::cell::RefCell; +use std::ffi::c_void; +use std::future::Future; +use std::io; +use std::pin::Pin; +use std::ptr::null; +use std::rc::Rc; + use cache_control::CacheControl; use deno_core::external; use deno_core::futures::future::poll_fn; @@ -44,6 +33,7 @@ use deno_core::ResourceId; use deno_net::ops_tls::TlsStream; use deno_net::raw::NetworkStream; use deno_websocket::ws_create_server_stream; +use fly_accept_encoding::Encoding; use hyper::body::Incoming; use hyper::header::HeaderMap; use hyper::header::ACCEPT_ENCODING; @@ -63,21 +53,31 @@ use hyper::StatusCode; use hyper_util::rt::TokioIo; use once_cell::sync::Lazy; use smallvec::SmallVec; -use std::borrow::Cow; -use std::cell::RefCell; -use std::ffi::c_void; -use std::future::Future; -use std::io; -use std::pin::Pin; -use std::ptr::null; -use std::rc::Rc; - -use super::fly_accept_encoding; -use fly_accept_encoding::Encoding; - use tokio::io::AsyncReadExt; use tokio::io::AsyncWriteExt; +use super::fly_accept_encoding; +use crate::compressible::is_content_compressible; +use crate::extract_network_stream; +use crate::network_buffered_stream::NetworkStreamPrefixCheck; +use crate::request_body::HttpRequestBody; +use crate::request_properties::HttpConnectionProperties; +use crate::request_properties::HttpListenProperties; +use crate::request_properties::HttpPropertyExtractor; +use crate::response_body::Compression; +use crate::response_body::ResponseBytesInner; +use crate::service::handle_request; +use crate::service::http_general_trace; +use crate::service::http_trace; +use crate::service::HttpRecord; +use crate::service::HttpRecordResponse; +use crate::service::HttpRequestBodyAutocloser; +use crate::service::HttpServerState; +use crate::service::SignallingRc; +use crate::websocket_upgrade::WebSocketUpgrade; +use crate::LocalExecutor; +use crate::Options; + type Request = hyper::Request; static USE_WRITEV: Lazy = Lazy::new(|| { @@ -146,24 +146,44 @@ macro_rules! clone_external { }}; } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum HttpNextError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] deno_core::error::ResourceError), + #[class(inherit)] #[error("{0}")] Io(#[from] io::Error), + #[class(inherit)] #[error(transparent)] WebSocketUpgrade(crate::websocket_upgrade::WebSocketUpgradeError), + #[class("Http")] #[error("{0}")] Hyper(#[from] hyper::Error), + #[class(inherit)] #[error(transparent)] - JoinError(#[from] tokio::task::JoinError), + JoinError( + #[from] + #[inherit] + tokio::task::JoinError, + ), + #[class(inherit)] #[error(transparent)] - Canceled(#[from] deno_core::Canceled), - #[error(transparent)] - HttpPropertyExtractor(deno_core::error::AnyError), + Canceled( + #[from] + #[inherit] + deno_core::Canceled, + ), + #[class(generic)] #[error(transparent)] UpgradeUnavailable(#[from] crate::service::UpgradeUnavailableError), + #[class(inherit)] + #[error("{0}")] + Other( + #[from] + #[inherit] + deno_error::JsErrorBox, + ), } #[op2(fast)] @@ -747,15 +767,9 @@ pub async fn op_http_set_response_body_resource( let resource = { let mut state = state.borrow_mut(); if auto_close { - state - .resource_table - .take_any(stream_rid) - .map_err(HttpNextError::Resource)? + state.resource_table.take_any(stream_rid)? } else { - state - .resource_table - .get_any(stream_rid) - .map_err(HttpNextError::Resource)? + state.resource_table.get_any(stream_rid)? } }; @@ -1063,8 +1077,7 @@ where HTTP: HttpPropertyExtractor, { let listener = - HTTP::get_listener_for_rid(&mut state.borrow_mut(), listener_rid) - .map_err(HttpNextError::Resource)?; + HTTP::get_listener_for_rid(&mut state.borrow_mut(), listener_rid)?; let listen_properties = HTTP::listen_properties_from_listener(&listener)?; @@ -1084,8 +1097,7 @@ where loop { let conn = HTTP::accept_connection_from_listener(&listener) .try_or_cancel(listen_cancel_clone.clone()) - .await - .map_err(HttpNextError::HttpPropertyExtractor)?; + .await?; serve_http_on::( conn, &listen_properties_clone, @@ -1120,8 +1132,7 @@ where HTTP: HttpPropertyExtractor, { let connection = - HTTP::get_connection_for_rid(&mut state.borrow_mut(), connection_rid) - .map_err(HttpNextError::Resource)?; + HTTP::get_connection_for_rid(&mut state.borrow_mut(), connection_rid)?; let listen_properties = HTTP::listen_properties_from_connection(&connection)?; @@ -1190,8 +1201,7 @@ pub async fn op_http_wait( let join_handle = state .borrow_mut() .resource_table - .get::(rid) - .map_err(HttpNextError::Resource)?; + .get::(rid)?; let cancel = join_handle.listen_cancel_handle(); let next = async { @@ -1236,7 +1246,7 @@ pub fn op_http_cancel( state: &mut OpState, #[smi] rid: ResourceId, graceful: bool, -) -> Result<(), deno_core::error::AnyError> { +) -> Result<(), deno_core::error::ResourceError> { let join_handle = state.resource_table.get::(rid)?; if graceful { @@ -1260,8 +1270,7 @@ pub async fn op_http_close( let join_handle = state .borrow_mut() .resource_table - .take::(rid) - .map_err(HttpNextError::Resource)?; + .take::(rid)?; if graceful { http_general_trace!("graceful shutdown"); @@ -1390,11 +1399,8 @@ pub async fn op_raw_write_vectored( #[buffer] buf1: JsBuffer, #[buffer] buf2: JsBuffer, ) -> Result { - let resource: Rc = state - .borrow() - .resource_table - .get::(rid) - .map_err(HttpNextError::Resource)?; + let resource: Rc = + state.borrow().resource_table.get::(rid)?; let nwritten = resource.write_vectored(&buf1, &buf2).await?; Ok(nwritten) } diff --git a/ext/http/lib.rs b/ext/http/lib.rs index 39b0bbc2af..981ca9f0c0 100644 --- a/ext/http/lib.rs +++ b/ext/http/lib.rs @@ -1,4 +1,20 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::borrow::Cow; +use std::cell::RefCell; +use std::cmp::min; +use std::error::Error; +use std::future::Future; +use std::io; +use std::io::Write; +use std::mem::replace; +use std::mem::take; +use std::pin::pin; +use std::pin::Pin; +use std::rc::Rc; +use std::sync::Arc; +use std::task::Context; +use std::task::Poll; use async_compression::tokio::write::BrotliEncoder; use async_compression::tokio::write::GzipEncoder; @@ -35,6 +51,7 @@ use deno_core::RcRef; use deno_core::Resource; use deno_core::ResourceId; use deno_core::StringOrBuffer; +use deno_error::JsErrorBox; use deno_net::raw::NetworkStream; use deno_websocket::ws_create_server_stream; use flate2::write::GzEncoder; @@ -54,21 +71,6 @@ use hyper_v014::HeaderMap; use hyper_v014::Request; use hyper_v014::Response; use serde::Serialize; -use std::borrow::Cow; -use std::cell::RefCell; -use std::cmp::min; -use std::error::Error; -use std::future::Future; -use std::io; -use std::io::Write; -use std::mem::replace; -use std::mem::take; -use std::pin::pin; -use std::pin::Pin; -use std::rc::Rc; -use std::sync::Arc; -use std::task::Context; -use std::task::Poll; use tokio::io::AsyncRead; use tokio::io::AsyncWrite; use tokio::io::AsyncWriteExt; @@ -164,36 +166,50 @@ deno_core::extension!( } ); -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum HttpError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] deno_core::error::ResourceError), + #[class(inherit)] #[error(transparent)] Canceled(#[from] deno_core::Canceled), + #[class("Http")] #[error("{0}")] HyperV014(#[source] Arc), + #[class(generic)] #[error("{0}")] InvalidHeaderName(#[from] hyper_v014::header::InvalidHeaderName), + #[class(generic)] #[error("{0}")] InvalidHeaderValue(#[from] hyper_v014::header::InvalidHeaderValue), + #[class(generic)] #[error("{0}")] Http(#[from] hyper_v014::http::Error), + #[class("Http")] #[error("response headers already sent")] ResponseHeadersAlreadySent, + #[class("Http")] #[error("connection closed while sending response")] ConnectionClosedWhileSendingResponse, + #[class("Http")] #[error("already in use")] AlreadyInUse, + #[class(inherit)] #[error("{0}")] Io(#[from] std::io::Error), + #[class("Http")] #[error("no response headers")] NoResponseHeaders, + #[class("Http")] #[error("response already completed")] ResponseAlreadyCompleted, + #[class("Http")] #[error("cannot upgrade because request body was used")] UpgradeBodyUsed, + #[class("Http")] #[error(transparent)] - Other(deno_core::error::AnyError), + Other(#[from] JsErrorBox), } pub enum HttpSocketAddr { @@ -485,7 +501,9 @@ impl Resource for HttpStreamReadResource { Some(_) => match body.as_mut().next().await.unwrap() { Ok(chunk) => assert!(chunk.is_empty()), Err(err) => { - break Err(HttpError::HyperV014(Arc::new(err)).into()) + break Err(JsErrorBox::from_err(HttpError::HyperV014( + Arc::new(err), + ))) } }, None => break Ok(BufView::empty()), @@ -609,11 +627,7 @@ async fn op_http_accept( state: Rc>, #[smi] rid: ResourceId, ) -> Result, HttpError> { - let conn = state - .borrow() - .resource_table - .get::(rid) - .map_err(HttpError::Resource)?; + let conn = state.borrow().resource_table.get::(rid)?; match conn.accept().await { Ok(Some((read_stream, write_stream, method, url))) => { @@ -728,8 +742,7 @@ async fn op_http_write_headers( let stream = state .borrow_mut() .resource_table - .get::(rid) - .map_err(HttpError::Resource)?; + .get::(rid)?; // Track supported encoding let encoding = stream.accept_encoding; @@ -794,10 +807,7 @@ fn op_http_headers( state: &mut OpState, #[smi] rid: u32, ) -> Result, HttpError> { - let stream = state - .resource_table - .get::(rid) - .map_err(HttpError::Resource)?; + let stream = state.resource_table.get::(rid)?; let rd = RcRef::map(&stream, |r| &r.rd) .try_borrow() .ok_or(HttpError::AlreadyInUse)?; @@ -953,14 +963,9 @@ async fn op_http_write_resource( let http_stream = state .borrow() .resource_table - .get::(rid) - .map_err(HttpError::Resource)?; + .get::(rid)?; let mut wr = RcRef::map(&http_stream, |r| &r.wr).borrow_mut().await; - let resource = state - .borrow() - .resource_table - .get_any(stream) - .map_err(HttpError::Resource)?; + let resource = state.borrow().resource_table.get_any(stream)?; loop { match *wr { HttpResponseWriter::Headers(_) => { @@ -972,11 +977,7 @@ async fn op_http_write_resource( _ => {} }; - let view = resource - .clone() - .read(64 * 1024) - .await - .map_err(HttpError::Other)?; // 64KB + let view = resource.clone().read(64 * 1024).await?; // 64KB if view.is_empty() { break; } @@ -1021,8 +1022,7 @@ async fn op_http_write( let stream = state .borrow() .resource_table - .get::(rid) - .map_err(HttpError::Resource)?; + .get::(rid)?; let mut wr = RcRef::map(&stream, |r| &r.wr).borrow_mut().await; match &mut *wr { @@ -1074,8 +1074,7 @@ async fn op_http_shutdown( let stream = state .borrow() .resource_table - .get::(rid) - .map_err(HttpError::Resource)?; + .get::(rid)?; let mut wr = RcRef::map(&stream, |r| &r.wr).borrow_mut().await; let wr = take(&mut *wr); match wr { @@ -1121,8 +1120,7 @@ async fn op_http_upgrade_websocket( let stream = state .borrow_mut() .resource_table - .get::(rid) - .map_err(HttpError::Resource)?; + .get::(rid)?; let mut rd = RcRef::map(&stream, |r| &r.rd).borrow_mut().await; let request = match &mut *rd { diff --git a/ext/http/network_buffered_stream.rs b/ext/http/network_buffered_stream.rs index 73df2dbd9f..5882dd14e3 100644 --- a/ext/http/network_buffered_stream.rs +++ b/ext/http/network_buffered_stream.rs @@ -1,12 +1,13 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use bytes::Bytes; -use deno_core::futures::future::poll_fn; -use deno_core::futures::ready; use std::io; use std::mem::MaybeUninit; use std::pin::Pin; use std::task::Poll; + +use bytes::Bytes; +use deno_core::futures::future::poll_fn; +use deno_core::futures::ready; use tokio::io::AsyncRead; use tokio::io::AsyncWrite; use tokio::io::ReadBuf; @@ -227,9 +228,10 @@ impl AsyncWrite #[cfg(test)] mod tests { - use super::*; use tokio::io::AsyncReadExt; + use super::*; + struct YieldsOneByteAtATime(&'static [u8]); impl AsyncRead for YieldsOneByteAtATime { diff --git a/ext/http/reader_stream.rs b/ext/http/reader_stream.rs index be6d571b1a..b6985927f4 100644 --- a/ext/http/reader_stream.rs +++ b/ext/http/reader_stream.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::pin::Pin; use std::sync::atomic::AtomicBool; @@ -66,11 +66,12 @@ impl Stream for ExternallyAbortableReaderStream { #[cfg(test)] mod tests { - use super::*; use bytes::Bytes; use deno_core::futures::StreamExt; use tokio::io::AsyncWriteExt; + use super::*; + #[tokio::test] async fn success() { let (a, b) = tokio::io::duplex(64 * 1024); diff --git a/ext/http/request_body.rs b/ext/http/request_body.rs index f1c3f358ea..50ca1635c3 100644 --- a/ext/http/request_body.rs +++ b/ext/http/request_body.rs @@ -1,4 +1,10 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. +use std::borrow::Cow; +use std::pin::Pin; +use std::rc::Rc; +use std::task::ready; +use std::task::Poll; + use bytes::Bytes; use deno_core::futures::stream::Peekable; use deno_core::futures::Stream; @@ -9,14 +15,10 @@ use deno_core::AsyncResult; use deno_core::BufView; use deno_core::RcRef; use deno_core::Resource; +use deno_error::JsErrorBox; use hyper::body::Body; use hyper::body::Incoming; use hyper::body::SizeHint; -use std::borrow::Cow; -use std::pin::Pin; -use std::rc::Rc; -use std::task::ready; -use std::task::Poll; /// Converts a hyper incoming body stream into a stream of [`Bytes`] that we can use to read in V8. struct ReadFuture(Incoming); @@ -82,7 +84,10 @@ impl Resource for HttpRequestBody { } fn read(self: Rc, limit: usize) -> AsyncResult { - Box::pin(HttpRequestBody::read(self, limit).map_err(Into::into)) + Box::pin( + HttpRequestBody::read(self, limit) + .map_err(|e| JsErrorBox::new("Http", e.to_string())), + ) } fn size_hint(&self) -> (u64, Option) { diff --git a/ext/http/request_properties.rs b/ext/http/request_properties.rs index 39d35a79f1..32ae33a34a 100644 --- a/ext/http/request_properties.rs +++ b/ext/http/request_properties.rs @@ -1,7 +1,13 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_core::error::AnyError; +// Copyright 2018-2025 the Deno authors. MIT license. +use std::borrow::Cow; +use std::net::Ipv4Addr; +use std::net::SocketAddr; +use std::net::SocketAddrV4; +use std::rc::Rc; + use deno_core::OpState; use deno_core::ResourceId; +use deno_error::JsErrorBox; use deno_net::raw::take_network_stream_listener_resource; use deno_net::raw::take_network_stream_resource; use deno_net::raw::NetworkStream; @@ -11,11 +17,6 @@ use deno_net::raw::NetworkStreamType; use hyper::header::HOST; use hyper::HeaderMap; use hyper::Uri; -use std::borrow::Cow; -use std::net::Ipv4Addr; -use std::net::SocketAddr; -use std::net::SocketAddrV4; -use std::rc::Rc; // TODO(mmastrac): I don't like that we have to clone this, but it's one-time setup #[derive(Clone)] @@ -49,13 +50,13 @@ pub trait HttpPropertyExtractor { fn get_listener_for_rid( state: &mut OpState, listener_rid: ResourceId, - ) -> Result; + ) -> Result; /// Given a connection [`ResourceId`], returns the [`HttpPropertyExtractor::Connection`]. fn get_connection_for_rid( state: &mut OpState, connection_rid: ResourceId, - ) -> Result; + ) -> Result; /// Determines the listener properties. fn listen_properties_from_listener( @@ -70,7 +71,7 @@ pub trait HttpPropertyExtractor { /// Accept a new [`HttpPropertyExtractor::Connection`] from the given listener [`HttpPropertyExtractor::Listener`]. async fn accept_connection_from_listener( listener: &Self::Listener, - ) -> Result; + ) -> Result; /// Determines the connection properties. fn connection_properties( @@ -102,7 +103,7 @@ impl HttpPropertyExtractor for DefaultHttpPropertyExtractor { fn get_listener_for_rid( state: &mut OpState, listener_rid: ResourceId, - ) -> Result { + ) -> Result { take_network_stream_listener_resource( &mut state.resource_table, listener_rid, @@ -112,17 +113,18 @@ impl HttpPropertyExtractor for DefaultHttpPropertyExtractor { fn get_connection_for_rid( state: &mut OpState, stream_rid: ResourceId, - ) -> Result { + ) -> Result { take_network_stream_resource(&mut state.resource_table, stream_rid) + .map_err(JsErrorBox::from_err) } async fn accept_connection_from_listener( listener: &NetworkStreamListener, - ) -> Result { + ) -> Result { listener .accept() .await - .map_err(Into::into) + .map_err(JsErrorBox::from_err) .map(|(stm, _)| stm) } diff --git a/ext/http/response_body.rs b/ext/http/response_body.rs index bac43bf3c8..6960e7c0fb 100644 --- a/ext/http/response_body.rs +++ b/ext/http/response_body.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::io::Write; use std::pin::Pin; use std::rc::Rc; @@ -9,12 +9,12 @@ use brotli::enc::encode::BrotliEncoderStateStruct; use brotli::writer::StandardAlloc; use bytes::Bytes; use bytes::BytesMut; -use deno_core::error::AnyError; use deno_core::futures::ready; use deno_core::futures::FutureExt; use deno_core::AsyncResult; use deno_core::BufView; use deno_core::Resource; +use deno_error::JsErrorBox; use flate2::write::GzEncoder; use hyper::body::Frame; use hyper::body::SizeHint; @@ -32,10 +32,10 @@ pub enum ResponseStreamResult { /// will only be returned from compression streams that require additional buffering. NoData, /// Stream failed. - Error(AnyError), + Error(JsErrorBox), } -impl From for Option, AnyError>> { +impl From for Option, JsErrorBox>> { fn from(value: ResponseStreamResult) -> Self { match value { ResponseStreamResult::EndOfStream => None, @@ -411,7 +411,9 @@ impl PollFrame for GZipResponseStream { }; let len = stm.total_out() - start_out; let res = match res { - Err(err) => ResponseStreamResult::Error(err.into()), + Err(err) => { + ResponseStreamResult::Error(JsErrorBox::generic(err.to_string())) + } Ok(flate2::Status::BufError) => { // This should not happen unreachable!("old={orig_state:?} new={state:?} buf_len={}", buf.len()); @@ -573,12 +575,14 @@ impl PollFrame for BrotliResponseStream { #[allow(clippy::print_stderr)] #[cfg(test)] mod tests { - use super::*; - use deno_core::futures::future::poll_fn; use std::hash::Hasher; use std::io::Read; use std::io::Write; + use deno_core::futures::future::poll_fn; + + use super::*; + fn zeros() -> Vec { vec![0; 1024 * 1024] } diff --git a/ext/http/service.rs b/ext/http/service.rs index ce24dea43f..f220f8d8a7 100644 --- a/ext/http/service.rs +++ b/ext/http/service.rs @@ -1,21 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use crate::request_properties::HttpConnectionProperties; -use crate::response_body::ResponseBytesInner; -use crate::response_body::ResponseStreamResult; -use deno_core::futures::ready; -use deno_core::BufView; -use deno_core::OpState; -use deno_core::ResourceId; -use http::request::Parts; -use hyper::body::Body; -use hyper::body::Frame; -use hyper::body::Incoming; -use hyper::body::SizeHint; -use hyper::header::HeaderMap; -use hyper::upgrade::OnUpgrade; - -use scopeguard::guard; -use scopeguard::ScopeGuard; +// Copyright 2018-2025 the Deno authors. MIT license. use std::cell::Cell; use std::cell::Ref; use std::cell::RefCell; @@ -27,8 +10,27 @@ use std::rc::Rc; use std::task::Context; use std::task::Poll; use std::task::Waker; + +use deno_core::futures::ready; +use deno_core::BufView; +use deno_core::OpState; +use deno_core::ResourceId; +use deno_error::JsErrorBox; +use http::request::Parts; +use hyper::body::Body; +use hyper::body::Frame; +use hyper::body::Incoming; +use hyper::body::SizeHint; +use hyper::header::HeaderMap; +use hyper::upgrade::OnUpgrade; +use scopeguard::guard; +use scopeguard::ScopeGuard; use tokio::sync::oneshot; +use crate::request_properties::HttpConnectionProperties; +use crate::response_body::ResponseBytesInner; +use crate::response_body::ResponseStreamResult; + pub type Request = hyper::Request; pub type Response = hyper::Response; @@ -528,7 +530,7 @@ pub struct HttpRecordResponse(ManuallyDrop>); impl Body for HttpRecordResponse { type Data = BufView; - type Error = deno_core::error::AnyError; + type Error = JsErrorBox; fn poll_frame( self: Pin<&mut Self>, @@ -606,16 +608,18 @@ impl Drop for HttpRecordResponse { #[cfg(test)] mod tests { - use super::*; - use crate::response_body::Compression; - use crate::response_body::ResponseBytesInner; + use std::error::Error as StdError; + use bytes::Buf; use deno_net::raw::NetworkStreamType; use hyper::body::Body; use hyper::service::service_fn; use hyper::service::HttpService; use hyper_util::rt::TokioIo; - use std::error::Error as StdError; + + use super::*; + use crate::response_body::Compression; + use crate::response_body::ResponseBytesInner; /// Execute client request on service and concurrently map the response. async fn serve_request( diff --git a/ext/http/websocket_upgrade.rs b/ext/http/websocket_upgrade.rs index af9504717e..e030f1c7ae 100644 --- a/ext/http/websocket_upgrade.rs +++ b/ext/http/websocket_upgrade.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::marker::PhantomData; @@ -12,22 +12,30 @@ use memmem::Searcher; use memmem::TwoWaySearcher; use once_cell::sync::OnceCell; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum WebSocketUpgradeError { + #[class("Http")] #[error("invalid headers")] InvalidHeaders, + #[class(generic)] #[error("{0}")] HttpParse(#[from] httparse::Error), + #[class(generic)] #[error("{0}")] Http(#[from] http::Error), + #[class(generic)] #[error("{0}")] Utf8(#[from] std::str::Utf8Error), + #[class(generic)] #[error("{0}")] InvalidHeaderName(#[from] http::header::InvalidHeaderName), + #[class(generic)] #[error("{0}")] InvalidHeaderValue(#[from] http::header::InvalidHeaderValue), + #[class("Http")] #[error("invalid HTTP status line")] InvalidHttpStatusLine, + #[class("Http")] #[error("attempted to write to completed upgrade buffer")] UpgradeBufferAlreadyCompleted, } @@ -169,9 +177,10 @@ impl WebSocketUpgrade { #[cfg(test)] mod tests { - use super::*; use hyper_v014::Body; + use super::*; + type ExpectedResponseAndHead = Option<(Response, &'static [u8])>; fn assert_response( diff --git a/ext/io/12_io.js b/ext/io/12_io.js index 3cdcb113ba..b2556649ee 100644 --- a/ext/io/12_io.js +++ b/ext/io/12_io.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Interfaces 100% copied from Go. // Documentation liberally lifted from them too. diff --git a/ext/io/Cargo.toml b/ext/io/Cargo.toml index 9298c654c1..35f138376d 100644 --- a/ext/io/Cargo.toml +++ b/ext/io/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_io" -version = "0.94.0" +version = "0.96.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -16,6 +16,7 @@ path = "lib.rs" [dependencies] async-trait.workspace = true deno_core.workspace = true +deno_error.workspace = true filetime.workspace = true fs3.workspace = true log.workspace = true diff --git a/ext/io/bi_pipe.rs b/ext/io/bi_pipe.rs index bf65d3037f..33c3267075 100644 --- a/ext/io/bi_pipe.rs +++ b/ext/io/bi_pipe.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::rc::Rc; @@ -338,6 +338,11 @@ pub fn bi_pipe_pair_raw( // TODO(nathanwhit): more granular unsafe blocks // SAFETY: win32 calls unsafe { + use std::io; + use std::os::windows::ffi::OsStrExt; + use std::path::Path; + use std::ptr; + use windows_sys::Win32::Foundation::CloseHandle; use windows_sys::Win32::Foundation::ERROR_ACCESS_DENIED; use windows_sys::Win32::Foundation::ERROR_PIPE_CONNECTED; @@ -355,11 +360,6 @@ pub fn bi_pipe_pair_raw( use windows_sys::Win32::System::Pipes::PIPE_READMODE_BYTE; use windows_sys::Win32::System::Pipes::PIPE_TYPE_BYTE; - use std::io; - use std::os::windows::ffi::OsStrExt; - use std::path::Path; - use std::ptr; - let (path, hd1) = loop { let name = format!("\\\\.\\pipe\\{}", uuid::Uuid::new_v4()); let mut path = Path::new(&name) diff --git a/ext/io/fs.rs b/ext/io/fs.rs index bd5dfd0bb9..d8767aa116 100644 --- a/ext/io/fs.rs +++ b/ext/io/fs.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::fmt::Formatter; @@ -7,18 +7,24 @@ use std::rc::Rc; use std::time::SystemTime; use std::time::UNIX_EPOCH; +use deno_core::error::ResourceError; use deno_core::BufMutView; use deno_core::BufView; use deno_core::OpState; use deno_core::ResourceHandleFd; use deno_core::ResourceId; +use deno_error::JsErrorBox; use tokio::task::JoinError; -#[derive(Debug)] +#[derive(Debug, deno_error::JsError)] pub enum FsError { + #[class(inherit)] Io(io::Error), + #[class("Busy")] FileBusy, + #[class(not_supported)] NotSupported, + #[class("NotCapable")] NotCapable(&'static str), } @@ -277,18 +283,21 @@ impl FileResource { state: &OpState, rid: ResourceId, f: F, - ) -> Result + ) -> Result where - F: FnOnce(Rc) -> Result, + F: FnOnce(Rc) -> Result, { - let resource = state.resource_table.get::(rid)?; + let resource = state + .resource_table + .get::(rid) + .map_err(JsErrorBox::from_err)?; f(resource) } pub fn get_file( state: &OpState, rid: ResourceId, - ) -> Result, deno_core::error::AnyError> { + ) -> Result, ResourceError> { let resource = state.resource_table.get::(rid)?; Ok(resource.file()) } @@ -297,9 +306,9 @@ impl FileResource { state: &OpState, rid: ResourceId, f: F, - ) -> Result + ) -> Result where - F: FnOnce(Rc) -> Result, + F: FnOnce(Rc) -> Result, { Self::with_resource(state, rid, |r| f(r.file.clone())) } @@ -321,7 +330,7 @@ impl deno_core::Resource for FileResource { .clone() .read(limit) .await - .map_err(|err| err.into()) + .map_err(JsErrorBox::from_err) }) } @@ -335,7 +344,7 @@ impl deno_core::Resource for FileResource { .clone() .read_byob(buf) .await - .map_err(|err| err.into()) + .map_err(JsErrorBox::from_err) }) } @@ -344,7 +353,12 @@ impl deno_core::Resource for FileResource { buf: BufView, ) -> deno_core::AsyncResult { Box::pin(async move { - self.file.clone().write(buf).await.map_err(|err| err.into()) + self + .file + .clone() + .write(buf) + .await + .map_err(JsErrorBox::from_err) }) } @@ -355,22 +369,27 @@ impl deno_core::Resource for FileResource { .clone() .write_all(buf) .await - .map_err(|err| err.into()) + .map_err(JsErrorBox::from_err) }) } fn read_byob_sync( self: Rc, data: &mut [u8], - ) -> Result { - self.file.clone().read_sync(data).map_err(|err| err.into()) + ) -> Result { + self + .file + .clone() + .read_sync(data) + .map_err(JsErrorBox::from_err) } - fn write_sync( - self: Rc, - data: &[u8], - ) -> Result { - self.file.clone().write_sync(data).map_err(|err| err.into()) + fn write_sync(self: Rc, data: &[u8]) -> Result { + self + .file + .clone() + .write_sync(data) + .map_err(JsErrorBox::from_err) } fn backing_fd(self: Rc) -> Option { diff --git a/ext/io/lib.rs b/ext/io/lib.rs index 873fccd7b8..1f92ae5c8b 100644 --- a/ext/io/lib.rs +++ b/ext/io/lib.rs @@ -1,5 +1,23 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. +use std::borrow::Cow; +use std::cell::RefCell; +use std::fs::File as StdFile; +use std::future::Future; +use std::io; +use std::io::ErrorKind; +use std::io::Read; +use std::io::Seek; +use std::io::Write; +#[cfg(unix)] +use std::os::unix::io::FromRawFd; +#[cfg(windows)] +use std::os::windows::io::FromRawHandle; +use std::rc::Rc; +#[cfg(windows)] +use std::sync::Arc; + +use deno_core::futures::TryFutureExt; use deno_core::op2; use deno_core::unsync::spawn_blocking; use deno_core::unsync::TaskQueue; @@ -15,46 +33,27 @@ use deno_core::RcRef; use deno_core::Resource; use deno_core::ResourceHandle; use deno_core::ResourceHandleFd; +use deno_error::JsErrorBox; use fs::FileResource; use fs::FsError; use fs::FsResult; use fs::FsStat; use fs3::FileExt; use once_cell::sync::Lazy; -use std::borrow::Cow; -use std::cell::RefCell; -use std::fs::File as StdFile; -use std::future::Future; -use std::io; -use std::io::ErrorKind; -use std::io::Read; -use std::io::Seek; -use std::io::Write; -use std::rc::Rc; +#[cfg(windows)] +use parking_lot::Condvar; +#[cfg(windows)] +use parking_lot::Mutex; use tokio::io::AsyncRead; use tokio::io::AsyncReadExt; use tokio::io::AsyncWrite; use tokio::io::AsyncWriteExt; use tokio::process; - -#[cfg(unix)] -use std::os::unix::io::FromRawFd; - -#[cfg(windows)] -use std::os::windows::io::FromRawHandle; #[cfg(windows)] use winapi::um::processenv::GetStdHandle; #[cfg(windows)] use winapi::um::winbase; -use deno_core::futures::TryFutureExt; -#[cfg(windows)] -use parking_lot::Condvar; -#[cfg(windows)] -use parking_lot::Mutex; -#[cfg(windows)] -use std::sync::Arc; - pub mod fs; mod pipe; #[cfg(windows)] @@ -62,19 +61,18 @@ mod winpipe; mod bi_pipe; -pub use pipe::pipe; -pub use pipe::AsyncPipeRead; -pub use pipe::AsyncPipeWrite; -pub use pipe::PipeRead; -pub use pipe::PipeWrite; -pub use pipe::RawPipeHandle; - pub use bi_pipe::bi_pipe_pair_raw; pub use bi_pipe::BiPipe; pub use bi_pipe::BiPipeRead; pub use bi_pipe::BiPipeResource; pub use bi_pipe::BiPipeWrite; pub use bi_pipe::RawBiPipeHandle; +pub use pipe::pipe; +pub use pipe::AsyncPipeRead; +pub use pipe::AsyncPipeWrite; +pub use pipe::PipeRead; +pub use pipe::PipeWrite; +pub use pipe::RawPipeHandle; /// Abstraction over `AsRawFd` (unix) and `AsRawHandle` (windows) pub trait AsRawIoHandle { @@ -417,7 +415,7 @@ impl Resource for ChildStdinResource { deno_core::impl_writable!(); fn shutdown(self: Rc) -> AsyncResult<()> { - Box::pin(self.shutdown().map_err(|e| e.into())) + Box::pin(self.shutdown().map_err(JsErrorBox::from_err)) } } @@ -1010,9 +1008,11 @@ pub fn op_print( state: &mut OpState, #[string] msg: &str, is_err: bool, -) -> Result<(), deno_core::error::AnyError> { +) -> Result<(), JsErrorBox> { let rid = if is_err { 2 } else { 1 }; FileResource::with_file(state, rid, move |file| { - Ok(file.write_all_sync(msg.as_bytes())?) + file + .write_all_sync(msg.as_bytes()) + .map_err(JsErrorBox::from_err) }) } diff --git a/ext/io/pipe.rs b/ext/io/pipe.rs index e0e019e277..5172bea10e 100644 --- a/ext/io/pipe.rs +++ b/ext/io/pipe.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::io; use std::pin::Pin; use std::process::Stdio; @@ -299,13 +299,14 @@ pub fn pipe_impl() -> io::Result<(PipeRead, PipeWrite)> { #[cfg(test)] mod tests { - use super::*; - use std::io::Read; use std::io::Write; + use tokio::io::AsyncReadExt; use tokio::io::AsyncWriteExt; + use super::*; + #[test] fn test_pipe() { let (mut read, mut write) = pipe().unwrap(); diff --git a/ext/io/winpipe.rs b/ext/io/winpipe.rs index 01d018008d..600eda4091 100644 --- a/ext/io/winpipe.rs +++ b/ext/io/winpipe.rs @@ -1,10 +1,11 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use rand::thread_rng; -use rand::RngCore; +// Copyright 2018-2025 the Deno authors. MIT license. use std::io; use std::os::windows::io::RawHandle; use std::sync::atomic::AtomicU32; use std::sync::atomic::Ordering; + +use rand::thread_rng; +use rand::RngCore; use winapi::shared::minwindef::DWORD; use winapi::um::errhandlingapi::GetLastError; use winapi::um::fileapi::CreateFileA; @@ -116,7 +117,6 @@ fn create_named_pipe_inner() -> io::Result<(RawHandle, RawHandle)> { #[cfg(test)] mod tests { - use super::*; use std::fs::File; use std::io::Read; use std::io::Write; @@ -124,6 +124,8 @@ mod tests { use std::sync::Arc; use std::sync::Barrier; + use super::*; + #[test] fn make_named_pipe() { let (server, client) = create_named_pipe().unwrap(); diff --git a/ext/kv/01_db.ts b/ext/kv/01_db.ts index c644ff7121..37d4c58c11 100644 --- a/ext/kv/01_db.ts +++ b/ext/kv/01_db.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, primordials } from "ext:core/mod.js"; const { @@ -77,7 +77,9 @@ const maxQueueBackoffInterval = 60 * 60 * 1000; function validateBackoffSchedule(backoffSchedule: number[]) { if (backoffSchedule.length > maxQueueBackoffIntervals) { - throw new TypeError("Invalid backoffSchedule"); + throw new TypeError( + `Invalid backoffSchedule, max ${maxQueueBackoffIntervals} intervals allowed`, + ); } for (let i = 0; i < backoffSchedule.length; ++i) { const interval = backoffSchedule[i]; @@ -85,7 +87,9 @@ function validateBackoffSchedule(backoffSchedule: number[]) { interval < 0 || interval > maxQueueBackoffInterval || NumberIsNaN(interval) ) { - throw new TypeError("Invalid backoffSchedule"); + throw new TypeError( + `Invalid backoffSchedule, interval at index ${i} is invalid`, + ); } } } diff --git a/ext/kv/Cargo.toml b/ext/kv/Cargo.toml index c97aa75552..6f7fcf8f54 100644 --- a/ext/kv/Cargo.toml +++ b/ext/kv/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_kv" -version = "0.92.0" +version = "0.94.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -21,6 +21,7 @@ boxed_error.workspace = true bytes.workspace = true chrono = { workspace = true, features = ["now"] } deno_core.workspace = true +deno_error.workspace = true deno_fetch.workspace = true deno_path_util.workspace = true deno_permissions.workspace = true diff --git a/ext/kv/config.rs b/ext/kv/config.rs index 7166bcbcc2..f762a74578 100644 --- a/ext/kv/config.rs +++ b/ext/kv/config.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. #[derive(Clone, Copy, Debug)] pub struct KvConfig { diff --git a/ext/kv/dynamic.rs b/ext/kv/dynamic.rs index 6d545d79f6..923e3cd4d8 100644 --- a/ext/kv/dynamic.rs +++ b/ext/kv/dynamic.rs @@ -1,8 +1,15 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::cell::RefCell; use std::rc::Rc; +use async_trait::async_trait; +use deno_core::OpState; +use deno_error::JsErrorBox; +use denokv_proto::CommitResult; +use denokv_proto::ReadRangeOutput; +use denokv_proto::WatchStream; + use crate::remote::RemoteDbHandlerPermissions; use crate::sqlite::SqliteDbHandler; use crate::sqlite::SqliteDbHandlerPermissions; @@ -12,13 +19,6 @@ use crate::DatabaseHandler; use crate::QueueMessageHandle; use crate::ReadRange; use crate::SnapshotReadOptions; -use async_trait::async_trait; -use deno_core::error::type_error; -use deno_core::error::AnyError; -use deno_core::OpState; -use denokv_proto::CommitResult; -use denokv_proto::ReadRangeOutput; -use denokv_proto::WatchStream; pub struct MultiBackendDbHandler { backends: Vec<(&'static [&'static str], Box)>, @@ -62,7 +62,7 @@ impl DatabaseHandler for MultiBackendDbHandler { &self, state: Rc>, path: Option, - ) -> Result { + ) -> Result { for (prefixes, handler) in &self.backends { for &prefix in *prefixes { if prefix.is_empty() { @@ -76,7 +76,7 @@ impl DatabaseHandler for MultiBackendDbHandler { } } } - Err(type_error(format!( + Err(JsErrorBox::type_error(format!( "No backend supports the given path: {:?}", path ))) @@ -89,7 +89,7 @@ pub trait DynamicDbHandler { &self, state: Rc>, path: Option, - ) -> Result; + ) -> Result; } #[async_trait(?Send)] @@ -100,7 +100,7 @@ impl DatabaseHandler for Box { &self, state: Rc>, path: Option, - ) -> Result { + ) -> Result { (**self).dyn_open(state, path).await } } @@ -115,7 +115,7 @@ where &self, state: Rc>, path: Option, - ) -> Result { + ) -> Result { Ok(RcDynamicDb(Rc::new(self.open(state, path).await?))) } } @@ -126,16 +126,16 @@ pub trait DynamicDb { &self, requests: Vec, options: SnapshotReadOptions, - ) -> Result, AnyError>; + ) -> Result, JsErrorBox>; async fn dyn_atomic_write( &self, write: AtomicWrite, - ) -> Result, AnyError>; + ) -> Result, JsErrorBox>; async fn dyn_dequeue_next_message( &self, - ) -> Result>, AnyError>; + ) -> Result>, JsErrorBox>; fn dyn_watch(&self, keys: Vec>) -> WatchStream; @@ -153,20 +153,20 @@ impl Database for RcDynamicDb { &self, requests: Vec, options: SnapshotReadOptions, - ) -> Result, AnyError> { + ) -> Result, JsErrorBox> { (*self.0).dyn_snapshot_read(requests, options).await } async fn atomic_write( &self, write: AtomicWrite, - ) -> Result, AnyError> { + ) -> Result, JsErrorBox> { (*self.0).dyn_atomic_write(write).await } async fn dequeue_next_message( &self, - ) -> Result>, AnyError> { + ) -> Result>, JsErrorBox> { (*self.0).dyn_dequeue_next_message().await } @@ -189,20 +189,20 @@ where &self, requests: Vec, options: SnapshotReadOptions, - ) -> Result, AnyError> { + ) -> Result, JsErrorBox> { Ok(self.snapshot_read(requests, options).await?) } async fn dyn_atomic_write( &self, write: AtomicWrite, - ) -> Result, AnyError> { + ) -> Result, JsErrorBox> { Ok(self.atomic_write(write).await?) } async fn dyn_dequeue_next_message( &self, - ) -> Result>, AnyError> { + ) -> Result>, JsErrorBox> { Ok( self .dequeue_next_message() diff --git a/ext/kv/interface.rs b/ext/kv/interface.rs index 9737a9366d..df106fde78 100644 --- a/ext/kv/interface.rs +++ b/ext/kv/interface.rs @@ -1,11 +1,11 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::cell::RefCell; use std::rc::Rc; use async_trait::async_trait; -use deno_core::error::AnyError; use deno_core::OpState; +use deno_error::JsErrorBox; use denokv_proto::Database; #[async_trait(?Send)] @@ -16,5 +16,5 @@ pub trait DatabaseHandler { &self, state: Rc>, path: Option, - ) -> Result; + ) -> Result; } diff --git a/ext/kv/lib.rs b/ext/kv/lib.rs index ce7509721a..61458888a9 100644 --- a/ext/kv/lib.rs +++ b/ext/kv/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. pub mod config; pub mod dynamic; @@ -17,7 +17,6 @@ use base64::Engine; use boxed_error::Boxed; use chrono::DateTime; use chrono::Utc; -use deno_core::error::get_custom_error_class; use deno_core::futures::StreamExt; use deno_core::op2; use deno_core::serde_v8::AnyValue; @@ -32,6 +31,8 @@ use deno_core::RcRef; use deno_core::Resource; use deno_core::ResourceId; use deno_core::ToJsBuffer; +use deno_error::JsErrorBox; +use deno_error::JsErrorClass; use denokv_proto::decode_key; use denokv_proto::encode_key; use denokv_proto::AtomicWrite; @@ -115,65 +116,93 @@ impl Resource for DatabaseWatcherResource { } } -#[derive(Debug, Boxed)] +#[derive(Debug, Boxed, deno_error::JsError)] pub struct KvError(pub Box); -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum KvErrorKind { + #[class(inherit)] #[error(transparent)] - DatabaseHandler(deno_core::error::AnyError), + DatabaseHandler(JsErrorBox), + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] deno_core::error::ResourceError), + #[class(type)] #[error("Too many ranges (max {0})")] TooManyRanges(usize), + #[class(type)] #[error("Too many entries (max {0})")] TooManyEntries(usize), + #[class(type)] #[error("Too many checks (max {0})")] TooManyChecks(usize), + #[class(type)] #[error("Too many mutations (max {0})")] TooManyMutations(usize), + #[class(type)] #[error("Too many keys (max {0})")] TooManyKeys(usize), + #[class(type)] #[error("limit must be greater than 0")] InvalidLimit, + #[class(type)] #[error("Invalid boundary key")] InvalidBoundaryKey, + #[class(type)] #[error("Key too large for read (max {0} bytes)")] KeyTooLargeToRead(usize), + #[class(type)] #[error("Key too large for write (max {0} bytes)")] KeyTooLargeToWrite(usize), + #[class(type)] #[error("Total mutation size too large (max {0} bytes)")] TotalMutationTooLarge(usize), + #[class(type)] #[error("Total key size too large (max {0} bytes)")] TotalKeyTooLarge(usize), + #[class(inherit)] #[error(transparent)] - Kv(deno_core::error::AnyError), + Kv(JsErrorBox), + #[class(inherit)] #[error(transparent)] Io(#[from] std::io::Error), + #[class(type)] #[error("Queue message not found")] QueueMessageNotFound, + #[class(type)] #[error("Start key is not in the keyspace defined by prefix")] StartKeyNotInKeyspace, + #[class(type)] #[error("End key is not in the keyspace defined by prefix")] EndKeyNotInKeyspace, + #[class(type)] #[error("Start key is greater than end key")] StartKeyGreaterThanEndKey, + #[class(inherit)] #[error("Invalid check")] InvalidCheck(#[source] KvCheckError), + #[class(inherit)] #[error("Invalid mutation")] InvalidMutation(#[source] KvMutationError), + #[class(inherit)] #[error("Invalid enqueue")] InvalidEnqueue(#[source] std::io::Error), + #[class(type)] #[error("key cannot be empty")] - EmptyKey, // TypeError + EmptyKey, + #[class(type)] #[error("Value too large (max {0} bytes)")] - ValueTooLarge(usize), // TypeError + ValueTooLarge(usize), + #[class(type)] #[error("enqueue payload too large (max {0} bytes)")] - EnqueuePayloadTooLarge(usize), // TypeError + EnqueuePayloadTooLarge(usize), + #[class(type)] #[error("invalid cursor")] InvalidCursor, + #[class(type)] #[error("cursor out of bounds")] CursorOutOfBounds, + #[class(type)] #[error("Invalid range")] InvalidRange, } @@ -418,7 +447,7 @@ where match state.resource_table.get::>(rid) { Ok(resource) => resource, Err(err) => { - if get_custom_error_class(&err) == Some("BadResource") { + if err.get_class() == "BadResource" { return Ok(None); } else { return Err(KvErrorKind::Resource(err).into_box()); @@ -568,10 +597,12 @@ where Ok(()) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum KvCheckError { + #[class(type)] #[error("invalid versionstamp")] InvalidVersionstamp, + #[class(inherit)] #[error(transparent)] Io(std::io::Error), } @@ -597,14 +628,22 @@ fn check_from_v8(value: V8KvCheck) -> Result { }) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum KvMutationError { + #[class(generic)] #[error(transparent)] BigInt(#[from] num_bigint::TryFromBigIntError), + #[class(inherit)] #[error(transparent)] - Io(#[from] std::io::Error), + Io( + #[from] + #[inherit] + std::io::Error, + ), + #[class(type)] #[error("Invalid mutation '{0}' with value")] InvalidMutationWithValue(String), + #[class(type)] #[error("Invalid mutation '{0}' without value")] InvalidMutationWithoutValue(String), } diff --git a/ext/kv/remote.rs b/ext/kv/remote.rs index 891786e319..e5a07ad96c 100644 --- a/ext/kv/remote.rs +++ b/ext/kv/remote.rs @@ -1,18 +1,16 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::cell::RefCell; use std::marker::PhantomData; use std::rc::Rc; use std::sync::Arc; -use crate::DatabaseHandler; use anyhow::Context; use async_trait::async_trait; use bytes::Bytes; -use deno_core::error::type_error; -use deno_core::error::AnyError; use deno_core::futures::Stream; use deno_core::OpState; +use deno_error::JsErrorBox; use deno_fetch::create_http_client; use deno_fetch::CreateHttpClientOptions; use deno_permissions::PermissionCheckError; @@ -27,6 +25,8 @@ use denokv_remote::RemoteTransport; use http_body_util::BodyExt; use url::Url; +use crate::DatabaseHandler; + #[derive(Clone)] pub struct HttpOptions { pub user_agent: String, @@ -37,7 +37,7 @@ pub struct HttpOptions { } impl HttpOptions { - pub fn root_cert_store(&self) -> Result, AnyError> { + pub fn root_cert_store(&self) -> Result, JsErrorBox> { Ok(match &self.root_cert_store_provider { Some(provider) => Some(provider.get_or_try_init()?.clone()), None => None, @@ -101,12 +101,12 @@ impl Clone for PermissionChecker

{ impl denokv_remote::RemotePermissions for PermissionChecker

{ - fn check_net_url(&self, url: &Url) -> Result<(), anyhow::Error> { + fn check_net_url(&self, url: &Url) -> Result<(), JsErrorBox> { let mut state = self.state.borrow_mut(); let permissions = state.borrow_mut::

(); permissions .check_net_url(url, "Deno.openKv") - .map_err(Into::into) + .map_err(JsErrorBox::from_err) } } @@ -121,31 +121,43 @@ impl RemoteTransport for FetchClient { url: Url, headers: http::HeaderMap, body: Bytes, - ) -> Result<(Url, http::StatusCode, Self::Response), anyhow::Error> { + ) -> Result<(Url, http::StatusCode, Self::Response), JsErrorBox> { let body = deno_fetch::ReqBody::full(body); let mut req = http::Request::new(body); *req.method_mut() = http::Method::POST; - *req.uri_mut() = url.as_str().parse()?; + *req.uri_mut() = + url.as_str().parse().map_err(|e: http::uri::InvalidUri| { + JsErrorBox::type_error(e.to_string()) + })?; *req.headers_mut() = headers; - let res = self.0.clone().send(req).await?; + let res = self + .0 + .clone() + .send(req) + .await + .map_err(JsErrorBox::from_err)?; let status = res.status(); Ok((url, status, FetchResponse(res))) } } impl RemoteResponse for FetchResponse { - async fn bytes(self) -> Result { + async fn bytes(self) -> Result { Ok(self.0.collect().await?.to_bytes()) } fn stream( self, - ) -> impl Stream> + Send + Sync { + ) -> impl Stream> + Send + Sync { self.0.into_body().into_data_stream() } - async fn text(self) -> Result { + async fn text(self) -> Result { let bytes = self.bytes().await?; - Ok(std::str::from_utf8(&bytes)?.into()) + Ok( + std::str::from_utf8(&bytes) + .map_err(JsErrorBox::from_err)? + .into(), + ) } } @@ -159,29 +171,36 @@ impl DatabaseHandler &self, state: Rc>, path: Option, - ) -> Result { + ) -> Result { const ENV_VAR_NAME: &str = "DENO_KV_ACCESS_TOKEN"; let Some(url) = path else { - return Err(type_error("Missing database url")); + return Err(JsErrorBox::type_error("Missing database url")); }; let Ok(parsed_url) = Url::parse(&url) else { - return Err(type_error(format!("Invalid database url: {}", url))); + return Err(JsErrorBox::type_error(format!( + "Invalid database url: {}", + url + ))); }; { let mut state = state.borrow_mut(); let permissions = state.borrow_mut::

(); - permissions.check_env(ENV_VAR_NAME)?; - permissions.check_net_url(&parsed_url, "Deno.openKv")?; + permissions + .check_env(ENV_VAR_NAME) + .map_err(JsErrorBox::from_err)?; + permissions + .check_net_url(&parsed_url, "Deno.openKv") + .map_err(JsErrorBox::from_err)?; } let access_token = std::env::var(ENV_VAR_NAME) .map_err(anyhow::Error::from) .with_context(|| { "Missing DENO_KV_ACCESS_TOKEN environment variable. Please set it to your access token from https://dash.deno.com/account." - })?; + }).map_err(|e| JsErrorBox::generic(e.to_string()))?; let metadata_endpoint = MetadataEndpoint { url: parsed_url.clone(), @@ -210,7 +229,8 @@ impl DatabaseHandler http2: true, client_builder_hook: None, }, - )?; + ) + .map_err(JsErrorBox::from_err)?; let fetch_client = FetchClient(client); let permissions = PermissionChecker { diff --git a/ext/kv/sqlite.rs b/ext/kv/sqlite.rs index 9de5209275..8be042eef0 100644 --- a/ext/kv/sqlite.rs +++ b/ext/kv/sqlite.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::cell::RefCell; @@ -13,12 +13,10 @@ use std::sync::Arc; use std::sync::Mutex; use std::sync::OnceLock; -use crate::DatabaseHandler; use async_trait::async_trait; -use deno_core::error::type_error; -use deno_core::error::AnyError; use deno_core::unsync::spawn_blocking; use deno_core::OpState; +use deno_error::JsErrorBox; use deno_path_util::normalize_path; use deno_permissions::PermissionCheckError; pub use denokv_sqlite::SqliteBackendError; @@ -27,6 +25,8 @@ use denokv_sqlite::SqliteNotifier; use rand::SeedableRng; use rusqlite::OpenFlags; +use crate::DatabaseHandler; + static SQLITE_NOTIFIERS_MAP: OnceLock>> = OnceLock::new(); @@ -84,6 +84,12 @@ impl SqliteDbHandler

{ } } +deno_error::js_error_wrapper!( + SqliteBackendError, + JsSqliteBackendError, + "TypeError" +); + #[async_trait(?Send)] impl DatabaseHandler for SqliteDbHandler

{ type DB = denokv_sqlite::Sqlite; @@ -92,12 +98,12 @@ impl DatabaseHandler for SqliteDbHandler

{ &self, state: Rc>, path: Option, - ) -> Result { + ) -> Result { #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] fn validate_path( state: &RefCell, path: Option, - ) -> Result, AnyError> { + ) -> Result, JsErrorBox> { let Some(path) = path else { return Ok(None); }; @@ -105,18 +111,22 @@ impl DatabaseHandler for SqliteDbHandler

{ return Ok(Some(path)); } if path.is_empty() { - return Err(type_error("Filename cannot be empty")); + return Err(JsErrorBox::type_error("Filename cannot be empty")); } if path.starts_with(':') { - return Err(type_error( + return Err(JsErrorBox::type_error( "Filename cannot start with ':' unless prefixed with './'", )); } { let mut state = state.borrow_mut(); let permissions = state.borrow_mut::

(); - let path = permissions.check_read(&path, "Deno.openKv")?; - let path = permissions.check_write(&path, "Deno.openKv")?; + let path = permissions + .check_read(&path, "Deno.openKv") + .map_err(JsErrorBox::from_err)?; + let path = permissions + .check_write(&path, "Deno.openKv") + .map_err(JsErrorBox::from_err)?; Ok(Some(path.to_string_lossy().to_string())) } } @@ -137,7 +147,7 @@ impl DatabaseHandler for SqliteDbHandler

{ let flags = OpenFlags::default().difference(OpenFlags::SQLITE_OPEN_URI); let resolved_path = canonicalize_path(&PathBuf::from(path)) - .map_err(anyhow::Error::from)?; + .map_err(JsErrorBox::from_err)?; let path = path.to_string(); ( Arc::new(move || { @@ -147,7 +157,7 @@ impl DatabaseHandler for SqliteDbHandler

{ ) } (None, Some(path)) => { - std::fs::create_dir_all(path).map_err(anyhow::Error::from)?; + std::fs::create_dir_all(path).map_err(JsErrorBox::from_err)?; let path = path.join("kv.sqlite3"); let path2 = path.clone(); ( @@ -161,7 +171,8 @@ impl DatabaseHandler for SqliteDbHandler

{ }) }) .await - .unwrap()?; + .unwrap() + .map_err(JsErrorBox::from_err)?; let notifier = if let Some(notifier_key) = notifier_key { SQLITE_NOTIFIERS_MAP @@ -184,8 +195,11 @@ impl DatabaseHandler for SqliteDbHandler

{ denokv_sqlite::Sqlite::new( move || { - let conn = conn_gen()?; - conn.pragma_update(None, "journal_mode", "wal")?; + let conn = + conn_gen().map_err(|e| JsErrorBox::generic(e.to_string()))?; + conn + .pragma_update(None, "journal_mode", "wal") + .map_err(|e| JsErrorBox::generic(e.to_string()))?; Ok(( conn, match versionstamp_rng_seed { @@ -197,11 +211,12 @@ impl DatabaseHandler for SqliteDbHandler

{ notifier, config, ) + .map_err(|e| JsErrorBox::generic(e.to_string())) } } /// Same as Path::canonicalize, but also handles non-existing paths. -fn canonicalize_path(path: &Path) -> Result { +fn canonicalize_path(path: &Path) -> Result { let path = normalize_path(path); let mut path = path; let mut names_stack = Vec::new(); @@ -224,7 +239,7 @@ fn canonicalize_path(path: &Path) -> Result { path.clone_from(¤t_dir); } } - Err(err) => return Err(err.into()), + Err(err) => return Err(err), } } } diff --git a/ext/napi/Cargo.toml b/ext/napi/Cargo.toml index 5d726b3e31..916f0c4da5 100644 --- a/ext/napi/Cargo.toml +++ b/ext/napi/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_napi" -version = "0.115.0" +version = "0.117.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -15,6 +15,7 @@ path = "lib.rs" [dependencies] deno_core.workspace = true +deno_error.workspace = true deno_permissions.workspace = true libc.workspace = true libloading = { version = "0.7" } diff --git a/ext/napi/build.rs b/ext/napi/build.rs index 8705830a95..71686d6451 100644 --- a/ext/napi/build.rs +++ b/ext/napi/build.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. fn main() { let symbols_file_name = match std::env::consts::OS { diff --git a/ext/napi/function.rs b/ext/napi/function.rs index a128ad7900..681f014421 100644 --- a/ext/napi/function.rs +++ b/ext/napi/function.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use crate::*; #[repr(C)] diff --git a/ext/napi/js_native_api.rs b/ext/napi/js_native_api.rs index 53a12d6eba..80579081f3 100644 --- a/ext/napi/js_native_api.rs +++ b/ext/napi/js_native_api.rs @@ -1,12 +1,14 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. #![allow(non_upper_case_globals)] #![deny(unsafe_op_in_unsafe_fn)] const NAPI_VERSION: u32 = 9; -use crate::*; +use std::ptr::NonNull; + use libc::INT_MAX; +use napi_sym::napi_sym; use super::util::check_new_from_utf8; use super::util::check_new_from_utf8_len; @@ -20,8 +22,7 @@ use crate::check_env; use crate::function::create_function; use crate::function::create_function_template; use crate::function::CallbackInfo; -use napi_sym::napi_sym; -use std::ptr::NonNull; +use crate::*; #[derive(Debug, Clone, Copy, PartialEq)] enum ReferenceOwnership { diff --git a/ext/napi/lib.rs b/ext/napi/lib.rs index 6db6af48a2..1db20ef647 100644 --- a/ext/napi/lib.rs +++ b/ext/napi/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. #![allow(non_camel_case_types)] #![allow(non_upper_case_globals)] @@ -22,49 +22,51 @@ pub mod util; pub mod uv; use core::ptr::NonNull; -use deno_core::op2; -use deno_core::parking_lot::RwLock; -use deno_core::url::Url; -use deno_core::ExternalOpsTracker; -use deno_core::OpState; -use deno_core::V8CrossThreadTaskSpawner; use std::cell::RefCell; use std::collections::HashMap; -use std::path::PathBuf; -use std::rc::Rc; -use std::thread_local; - -#[derive(Debug, thiserror::Error)] -pub enum NApiError { - #[error("Invalid path")] - InvalidPath, - #[error(transparent)] - LibLoading(#[from] libloading::Error), - #[error("Unable to find register Node-API module at {}", .0.display())] - ModuleNotFound(PathBuf), - #[error(transparent)] - Permission(#[from] PermissionCheckError), -} - -#[cfg(unix)] -use libloading::os::unix::*; - -#[cfg(windows)] -use libloading::os::windows::*; - -// Expose common stuff for ease of use. -// `use deno_napi::*` -pub use deno_core::v8; -use deno_permissions::PermissionCheckError; pub use std::ffi::CStr; pub use std::os::raw::c_char; pub use std::os::raw::c_void; +use std::path::PathBuf; pub use std::ptr; +use std::rc::Rc; +use std::thread_local; + +use deno_core::op2; +use deno_core::parking_lot::RwLock; +use deno_core::url::Url; +// Expose common stuff for ease of use. +// `use deno_napi::*` +pub use deno_core::v8; +use deno_core::ExternalOpsTracker; +use deno_core::OpState; +use deno_core::V8CrossThreadTaskSpawner; +use deno_permissions::PermissionCheckError; +#[cfg(unix)] +use libloading::os::unix::*; +#[cfg(windows)] +use libloading::os::windows::*; pub use value::napi_value; pub mod function; mod value; +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum NApiError { + #[class(type)] + #[error("Invalid path")] + InvalidPath, + #[class(type)] + #[error(transparent)] + LibLoading(#[from] libloading::Error), + #[class(type)] + #[error("Unable to find register Node-API module at {}", .0.display())] + ModuleNotFound(PathBuf), + #[class(inherit)] + #[error(transparent)] + Permission(#[from] PermissionCheckError), +} + pub type napi_status = i32; pub type napi_env = *mut c_void; pub type napi_callback_info = *mut c_void; diff --git a/ext/napi/node_api.rs b/ext/napi/node_api.rs index 2ca5c8d0b4..13ea0b3e62 100644 --- a/ext/napi/node_api.rs +++ b/ext/napi/node_api.rs @@ -1,7 +1,18 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. #![deny(unsafe_op_in_unsafe_fn)] +use std::sync::atomic::AtomicBool; +use std::sync::atomic::AtomicU8; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; +use std::sync::Arc; + +use deno_core::parking_lot::Condvar; +use deno_core::parking_lot::Mutex; +use deno_core::V8CrossThreadTaskSpawner; +use napi_sym::napi_sym; + use super::util::get_array_buffer_ptr; use super::util::make_external_backing_store; use super::util::napi_clear_last_error; @@ -10,15 +21,6 @@ use super::util::SendPtr; use crate::check_arg; use crate::check_env; use crate::*; -use deno_core::parking_lot::Condvar; -use deno_core::parking_lot::Mutex; -use deno_core::V8CrossThreadTaskSpawner; -use napi_sym::napi_sym; -use std::sync::atomic::AtomicBool; -use std::sync::atomic::AtomicU8; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering; -use std::sync::Arc; #[napi_sym] fn napi_module_register(module: *const NapiModule) -> napi_status { diff --git a/ext/napi/sym/Cargo.toml b/ext/napi/sym/Cargo.toml index 22228bd2f6..198e52474b 100644 --- a/ext/napi/sym/Cargo.toml +++ b/ext/napi/sym/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "napi_sym" -version = "0.114.0" +version = "0.116.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/napi/sym/lib.rs b/ext/napi/sym/lib.rs index e2826306b9..94444d8541 100644 --- a/ext/napi/sym/lib.rs +++ b/ext/napi/sym/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use proc_macro::TokenStream; use quote::quote; diff --git a/ext/napi/util.rs b/ext/napi/util.rs index 21e9d433aa..a913eade16 100644 --- a/ext/napi/util.rs +++ b/ext/napi/util.rs @@ -1,7 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use crate::*; +// Copyright 2018-2025 the Deno authors. MIT license. use libc::INT_MAX; +use crate::*; + #[repr(transparent)] pub(crate) struct SendPtr(pub *const T); diff --git a/ext/napi/uv.rs b/ext/napi/uv.rs index ea6b539665..ef4ac495c3 100644 --- a/ext/napi/uv.rs +++ b/ext/napi/uv.rs @@ -1,10 +1,12 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::*; -use deno_core::parking_lot::Mutex; use std::mem::MaybeUninit; use std::ptr::addr_of_mut; +use deno_core::parking_lot::Mutex; + +use crate::*; + fn assert_ok(res: c_int) -> c_int { if res != 0 { log::error!("bad result in uv polyfill: {res}"); @@ -15,11 +17,12 @@ fn assert_ok(res: c_int) -> c_int { res } +use std::ffi::c_int; + use js_native_api::napi_create_string_utf8; use node_api::napi_create_async_work; use node_api::napi_delete_async_work; use node_api::napi_queue_async_work; -use std::ffi::c_int; const UV_MUTEX_SIZE: usize = { #[cfg(unix)] diff --git a/ext/napi/value.rs b/ext/napi/value.rs index 71beac07e2..851a56e963 100644 --- a/ext/napi/value.rs +++ b/ext/napi/value.rs @@ -1,11 +1,12 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use deno_core::v8; use std::mem::transmute; use std::ops::Deref; use std::os::raw::c_void; use std::ptr::NonNull; +use deno_core::v8; + /// An FFI-opaque, nullable wrapper around v8::Local. /// rusty_v8 Local handle cannot be empty but napi_value can be. #[repr(transparent)] diff --git a/ext/net/01_net.js b/ext/net/01_net.js index c3e5f9e5ca..3afbd031e6 100644 --- a/ext/net/01_net.js +++ b/ext/net/01_net.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, primordials } from "ext:core/mod.js"; const { diff --git a/ext/net/02_tls.js b/ext/net/02_tls.js index 6dad965590..21d5512ebd 100644 --- a/ext/net/02_tls.js +++ b/ext/net/02_tls.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, internals, primordials } from "ext:core/mod.js"; const { internalRidSymbol } = core; diff --git a/ext/net/03_quic.js b/ext/net/03_quic.js index e100e7bd64..d74d356edb 100644 --- a/ext/net/03_quic.js +++ b/ext/net/03_quic.js @@ -1,33 +1,42 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, primordials } from "ext:core/mod.js"; import { - op_quic_accept, - op_quic_accept_bi, - op_quic_accept_incoming, - op_quic_accept_uni, - op_quic_close_connection, - op_quic_close_endpoint, - op_quic_connect, + op_quic_connecting_0rtt, + op_quic_connecting_1rtt, + op_quic_connection_accept_bi, + op_quic_connection_accept_uni, + op_quic_connection_close, op_quic_connection_closed, + op_quic_connection_get_max_datagram_size, op_quic_connection_get_protocol, op_quic_connection_get_remote_addr, + op_quic_connection_get_server_name, + op_quic_connection_handshake, + op_quic_connection_open_bi, + op_quic_connection_open_uni, + op_quic_connection_read_datagram, + op_quic_connection_send_datagram, + op_quic_endpoint_close, + op_quic_endpoint_connect, + op_quic_endpoint_create, op_quic_endpoint_get_addr, - op_quic_get_send_stream_priority, + op_quic_endpoint_listen, op_quic_incoming_accept, + op_quic_incoming_accept_0rtt, op_quic_incoming_ignore, op_quic_incoming_local_ip, op_quic_incoming_refuse, op_quic_incoming_remote_addr, op_quic_incoming_remote_addr_validated, - op_quic_listen, - op_quic_max_datagram_size, - op_quic_open_bi, - op_quic_open_uni, - op_quic_read_datagram, - op_quic_send_datagram, - op_quic_set_send_stream_priority, + op_quic_listener_accept, + op_quic_listener_stop, + op_quic_recv_stream_get_id, + op_quic_send_stream_get_id, + op_quic_send_stream_get_priority, + op_quic_send_stream_set_priority, } from "ext:core/ops"; import { + getReadableStreamResourceBacking, getWritableStreamResourceBacking, ReadableStream, readableStreamForRid, @@ -39,29 +48,297 @@ const { BadResourcePrototype, } = core; const { - Uint8Array, - TypedArrayPrototypeSubarray, + ObjectPrototypeIsPrototypeOf, + PromisePrototypeThen, + Symbol, SymbolAsyncIterator, SafePromisePrototypeFinally, - ObjectPrototypeIsPrototypeOf, } = primordials; +let getEndpointResource; + +function transportOptions({ + keepAliveInterval, + maxIdleTimeout, + maxConcurrentBidirectionalStreams, + maxConcurrentUnidirectionalStreams, + preferredAddressV4, + preferredAddressV6, + congestionControl, +}) { + return { + keepAliveInterval, + maxIdleTimeout, + maxConcurrentBidirectionalStreams, + maxConcurrentUnidirectionalStreams, + preferredAddressV4, + preferredAddressV6, + congestionControl, + }; +} + +const kRid = Symbol("rid"); + +class QuicEndpoint { + #endpoint; + + constructor( + { hostname = "::", port = 0, [kRid]: rid } = { __proto__: null }, + ) { + this.#endpoint = rid ?? op_quic_endpoint_create({ hostname, port }, true); + } + + get addr() { + return op_quic_endpoint_get_addr(this.#endpoint); + } + + listen(options) { + const keyPair = loadTlsKeyPair("Deno.QuicEndpoint.listen", { + cert: options.cert, + key: options.key, + }); + const listener = op_quic_endpoint_listen( + this.#endpoint, + { alpnProtocols: options.alpnProtocols }, + transportOptions(options), + keyPair, + ); + return new QuicListener(listener, this); + } + + close({ closeCode = 0, reason = "" } = { __proto__: null }) { + op_quic_endpoint_close(this.#endpoint, closeCode, reason); + } + + static { + getEndpointResource = (e) => e.#endpoint; + } +} + +class QuicListener { + #listener; + #endpoint; + + constructor(listener, endpoint) { + this.#listener = listener; + this.#endpoint = endpoint; + } + + get endpoint() { + return this.#endpoint; + } + + async incoming() { + const incoming = await op_quic_listener_accept(this.#listener); + return new QuicIncoming(incoming, this.#endpoint); + } + + async accept() { + const incoming = await this.incoming(); + const connection = await incoming.accept(); + return connection; + } + + async next() { + try { + const connection = await this.accept(); + return { value: connection, done: false }; + } catch (error) { + if (ObjectPrototypeIsPrototypeOf(BadResourcePrototype, error)) { + return { value: undefined, done: true }; + } + throw error; + } + } + + [SymbolAsyncIterator]() { + return this; + } + + stop() { + op_quic_listener_stop(this.#listener); + } +} + +class QuicIncoming { + #incoming; + #endpoint; + + constructor(incoming, endpoint) { + this.#incoming = incoming; + this.#endpoint = endpoint; + } + + get localIp() { + return op_quic_incoming_local_ip(this.#incoming); + } + + get remoteAddr() { + return op_quic_incoming_remote_addr(this.#incoming); + } + + get remoteAddressValidated() { + return op_quic_incoming_remote_addr_validated(this.#incoming); + } + + accept(options) { + const tOptions = options ? transportOptions(options) : null; + if (options?.zeroRtt) { + const conn = op_quic_incoming_accept_0rtt( + this.#incoming, + tOptions, + ); + return new QuicConn(conn, this.#endpoint); + } + return PromisePrototypeThen( + op_quic_incoming_accept(this.#incoming, tOptions), + (conn) => new QuicConn(conn, this.#endpoint), + ); + } + + refuse() { + op_quic_incoming_refuse(this.#incoming); + } + + ignore() { + op_quic_incoming_ignore(this.#incoming); + } +} + +class QuicConn { + #resource; + #bidiStream = null; + #uniStream = null; + #closed; + #handshake; + #endpoint; + + constructor(resource, endpoint) { + this.#resource = resource; + this.#endpoint = endpoint; + + this.#closed = op_quic_connection_closed(this.#resource); + core.unrefOpPromise(this.#closed); + } + + get endpoint() { + return this.#endpoint; + } + + get protocol() { + return op_quic_connection_get_protocol(this.#resource); + } + + get remoteAddr() { + return op_quic_connection_get_remote_addr(this.#resource); + } + + get serverName() { + return op_quic_connection_get_server_name(this.#resource); + } + + async createBidirectionalStream( + { sendOrder, waitUntilAvailable } = { __proto__: null }, + ) { + const { 0: txRid, 1: rxRid } = await op_quic_connection_open_bi( + this.#resource, + waitUntilAvailable ?? false, + ); + if (sendOrder !== null && sendOrder !== undefined) { + op_quic_send_stream_set_priority(txRid, sendOrder); + } + return new QuicBidirectionalStream(txRid, rxRid, this.#closed); + } + + async createUnidirectionalStream( + { sendOrder, waitUntilAvailable } = { __proto__: null }, + ) { + const rid = await op_quic_connection_open_uni( + this.#resource, + waitUntilAvailable ?? false, + ); + if (sendOrder !== null && sendOrder !== undefined) { + op_quic_send_stream_set_priority(rid, sendOrder); + } + return writableStream(rid, this.#closed); + } + + get incomingBidirectionalStreams() { + if (this.#bidiStream === null) { + this.#bidiStream = ReadableStream.from( + bidiStream(this.#resource, this.#closed), + ); + } + return this.#bidiStream; + } + + get incomingUnidirectionalStreams() { + if (this.#uniStream === null) { + this.#uniStream = ReadableStream.from( + uniStream(this.#resource, this.#closed), + ); + } + return this.#uniStream; + } + + get maxDatagramSize() { + return op_quic_connection_get_max_datagram_size(this.#resource); + } + + async readDatagram() { + const buffer = await op_quic_connection_read_datagram(this.#resource); + return buffer; + } + + async sendDatagram(data) { + await op_quic_connection_send_datagram(this.#resource, data); + } + + get handshake() { + if (!this.#handshake) { + this.#handshake = op_quic_connection_handshake(this.#resource); + } + return this.#handshake; + } + + get closed() { + core.refOpPromise(this.#closed); + return this.#closed; + } + + close({ closeCode = 0, reason = "" } = { __proto__: null }) { + op_quic_connection_close(this.#resource, closeCode, reason); + } +} + class QuicSendStream extends WritableStream { get sendOrder() { - return op_quic_get_send_stream_priority( + return op_quic_send_stream_get_priority( getWritableStreamResourceBacking(this).rid, ); } set sendOrder(p) { - op_quic_set_send_stream_priority( + op_quic_send_stream_set_priority( getWritableStreamResourceBacking(this).rid, p, ); } + + get id() { + return op_quic_send_stream_get_id( + getWritableStreamResourceBacking(this).rid, + ); + } } -class QuicReceiveStream extends ReadableStream {} +class QuicReceiveStream extends ReadableStream { + get id() { + return op_quic_recv_stream_get_id( + getReadableStreamResourceBacking(this).rid, + ); + } +} function readableStream(rid, closed) { // stream can be indirectly closed by closing connection. @@ -100,7 +377,7 @@ class QuicBidirectionalStream { async function* bidiStream(conn, closed) { try { while (true) { - const r = await op_quic_accept_bi(conn); + const r = await op_quic_connection_accept_bi(conn); yield new QuicBidirectionalStream(r[0], r[1], closed); } } catch (error) { @@ -114,7 +391,7 @@ async function* bidiStream(conn, closed) { async function* uniStream(conn, closed) { try { while (true) { - const uniRid = await op_quic_accept_uni(conn); + const uniRid = await op_quic_connection_accept_uni(conn); yield readableStream(uniRid, closed); } } catch (error) { @@ -125,241 +402,48 @@ async function* uniStream(conn, closed) { } } -class QuicConn { - #resource; - #bidiStream = null; - #uniStream = null; - #closed; - - constructor(resource) { - this.#resource = resource; - - this.#closed = op_quic_connection_closed(this.#resource); - core.unrefOpPromise(this.#closed); - } - - get protocol() { - return op_quic_connection_get_protocol(this.#resource); - } - - get remoteAddr() { - return op_quic_connection_get_remote_addr(this.#resource); - } - - async createBidirectionalStream( - { sendOrder, waitUntilAvailable } = { __proto__: null }, - ) { - const { 0: txRid, 1: rxRid } = await op_quic_open_bi( - this.#resource, - waitUntilAvailable ?? false, - ); - if (sendOrder !== null && sendOrder !== undefined) { - op_quic_set_send_stream_priority(txRid, sendOrder); - } - return new QuicBidirectionalStream(txRid, rxRid, this.#closed); - } - - async createUnidirectionalStream( - { sendOrder, waitUntilAvailable } = { __proto__: null }, - ) { - const rid = await op_quic_open_uni( - this.#resource, - waitUntilAvailable ?? false, - ); - if (sendOrder !== null && sendOrder !== undefined) { - op_quic_set_send_stream_priority(rid, sendOrder); - } - return writableStream(rid, this.#closed); - } - - get incomingBidirectionalStreams() { - if (this.#bidiStream === null) { - this.#bidiStream = ReadableStream.from( - bidiStream(this.#resource, this.#closed), - ); - } - return this.#bidiStream; - } - - get incomingUnidirectionalStreams() { - if (this.#uniStream === null) { - this.#uniStream = ReadableStream.from( - uniStream(this.#resource, this.#closed), - ); - } - return this.#uniStream; - } - - get maxDatagramSize() { - return op_quic_max_datagram_size(this.#resource); - } - - async readDatagram(p) { - const view = p || new Uint8Array(this.maxDatagramSize); - const nread = await op_quic_read_datagram(this.#resource, view); - return TypedArrayPrototypeSubarray(view, 0, nread); - } - - async sendDatagram(data) { - await op_quic_send_datagram(this.#resource, data); - } - - get closed() { - core.refOpPromise(this.#closed); - return this.#closed; - } - - close({ closeCode, reason }) { - op_quic_close_connection(this.#resource, closeCode, reason); - } -} - -class QuicIncoming { - #incoming; - - constructor(incoming) { - this.#incoming = incoming; - } - - get localIp() { - return op_quic_incoming_local_ip(this.#incoming); - } - - get remoteAddr() { - return op_quic_incoming_remote_addr(this.#incoming); - } - - get remoteAddressValidated() { - return op_quic_incoming_remote_addr_validated(this.#incoming); - } - - async accept() { - const conn = await op_quic_incoming_accept(this.#incoming); - return new QuicConn(conn); - } - - refuse() { - op_quic_incoming_refuse(this.#incoming); - } - - ignore() { - op_quic_incoming_ignore(this.#incoming); - } -} - -class QuicListener { - #endpoint; - - constructor(endpoint) { - this.#endpoint = endpoint; - } - - get addr() { - return op_quic_endpoint_get_addr(this.#endpoint); - } - - async accept() { - const conn = await op_quic_accept(this.#endpoint); - return new QuicConn(conn); - } - - async incoming() { - const incoming = await op_quic_accept_incoming(this.#endpoint); - return new QuicIncoming(incoming); - } - - async next() { - let conn; - try { - conn = await this.accept(); - } catch (error) { - if (ObjectPrototypeIsPrototypeOf(BadResourcePrototype, error)) { - return { value: undefined, done: true }; - } - throw error; - } - return { value: conn, done: false }; - } - - [SymbolAsyncIterator]() { - return this; - } - - close({ closeCode, reason }) { - op_quic_close_endpoint(this.#endpoint, closeCode, reason); - } -} - -async function listenQuic( - { - hostname, - port, - cert, - key, - alpnProtocols, - keepAliveInterval, - maxIdleTimeout, - maxConcurrentBidirectionalStreams, - maxConcurrentUnidirectionalStreams, - }, -) { - hostname = hostname || "0.0.0.0"; - const keyPair = loadTlsKeyPair("Deno.listenQuic", { cert, key }); - const endpoint = await op_quic_listen( - { hostname, port }, - { alpnProtocols }, +function connectQuic(options) { + const endpoint = options.endpoint ?? + new QuicEndpoint({ + [kRid]: op_quic_endpoint_create({ hostname: "::", port: 0 }, 0, false), + }); + const keyPair = loadTlsKeyPair("Deno.connectQuic", { + cert: options.cert, + key: options.key, + }); + const connecting = op_quic_endpoint_connect( + getEndpointResource(endpoint), { - keepAliveInterval, - maxIdleTimeout, - maxConcurrentBidirectionalStreams, - maxConcurrentUnidirectionalStreams, + addr: { + hostname: options.hostname, + port: options.port, + }, + caCerts: options.caCerts, + alpnProtocols: options.alpnProtocols, + serverName: options.serverName, }, + transportOptions(options), keyPair, ); - return new QuicListener(endpoint); -} -async function connectQuic( - { - hostname, - port, - serverName, - caCerts, - cert, - key, - alpnProtocols, - keepAliveInterval, - maxIdleTimeout, - maxConcurrentBidirectionalStreams, - maxConcurrentUnidirectionalStreams, - congestionControl, - }, -) { - const keyPair = loadTlsKeyPair("Deno.connectQuic", { cert, key }); - const conn = await op_quic_connect( - { hostname, port }, - { - caCerts, - alpnProtocols, - serverName, - }, - { - keepAliveInterval, - maxIdleTimeout, - maxConcurrentBidirectionalStreams, - maxConcurrentUnidirectionalStreams, - congestionControl, - }, - keyPair, + if (options.zeroRtt) { + const conn = op_quic_connecting_0rtt(connecting); + if (conn) { + return new QuicConn(conn, endpoint); + } + } + + return PromisePrototypeThen( + op_quic_connecting_1rtt(connecting), + (conn) => new QuicConn(conn, endpoint), ); - return new QuicConn(conn); } export { connectQuic, - listenQuic, QuicBidirectionalStream, QuicConn, + QuicEndpoint, QuicIncoming, QuicListener, QuicReceiveStream, diff --git a/ext/net/Cargo.toml b/ext/net/Cargo.toml index eaee7bfb4b..348d8682ae 100644 --- a/ext/net/Cargo.toml +++ b/ext/net/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_net" -version = "0.176.0" +version = "0.178.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -15,6 +15,7 @@ path = "lib.rs" [dependencies] deno_core.workspace = true +deno_error.workspace = true deno_permissions.workspace = true deno_tls.workspace = true hickory-proto = "0.25.0-alpha.4" diff --git a/ext/net/io.rs b/ext/net/io.rs index 2907fa398b..71ae577cd0 100644 --- a/ext/net/io.rs +++ b/ext/net/io.rs @@ -1,4 +1,7 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::borrow::Cow; +use std::rc::Rc; use deno_core::futures::TryFutureExt; use deno_core::AsyncMutFuture; @@ -8,15 +11,13 @@ use deno_core::CancelHandle; use deno_core::CancelTryFuture; use deno_core::RcRef; use deno_core::Resource; +use deno_error::JsErrorBox; use socket2::SockRef; -use std::borrow::Cow; -use std::rc::Rc; use tokio::io::AsyncRead; use tokio::io::AsyncReadExt; use tokio::io::AsyncWrite; use tokio::io::AsyncWriteExt; use tokio::net::tcp; - #[cfg(unix)] use tokio::net::unix; @@ -90,10 +91,12 @@ where } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum MapError { + #[class(inherit)] #[error("{0}")] Io(std::io::Error), + #[class(generic)] #[error("Unable to get resources")] NoResources, } @@ -110,7 +113,7 @@ impl Resource for TcpStreamResource { } fn shutdown(self: Rc) -> AsyncResult<()> { - Box::pin(self.shutdown().map_err(Into::into)) + Box::pin(self.shutdown().map_err(JsErrorBox::from_err)) } fn close(self: Rc) { @@ -162,9 +165,7 @@ impl UnixStreamResource { unreachable!() } #[allow(clippy::unused_async)] - pub async fn shutdown( - self: Rc, - ) -> Result<(), deno_core::error::AnyError> { + pub async fn shutdown(self: Rc) -> Result<(), JsErrorBox> { unreachable!() } pub fn cancel_read_ops(&self) { @@ -181,7 +182,7 @@ impl Resource for UnixStreamResource { } fn shutdown(self: Rc) -> AsyncResult<()> { - Box::pin(self.shutdown().map_err(Into::into)) + Box::pin(self.shutdown().map_err(JsErrorBox::from_err)) } fn close(self: Rc) { diff --git a/ext/net/lib.deno_net.d.ts b/ext/net/lib.deno_net.d.ts index 958474cbbd..30d3357395 100644 --- a/ext/net/lib.deno_net.d.ts +++ b/ext/net/lib.deno_net.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// /// @@ -450,6 +450,24 @@ declare namespace Deno { options?: StartTlsOptions, ): Promise; + /** + * **UNSTABLE**: New API, yet to be vetted. + * @experimental + * @category Network + */ + export interface QuicEndpointOptions { + /** + * A literal IP address or host name that can be resolved to an IP address. + * @default {"::"} + */ + hostname?: string; + /** + * The port to bind to. + * @default {0} + */ + port?: number; + } + /** * **UNSTABLE**: New API, yet to be vetted. * @experimental @@ -479,53 +497,20 @@ declare namespace Deno { * @default {100} */ maxConcurrentUnidirectionalStreams?: number; - } - - /** - * **UNSTABLE**: New API, yet to be vetted. - * @experimental - * @category Network - */ - export interface ListenQuicOptions extends QuicTransportOptions { - /** The port to connect to. */ - port: number; /** - * A literal IP address or host name that can be resolved to an IP address. - * @default {"0.0.0.0"} + * The congestion control algorithm used when sending data over this connection. + * @default {"default"} */ - hostname?: string; - /** Server private key in PEM format */ - key: string; - /** Cert chain in PEM format */ - cert: string; - /** Application-Layer Protocol Negotiation (ALPN) protocols to announce to - * the client. QUIC requires the use of ALPN. - */ - alpnProtocols: string[]; + congestionControl?: "throughput" | "low-latency" | "default"; } - /** - * **UNSTABLE**: New API, yet to be vetted. - * Listen announces on the local transport address over QUIC. - * - * ```ts - * const lstnr = await Deno.listenQuic({ port: 443, cert: "...", key: "...", alpnProtocols: ["h3"] }); - * ``` - * - * Requires `allow-net` permission. - * - * @experimental - * @tags allow-net - * @category Network - */ - export function listenQuic(options: ListenQuicOptions): Promise; - /** * **UNSTABLE**: New API, yet to be vetted. * @experimental * @category Network */ - export interface ConnectQuicOptions extends QuicTransportOptions { + export interface ConnectQuicOptions + extends QuicTransportOptions { /** The port to connect to. */ port: number; /** A literal IP address or host name that can be resolved to an IP address. */ @@ -543,30 +528,73 @@ declare namespace Deno { * Must be in PEM format. */ caCerts?: string[]; /** - * The congestion control algorithm used when sending data over this connection. + * If no endpoint is provided, a new one is bound on an ephemeral port. */ - congestionControl?: "throughput" | "low-latency"; + endpoint?: QuicEndpoint; + /** + * Attempt to convert the connection into 0-RTT. Any data sent before + * the TLS handshake completes is vulnerable to replay attacks. + * @default {false} + */ + zeroRtt?: ZRTT; } /** * **UNSTABLE**: New API, yet to be vetted. - * Establishes a secure connection over QUIC using a hostname and port. The - * cert file is optional and if not included Mozilla's root certificates will - * be used. See also https://github.com/ctz/webpki-roots for specifics. - * - * ```ts - * const caCert = await Deno.readTextFile("./certs/my_custom_root_CA.pem"); - * const conn1 = await Deno.connectQuic({ hostname: "example.com", port: 443, alpnProtocols: ["h3"] }); - * const conn2 = await Deno.connectQuic({ caCerts: [caCert], hostname: "example.com", port: 443, alpnProtocols: ["h3"] }); - * ``` - * - * Requires `allow-net` permission. - * * @experimental - * @tags allow-net * @category Network */ - export function connectQuic(options: ConnectQuicOptions): Promise; + export interface QuicServerTransportOptions extends QuicTransportOptions { + /** + * Preferred IPv4 address to be communicated to the client during + * handshaking. If the client is able to reach this address it will switch + * to it. + * @default {undefined} + */ + preferredAddressV4?: string; + /** + * Preferred IPv6 address to be communicated to the client during + * handshaking. If the client is able to reach this address it will switch + * to it. + * @default {undefined} + */ + preferredAddressV6?: string; + } + + /** + * **UNSTABLE**: New API, yet to be vetted. + * @experimental + * @category Network + */ + export interface QuicListenOptions extends QuicServerTransportOptions { + /** Application-Layer Protocol Negotiation (ALPN) protocols to announce to + * the client. QUIC requires the use of ALPN. + */ + alpnProtocols: string[]; + /** Server private key in PEM format */ + key: string; + /** Cert chain in PEM format */ + cert: string; + } + + /** + * **UNSTABLE**: New API, yet to be vetted. + * @experimental + * @category Network + */ + export interface QuicAcceptOptions + extends QuicServerTransportOptions { + /** Application-Layer Protocol Negotiation (ALPN) protocols to announce to + * the client. QUIC requires the use of ALPN. + */ + alpnProtocols?: string[]; + /** + * Convert this connection into 0.5-RTT at the cost of weakened security, as + * 0.5-RTT data may be sent before TLS client authentication has occurred. + * @default {false} + */ + zeroRtt?: ZRTT; + } /** * **UNSTABLE**: New API, yet to be vetted. @@ -582,14 +610,93 @@ declare namespace Deno { /** * **UNSTABLE**: New API, yet to be vetted. - * An incoming connection for which the server has not yet begun its part of the handshake. + * + * @experimental + * @category Network + */ + export interface QuicSendStreamOptions { + /** Indicates the send priority of this stream relative to other streams for + * which the value has been set. + * @default {0} + */ + sendOrder?: number; + /** Wait until there is sufficient flow credit to create the stream. + * @default {false} + */ + waitUntilAvailable?: boolean; + } + + /** + * **UNSTABLE**: New API, yet to be vetted. + * @experimental + * @category Network + */ + export class QuicEndpoint { + /** + * Create a QUIC endpoint which may be used for client or server connections. + * + * Requires `allow-net` permission. + * + * @experimental + * @tags allow-net + * @category Network + */ + constructor(options?: QuicEndpointOptions); + + /** Return the address of the `QuicListener`. */ + readonly addr: NetAddr; + + /** + * **UNSTABLE**: New API, yet to be vetted. + * Listen announces on the local transport address over QUIC. + * + * @experimental + * @category Network + */ + listen(options: QuicListenOptions): QuicListener; + + /** + * Closes the endpoint. All associated connections will be closed and incoming + * connections will be rejected. + */ + close(info?: QuicCloseInfo): void; + } + + /** + * **UNSTABLE**: New API, yet to be vetted. + * Specialized listener that accepts QUIC connections. + * + * @experimental + * @category Network + */ + export interface QuicListener extends AsyncIterable { + /** Waits for and resolves to the next incoming connection. */ + incoming(): Promise; + + /** Wait for the next incoming connection and accepts it. */ + accept(): Promise; + + /** Stops the listener. This does not close the endpoint. */ + stop(): void; + + [Symbol.asyncIterator](): AsyncIterableIterator; + + /** The endpoint for this listener. */ + readonly endpoint: QuicEndpoint; + } + + /** + * **UNSTABLE**: New API, yet to be vetted. + * An incoming connection for which the server has not yet begun its part of + * the handshake. * * @experimental * @category Network */ export interface QuicIncoming { /** - * The local IP address which was used when the peer established the connection. + * The local IP address which was used when the peer established the + * connection. */ readonly localIp: string; @@ -599,14 +706,17 @@ declare namespace Deno { readonly remoteAddr: NetAddr; /** - * Whether the socket address that is initiating this connection has proven that they can receive traffic. + * Whether the socket address that is initiating this connection has proven + * that they can receive traffic. */ readonly remoteAddressValidated: boolean; /** * Accept this incoming connection. */ - accept(): Promise; + accept( + options?: QuicAcceptOptions, + ): ZRTT extends true ? QuicConn : Promise; /** * Refuse this incoming connection. @@ -619,48 +729,6 @@ declare namespace Deno { ignore(): void; } - /** - * **UNSTABLE**: New API, yet to be vetted. - * Specialized listener that accepts QUIC connections. - * - * @experimental - * @category Network - */ - export interface QuicListener extends AsyncIterable { - /** Return the address of the `QuicListener`. */ - readonly addr: NetAddr; - - /** Waits for and resolves to the next connection to the `QuicListener`. */ - accept(): Promise; - - /** Waits for and resolves to the next incoming request to the `QuicListener`. */ - incoming(): Promise; - - /** Close closes the listener. Any pending accept promises will be rejected - * with errors. */ - close(info: QuicCloseInfo): void; - - [Symbol.asyncIterator](): AsyncIterableIterator; - } - - /** - * **UNSTABLE**: New API, yet to be vetted. - * - * @experimental - * @category Network - */ - export interface QuicSendStreamOptions { - /** Indicates the send priority of this stream relative to other streams for - * which the value has been set. - * @default {undefined} - */ - sendOrder?: number; - /** Wait until there is sufficient flow credit to create the stream. - * @default {false} - */ - waitUntilAvailable?: boolean; - } - /** * **UNSTABLE**: New API, yet to be vetted. * @@ -670,7 +738,7 @@ declare namespace Deno { export interface QuicConn { /** Close closes the listener. Any pending accept promises will be rejected * with errors. */ - close(info: QuicCloseInfo): void; + close(info?: QuicCloseInfo): void; /** Opens and returns a bidirectional stream. */ createBidirectionalStream( options?: QuicSendStreamOptions, @@ -682,17 +750,25 @@ declare namespace Deno { /** Send a datagram. The provided data cannot be larger than * `maxDatagramSize`. */ sendDatagram(data: Uint8Array): Promise; - /** Receive a datagram. If no buffer is provider, one will be allocated. - * The size of the provided buffer should be at least `maxDatagramSize`. */ - readDatagram(buffer?: Uint8Array): Promise; + /** Receive a datagram. */ + readDatagram(): Promise; + /** The endpoint for this connection. */ + readonly endpoint: QuicEndpoint; + /** Returns a promise that resolves when the TLS handshake is complete. */ + readonly handshake: Promise; /** Return the remote address for the connection. Clients may change * addresses at will, for example when switching to a cellular internet * connection. */ readonly remoteAddr: NetAddr; - /** The negotiated ALPN protocol, if provided. */ + /** + * The negotiated ALPN protocol, if provided. Only available after the + * handshake is complete. */ readonly protocol: string | undefined; + /** The negotiated server name. Only available on the server after the + * handshake is complete. */ + readonly serverName: string | undefined; /** Returns a promise that resolves when the connection is closed. */ readonly closed: Promise; /** A stream of bidirectional streams opened by the peer. */ @@ -728,6 +804,11 @@ declare namespace Deno { /** Indicates the send priority of this stream relative to other streams for * which the value has been set. */ sendOrder: number; + + /** + * 62-bit stream ID, unique within this connection. + */ + readonly id: bigint; } /** @@ -736,7 +817,39 @@ declare namespace Deno { * @experimental * @category Network */ - export interface QuicReceiveStream extends ReadableStream {} + export interface QuicReceiveStream extends ReadableStream { + /** + * 62-bit stream ID, unique within this connection. + */ + readonly id: bigint; + } + + /** + * **UNSTABLE**: New API, yet to be vetted. + * Establishes a secure connection over QUIC using a hostname and port. The + * cert file is optional and if not included Mozilla's root certificates will + * be used. See also https://github.com/ctz/webpki-roots for specifics. + * + * ```ts + * const caCert = await Deno.readTextFile("./certs/my_custom_root_CA.pem"); + * const conn1 = await Deno.connectQuic({ hostname: "example.com", port: 443, alpnProtocols: ["h3"] }); + * const conn2 = await Deno.connectQuic({ caCerts: [caCert], hostname: "example.com", port: 443, alpnProtocols: ["h3"] }); + * ``` + * + * If an endpoint is shared among many connections, 0-RTT can be enabled. + * When 0-RTT is successful, a QuicConn will be synchronously returned + * and data can be sent immediately with it. **Any data sent before the + * TLS handshake completes is vulnerable to replay attacks.** + * + * Requires `allow-net` permission. + * + * @experimental + * @tags allow-net + * @category Network + */ + export function connectQuic( + options: ConnectQuicOptions, + ): ZRTT extends true ? (QuicConn | Promise) : Promise; export {}; // only export exports } diff --git a/ext/net/lib.rs b/ext/net/lib.rs index 04b3f80010..b21da19f30 100644 --- a/ext/net/lib.rs +++ b/ext/net/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. pub mod io; pub mod ops; @@ -10,16 +10,17 @@ pub mod raw; pub mod resolve_addr; pub mod tcp; -use deno_core::error::AnyError; -use deno_core::OpState; -use deno_permissions::PermissionCheckError; -use deno_tls::rustls::RootCertStore; -use deno_tls::RootCertStoreProvider; use std::borrow::Cow; use std::path::Path; use std::path::PathBuf; use std::sync::Arc; +use deno_core::OpState; +use deno_permissions::PermissionCheckError; +use deno_tls::rustls::RootCertStore; +use deno_tls::RootCertStoreProvider; +pub use quic::QuicError; + pub const UNSTABLE_FEATURE_NAME: &str = "net"; pub trait NetPermissions { @@ -105,7 +106,9 @@ pub struct DefaultTlsOptions { } impl DefaultTlsOptions { - pub fn root_cert_store(&self) -> Result, AnyError> { + pub fn root_cert_store( + &self, + ) -> Result, deno_error::JsErrorBox> { Ok(match &self.root_cert_store_provider { Some(provider) => Some(provider.get_or_try_init()?.clone()), None => None, @@ -160,33 +163,42 @@ deno_core::extension!(deno_net, ops_unix::op_net_recv_unixpacket, ops_unix::op_net_send_unixpacket

, - quic::op_quic_accept, - quic::op_quic_accept_bi, - quic::op_quic_accept_incoming, - quic::op_quic_accept_uni, - quic::op_quic_close_connection, - quic::op_quic_close_endpoint, + quic::op_quic_connecting_0rtt, + quic::op_quic_connecting_1rtt, + quic::op_quic_connection_accept_bi, + quic::op_quic_connection_accept_uni, + quic::op_quic_connection_close, quic::op_quic_connection_closed, quic::op_quic_connection_get_protocol, quic::op_quic_connection_get_remote_addr, - quic::op_quic_connect

, + quic::op_quic_connection_get_server_name, + quic::op_quic_connection_handshake, + quic::op_quic_connection_open_bi, + quic::op_quic_connection_open_uni, + quic::op_quic_connection_get_max_datagram_size, + quic::op_quic_connection_read_datagram, + quic::op_quic_connection_send_datagram, + quic::op_quic_endpoint_close, + quic::op_quic_endpoint_connect

, + quic::op_quic_endpoint_create

, quic::op_quic_endpoint_get_addr, - quic::op_quic_get_send_stream_priority, + quic::op_quic_endpoint_listen, quic::op_quic_incoming_accept, - quic::op_quic_incoming_refuse, + quic::op_quic_incoming_accept_0rtt, quic::op_quic_incoming_ignore, quic::op_quic_incoming_local_ip, + quic::op_quic_incoming_refuse, quic::op_quic_incoming_remote_addr, quic::op_quic_incoming_remote_addr_validated, - quic::op_quic_listen

, - quic::op_quic_max_datagram_size, - quic::op_quic_open_bi, - quic::op_quic_open_uni, - quic::op_quic_read_datagram, - quic::op_quic_send_datagram, - quic::op_quic_set_send_stream_priority, + quic::op_quic_listener_accept, + quic::op_quic_listener_stop, + quic::op_quic_recv_stream_get_id, + quic::op_quic_send_stream_get_id, + quic::op_quic_send_stream_get_priority, + quic::op_quic_send_stream_set_priority, ], - esm = [ "01_net.js", "02_tls.js", "03_quic.js" ], + esm = [ "01_net.js", "02_tls.js" ], + lazy_loaded_esm = [ "03_quic.js" ], options = { root_cert_store_provider: Option>, unsafely_ignore_certificate_errors: Option>, @@ -204,9 +216,10 @@ deno_core::extension!(deno_net, /// Stub ops for non-unix platforms. #[cfg(not(unix))] mod ops_unix { - use crate::NetPermissions; use deno_core::op2; + use crate::NetPermissions; + macro_rules! stub_op { ($name:ident) => { #[op2(fast)] diff --git a/ext/net/ops.rs b/ext/net/ops.rs index 16148ac90d..768dd33135 100644 --- a/ext/net/ops.rs +++ b/ext/net/ops.rs @@ -1,16 +1,17 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::borrow::Cow; +use std::cell::RefCell; +use std::net::Ipv4Addr; +use std::net::Ipv6Addr; +use std::net::SocketAddr; +use std::rc::Rc; +use std::str::FromStr; -use crate::io::TcpStreamResource; -use crate::raw::NetworkListenerResource; -use crate::resolve_addr::resolve_addr; -use crate::resolve_addr::resolve_addr_sync; -use crate::tcp::TcpListener; -use crate::NetPermissions; use deno_core::op2; -use deno_core::CancelFuture; - use deno_core::AsyncRefCell; use deno_core::ByteString; +use deno_core::CancelFuture; use deno_core::CancelHandle; use deno_core::CancelTryFuture; use deno_core::JsBuffer; @@ -35,16 +36,16 @@ use socket2::Domain; use socket2::Protocol; use socket2::Socket; use socket2::Type; -use std::borrow::Cow; -use std::cell::RefCell; -use std::net::Ipv4Addr; -use std::net::Ipv6Addr; -use std::net::SocketAddr; -use std::rc::Rc; -use std::str::FromStr; use tokio::net::TcpStream; use tokio::net::UdpSocket; +use crate::io::TcpStreamResource; +use crate::raw::NetworkListenerResource; +use crate::resolve_addr::resolve_addr; +use crate::resolve_addr::resolve_addr_sync; +use crate::tcp::TcpListener; +use crate::NetPermissions; + #[derive(Serialize, Clone, Debug)] #[serde(rename_all = "camelCase")] pub struct TlsHandshakeInfo { @@ -66,60 +67,87 @@ impl From for IpAddr { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum NetError { + #[class("BadResource")] #[error("Listener has been closed")] ListenerClosed, + #[class("Busy")] #[error("Listener already in use")] ListenerBusy, + #[class("BadResource")] #[error("Socket has been closed")] SocketClosed, + #[class("NotConnected")] #[error("Socket has been closed")] SocketClosedNotConnected, + #[class("Busy")] #[error("Socket already in use")] SocketBusy, + #[class(inherit)] #[error("{0}")] Io(#[from] std::io::Error), + #[class("Busy")] #[error("Another accept task is ongoing")] AcceptTaskOngoing, + #[class(inherit)] #[error(transparent)] Permission(#[from] deno_permissions::PermissionCheckError), + #[class(inherit)] #[error("{0}")] - Resource(deno_core::error::AnyError), + Resource(#[from] deno_core::error::ResourceError), + #[class(generic)] #[error("No resolved address found")] NoResolvedAddress, + #[class(generic)] #[error("{0}")] AddrParse(#[from] std::net::AddrParseError), + #[class(inherit)] #[error("{0}")] Map(crate::io::MapError), + #[class(inherit)] #[error("{0}")] Canceled(#[from] deno_core::Canceled), + #[class("NotFound")] #[error("{0}")] DnsNotFound(ResolveError), + #[class("NotConnected")] #[error("{0}")] DnsNotConnected(ResolveError), + #[class("TimedOut")] #[error("{0}")] DnsTimedOut(ResolveError), + #[class(generic)] #[error("{0}")] Dns(#[from] ResolveError), + #[class("NotSupported")] #[error("Provided record type is not supported")] UnsupportedRecordType, + #[class("InvalidData")] #[error("File name or path {0:?} is not valid UTF-8")] InvalidUtf8(std::ffi::OsString), + #[class(generic)] #[error("unexpected key type")] UnexpectedKeyType, + #[class(type)] #[error("Invalid hostname: '{0}'")] - InvalidHostname(String), // TypeError + InvalidHostname(String), + #[class("Busy")] #[error("TCP stream is currently in use")] TcpStreamBusy, + #[class(generic)] #[error("{0}")] Rustls(#[from] deno_tls::rustls::Error), + #[class(inherit)] #[error("{0}")] Tls(#[from] deno_tls::TlsError), + #[class("InvalidData")] #[error("Error creating TLS certificate: Deno.listenTls requires a key")] - ListenTlsRequiresKey, // InvalidData + ListenTlsRequiresKey, + #[class(inherit)] #[error("{0}")] - RootCertStore(deno_core::anyhow::Error), + RootCertStore(deno_error::JsErrorBox), + #[class(generic)] #[error("{0}")] Reunite(tokio::net::tcp::ReuniteError), } @@ -712,10 +740,8 @@ pub fn op_set_nodelay_inner( rid: ResourceId, nodelay: bool, ) -> Result<(), NetError> { - let resource: Rc = state - .resource_table - .get::(rid) - .map_err(NetError::Resource)?; + let resource: Rc = + state.resource_table.get::(rid)?; resource.set_nodelay(nodelay).map_err(NetError::Map) } @@ -734,10 +760,8 @@ pub fn op_set_keepalive_inner( rid: ResourceId, keepalive: bool, ) -> Result<(), NetError> { - let resource: Rc = state - .resource_table - .get::(rid) - .map_err(NetError::Resource)?; + let resource: Rc = + state.resource_table.get::(rid)?; resource.set_keepalive(keepalive).map_err(NetError::Map) } @@ -834,7 +858,14 @@ fn rdata_to_return_record( #[cfg(test)] mod tests { - use super::*; + use std::net::Ipv4Addr; + use std::net::Ipv6Addr; + use std::net::ToSocketAddrs; + use std::path::Path; + use std::path::PathBuf; + use std::sync::Arc; + use std::sync::Mutex; + use deno_core::futures::FutureExt; use deno_core::JsRuntime; use deno_core::RuntimeOptions; @@ -855,13 +886,8 @@ mod tests { use hickory_proto::rr::record_data::RData; use hickory_proto::rr::Name; use socket2::SockRef; - use std::net::Ipv4Addr; - use std::net::Ipv6Addr; - use std::net::ToSocketAddrs; - use std::path::Path; - use std::path::PathBuf; - use std::sync::Arc; - use std::sync::Mutex; + + use super::*; #[test] fn rdata_to_return_record_a() { diff --git a/ext/net/ops_tls.rs b/ext/net/ops_tls.rs index 4d2073fd09..12c6580136 100644 --- a/ext/net/ops_tls.rs +++ b/ext/net/ops_tls.rs @@ -1,16 +1,17 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::borrow::Cow; +use std::cell::RefCell; +use std::convert::From; +use std::fs::File; +use std::io::BufReader; +use std::io::ErrorKind; +use std::io::Read; +use std::net::SocketAddr; +use std::num::NonZeroUsize; +use std::rc::Rc; +use std::sync::Arc; -use crate::io::TcpStreamResource; -use crate::ops::IpAddr; -use crate::ops::NetError; -use crate::ops::TlsHandshakeInfo; -use crate::raw::NetworkListenerResource; -use crate::resolve_addr::resolve_addr; -use crate::resolve_addr::resolve_addr_sync; -use crate::tcp::TcpListener; -use crate::DefaultTlsOptions; -use crate::NetPermissions; -use crate::UnsafelyIgnoreCertificateErrors; use deno_core::futures::TryFutureExt; use deno_core::op2; use deno_core::v8; @@ -22,6 +23,7 @@ use deno_core::OpState; use deno_core::RcRef; use deno_core::Resource; use deno_core::ResourceId; +use deno_error::JsErrorBox; use deno_tls::create_client_config; use deno_tls::load_certs; use deno_tls::load_private_keys; @@ -35,25 +37,25 @@ use deno_tls::TlsKey; use deno_tls::TlsKeyLookup; use deno_tls::TlsKeys; use deno_tls::TlsKeysHolder; +pub use rustls_tokio_stream::TlsStream; use rustls_tokio_stream::TlsStreamRead; use rustls_tokio_stream::TlsStreamWrite; use serde::Deserialize; -use std::borrow::Cow; -use std::cell::RefCell; -use std::convert::From; -use std::fs::File; -use std::io::BufReader; -use std::io::ErrorKind; -use std::io::Read; -use std::net::SocketAddr; -use std::num::NonZeroUsize; -use std::rc::Rc; -use std::sync::Arc; use tokio::io::AsyncReadExt; use tokio::io::AsyncWriteExt; use tokio::net::TcpStream; -pub use rustls_tokio_stream::TlsStream; +use crate::io::TcpStreamResource; +use crate::ops::IpAddr; +use crate::ops::NetError; +use crate::ops::TlsHandshakeInfo; +use crate::raw::NetworkListenerResource; +use crate::resolve_addr::resolve_addr; +use crate::resolve_addr::resolve_addr_sync; +use crate::tcp::TcpListener; +use crate::DefaultTlsOptions; +use crate::NetPermissions; +use crate::UnsafelyIgnoreCertificateErrors; pub(crate) const TLS_BUFFER_SIZE: Option = NonZeroUsize::new(65536); @@ -162,7 +164,7 @@ impl Resource for TlsStreamResource { } fn shutdown(self: Rc) -> AsyncResult<()> { - Box::pin(self.shutdown().map_err(Into::into)) + Box::pin(self.shutdown().map_err(JsErrorBox::from_err)) } fn close(self: Rc) { diff --git a/ext/net/ops_unix.rs b/ext/net/ops_unix.rs index 483dc99b40..b347b81dc7 100644 --- a/ext/net/ops_unix.rs +++ b/ext/net/ops_unix.rs @@ -1,9 +1,10 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::borrow::Cow; +use std::cell::RefCell; +use std::path::Path; +use std::rc::Rc; -use crate::io::UnixStreamResource; -use crate::ops::NetError; -use crate::raw::NetworkListenerResource; -use crate::NetPermissions; use deno_core::op2; use deno_core::AsyncRefCell; use deno_core::CancelHandle; @@ -15,14 +16,15 @@ use deno_core::Resource; use deno_core::ResourceId; use serde::Deserialize; use serde::Serialize; -use std::borrow::Cow; -use std::cell::RefCell; -use std::path::Path; -use std::rc::Rc; use tokio::net::UnixDatagram; use tokio::net::UnixListener; pub use tokio::net::UnixStream; +use crate::io::UnixStreamResource; +use crate::ops::NetError; +use crate::raw::NetworkListenerResource; +use crate::NetPermissions; + /// A utility function to map OsStrings to Strings pub fn into_string(s: std::ffi::OsString) -> Result { s.into_string().map_err(NetError::InvalidUtf8) diff --git a/ext/net/quic.rs b/ext/net/quic.rs index 16f68364be..e075745495 100644 --- a/ext/net/quic.rs +++ b/ext/net/quic.rs @@ -1,16 +1,28 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::resolve_addr::resolve_addr; -use crate::DefaultTlsOptions; -use crate::NetPermissions; -use crate::UnsafelyIgnoreCertificateErrors; -use deno_core::error::bad_resource; -use deno_core::error::generic_error; -use deno_core::error::AnyError; +use std::borrow::Cow; +use std::cell::RefCell; +use std::future::Future; +use std::net::IpAddr; +use std::net::Ipv6Addr; +use std::net::SocketAddr; +use std::net::SocketAddrV4; +use std::net::SocketAddrV6; +use std::pin::pin; +use std::rc::Rc; +use std::sync::atomic::AtomicI32; +use std::sync::atomic::Ordering; +use std::sync::Arc; +use std::task::Context; +use std::task::Poll; +use std::time::Duration; + +use deno_core::error::ResourceError; use deno_core::futures::task::noop_waker_ref; use deno_core::op2; use deno_core::AsyncRefCell; use deno_core::AsyncResult; +use deno_core::BufMutView; use deno_core::BufView; use deno_core::GarbageCollected; use deno_core::JsBuffer; @@ -19,28 +31,88 @@ use deno_core::RcRef; use deno_core::Resource; use deno_core::ResourceId; use deno_core::WriteOutcome; +use deno_error::JsError; +use deno_error::JsErrorBox; +use deno_permissions::PermissionCheckError; use deno_tls::create_client_config; use deno_tls::SocketUse; +use deno_tls::TlsError; use deno_tls::TlsKeys; use deno_tls::TlsKeysHolder; use quinn::crypto::rustls::QuicClientConfig; use quinn::crypto::rustls::QuicServerConfig; +use quinn::rustls::client::ClientSessionMemoryCache; +use quinn::rustls::client::ClientSessionStore; +use quinn::rustls::client::Resumption; use serde::Deserialize; use serde::Serialize; -use std::borrow::Cow; -use std::cell::RefCell; -use std::future::Future; -use std::net::IpAddr; -use std::net::Ipv4Addr; -use std::net::Ipv6Addr; -use std::net::SocketAddrV4; -use std::net::SocketAddrV6; -use std::pin::pin; -use std::rc::Rc; -use std::sync::Arc; -use std::task::Context; -use std::task::Poll; -use std::time::Duration; + +use crate::resolve_addr::resolve_addr_sync; +use crate::DefaultTlsOptions; +use crate::NetPermissions; +use crate::UnsafelyIgnoreCertificateErrors; + +#[derive(Debug, thiserror::Error, JsError)] +pub enum QuicError { + #[class(generic)] + #[error("Endpoint created by 'connectQuic' cannot be used for listening")] + CannotListen, + #[class(type)] + #[error("key and cert are required")] + MissingTlsKey, + #[class(type)] + #[error("Duration is invalid")] + InvalidDuration, + #[class(generic)] + #[error("Unable to resolve hostname")] + UnableToResolve, + #[class(inherit)] + #[error("{0}")] + StdIo(#[from] std::io::Error), + #[class(inherit)] + #[error("{0}")] + PermissionCheck(#[from] PermissionCheckError), + #[class(range)] + #[error("{0}")] + VarIntBoundsExceeded(#[from] quinn::VarIntBoundsExceeded), + #[class(generic)] + #[error("{0}")] + Rustls(#[from] quinn::rustls::Error), + #[class(inherit)] + #[error("{0}")] + Tls(#[from] TlsError), + #[class(generic)] + #[error("{0}")] + ConnectionError(#[from] quinn::ConnectionError), + #[class(generic)] + #[error("{0}")] + ConnectError(#[from] quinn::ConnectError), + #[class(generic)] + #[error("{0}")] + SendDatagramError(#[from] quinn::SendDatagramError), + #[class("BadResource")] + #[error("{0}")] + ClosedStream(#[from] quinn::ClosedStream), + #[class("BadResource")] + #[error("Invalid {0} resource")] + BadResource(&'static str), + #[class(range)] + #[error("Connection has reached the maximum number of concurrent outgoing {0} streams")] + MaxStreams(&'static str), + #[class(generic)] + #[error("{0}")] + Core(#[from] deno_core::error::AnyError), + #[class(inherit)] + #[error(transparent)] + Other(#[from] JsErrorBox), +} + +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct CloseInfo { + close_code: u64, + reason: String, +} #[derive(Debug, Deserialize, Serialize)] struct Addr { @@ -54,7 +126,7 @@ struct ListenArgs { alpn_protocols: Option>, } -#[derive(Deserialize)] +#[derive(Deserialize, Default, PartialEq)] #[serde(rename_all = "camelCase")] struct TransportConfig { keep_alive_interval: Option, @@ -67,9 +139,9 @@ struct TransportConfig { } impl TryInto for TransportConfig { - type Error = AnyError; + type Error = QuicError; - fn try_into(self) -> Result { + fn try_into(self) -> Result { let mut cfg = quinn::TransportConfig::default(); if let Some(interval) = self.keep_alive_interval { @@ -77,7 +149,11 @@ impl TryInto for TransportConfig { } if let Some(timeout) = self.max_idle_timeout { - cfg.max_idle_timeout(Some(Duration::from_millis(timeout).try_into()?)); + cfg.max_idle_timeout(Some( + Duration::from_millis(timeout) + .try_into() + .map_err(|_| QuicError::InvalidDuration)?, + )); } if let Some(max) = self.max_concurrent_bidirectional_streams { @@ -109,34 +185,119 @@ impl TryInto for TransportConfig { } } -struct EndpointResource(quinn::Endpoint, Arc); +fn apply_server_transport_config( + config: &mut quinn::ServerConfig, + transport_config: TransportConfig, +) -> Result<(), QuicError> { + config.preferred_address_v4(transport_config.preferred_address_v4); + config.preferred_address_v6(transport_config.preferred_address_v6); + config.transport_config(Arc::new(transport_config.try_into()?)); + Ok(()) +} + +struct EndpointResource { + endpoint: quinn::Endpoint, + can_listen: bool, + session_store: Arc, +} impl GarbageCollected for EndpointResource {} -#[op2(async)] +#[op2] #[cppgc] -pub(crate) async fn op_quic_listen( +pub(crate) fn op_quic_endpoint_create( state: Rc>, #[serde] addr: Addr, - #[serde] args: ListenArgs, - #[serde] transport_config: TransportConfig, - #[cppgc] keys: &TlsKeysHolder, -) -> Result + can_listen: bool, +) -> Result where NP: NetPermissions + 'static, { - state - .borrow_mut() - .borrow_mut::() - .check_net(&(&addr.hostname, Some(addr.port)), "Deno.listenQuic()")?; - - let addr = resolve_addr(&addr.hostname, addr.port) - .await? + let addr = resolve_addr_sync(&addr.hostname, addr.port)? .next() - .ok_or_else(|| generic_error("No resolved address found"))?; + .ok_or_else(|| QuicError::UnableToResolve)?; + + if can_listen { + state.borrow_mut().borrow_mut::().check_net( + &(&addr.ip().to_string(), Some(addr.port())), + "new Deno.QuicEndpoint()", + )?; + } else { + // If this is not a can-listen, assert that we will bind to an ephemeral port. + assert_eq!( + addr, + SocketAddr::from(( + IpAddr::from(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), + 0 + )) + ); + } + + let config = quinn::EndpointConfig::default(); + let socket = std::net::UdpSocket::bind(addr)?; + let endpoint = quinn::Endpoint::new( + config, + None, + socket, + quinn::default_runtime().unwrap(), + )?; + + Ok(EndpointResource { + endpoint, + can_listen, + session_store: Arc::new(ClientSessionMemoryCache::new(256)), + }) +} + +#[op2] +#[serde] +pub(crate) fn op_quic_endpoint_get_addr( + #[cppgc] endpoint: &EndpointResource, +) -> Result { + let addr = endpoint.endpoint.local_addr()?; + let addr = Addr { + hostname: format!("{}", addr.ip()), + port: addr.port(), + }; + Ok(addr) +} + +#[op2(fast)] +pub(crate) fn op_quic_endpoint_close( + #[cppgc] endpoint: &EndpointResource, + #[bigint] close_code: u64, + #[string] reason: String, +) -> Result<(), QuicError> { + endpoint + .endpoint + .close(quinn::VarInt::from_u64(close_code)?, reason.as_bytes()); + Ok(()) +} + +struct ListenerResource(quinn::Endpoint, Arc); + +impl Drop for ListenerResource { + fn drop(&mut self) { + self.0.set_server_config(None); + } +} + +impl GarbageCollected for ListenerResource {} + +#[op2] +#[cppgc] +pub(crate) fn op_quic_endpoint_listen( + #[cppgc] endpoint: &EndpointResource, + #[serde] args: ListenArgs, + #[serde] transport_config: TransportConfig, + #[cppgc] keys: &TlsKeysHolder, +) -> Result { + if !endpoint.can_listen { + return Err(QuicError::CannotListen); + } let TlsKeys::Static(deno_tls::TlsKey(cert, key)) = keys.take() else { - unreachable!() + return Err(QuicError::MissingTlsKey); }; let mut crypto = @@ -146,6 +307,9 @@ where .with_no_client_auth() .with_single_cert(cert.clone(), key.clone_key())?; + // required by QUIC spec. + crypto.max_early_data_size = u32::MAX; + if let Some(alpn_protocols) = args.alpn_protocols { crypto.alpn_protocols = alpn_protocols .into_iter() @@ -153,66 +317,24 @@ where .collect(); } - let server_config = Arc::new(QuicServerConfig::try_from(crypto)?); + let server_config = Arc::new( + QuicServerConfig::try_from(crypto).expect("TLS13 is explicitly configured"), + ); let mut config = quinn::ServerConfig::with_crypto(server_config.clone()); - config.preferred_address_v4(transport_config.preferred_address_v4); - config.preferred_address_v6(transport_config.preferred_address_v6); - config.transport_config(Arc::new(transport_config.try_into()?)); - let endpoint = quinn::Endpoint::server(config, addr)?; + apply_server_transport_config(&mut config, transport_config)?; - Ok(EndpointResource(endpoint, server_config)) + endpoint.endpoint.set_server_config(Some(config)); + + Ok(ListenerResource(endpoint.endpoint.clone(), server_config)) } -#[op2] -#[serde] -pub(crate) fn op_quic_endpoint_get_addr( - #[cppgc] endpoint: &EndpointResource, -) -> Result { - let addr = endpoint.0.local_addr()?; - let addr = Addr { - hostname: format!("{}", addr.ip()), - port: addr.port(), - }; - Ok(addr) -} - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -struct CloseInfo { - close_code: u64, - reason: String, -} - -#[op2(fast)] -pub(crate) fn op_quic_close_endpoint( - #[cppgc] endpoint: &EndpointResource, - #[bigint] close_code: u64, - #[string] reason: String, -) -> Result<(), AnyError> { - endpoint - .0 - .close(quinn::VarInt::from_u64(close_code)?, reason.as_bytes()); - Ok(()) -} - -struct ConnectionResource(quinn::Connection); +struct ConnectionResource( + quinn::Connection, + RefCell>, +); impl GarbageCollected for ConnectionResource {} -#[op2(async)] -#[cppgc] -pub(crate) async fn op_quic_accept( - #[cppgc] endpoint: &EndpointResource, -) -> Result { - match endpoint.0.accept().await { - Some(incoming) => { - let conn = incoming.accept()?.await?; - Ok(ConnectionResource(conn)) - } - None => Err(bad_resource("QuicListener is closed")), - } -} - struct IncomingResource( RefCell>, Arc, @@ -222,25 +344,30 @@ impl GarbageCollected for IncomingResource {} #[op2(async)] #[cppgc] -pub(crate) async fn op_quic_accept_incoming( - #[cppgc] endpoint: &EndpointResource, -) -> Result { - match endpoint.0.accept().await { +pub(crate) async fn op_quic_listener_accept( + #[cppgc] resource: &ListenerResource, +) -> Result { + match resource.0.accept().await { Some(incoming) => Ok(IncomingResource( RefCell::new(Some(incoming)), - endpoint.1.clone(), + resource.1.clone(), )), - None => Err(bad_resource("QuicListener is closed")), + None => Err(QuicError::BadResource("QuicListener")), } } +#[op2(fast)] +pub(crate) fn op_quic_listener_stop(#[cppgc] resource: &ListenerResource) { + resource.0.set_server_config(None); +} + #[op2] #[string] pub(crate) fn op_quic_incoming_local_ip( #[cppgc] incoming_resource: &IncomingResource, -) -> Result, AnyError> { +) -> Result, QuicError> { let Some(incoming) = incoming_resource.0.borrow_mut().take() else { - return Err(bad_resource("QuicIncoming already used")); + return Err(QuicError::BadResource("QuicIncoming")); }; Ok(incoming.local_ip().map(|ip| ip.to_string())) } @@ -249,9 +376,9 @@ pub(crate) fn op_quic_incoming_local_ip( #[serde] pub(crate) fn op_quic_incoming_remote_addr( #[cppgc] incoming_resource: &IncomingResource, -) -> Result { +) -> Result { let Some(incoming) = incoming_resource.0.borrow_mut().take() else { - return Err(bad_resource("QuicIncoming already used")); + return Err(QuicError::BadResource("QuicIncoming")); }; let addr = incoming.remote_address(); Ok(Addr { @@ -263,43 +390,66 @@ pub(crate) fn op_quic_incoming_remote_addr( #[op2(fast)] pub(crate) fn op_quic_incoming_remote_addr_validated( #[cppgc] incoming_resource: &IncomingResource, -) -> Result { +) -> Result { let Some(incoming) = incoming_resource.0.borrow_mut().take() else { - return Err(bad_resource("QuicIncoming already used")); + return Err(QuicError::BadResource("QuicIncoming")); }; Ok(incoming.remote_address_validated()) } +fn quic_incoming_accept( + incoming_resource: &IncomingResource, + transport_config: Option, +) -> Result { + let Some(incoming) = incoming_resource.0.borrow_mut().take() else { + return Err(QuicError::BadResource("QuicIncoming")); + }; + match transport_config { + Some(transport_config) if transport_config != Default::default() => { + let mut config = + quinn::ServerConfig::with_crypto(incoming_resource.1.clone()); + apply_server_transport_config(&mut config, transport_config)?; + Ok(incoming.accept_with(Arc::new(config))?) + } + _ => Ok(incoming.accept()?), + } +} + #[op2(async)] #[cppgc] pub(crate) async fn op_quic_incoming_accept( #[cppgc] incoming_resource: &IncomingResource, #[serde] transport_config: Option, -) -> Result { - let Some(incoming) = incoming_resource.0.borrow_mut().take() else { - return Err(bad_resource("QuicIncoming already used")); - }; - let conn = match transport_config { - Some(transport_config) => { - let mut config = - quinn::ServerConfig::with_crypto(incoming_resource.1.clone()); - config.preferred_address_v4(transport_config.preferred_address_v4); - config.preferred_address_v6(transport_config.preferred_address_v6); - config.transport_config(Arc::new(transport_config.try_into()?)); - incoming.accept_with(Arc::new(config))?.await? +) -> Result { + let connecting = quic_incoming_accept(incoming_resource, transport_config)?; + let conn = connecting.await?; + Ok(ConnectionResource(conn, RefCell::new(None))) +} + +#[op2] +#[cppgc] +pub(crate) fn op_quic_incoming_accept_0rtt( + #[cppgc] incoming_resource: &IncomingResource, + #[serde] transport_config: Option, +) -> Result { + let connecting = quic_incoming_accept(incoming_resource, transport_config)?; + match connecting.into_0rtt() { + Ok((conn, zrtt_accepted)) => { + Ok(ConnectionResource(conn, RefCell::new(Some(zrtt_accepted)))) } - None => incoming.accept()?.await?, - }; - Ok(ConnectionResource(conn)) + Err(_connecting) => { + unreachable!("0.5-RTT always succeeds"); + } + } } #[op2] #[serde] pub(crate) fn op_quic_incoming_refuse( #[cppgc] incoming: &IncomingResource, -) -> Result<(), AnyError> { +) -> Result<(), QuicError> { let Some(incoming) = incoming.0.borrow_mut().take() else { - return Err(bad_resource("QuicIncoming already used")); + return Err(QuicError::BadResource("QuicIncoming")); }; incoming.refuse(); Ok(()) @@ -309,43 +459,47 @@ pub(crate) fn op_quic_incoming_refuse( #[serde] pub(crate) fn op_quic_incoming_ignore( #[cppgc] incoming: &IncomingResource, -) -> Result<(), AnyError> { +) -> Result<(), QuicError> { let Some(incoming) = incoming.0.borrow_mut().take() else { - return Err(bad_resource("QuicIncoming already used")); + return Err(QuicError::BadResource("QuicIncoming")); }; incoming.ignore(); Ok(()) } +struct ConnectingResource(RefCell>); + +impl GarbageCollected for ConnectingResource {} + #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct ConnectArgs { + addr: Addr, ca_certs: Option>, alpn_protocols: Option>, server_name: Option, } -#[op2(async)] +#[op2] #[cppgc] -pub(crate) async fn op_quic_connect( +pub(crate) fn op_quic_endpoint_connect( state: Rc>, - #[serde] addr: Addr, + #[cppgc] endpoint: &EndpointResource, #[serde] args: ConnectArgs, #[serde] transport_config: TransportConfig, #[cppgc] key_pair: &TlsKeysHolder, -) -> Result +) -> Result where NP: NetPermissions + 'static, { - state - .borrow_mut() - .borrow_mut::() - .check_net(&(&addr.hostname, Some(addr.port)), "Deno.connectQuic()")?; + state.borrow_mut().borrow_mut::().check_net( + &(&args.addr.hostname, Some(args.addr.port)), + "Deno.connectQuic()", + )?; - let sock_addr = resolve_addr(&addr.hostname, addr.port) - .await? + let sock_addr = resolve_addr_sync(&args.addr.hostname, args.addr.port)? .next() - .ok_or_else(|| generic_error("No resolved address found"))?; + .ok_or_else(|| QuicError::UnableToResolve)?; let root_cert_store = state .borrow() @@ -377,24 +531,50 @@ where alpn_protocols.into_iter().map(|s| s.into_bytes()).collect(); } - let client_config = QuicClientConfig::try_from(tls_config)?; + tls_config.enable_early_data = true; + tls_config.resumption = Resumption::store(endpoint.session_store.clone()); + + let client_config = + QuicClientConfig::try_from(tls_config).expect("TLS13 supported"); let mut client_config = quinn::ClientConfig::new(Arc::new(client_config)); client_config.transport_config(Arc::new(transport_config.try_into()?)); - let local_addr = match sock_addr.ip() { - IpAddr::V4(_) => IpAddr::from(Ipv4Addr::new(0, 0, 0, 0)), - IpAddr::V6(_) => IpAddr::from(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), + let connecting = endpoint.endpoint.connect_with( + client_config, + sock_addr, + &args.server_name.unwrap_or(args.addr.hostname), + )?; + + Ok(ConnectingResource(RefCell::new(Some(connecting)))) +} + +#[op2(async)] +#[cppgc] +pub(crate) async fn op_quic_connecting_1rtt( + #[cppgc] connecting: &ConnectingResource, +) -> Result { + let Some(connecting) = connecting.0.borrow_mut().take() else { + return Err(QuicError::BadResource("QuicConnecting")); }; + let conn = connecting.await?; + Ok(ConnectionResource(conn, RefCell::new(None))) +} - let conn = quinn::Endpoint::client((local_addr, 0).into())? - .connect_with( - client_config, - sock_addr, - &args.server_name.unwrap_or(addr.hostname), - )? - .await?; - - Ok(ConnectionResource(conn)) +#[op2] +#[cppgc] +pub(crate) fn op_quic_connecting_0rtt( + #[cppgc] connecting_res: &ConnectingResource, +) -> Option { + let connecting = connecting_res.0.borrow_mut().take()?; + match connecting.into_0rtt() { + Ok((conn, zrtt_accepted)) => { + Some(ConnectionResource(conn, RefCell::new(Some(zrtt_accepted)))) + } + Err(connecting) => { + *connecting_res.0.borrow_mut() = Some(connecting); + None + } + } } #[op2] @@ -410,11 +590,23 @@ pub(crate) fn op_quic_connection_get_protocol( .map(|p| String::from_utf8_lossy(&p).into_owned()) } +#[op2] +#[string] +pub(crate) fn op_quic_connection_get_server_name( + #[cppgc] connection: &ConnectionResource, +) -> Option { + connection + .0 + .handshake_data() + .and_then(|h| h.downcast::().ok()) + .and_then(|h| h.server_name) +} + #[op2] #[serde] pub(crate) fn op_quic_connection_get_remote_addr( #[cppgc] connection: &ConnectionResource, -) -> Result { +) -> Result { let addr = connection.0.remote_address(); Ok(Addr { hostname: format!("{}", addr.ip()), @@ -423,11 +615,11 @@ pub(crate) fn op_quic_connection_get_remote_addr( } #[op2(fast)] -pub(crate) fn op_quic_close_connection( +pub(crate) fn op_quic_connection_close( #[cppgc] connection: &ConnectionResource, #[bigint] close_code: u64, #[string] reason: String, -) -> Result<(), AnyError> { +) -> Result<(), QuicError> { connection .0 .close(quinn::VarInt::from_u64(close_code)?, reason.as_bytes()); @@ -438,7 +630,7 @@ pub(crate) fn op_quic_close_connection( #[serde] pub(crate) async fn op_quic_connection_closed( #[cppgc] connection: &ConnectionResource, -) -> Result { +) -> Result { let e = connection.0.closed().await; match e { quinn::ConnectionError::LocallyClosed => Ok(CloseInfo { @@ -453,11 +645,29 @@ pub(crate) async fn op_quic_connection_closed( } } -struct SendStreamResource(AsyncRefCell); +#[op2(async)] +pub(crate) async fn op_quic_connection_handshake( + #[cppgc] connection: &ConnectionResource, +) { + let Some(zrtt_accepted) = connection.1.borrow_mut().take() else { + return; + }; + zrtt_accepted.await; +} + +struct SendStreamResource { + stream: AsyncRefCell, + stream_id: quinn::StreamId, + priority: AtomicI32, +} impl SendStreamResource { fn new(stream: quinn::SendStream) -> Self { - Self(AsyncRefCell::new(stream)) + Self { + stream_id: stream.id(), + priority: AtomicI32::new(stream.priority().unwrap_or(0)), + stream: AsyncRefCell::new(stream), + } } } @@ -468,18 +678,33 @@ impl Resource for SendStreamResource { fn write(self: Rc, view: BufView) -> AsyncResult { Box::pin(async move { - let mut r = RcRef::map(self, |r| &r.0).borrow_mut().await; - let nwritten = r.write(&view).await?; + let mut stream = + RcRef::map(self.clone(), |r| &r.stream).borrow_mut().await; + stream + .set_priority(self.priority.load(Ordering::Relaxed)) + .map_err(|e| JsErrorBox::from_err(std::io::Error::from(e)))?; + let nwritten = stream + .write(&view) + .await + .map_err(|e| JsErrorBox::from_err(std::io::Error::from(e)))?; Ok(WriteOutcome::Partial { nwritten, view }) }) } + + fn close(self: Rc) {} } -struct RecvStreamResource(AsyncRefCell); +struct RecvStreamResource { + stream: AsyncRefCell, + stream_id: quinn::StreamId, +} impl RecvStreamResource { fn new(stream: quinn::RecvStream) -> Self { - Self(AsyncRefCell::new(stream)) + Self { + stream_id: stream.id(), + stream: AsyncRefCell::new(stream), + } } } @@ -490,21 +715,49 @@ impl Resource for RecvStreamResource { fn read(self: Rc, limit: usize) -> AsyncResult { Box::pin(async move { - let mut r = RcRef::map(self, |r| &r.0).borrow_mut().await; + let mut r = RcRef::map(self, |r| &r.stream).borrow_mut().await; let mut data = vec![0; limit]; - let nread = r.read(&mut data).await?.unwrap_or(0); + let nread = r + .read(&mut data) + .await + .map_err(|e| JsErrorBox::from_err(std::io::Error::from(e)))? + .unwrap_or(0); data.truncate(nread); Ok(BufView::from(data)) }) } + + fn read_byob( + self: Rc, + mut buf: BufMutView, + ) -> AsyncResult<(usize, BufMutView)> { + Box::pin(async move { + let mut r = RcRef::map(self, |r| &r.stream).borrow_mut().await; + let nread = r + .read(&mut buf) + .await + .map_err(|e| JsErrorBox::from_err(std::io::Error::from(e)))? + .unwrap_or(0); + Ok((nread, buf)) + }) + } + + fn shutdown(self: Rc) -> AsyncResult<()> { + Box::pin(async move { + let mut r = RcRef::map(self, |r| &r.stream).borrow_mut().await; + r.stop(quinn::VarInt::from(0u32)) + .map_err(|e| JsErrorBox::from_err(std::io::Error::from(e)))?; + Ok(()) + }) + } } #[op2(async)] #[serde] -pub(crate) async fn op_quic_accept_bi( +pub(crate) async fn op_quic_connection_accept_bi( #[cppgc] connection: &ConnectionResource, state: Rc>, -) -> Result<(ResourceId, ResourceId), AnyError> { +) -> Result<(ResourceId, ResourceId), QuicError> { match connection.0.accept_bi().await { Ok((tx, rx)) => { let mut state = state.borrow_mut(); @@ -515,7 +768,7 @@ pub(crate) async fn op_quic_accept_bi( Err(e) => match e { quinn::ConnectionError::LocallyClosed | quinn::ConnectionError::ApplicationClosed(..) => { - Err(bad_resource("QuicConn is closed")) + Err(QuicError::BadResource("QuicConnection")) } _ => Err(e.into()), }, @@ -524,11 +777,11 @@ pub(crate) async fn op_quic_accept_bi( #[op2(async)] #[serde] -pub(crate) async fn op_quic_open_bi( +pub(crate) async fn op_quic_connection_open_bi( #[cppgc] connection: &ConnectionResource, state: Rc>, wait_for_available: bool, -) -> Result<(ResourceId, ResourceId), AnyError> { +) -> Result<(ResourceId, ResourceId), QuicError> { let (tx, rx) = if wait_for_available { connection.0.open_bi().await? } else { @@ -537,7 +790,7 @@ pub(crate) async fn op_quic_open_bi( match pin!(connection.0.open_bi()).poll(&mut cx) { Poll::Ready(r) => r?, Poll::Pending => { - return Err(generic_error("Connection has reached the maximum number of outgoing concurrent bidirectional streams")); + return Err(QuicError::MaxStreams("bidirectional")); } } }; @@ -549,10 +802,10 @@ pub(crate) async fn op_quic_open_bi( #[op2(async)] #[serde] -pub(crate) async fn op_quic_accept_uni( +pub(crate) async fn op_quic_connection_accept_uni( #[cppgc] connection: &ConnectionResource, state: Rc>, -) -> Result { +) -> Result { match connection.0.accept_uni().await { Ok(rx) => { let rid = state @@ -564,7 +817,7 @@ pub(crate) async fn op_quic_accept_uni( Err(e) => match e { quinn::ConnectionError::LocallyClosed | quinn::ConnectionError::ApplicationClosed(..) => { - Err(bad_resource("QuicConn is closed")) + Err(QuicError::BadResource("QuicConnection")) } _ => Err(e.into()), }, @@ -573,11 +826,11 @@ pub(crate) async fn op_quic_accept_uni( #[op2(async)] #[serde] -pub(crate) async fn op_quic_open_uni( +pub(crate) async fn op_quic_connection_open_uni( #[cppgc] connection: &ConnectionResource, state: Rc>, wait_for_available: bool, -) -> Result { +) -> Result { let tx = if wait_for_available { connection.0.open_uni().await? } else { @@ -586,7 +839,7 @@ pub(crate) async fn op_quic_open_uni( match pin!(connection.0.open_uni()).poll(&mut cx) { Poll::Ready(r) => r?, Poll::Pending => { - return Err(generic_error("Connection has reached the maximum number of outgoing concurrent unidirectional streams")); + return Err(QuicError::MaxStreams("unidirectional")); } } }; @@ -598,63 +851,80 @@ pub(crate) async fn op_quic_open_uni( } #[op2(async)] -pub(crate) async fn op_quic_send_datagram( +pub(crate) async fn op_quic_connection_send_datagram( #[cppgc] connection: &ConnectionResource, #[buffer] buf: JsBuffer, -) -> Result<(), AnyError> { +) -> Result<(), QuicError> { connection.0.send_datagram_wait(buf.to_vec().into()).await?; Ok(()) } #[op2(async)] -pub(crate) async fn op_quic_read_datagram( +#[buffer] +pub(crate) async fn op_quic_connection_read_datagram( #[cppgc] connection: &ConnectionResource, - #[buffer] mut buf: JsBuffer, -) -> Result { +) -> Result, QuicError> { let data = connection.0.read_datagram().await?; - buf[0..data.len()].copy_from_slice(&data); - Ok(data.len() as _) + Ok(data.into()) } #[op2(fast)] -pub(crate) fn op_quic_max_datagram_size( +pub(crate) fn op_quic_connection_get_max_datagram_size( #[cppgc] connection: &ConnectionResource, -) -> Result { - Ok(connection.0.max_datagram_size().unwrap_or(0) as _) +) -> u32 { + connection.0.max_datagram_size().unwrap_or(0) as _ } #[op2(fast)] -pub(crate) fn op_quic_get_send_stream_priority( +pub(crate) fn op_quic_send_stream_get_priority( state: Rc>, #[smi] rid: ResourceId, -) -> Result { +) -> Result { let resource = state .borrow() .resource_table .get::(rid)?; - let r = RcRef::map(resource, |r| &r.0).try_borrow(); - match r { - Some(s) => Ok(s.priority()?), - None => Err(generic_error("Unable to get priority")), - } + Ok(resource.priority.load(Ordering::Relaxed)) } #[op2(fast)] -pub(crate) fn op_quic_set_send_stream_priority( +pub(crate) fn op_quic_send_stream_set_priority( state: Rc>, #[smi] rid: ResourceId, priority: i32, -) -> Result<(), AnyError> { +) -> Result<(), ResourceError> { let resource = state .borrow() .resource_table .get::(rid)?; - let r = RcRef::map(resource, |r| &r.0).try_borrow(); - match r { - Some(s) => { - s.set_priority(priority)?; - Ok(()) - } - None => Err(generic_error("Unable to set priority")), - } + resource.priority.store(priority, Ordering::Relaxed); + Ok(()) +} + +#[op2(fast)] +#[bigint] +pub(crate) fn op_quic_send_stream_get_id( + state: Rc>, + #[smi] rid: ResourceId, +) -> Result { + let resource = state + .borrow() + .resource_table + .get::(rid)?; + let stream_id = quinn::VarInt::from(resource.stream_id).into_inner(); + Ok(stream_id) +} + +#[op2(fast)] +#[bigint] +pub(crate) fn op_quic_recv_stream_get_id( + state: Rc>, + #[smi] rid: ResourceId, +) -> Result { + let resource = state + .borrow() + .resource_table + .get::(rid)?; + let stream_id = quinn::VarInt::from(resource.stream_id).into_inner(); + Ok(stream_id) } diff --git a/ext/net/raw.rs b/ext/net/raw.rs index a2ebfb5acb..fc380635f6 100644 --- a/ext/net/raw.rs +++ b/ext/net/raw.rs @@ -1,16 +1,18 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use crate::io::TcpStreamResource; -use crate::ops_tls::TlsStreamResource; -use deno_core::error::bad_resource_id; -use deno_core::error::custom_error; -use deno_core::error::AnyError; +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::borrow::Cow; +use std::rc::Rc; + +use deno_core::error::ResourceError; use deno_core::AsyncRefCell; use deno_core::CancelHandle; use deno_core::Resource; use deno_core::ResourceId; use deno_core::ResourceTable; -use std::borrow::Cow; -use std::rc::Rc; +use deno_error::JsErrorBox; + +use crate::io::TcpStreamResource; +use crate::ops_tls::TlsStreamResource; pub trait NetworkStreamTrait: Into { type Resource; @@ -67,10 +69,10 @@ impl NetworkListenerResource { fn take( resource_table: &mut ResourceTable, listener_rid: ResourceId, - ) -> Result, AnyError> { + ) -> Result, JsErrorBox> { if let Ok(resource_rc) = resource_table.take::(listener_rid) { let resource = Rc::try_unwrap(resource_rc) - .map_err(|_| custom_error("Busy", "Listener is currently in use"))?; + .map_err(|_| JsErrorBox::new("Busy", "Listener is currently in use"))?; return Ok(Some(resource.listener.into_inner().into())); } Ok(None) @@ -241,13 +243,13 @@ macro_rules! network_stream { /// Return a `NetworkStreamListener` if a resource exists for this `ResourceId` and it is currently /// not locked. - pub fn take_resource(resource_table: &mut ResourceTable, listener_rid: ResourceId) -> Result { + pub fn take_resource(resource_table: &mut ResourceTable, listener_rid: ResourceId) -> Result { $( if let Some(resource) = NetworkListenerResource::<$listener>::take(resource_table, listener_rid)? { return Ok(resource) } )* - Err(bad_resource_id()) + Err(JsErrorBox::from_err(ResourceError::BadResourceId)) } } }; @@ -320,12 +322,36 @@ impl From for NetworkStreamAddress { } } +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum TakeNetworkStreamError { + #[class("Busy")] + #[error("TCP stream is currently in use")] + TcpBusy, + #[class("Busy")] + #[error("TLS stream is currently in use")] + TlsBusy, + #[cfg(unix)] + #[class("Busy")] + #[error("Unix socket is currently in use")] + UnixBusy, + #[class(generic)] + #[error(transparent)] + ReuniteTcp(#[from] tokio::net::tcp::ReuniteError), + #[cfg(unix)] + #[class(generic)] + #[error(transparent)] + ReuniteUnix(#[from] tokio::net::unix::ReuniteError), + #[class(inherit)] + #[error(transparent)] + Resource(deno_core::error::ResourceError), +} + /// In some cases it may be more efficient to extract the resource from the resource table and use it directly (for example, an HTTP server). /// This method will extract a stream from the resource table and return it, unwrapped. pub fn take_network_stream_resource( resource_table: &mut ResourceTable, stream_rid: ResourceId, -) -> Result { +) -> Result { // The stream we're attempting to unwrap may be in use somewhere else. If that's the case, we cannot proceed // with the process of unwrapping this connection, so we just return a bad resource error. // See also: https://github.com/denoland/deno/pull/16242 @@ -334,7 +360,7 @@ pub fn take_network_stream_resource( { // This TCP connection might be used somewhere else. let resource = Rc::try_unwrap(resource_rc) - .map_err(|_| custom_error("Busy", "TCP stream is currently in use"))?; + .map_err(|_| TakeNetworkStreamError::TcpBusy)?; let (read_half, write_half) = resource.into_inner(); let tcp_stream = read_half.reunite(write_half)?; return Ok(NetworkStream::Tcp(tcp_stream)); @@ -344,7 +370,7 @@ pub fn take_network_stream_resource( { // This TLS connection might be used somewhere else. let resource = Rc::try_unwrap(resource_rc) - .map_err(|_| custom_error("Busy", "TLS stream is currently in use"))?; + .map_err(|_| TakeNetworkStreamError::TlsBusy)?; let (read_half, write_half) = resource.into_inner(); let tls_stream = read_half.unsplit(write_half); return Ok(NetworkStream::Tls(tls_stream)); @@ -356,13 +382,15 @@ pub fn take_network_stream_resource( { // This UNIX socket might be used somewhere else. let resource = Rc::try_unwrap(resource_rc) - .map_err(|_| custom_error("Busy", "Unix socket is currently in use"))?; + .map_err(|_| TakeNetworkStreamError::UnixBusy)?; let (read_half, write_half) = resource.into_inner(); let unix_stream = read_half.reunite(write_half)?; return Ok(NetworkStream::Unix(unix_stream)); } - Err(bad_resource_id()) + Err(TakeNetworkStreamError::Resource( + ResourceError::BadResourceId, + )) } /// In some cases it may be more efficient to extract the resource from the resource table and use it directly (for example, an HTTP server). @@ -370,6 +398,6 @@ pub fn take_network_stream_resource( pub fn take_network_stream_listener_resource( resource_table: &mut ResourceTable, listener_rid: ResourceId, -) -> Result { +) -> Result { NetworkStreamListener::take_resource(resource_table, listener_rid) } diff --git a/ext/net/resolve_addr.rs b/ext/net/resolve_addr.rs index 3a97081eac..9a757391ea 100644 --- a/ext/net/resolve_addr.rs +++ b/ext/net/resolve_addr.rs @@ -1,7 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::net::SocketAddr; use std::net::ToSocketAddrs; + use tokio::net::lookup_host; /// Resolve network address *asynchronously*. @@ -38,12 +39,13 @@ fn make_addr_port_pair(hostname: &str, port: u16) -> (&str, u16) { #[cfg(test)] mod tests { - use super::*; use std::net::Ipv4Addr; use std::net::Ipv6Addr; use std::net::SocketAddrV4; use std::net::SocketAddrV6; + use super::*; + #[tokio::test] async fn resolve_addr1() { let expected = vec![SocketAddr::V4(SocketAddrV4::new( diff --git a/ext/net/tcp.rs b/ext/net/tcp.rs index 63baa8e4be..f2cd5f5705 100644 --- a/ext/net/tcp.rs +++ b/ext/net/tcp.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashMap; use std::net::SocketAddr; use std::sync::Arc; diff --git a/ext/node/Cargo.toml b/ext/node/Cargo.toml index 1f8104d978..2f54440c23 100644 --- a/ext/node/Cargo.toml +++ b/ext/node/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_node" -version = "0.122.0" +version = "0.124.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -29,6 +29,7 @@ cbc.workspace = true const-oid = "0.9.5" data-encoding.workspace = true deno_core.workspace = true +deno_error.workspace = true deno_fetch.workspace = true deno_fs.workspace = true deno_io.workspace = true @@ -37,6 +38,7 @@ deno_net.workspace = true deno_package_json.workspace = true deno_path_util.workspace = true deno_permissions.workspace = true +deno_process.workspace = true deno_whoami = "0.1.0" der = { version = "0.7.9", features = ["derive"] } digest = { version = "0.10.5", features = ["core-api", "std"] } @@ -49,7 +51,6 @@ errno = "0.2.8" faster-hex.workspace = true h2.workspace = true hkdf.workspace = true -home = "0.5.9" http.workspace = true http-body-util.workspace = true hyper.workspace = true @@ -76,7 +77,6 @@ p256.workspace = true p384.workspace = true path-clean = "=0.1.0" pbkdf2 = "0.12.1" -pin-project-lite = "0.2.13" pkcs8 = { version = "0.10.2", features = ["std", "pkcs5", "encryption"] } rand.workspace = true regex.workspace = true @@ -95,7 +95,7 @@ simd-json = "0.14.0" sm3 = "0.4.2" spki.workspace = true stable_deref_trait = "1.2.0" -sys_traits = { workspace = true, features = ["real"] } +sys_traits = { workspace = true, features = ["real", "winapi", "libc"] } thiserror.workspace = true tokio.workspace = true tokio-eld = "0.2" diff --git a/ext/node/benchmarks/child_process_ipc.mjs b/ext/node/benchmarks/child_process_ipc.mjs index fa671d76f7..aa4e2699d7 100644 --- a/ext/node/benchmarks/child_process_ipc.mjs +++ b/ext/node/benchmarks/child_process_ipc.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { fork } from "node:child_process"; import process from "node:process"; diff --git a/ext/node/build.rs b/ext/node/build.rs index 041110f257..0d42f2cd76 100644 --- a/ext/node/build.rs +++ b/ext/node/build.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::env; diff --git a/ext/node/global.rs b/ext/node/global.rs index 4d6695431d..92439773d6 100644 --- a/ext/node/global.rs +++ b/ext/node/global.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::v8; use deno_core::v8::GetPropertyNamesArgs; @@ -54,6 +54,8 @@ const fn str_to_utf16(s: &str) -> [u16; N] { // - clearTimeout (both, but different implementation) // - global (node only) // - performance (both, but different implementation) +// - process (always available in Node, while the availability in Deno depends +// on project creation time in Deno Deploy) // - setImmediate (node only) // - setInterval (both, but different implementation) // - setTimeout (both, but different implementation) @@ -61,7 +63,7 @@ const fn str_to_utf16(s: &str) -> [u16; N] { // UTF-16 encodings of the managed globals. THIS LIST MUST BE SORTED. #[rustfmt::skip] -const MANAGED_GLOBALS: [&[u16]; 12] = [ +const MANAGED_GLOBALS: [&[u16]; 13] = [ &str_to_utf16::<6>("Buffer"), &str_to_utf16::<17>("WorkerGlobalScope"), &str_to_utf16::<14>("clearImmediate"), @@ -69,6 +71,7 @@ const MANAGED_GLOBALS: [&[u16]; 12] = [ &str_to_utf16::<12>("clearTimeout"), &str_to_utf16::<6>("global"), &str_to_utf16::<11>("performance"), + &str_to_utf16::<7>("process"), &str_to_utf16::<4>("self"), &str_to_utf16::<12>("setImmediate"), &str_to_utf16::<11>("setInterval"), diff --git a/ext/node/lib.rs b/ext/node/lib.rs index 5c7cea75ed..5c9afeeef0 100644 --- a/ext/node/lib.rs +++ b/ext/node/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. #![deny(clippy::print_stderr)] #![deny(clippy::print_stdout)] @@ -8,15 +8,16 @@ use std::collections::HashSet; use std::path::Path; use std::path::PathBuf; -use deno_core::error::AnyError; use deno_core::op2; use deno_core::url::Url; #[allow(unused_imports)] use deno_core::v8; use deno_core::v8::ExternalReference; +use deno_error::JsErrorBox; use node_resolver::errors::ClosestPkgJsonError; +use node_resolver::InNpmPackageChecker; use node_resolver::IsBuiltInNodeModuleChecker; -use node_resolver::NpmPackageFolderResolverRc; +use node_resolver::NpmPackageFolderResolver; use node_resolver::PackageJsonResolverRc; use once_cell::sync::Lazy; @@ -30,8 +31,6 @@ pub use deno_package_json::PackageJson; use deno_permissions::PermissionCheckError; pub use node_resolver::PathClean; pub use ops::ipc::ChildPipeFd; -pub use ops::ipc::IpcJsonStreamResource; -pub use ops::ipc::IpcRefTracker; use ops::vm; pub use ops::vm::create_v8_context; pub use ops::vm::init_global_template; @@ -157,12 +156,12 @@ pub trait NodeRequireLoader { &self, permissions: &mut dyn NodePermissions, path: &'a Path, - ) -> Result, AnyError>; + ) -> Result, JsErrorBox>; fn load_text_file_lossy( &self, path: &Path, - ) -> Result, AnyError>; + ) -> Result, JsErrorBox>; /// Get if the module kind is maybe CJS and loading should determine /// if its CJS or ESM. @@ -185,17 +184,21 @@ fn op_node_build_os() -> String { } #[derive(Clone)] -pub struct NodeExtInitServices { +pub struct NodeExtInitServices< + TInNpmPackageChecker: InNpmPackageChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, + TSys: ExtNodeSys, +> { pub node_require_loader: NodeRequireLoaderRc, - pub node_resolver: NodeResolverRc, - pub npm_resolver: NpmPackageFolderResolverRc, + pub node_resolver: + NodeResolverRc, pub pkg_json_resolver: PackageJsonResolverRc, pub sys: TSys, } deno_core::extension!(deno_node, deps = [ deno_io, deno_fs ], - parameters = [P: NodePermissions, TSys: ExtNodeSys], + parameters = [P: NodePermissions, TInNpmPackageChecker: InNpmPackageChecker, TNpmPackageFolderResolver: NpmPackageFolderResolver, TSys: ExtNodeSys], ops = [ ops::blocklist::op_socket_address_parse, ops::blocklist::op_socket_address_get_serialization, @@ -395,13 +398,13 @@ deno_core::extension!(deno_node, ops::require::op_require_init_paths, ops::require::op_require_node_module_paths, ops::require::op_require_proxy_path, - ops::require::op_require_is_deno_dir_package, - ops::require::op_require_resolve_deno_dir, + ops::require::op_require_is_deno_dir_package, + ops::require::op_require_resolve_deno_dir, ops::require::op_require_is_maybe_cjs, ops::require::op_require_is_request_relative, ops::require::op_require_resolve_lookup_paths, ops::require::op_require_try_self_parent_path, - ops::require::op_require_try_self, + ops::require::op_require_try_self, ops::require::op_require_real_path, ops::require::op_require_path_is_absolute, ops::require::op_require_path_dirname, @@ -410,9 +413,9 @@ deno_core::extension!(deno_node, ops::require::op_require_path_basename, ops::require::op_require_read_file

, ops::require::op_require_as_file_path, - ops::require::op_require_resolve_exports, + ops::require::op_require_resolve_exports, ops::require::op_require_read_package_scope, - ops::require::op_require_package_imports_resolve, + ops::require::op_require_package_imports_resolve, ops::require::op_require_break_on_next_statement, ops::util::op_node_guess_handle_type, ops::worker_threads::op_worker_threads_filename, @@ -489,7 +492,7 @@ deno_core::extension!(deno_node, "_fs/_fs_watch.ts", "_fs/_fs_write.mjs", "_fs/_fs_writeFile.ts", - "_fs/_fs_writev.mjs", + "_fs/_fs_writev.ts", "_next_tick.ts", "_process/exiting.ts", "_process/process.ts", @@ -684,7 +687,7 @@ deno_core::extension!(deno_node, "node:zlib" = "zlib.ts", ], options = { - maybe_init: Option>, + maybe_init: Option>, fs: deno_fs::FileSystemRc, }, state = |state, options| { @@ -694,7 +697,6 @@ deno_core::extension!(deno_node, state.put(init.sys.clone()); state.put(init.node_require_loader.clone()); state.put(init.node_resolver.clone()); - state.put(init.npm_resolver.clone()); state.put(init.pkg_json_resolver.clone()); } }, @@ -836,10 +838,18 @@ pub trait ExtNodeSys: impl ExtNodeSys for sys_traits::impls::RealSys {} -pub type NodeResolver = - node_resolver::NodeResolver; +pub type NodeResolver = + node_resolver::NodeResolver< + TInNpmPackageChecker, + RealIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >; #[allow(clippy::disallowed_types)] -pub type NodeResolverRc = deno_fs::sync::MaybeArc>; +pub type NodeResolverRc = + deno_fs::sync::MaybeArc< + NodeResolver, + >; #[allow(clippy::disallowed_types)] pub fn create_host_defined_options<'s>( diff --git a/ext/node/ops/blocklist.rs b/ext/node/ops/blocklist.rs index 6c64d68eca..16bda73fe0 100644 --- a/ext/node/ops/blocklist.rs +++ b/ext/node/ops/blocklist.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::cell::RefCell; use std::collections::HashSet; @@ -9,7 +9,6 @@ use std::net::SocketAddr; use deno_core::op2; use deno_core::OpState; - use ipnetwork::IpNetwork; use ipnetwork::Ipv4Network; use ipnetwork::Ipv6Network; @@ -24,7 +23,8 @@ impl deno_core::GarbageCollected for BlockListResource {} #[derive(Serialize)] struct SocketAddressSerialization(String, String); -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(generic)] pub enum BlocklistError { #[error("{0}")] AddrParse(#[from] std::net::AddrParseError), diff --git a/ext/node/ops/buffer.rs b/ext/node/ops/buffer.rs index 01f878ec15..0e8cff5cc0 100644 --- a/ext/node/ops/buffer.rs +++ b/ext/node/ops/buffer.rs @@ -1,8 +1,7 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use deno_core::anyhow::anyhow; -use deno_core::anyhow::Result; use deno_core::op2; +use deno_error::JsErrorBox; #[op2(fast)] pub fn op_is_ascii(#[buffer] buf: &[u8]) -> bool { @@ -20,7 +19,7 @@ pub fn op_transcode( #[buffer] source: &[u8], #[string] from_encoding: &str, #[string] to_encoding: &str, -) -> Result> { +) -> Result, JsErrorBox> { match (from_encoding, to_encoding) { ("utf8", "ascii") => Ok(utf8_to_ascii(source)), ("utf8", "latin1") => Ok(utf8_to_latin1(source)), @@ -29,7 +28,9 @@ pub fn op_transcode( ("latin1", "utf16le") | ("ascii", "utf16le") => { Ok(latin1_ascii_to_utf16le(source)) } - (from, to) => Err(anyhow!("Unable to transcode Buffer {from}->{to}")), + (from, to) => Err(JsErrorBox::generic(format!( + "Unable to transcode Buffer {from}->{to}" + ))), } } @@ -42,18 +43,19 @@ fn latin1_ascii_to_utf16le(source: &[u8]) -> Vec { result } -fn utf16le_to_utf8(source: &[u8]) -> Result> { +fn utf16le_to_utf8(source: &[u8]) -> Result, JsErrorBox> { let ucs2_vec: Vec = source .chunks(2) .map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]])) .collect(); String::from_utf16(&ucs2_vec) .map(|utf8_string| utf8_string.into_bytes()) - .map_err(|e| anyhow!("Invalid UTF-16 sequence: {}", e)) + .map_err(|e| JsErrorBox::generic(format!("Invalid UTF-16 sequence: {}", e))) } -fn utf8_to_utf16le(source: &[u8]) -> Result> { - let utf8_string = std::str::from_utf8(source)?; +fn utf8_to_utf16le(source: &[u8]) -> Result, JsErrorBox> { + let utf8_string = + std::str::from_utf8(source).map_err(JsErrorBox::from_err)?; let ucs2_vec: Vec = utf8_string.encode_utf16().collect(); let bytes: Vec = ucs2_vec.iter().flat_map(|&x| x.to_le_bytes()).collect(); Ok(bytes) diff --git a/ext/node/ops/crypto/cipher.rs b/ext/node/ops/crypto/cipher.rs index 7f5b108a04..a12f36e04a 100644 --- a/ext/node/ops/crypto/cipher.rs +++ b/ext/node/ops/crypto/cipher.rs @@ -1,4 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::borrow::Cow; +use std::cell::RefCell; +use std::rc::Rc; use aes::cipher::block_padding::Pkcs7; use aes::cipher::BlockDecryptMut; @@ -8,10 +12,6 @@ use deno_core::Resource; use digest::generic_array::GenericArray; use digest::KeyInit; -use std::borrow::Cow; -use std::cell::RefCell; -use std::rc::Rc; - type Tag = Option>; type Aes128Gcm = aead_gcm_stream::AesGcm; @@ -47,12 +47,15 @@ pub struct DecipherContext { decipher: Rc>, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum CipherContextError { + #[class(type)] #[error("Cipher context is already in use")] ContextInUse, + #[class(inherit)] #[error("{0}")] - Resource(deno_core::error::AnyError), + Resource(#[from] deno_core::error::ResourceError), + #[class(inherit)] #[error(transparent)] Cipher(#[from] CipherError), } @@ -94,12 +97,15 @@ impl CipherContext { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum DecipherContextError { + #[class(type)] #[error("Decipher context is already in use")] ContextInUse, + #[class(inherit)] #[error("{0}")] - Resource(deno_core::error::AnyError), + Resource(#[from] deno_core::error::ResourceError), + #[class(inherit)] #[error(transparent)] Decipher(#[from] DecipherError), } @@ -150,16 +156,21 @@ impl Resource for DecipherContext { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum CipherError { + #[class(type)] #[error("IV length must be 12 bytes")] InvalidIvLength, + #[class(range)] #[error("Invalid key length")] InvalidKeyLength, + #[class(type)] #[error("Invalid initialization vector")] InvalidInitializationVector, + #[class(type)] #[error("Cannot pad the input data")] CannotPadInputData, + #[class(type)] #[error("Unknown cipher {0}")] UnknownCipher(String), } @@ -352,22 +363,30 @@ impl Cipher { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum DecipherError { + #[class(type)] #[error("IV length must be 12 bytes")] InvalidIvLength, + #[class(range)] #[error("Invalid key length")] InvalidKeyLength, + #[class(type)] #[error("Invalid initialization vector")] InvalidInitializationVector, + #[class(type)] #[error("Cannot unpad the input data")] CannotUnpadInputData, + #[class(type)] #[error("Failed to authenticate data")] DataAuthenticationFailed, + #[class(type)] #[error("setAutoPadding(false) not supported for Aes128Gcm yet")] SetAutoPaddingFalseAes128GcmUnsupported, + #[class(type)] #[error("setAutoPadding(false) not supported for Aes256Gcm yet")] SetAutoPaddingFalseAes256GcmUnsupported, + #[class(type)] #[error("Unknown cipher {0}")] UnknownCipher(String), } diff --git a/ext/node/ops/crypto/dh.rs b/ext/node/ops/crypto/dh.rs index ff2bd030eb..88452c3660 100644 --- a/ext/node/ops/crypto/dh.rs +++ b/ext/node/ops/crypto/dh.rs @@ -1,10 +1,11 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use super::primes::Prime; use num_bigint_dig::BigUint; use num_bigint_dig::RandBigInt; use num_traits::FromPrimitive; +use super::primes::Prime; + #[derive(Clone)] pub struct PublicKey(BigUint); diff --git a/ext/node/ops/crypto/digest.rs b/ext/node/ops/crypto/digest.rs index a7d8fb51f1..5f15dace30 100644 --- a/ext/node/ops/crypto/digest.rs +++ b/ext/node/ops/crypto/digest.rs @@ -1,11 +1,12 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. +use std::cell::RefCell; +use std::rc::Rc; + use deno_core::GarbageCollected; use digest::Digest; use digest::DynDigest; use digest::ExtendableOutput; use digest::Update; -use std::cell::RefCell; -use std::rc::Rc; pub struct Hasher { pub hash: Rc>>, @@ -182,7 +183,8 @@ pub enum Hash { use Hash::*; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(generic)] pub enum HashError { #[error("Output length mismatch for non-extendable algorithm")] OutputLengthMismatch, diff --git a/ext/node/ops/crypto/keys.rs b/ext/node/ops/crypto/keys.rs index dfcd3d11bf..79b09faa26 100644 --- a/ext/node/ops/crypto/keys.rs +++ b/ext/node/ops/crypto/keys.rs @@ -1,15 +1,15 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::cell::RefCell; use base64::Engine; -use deno_core::error::type_error; use deno_core::op2; use deno_core::serde_v8::BigInt as V8BigInt; use deno_core::unsync::spawn_blocking; use deno_core::GarbageCollected; use deno_core::ToJsBuffer; +use deno_error::JsErrorBox; use ed25519_dalek::pkcs8::BitStringRef; use elliptic_curve::JwkEcKey; use num_bigint::BigInt; @@ -375,55 +375,72 @@ impl<'a> TryFrom> for RsaPssParameters<'a> { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum X509PublicKeyError { + #[class(generic)] #[error(transparent)] - X509(#[from] x509_parser::error::X509Error), + X509(#[from] X509Error), + #[class(generic)] #[error(transparent)] Rsa(#[from] rsa::Error), + #[class(generic)] #[error(transparent)] Asn1(#[from] x509_parser::der_parser::asn1_rs::Error), + #[class(generic)] #[error(transparent)] Ec(#[from] elliptic_curve::Error), + #[class(type)] #[error("unsupported ec named curve")] UnsupportedEcNamedCurve, + #[class(type)] #[error("missing ec parameters")] MissingEcParameters, + #[class(type)] #[error("malformed DSS public key")] MalformedDssPublicKey, + #[class(type)] #[error("unsupported x509 public key type")] UnsupportedX509KeyType, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum RsaJwkError { + #[class(generic)] #[error(transparent)] Base64(#[from] base64::DecodeError), + #[class(generic)] #[error(transparent)] Rsa(#[from] rsa::Error), + #[class(type)] #[error("missing RSA private component")] MissingRsaPrivateComponent, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum EcJwkError { + #[class(generic)] #[error(transparent)] Ec(#[from] elliptic_curve::Error), + #[class(type)] #[error("unsupported curve: {0}")] UnsupportedCurve(String), } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum EdRawError { + #[class(generic)] #[error(transparent)] Ed25519Signature(#[from] ed25519_dalek::SignatureError), + #[class(type)] #[error("invalid Ed25519 key")] InvalidEd25519Key, + #[class(type)] #[error("unsupported curve")] UnsupportedCurve, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(type)] pub enum AsymmetricPrivateKeyError { #[error("invalid PEM private key: not valid utf8 starting at byte {0}")] InvalidPemPrivateKeyInvalidUtf8(usize), @@ -439,8 +456,13 @@ pub enum AsymmetricPrivateKeyError { InvalidSec1PrivateKey, #[error("unsupported PEM label: {0}")] UnsupportedPemLabel(String), + #[class(inherit)] #[error(transparent)] - RsaPssParamsParse(#[from] RsaPssParamsParseError), + RsaPssParamsParse( + #[from] + #[inherit] + RsaPssParamsParseError, + ), #[error("invalid encrypted PKCS#8 private key")] InvalidEncryptedPkcs8PrivateKey, #[error("invalid PKCS#8 private key")] @@ -473,58 +495,96 @@ pub enum AsymmetricPrivateKeyError { UnsupportedPrivateKeyOid, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum AsymmetricPublicKeyError { + #[class(type)] #[error("invalid PEM private key: not valid utf8 starting at byte {0}")] InvalidPemPrivateKeyInvalidUtf8(usize), + #[class(type)] #[error("invalid PEM public key")] InvalidPemPublicKey, + #[class(type)] #[error("invalid PKCS#1 public key")] InvalidPkcs1PublicKey, + #[class(inherit)] #[error(transparent)] - AsymmetricPrivateKey(#[from] AsymmetricPrivateKeyError), + AsymmetricPrivateKey( + #[from] + #[inherit] + AsymmetricPrivateKeyError, + ), + #[class(type)] #[error("invalid x509 certificate")] InvalidX509Certificate, + #[class(generic)] #[error(transparent)] X509(#[from] x509_parser::nom::Err), + #[class(inherit)] #[error(transparent)] - X509PublicKey(#[from] X509PublicKeyError), + X509PublicKey( + #[from] + #[inherit] + X509PublicKeyError, + ), + #[class(type)] #[error("unsupported PEM label: {0}")] UnsupportedPemLabel(String), + #[class(type)] #[error("invalid SPKI public key")] InvalidSpkiPublicKey, + #[class(type)] #[error("unsupported key type: {0}")] UnsupportedKeyType(String), + #[class(type)] #[error("unsupported key format: {0}")] UnsupportedKeyFormat(String), + #[class(generic)] #[error(transparent)] Spki(#[from] spki::Error), + #[class(generic)] #[error(transparent)] Pkcs1(#[from] rsa::pkcs1::Error), + #[class(inherit)] #[error(transparent)] - RsaPssParamsParse(#[from] RsaPssParamsParseError), + RsaPssParamsParse( + #[from] + #[inherit] + RsaPssParamsParseError, + ), + #[class(type)] #[error("malformed DSS public key")] MalformedDssPublicKey, + #[class(type)] #[error("malformed or missing named curve in ec parameters")] MalformedOrMissingNamedCurveInEcParameters, + #[class(type)] #[error("malformed or missing public key in ec spki")] MalformedOrMissingPublicKeyInEcSpki, + #[class(generic)] #[error(transparent)] Ec(#[from] elliptic_curve::Error), + #[class(type)] #[error("unsupported ec named curve")] UnsupportedEcNamedCurve, + #[class(type)] #[error("malformed or missing public key in x25519 spki")] MalformedOrMissingPublicKeyInX25519Spki, + #[class(type)] #[error("x25519 public key is too short")] X25519PublicKeyIsTooShort, + #[class(type)] #[error("invalid Ed25519 public key")] InvalidEd25519PublicKey, + #[class(type)] #[error("missing dh parameters")] MissingDhParameters, + #[class(type)] #[error("malformed dh parameters")] MalformedDhParameters, + #[class(type)] #[error("malformed or missing public key in dh spki")] MalformedOrMissingPublicKeyInDhSpki, + #[class(type)] #[error("unsupported private key oid")] UnsupportedPrivateKeyOid, } @@ -1043,7 +1103,8 @@ impl KeyObjectHandle { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(type)] pub enum RsaPssParamsParseError { #[error("malformed pss private key parameters")] MalformedPssPrivateKeyParameters, @@ -1118,7 +1179,8 @@ fn bytes_to_b64(bytes: &[u8]) -> String { BASE64_URL_SAFE_NO_PAD.encode(bytes) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(type)] pub enum AsymmetricPrivateKeyJwkError { #[error("key is not an asymmetric private key")] KeyIsNotAsymmetricPrivateKey, @@ -1128,7 +1190,8 @@ pub enum AsymmetricPrivateKeyJwkError { JwkExportNotImplementedForKeyType, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(type)] pub enum AsymmetricPublicKeyJwkError { #[error("key is not an asymmetric public key")] KeyIsNotAsymmetricPublicKey, @@ -1138,7 +1201,8 @@ pub enum AsymmetricPublicKeyJwkError { JwkExportNotImplementedForKeyType, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(type)] pub enum AsymmetricPublicKeyDerError { #[error("key is not an asymmetric public key")] KeyIsNotAsymmetricPublicKey, @@ -1323,7 +1387,8 @@ impl AsymmetricPublicKey { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(type)] pub enum AsymmetricPrivateKeyDerError { #[error("key is not an asymmetric private key")] KeyIsNotAsymmetricPrivateKey, @@ -1335,6 +1400,7 @@ pub enum AsymmetricPrivateKeyDerError { InvalidEcPrivateKey, #[error("exporting non-EC private key as SEC1 is not supported")] ExportingNonEcPrivateKeyAsSec1Unsupported, + #[class(type)] #[error("exporting RSA-PSS private key as PKCS#8 is not supported yet")] ExportingNonRsaPssPrivateKeyAsPkcs8Unsupported, #[error("invalid DSA private key")] @@ -1615,7 +1681,7 @@ pub fn op_node_create_secret_key( #[string] pub fn op_node_get_asymmetric_key_type( #[cppgc] handle: &KeyObjectHandle, -) -> Result<&'static str, deno_core::error::AnyError> { +) -> Result<&'static str, JsErrorBox> { match handle { KeyObjectHandle::AsymmetricPrivate(AsymmetricPrivateKey::Rsa(_)) | KeyObjectHandle::AsymmetricPublic(AsymmetricPublicKey::Rsa(_)) => { @@ -1641,9 +1707,9 @@ pub fn op_node_get_asymmetric_key_type( } KeyObjectHandle::AsymmetricPrivate(AsymmetricPrivateKey::Dh(_)) | KeyObjectHandle::AsymmetricPublic(AsymmetricPublicKey::Dh(_)) => Ok("dh"), - KeyObjectHandle::Secret(_) => { - Err(type_error("symmetric key is not an asymmetric key")) - } + KeyObjectHandle::Secret(_) => Err(JsErrorBox::type_error( + "symmetric key is not an asymmetric key", + )), } } @@ -1686,7 +1752,7 @@ pub enum AsymmetricKeyDetails { #[serde] pub fn op_node_get_asymmetric_key_details( #[cppgc] handle: &KeyObjectHandle, -) -> Result { +) -> Result { match handle { KeyObjectHandle::AsymmetricPrivate(private_key) => match private_key { AsymmetricPrivateKey::Rsa(key) => { @@ -1794,9 +1860,9 @@ pub fn op_node_get_asymmetric_key_details( AsymmetricPublicKey::Ed25519(_) => Ok(AsymmetricKeyDetails::Ed25519), AsymmetricPublicKey::Dh(_) => Ok(AsymmetricKeyDetails::Dh), }, - KeyObjectHandle::Secret(_) => { - Err(type_error("symmetric key is not an asymmetric key")) - } + KeyObjectHandle::Secret(_) => Err(JsErrorBox::type_error( + "symmetric key is not an asymmetric key", + )), } } @@ -1804,12 +1870,12 @@ pub fn op_node_get_asymmetric_key_details( #[smi] pub fn op_node_get_symmetric_key_size( #[cppgc] handle: &KeyObjectHandle, -) -> Result { +) -> Result { match handle { KeyObjectHandle::AsymmetricPrivate(_) - | KeyObjectHandle::AsymmetricPublic(_) => { - Err(type_error("asymmetric key is not a symmetric key")) - } + | KeyObjectHandle::AsymmetricPublic(_) => Err(JsErrorBox::type_error( + "asymmetric key is not a symmetric key", + )), KeyObjectHandle::Secret(key) => Ok(key.len() * 8), } } @@ -1912,7 +1978,8 @@ pub async fn op_node_generate_rsa_key_async( .unwrap() } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(type)] #[error("digest not allowed for RSA-PSS keys{}", .0.as_ref().map(|digest| format!(": {digest}")).unwrap_or_default())] pub struct GenerateRsaPssError(Option); @@ -2016,7 +2083,7 @@ pub async fn op_node_generate_rsa_pss_key_async( fn dsa_generate( modulus_length: usize, divisor_length: usize, -) -> Result { +) -> Result { let mut rng = rand::thread_rng(); use dsa::Components; use dsa::KeySize; @@ -2029,7 +2096,7 @@ fn dsa_generate( (2048, 256) => KeySize::DSA_2048_256, (3072, 256) => KeySize::DSA_3072_256, _ => { - return Err(type_error( + return Err(JsErrorBox::type_error( "Invalid modulusLength+divisorLength combination", )) } @@ -2047,7 +2114,7 @@ fn dsa_generate( pub fn op_node_generate_dsa_key( #[smi] modulus_length: usize, #[smi] divisor_length: usize, -) -> Result { +) -> Result { dsa_generate(modulus_length, divisor_length) } @@ -2056,15 +2123,13 @@ pub fn op_node_generate_dsa_key( pub async fn op_node_generate_dsa_key_async( #[smi] modulus_length: usize, #[smi] divisor_length: usize, -) -> Result { +) -> Result { spawn_blocking(move || dsa_generate(modulus_length, divisor_length)) .await .unwrap() } -fn ec_generate( - named_curve: &str, -) -> Result { +fn ec_generate(named_curve: &str) -> Result { let mut rng = rand::thread_rng(); // TODO(@littledivy): Support public key point encoding. // Default is uncompressed. @@ -2082,7 +2147,7 @@ fn ec_generate( AsymmetricPrivateKey::Ec(EcPrivateKey::P384(key)) } _ => { - return Err(type_error(format!( + return Err(JsErrorBox::type_error(format!( "unsupported named curve: {}", named_curve ))) @@ -2096,7 +2161,7 @@ fn ec_generate( #[cppgc] pub fn op_node_generate_ec_key( #[string] named_curve: &str, -) -> Result { +) -> Result { ec_generate(named_curve) } @@ -2104,7 +2169,7 @@ pub fn op_node_generate_ec_key( #[cppgc] pub async fn op_node_generate_ec_key_async( #[string] named_curve: String, -) -> Result { +) -> Result { spawn_blocking(move || ec_generate(&named_curve)) .await .unwrap() @@ -2160,7 +2225,7 @@ fn u32_slice_to_u8_slice(slice: &[u32]) -> &[u8] { fn dh_group_generate( group_name: &str, -) -> Result { +) -> Result { let (dh, prime, generator) = match group_name { "modp5" => ( dh::DiffieHellman::group::(), @@ -2192,7 +2257,7 @@ fn dh_group_generate( dh::Modp8192::MODULUS, dh::Modp8192::GENERATOR, ), - _ => return Err(type_error("Unsupported group name")), + _ => return Err(JsErrorBox::type_error("Unsupported group name")), }; let params = DhParameter { prime: asn1::Int::new(u32_slice_to_u8_slice(prime)).unwrap(), @@ -2215,7 +2280,7 @@ fn dh_group_generate( #[cppgc] pub fn op_node_generate_dh_group_key( #[string] group_name: &str, -) -> Result { +) -> Result { dh_group_generate(group_name) } @@ -2223,7 +2288,7 @@ pub fn op_node_generate_dh_group_key( #[cppgc] pub async fn op_node_generate_dh_group_key_async( #[string] group_name: String, -) -> Result { +) -> Result { spawn_blocking(move || dh_group_generate(&group_name)) .await .unwrap() @@ -2297,10 +2362,10 @@ pub fn op_node_dh_keys_generate_and_export( #[buffer] pub fn op_node_export_secret_key( #[cppgc] handle: &KeyObjectHandle, -) -> Result, deno_core::error::AnyError> { +) -> Result, JsErrorBox> { let key = handle .as_secret_key() - .ok_or_else(|| type_error("key is not a secret key"))?; + .ok_or_else(|| JsErrorBox::type_error("key is not a secret key"))?; Ok(key.to_vec().into_boxed_slice()) } @@ -2308,10 +2373,10 @@ pub fn op_node_export_secret_key( #[string] pub fn op_node_export_secret_key_b64url( #[cppgc] handle: &KeyObjectHandle, -) -> Result { +) -> Result { let key = handle .as_secret_key() - .ok_or_else(|| type_error("key is not a secret key"))?; + .ok_or_else(|| JsErrorBox::type_error("key is not a secret key"))?; Ok(base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(key)) } @@ -2327,12 +2392,19 @@ pub fn op_node_export_public_key_jwk( public_key.export_jwk() } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum ExportPublicKeyPemError { + #[class(inherit)] #[error(transparent)] - AsymmetricPublicKeyDer(#[from] AsymmetricPublicKeyDerError), + AsymmetricPublicKeyDer( + #[from] + #[inherit] + AsymmetricPublicKeyDerError, + ), + #[class(type)] #[error("very large data")] VeryLargeData, + #[class(generic)] #[error(transparent)] Der(#[from] der::Error), } @@ -2377,12 +2449,19 @@ pub fn op_node_export_public_key_der( public_key.export_der(typ) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum ExportPrivateKeyPemError { + #[class(inherit)] #[error(transparent)] - AsymmetricPublicKeyDer(#[from] AsymmetricPrivateKeyDerError), + AsymmetricPublicKeyDer( + #[from] + #[inherit] + AsymmetricPrivateKeyDerError, + ), + #[class(type)] #[error("very large data")] VeryLargeData, + #[class(generic)] #[error(transparent)] Der(#[from] der::Error), } @@ -2416,12 +2495,15 @@ pub fn op_node_export_private_key_pem( Ok(String::from_utf8(out).expect("invalid pem is not possible")) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum ExportPrivateKeyJwkError { + #[class(inherit)] #[error(transparent)] AsymmetricPublicKeyJwk(#[from] AsymmetricPrivateKeyJwkError), + #[class(type)] #[error("very large data")] VeryLargeData, + #[class(generic)] #[error(transparent)] Der(#[from] der::Error), } @@ -2464,9 +2546,9 @@ pub fn op_node_key_type(#[cppgc] handle: &KeyObjectHandle) -> &'static str { #[cppgc] pub fn op_node_derive_public_key_from_private_key( #[cppgc] handle: &KeyObjectHandle, -) -> Result { +) -> Result { let Some(private_key) = handle.as_private_key() else { - return Err(type_error("expected private key")); + return Err(JsErrorBox::type_error("expected private key")); }; Ok(KeyObjectHandle::AsymmetricPublic( diff --git a/ext/node/ops/crypto/md5_sha1.rs b/ext/node/ops/crypto/md5_sha1.rs index 9164b0a1cb..c6c6eb1c83 100644 --- a/ext/node/ops/crypto/md5_sha1.rs +++ b/ext/node/ops/crypto/md5_sha1.rs @@ -1,5 +1,6 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use core::fmt; + use digest::core_api::AlgorithmName; use digest::core_api::BlockSizeUser; use digest::core_api::Buffer; diff --git a/ext/node/ops/crypto/mod.rs b/ext/node/ops/crypto/mod.rs index e90e820909..8c6b571316 100644 --- a/ext/node/ops/crypto/mod.rs +++ b/ext/node/ops/crypto/mod.rs @@ -1,12 +1,14 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_core::error::generic_error; -use deno_core::error::type_error; +// Copyright 2018-2025 the Deno authors. MIT license. +use std::future::Future; +use std::rc::Rc; + use deno_core::op2; use deno_core::unsync::spawn_blocking; use deno_core::JsBuffer; use deno_core::OpState; use deno_core::StringOrBuffer; use deno_core::ToJsBuffer; +use deno_error::JsErrorBox; use elliptic_curve::sec1::ToEncodedPoint; use hkdf::Hkdf; use keys::AsymmetricPrivateKey; @@ -16,16 +18,13 @@ use keys::EcPublicKey; use keys::KeyObjectHandle; use num_bigint::BigInt; use num_bigint_dig::BigUint; +use p224::NistP224; +use p256::NistP256; +use p384::NistP384; use rand::distributions::Distribution; use rand::distributions::Uniform; use rand::Rng; use ring::signature::Ed25519KeyPair; -use std::future::Future; -use std::rc::Rc; - -use p224::NistP224; -use p256::NistP256; -use p384::NistP384; use rsa::pkcs8::DecodePrivateKey; use rsa::pkcs8::DecodePublicKey; use rsa::Oaep; @@ -141,16 +140,21 @@ pub fn op_node_hash_clone( hasher.clone_inner(output_length.map(|l| l as usize)) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum PrivateEncryptDecryptError { + #[class(generic)] #[error(transparent)] Pkcs8(#[from] pkcs8::Error), + #[class(generic)] #[error(transparent)] Spki(#[from] spki::Error), + #[class(generic)] #[error(transparent)] Utf8(#[from] std::str::Utf8Error), + #[class(generic)] #[error(transparent)] Rsa(#[from] rsa::Error), + #[class(type)] #[error("Unknown padding")] UnknownPadding, } @@ -269,10 +273,7 @@ pub fn op_node_cipheriv_final( #[buffer] input: &[u8], #[anybuffer] output: &mut [u8], ) -> Result>, cipher::CipherContextError> { - let context = state - .resource_table - .take::(rid) - .map_err(cipher::CipherContextError::Resource)?; + let context = state.resource_table.take::(rid)?; let context = Rc::try_unwrap(context) .map_err(|_| cipher::CipherContextError::ContextInUse)?; context.r#final(auto_pad, input, output).map_err(Into::into) @@ -284,10 +285,7 @@ pub fn op_node_cipheriv_take( state: &mut OpState, #[smi] rid: u32, ) -> Result>, cipher::CipherContextError> { - let context = state - .resource_table - .take::(rid) - .map_err(cipher::CipherContextError::Resource)?; + let context = state.resource_table.take::(rid)?; let context = Rc::try_unwrap(context) .map_err(|_| cipher::CipherContextError::ContextInUse)?; Ok(context.take_tag()) @@ -339,10 +337,7 @@ pub fn op_node_decipheriv_take( state: &mut OpState, #[smi] rid: u32, ) -> Result<(), cipher::DecipherContextError> { - let context = state - .resource_table - .take::(rid) - .map_err(cipher::DecipherContextError::Resource)?; + let context = state.resource_table.take::(rid)?; Rc::try_unwrap(context) .map_err(|_| cipher::DecipherContextError::ContextInUse)?; Ok(()) @@ -357,10 +352,7 @@ pub fn op_node_decipheriv_final( #[anybuffer] output: &mut [u8], #[buffer] auth_tag: &[u8], ) -> Result<(), cipher::DecipherContextError> { - let context = state - .resource_table - .take::(rid) - .map_err(cipher::DecipherContextError::Resource)?; + let context = state.resource_table.take::(rid)?; let context = Rc::try_unwrap(context) .map_err(|_| cipher::DecipherContextError::ContextInUse)?; context @@ -403,10 +395,12 @@ pub fn op_node_verify( ) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum Pbkdf2Error { + #[class(type)] #[error("unsupported digest: {0}")] UnsupportedDigest(String), + #[class(inherit)] #[error(transparent)] Join(#[from] tokio::task::JoinError), } @@ -475,14 +469,18 @@ pub async fn op_node_fill_random_async(#[smi] len: i32) -> ToJsBuffer { .unwrap() } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum HkdfError { + #[class(type)] #[error("expected secret key")] ExpectedSecretKey, + #[class(type)] #[error("HKDF-Expand failed")] HkdfExpandFailed, + #[class(type)] #[error("Unsupported digest: {0}")] UnsupportedDigest(String), + #[class(inherit)] #[error(transparent)] Join(#[from] tokio::task::JoinError), } @@ -576,7 +574,7 @@ fn scrypt( parallelization: u32, _maxmem: u32, output_buffer: &mut [u8], -) -> Result<(), deno_core::error::AnyError> { +) -> Result<(), JsErrorBox> { // Construct Params let params = scrypt::Params::new( cost as u8, @@ -592,7 +590,7 @@ fn scrypt( Ok(()) } else { // TODO(lev): key derivation failed, so what? - Err(generic_error("scrypt key derivation failed")) + Err(JsErrorBox::generic("scrypt key derivation failed")) } } @@ -607,7 +605,7 @@ pub fn op_node_scrypt_sync( #[smi] parallelization: u32, #[smi] maxmem: u32, #[anybuffer] output_buffer: &mut [u8], -) -> Result<(), deno_core::error::AnyError> { +) -> Result<(), JsErrorBox> { scrypt( password, salt, @@ -620,12 +618,14 @@ pub fn op_node_scrypt_sync( ) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum ScryptAsyncError { + #[class(inherit)] #[error(transparent)] Join(#[from] tokio::task::JoinError), + #[class(inherit)] #[error(transparent)] - Other(deno_core::error::AnyError), + Other(JsErrorBox), } #[op2(async)] @@ -658,12 +658,15 @@ pub async fn op_node_scrypt_async( .await? } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum EcdhEncodePubKey { + #[class(type)] #[error("Invalid public key")] InvalidPublicKey, + #[class(type)] #[error("Unsupported curve")] UnsupportedCurve, + #[class(generic)] #[error(transparent)] Sec1(#[from] sec1::Error), } @@ -743,7 +746,7 @@ pub fn op_node_ecdh_generate_keys( #[buffer] pubbuf: &mut [u8], #[buffer] privbuf: &mut [u8], #[string] format: &str, -) -> Result<(), deno_core::error::AnyError> { +) -> Result<(), JsErrorBox> { let mut rng = rand::thread_rng(); let compress = format == "compressed"; match curve { @@ -780,7 +783,10 @@ pub fn op_node_ecdh_generate_keys( Ok(()) } - &_ => Err(type_error(format!("Unsupported curve: {}", curve))), + &_ => Err(JsErrorBox::type_error(format!( + "Unsupported curve: {}", + curve + ))), } } @@ -913,7 +919,8 @@ pub async fn op_node_gen_prime_async( spawn_blocking(move || gen_prime(size)).await } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(type)] pub enum DiffieHellmanError { #[error("Expected private key")] ExpectedPrivateKey, @@ -1005,7 +1012,8 @@ pub fn op_node_diffie_hellman( Ok(res) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(type)] pub enum SignEd25519Error { #[error("Expected private key")] ExpectedPrivateKey, @@ -1037,7 +1045,8 @@ pub fn op_node_sign_ed25519( Ok(()) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(type)] pub enum VerifyEd25519Error { #[error("Expected public key")] ExpectedPublicKey, diff --git a/ext/node/ops/crypto/pkcs3.rs b/ext/node/ops/crypto/pkcs3.rs index 5772514608..6668148d23 100644 --- a/ext/node/ops/crypto/pkcs3.rs +++ b/ext/node/ops/crypto/pkcs3.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // // PKCS #3: Diffie-Hellman Key Agreement Standard diff --git a/ext/node/ops/crypto/primes.rs b/ext/node/ops/crypto/primes.rs index 2e5d1ff63c..65ffa7a7a0 100644 --- a/ext/node/ops/crypto/primes.rs +++ b/ext/node/ops/crypto/primes.rs @@ -1,4 +1,6 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::ops::Deref; use num_bigint::BigInt; use num_bigint_dig::RandPrime; @@ -6,7 +8,6 @@ use num_integer::Integer; use num_traits::One; use num_traits::Zero; use rand::Rng; -use std::ops::Deref; #[derive(Clone)] pub struct Prime(pub num_bigint_dig::BigUint); @@ -283,9 +284,10 @@ static SMALL_PRIMES: [u32; 2047] = [ #[cfg(test)] mod tests { - use super::*; use num_bigint::BigInt; + use super::*; + #[test] fn test_prime() { for &p in SMALL_PRIMES.iter() { diff --git a/ext/node/ops/crypto/sign.rs b/ext/node/ops/crypto/sign.rs index 30094c0765..74ed50eb2b 100644 --- a/ext/node/ops/crypto/sign.rs +++ b/ext/node/ops/crypto/sign.rs @@ -1,24 +1,24 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. +use core::ops::Add; + +use ecdsa::der::MaxOverhead; +use ecdsa::der::MaxSize; +use elliptic_curve::generic_array::ArrayLength; +use elliptic_curve::FieldBytesSize; use rand::rngs::OsRng; use rsa::signature::hazmat::PrehashSigner as _; use rsa::signature::hazmat::PrehashVerifier as _; use rsa::traits::SignatureScheme as _; use spki::der::Decode; -use crate::ops::crypto::digest::match_fixed_digest; -use crate::ops::crypto::digest::match_fixed_digest_with_oid; - use super::keys::AsymmetricPrivateKey; use super::keys::AsymmetricPublicKey; use super::keys::EcPrivateKey; use super::keys::EcPublicKey; use super::keys::KeyObjectHandle; use super::keys::RsaPssHashAlgorithm; -use core::ops::Add; -use ecdsa::der::MaxOverhead; -use ecdsa::der::MaxSize; -use elliptic_curve::generic_array::ArrayLength; -use elliptic_curve::FieldBytesSize; +use crate::ops::crypto::digest::match_fixed_digest; +use crate::ops::crypto::digest::match_fixed_digest_with_oid; fn dsa_signature( encoding: u32, @@ -39,7 +39,8 @@ where } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(type)] pub enum KeyObjectHandlePrehashedSignAndVerifyError { #[error("invalid DSA signature encoding")] InvalidDsaSignatureEncoding, @@ -47,10 +48,12 @@ pub enum KeyObjectHandlePrehashedSignAndVerifyError { KeyIsNotPrivate, #[error("digest not allowed for RSA signature: {0}")] DigestNotAllowedForRsaSignature(String), + #[class(generic)] #[error("failed to sign digest with RSA")] FailedToSignDigestWithRsa, #[error("digest not allowed for RSA-PSS signature: {0}")] DigestNotAllowedForRsaPssSignature(String), + #[class(generic)] #[error("failed to sign digest with RSA-PSS")] FailedToSignDigestWithRsaPss, #[error("failed to sign digest with DSA")] diff --git a/ext/node/ops/crypto/x509.rs b/ext/node/ops/crypto/x509.rs index ab8e52f703..ad931f01ff 100644 --- a/ext/node/ops/crypto/x509.rs +++ b/ext/node/ops/crypto/x509.rs @@ -1,7 +1,9 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::ops::Deref; use deno_core::op2; - +use digest::Digest; use x509_parser::der_parser::asn1_rs::Any; use x509_parser::der_parser::asn1_rs::Tag; use x509_parser::der_parser::oid::Oid; @@ -9,14 +11,10 @@ pub use x509_parser::error::X509Error; use x509_parser::extensions; use x509_parser::pem; use x509_parser::prelude::*; - -use super::KeyObjectHandle; - -use std::ops::Deref; use yoke::Yoke; use yoke::Yokeable; -use digest::Digest; +use super::KeyObjectHandle; enum CertificateSources { Der(Box<[u8]>), @@ -61,11 +59,13 @@ impl<'a> Deref for CertificateView<'a> { } } +deno_error::js_error_wrapper!(X509Error, JsX509Error, "Error"); + #[op2] #[cppgc] pub fn op_node_x509_parse( #[buffer] buf: &[u8], -) -> Result { +) -> Result { let source = match pem::parse_x509_pem(buf) { Ok((_, pem)) => CertificateSources::Pem(pem), Err(_) => CertificateSources::Der(buf.to_vec().into_boxed_slice()), @@ -156,18 +156,18 @@ pub fn op_node_x509_fingerprint512( #[string] pub fn op_node_x509_get_issuer( #[cppgc] cert: &Certificate, -) -> Result { +) -> Result { let cert = cert.inner.get().deref(); - x509name_to_string(cert.issuer(), oid_registry()) + x509name_to_string(cert.issuer(), oid_registry()).map_err(Into::into) } #[op2] #[string] pub fn op_node_x509_get_subject( #[cppgc] cert: &Certificate, -) -> Result { +) -> Result { let cert = cert.inner.get().deref(); - x509name_to_string(cert.subject(), oid_registry()) + x509name_to_string(cert.subject(), oid_registry()).map_err(Into::into) } #[op2] diff --git a/ext/node/ops/fs.rs b/ext/node/ops/fs.rs index 58a688a1fe..0e9310375c 100644 --- a/ext/node/ops/fs.rs +++ b/ext/node/ops/fs.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::cell::RefCell; use std::rc::Rc; @@ -10,27 +10,40 @@ use serde::Serialize; use crate::NodePermissions; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum FsError { + #[class(inherit)] #[error(transparent)] Permission(#[from] deno_permissions::PermissionCheckError), + #[class(inherit)] #[error("{0}")] - Io(#[from] std::io::Error), + Io( + #[from] + #[inherit] + std::io::Error, + ), #[cfg(windows)] + #[class(generic)] #[error("Path has no root.")] PathHasNoRoot, #[cfg(not(any(unix, windows)))] + #[class(generic)] #[error("Unsupported platform.")] UnsupportedPlatform, + #[class(inherit)] #[error(transparent)] - Fs(#[from] deno_io::fs::FsError), + Fs( + #[from] + #[inherit] + deno_io::fs::FsError, + ), } #[op2(fast, stack_trace)] pub fn op_node_fs_exists_sync

( state: &mut OpState, #[string] path: String, -) -> Result +) -> Result where P: NodePermissions + 'static, { @@ -207,6 +220,7 @@ where { use std::ffi::OsStr; use std::os::windows::ffi::OsStrExt; + use windows_sys::Win32::Storage::FileSystem::GetDiskFreeSpaceW; let _ = bigint; diff --git a/ext/node/ops/http.rs b/ext/node/ops/http.rs index eb28e68aee..9723b0d3be 100644 --- a/ext/node/ops/http.rs +++ b/ext/node/ops/http.rs @@ -1,7 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::cell::RefCell; +use std::cmp::min; use std::fmt::Debug; use std::pin::Pin; use std::rc::Rc; @@ -9,8 +10,7 @@ use std::task::Context; use std::task::Poll; use bytes::Bytes; -use deno_core::error::bad_resource; -use deno_core::error::type_error; +use deno_core::error::ResourceError; use deno_core::futures::stream::Peekable; use deno_core::futures::Future; use deno_core::futures::FutureExt; @@ -32,6 +32,8 @@ use deno_core::OpState; use deno_core::RcRef; use deno_core::Resource; use deno_core::ResourceId; +use deno_error::JsError; +use deno_error::JsErrorBox; use deno_fetch::FetchCancelHandle; use deno_fetch::FetchReturn; use deno_fetch::ResBody; @@ -48,7 +50,6 @@ use http_body_util::BodyExt; use hyper::body::Frame; use hyper::body::Incoming; use hyper_util::rt::TokioIo; -use std::cmp::min; use tokio::io::AsyncReadExt; use tokio::io::AsyncWriteExt; @@ -88,32 +89,45 @@ impl deno_core::Resource for NodeHttpClientResponse { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, JsError)] pub enum ConnError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(ResourceError), + #[class(inherit)] #[error(transparent)] Permission(#[from] PermissionCheckError), + #[class(type)] #[error("Invalid URL {0}")] InvalidUrl(Url), + #[class(type)] #[error(transparent)] InvalidHeaderName(#[from] http::header::InvalidHeaderName), + #[class(type)] #[error(transparent)] InvalidHeaderValue(#[from] http::header::InvalidHeaderValue), + #[class(inherit)] #[error(transparent)] Url(#[from] url::ParseError), + #[class(type)] #[error(transparent)] Method(#[from] http::method::InvalidMethod), + #[class(inherit)] #[error(transparent)] Io(#[from] std::io::Error), + #[class("Busy")] #[error("TLS stream is currently in use")] TlsStreamBusy, + #[class("Busy")] #[error("TCP stream is currently in use")] TcpStreamBusy, + #[class(generic)] #[error(transparent)] ReuniteTcp(#[from] tokio::net::tcp::ReuniteError), + #[class(inherit)] #[error(transparent)] Canceled(#[from] deno_core::Canceled), + #[class("Http")] #[error(transparent)] Hyper(#[from] hyper::Error), } @@ -274,8 +288,11 @@ pub async fn op_node_http_await_response( .resource_table .take::(rid) .map_err(ConnError::Resource)?; - let resource = Rc::try_unwrap(resource) - .map_err(|_| ConnError::Resource(bad_resource("NodeHttpClientResponse")))?; + let resource = Rc::try_unwrap(resource).map_err(|_| { + ConnError::Resource(ResourceError::Other( + "NodeHttpClientResponse".to_string(), + )) + })?; let res = resource.response.await??; let status = res.status(); @@ -296,7 +313,7 @@ pub async fn op_node_http_await_response( }; let (parts, body) = res.into_parts(); - let body = body.map_err(deno_core::anyhow::Error::from); + let body = body.map_err(|e| JsErrorBox::new("Http", e.to_string())); let body = body.boxed(); let res = http::Response::from_parts(parts, body); @@ -523,7 +540,7 @@ impl Resource for NodeHttpResponseResource { // safely call `await` on it without creating a race condition. Some(_) => match reader.as_mut().next().await.unwrap() { Ok(chunk) => assert!(chunk.is_empty()), - Err(err) => break Err(type_error(err.to_string())), + Err(err) => break Err(JsErrorBox::type_error(err.to_string())), }, None => break Ok(BufView::empty()), } @@ -547,9 +564,7 @@ impl Resource for NodeHttpResponseResource { #[allow(clippy::type_complexity)] pub struct NodeHttpResourceToBodyAdapter( Rc, - Option< - Pin>>>, - >, + Option>>>>, ); impl NodeHttpResourceToBodyAdapter { @@ -565,7 +580,7 @@ unsafe impl Send for NodeHttpResourceToBodyAdapter {} unsafe impl Sync for NodeHttpResourceToBodyAdapter {} impl Stream for NodeHttpResourceToBodyAdapter { - type Item = Result; + type Item = Result; fn poll_next( self: Pin<&mut Self>, @@ -596,7 +611,7 @@ impl Stream for NodeHttpResourceToBodyAdapter { impl hyper::body::Body for NodeHttpResourceToBodyAdapter { type Data = Bytes; - type Error = deno_core::anyhow::Error; + type Error = JsErrorBox; fn poll_frame( self: Pin<&mut Self>, diff --git a/ext/node/ops/http2.rs b/ext/node/ops/http2.rs index 53dada9f41..2308ca8254 100644 --- a/ext/node/ops/http2.rs +++ b/ext/node/ops/http2.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::cell::RefCell; @@ -7,6 +7,7 @@ use std::rc::Rc; use std::task::Poll; use bytes::Bytes; +use deno_core::error::ResourceError; use deno_core::futures::future::poll_fn; use deno_core::op2; use deno_core::serde::Serialize; @@ -109,14 +110,32 @@ impl Resource for Http2ServerSendResponse { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum Http2Error { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource( + #[from] + #[inherit] + ResourceError, + ), + #[class(inherit)] #[error(transparent)] - UrlParse(#[from] url::ParseError), + UrlParse( + #[from] + #[inherit] + url::ParseError, + ), + #[class(generic)] #[error(transparent)] H2(#[from] h2::Error), + #[class(inherit)] + #[error(transparent)] + TakeNetworkStream( + #[from] + #[inherit] + deno_net::raw::TakeNetworkStreamError, + ), } #[op2(async)] @@ -129,8 +148,7 @@ pub async fn op_http2_connect( // No permission check necessary because we're using an existing connection let network_stream = { let mut state = state.borrow_mut(); - take_network_stream_resource(&mut state.resource_table, rid) - .map_err(Http2Error::Resource)? + take_network_stream_resource(&mut state.resource_table, rid)? }; let url = Url::parse(&url)?; @@ -156,8 +174,7 @@ pub async fn op_http2_listen( #[smi] rid: ResourceId, ) -> Result { let stream = - take_network_stream_resource(&mut state.borrow_mut().resource_table, rid) - .map_err(Http2Error::Resource)?; + take_network_stream_resource(&mut state.borrow_mut().resource_table, rid)?; let conn = h2::server::Builder::new().handshake(stream).await?; Ok( @@ -182,8 +199,7 @@ pub async fn op_http2_accept( let resource = state .borrow() .resource_table - .get::(rid) - .map_err(Http2Error::Resource)?; + .get::(rid)?; let mut conn = RcRef::map(&resource, |r| &r.conn).borrow_mut().await; if let Some(res) = conn.accept().await { let (req, resp) = res?; @@ -249,8 +265,7 @@ pub async fn op_http2_send_response( let resource = state .borrow() .resource_table - .get::(rid) - .map_err(Http2Error::Resource)?; + .get::(rid)?; let mut send_response = RcRef::map(resource, |r| &r.send_response) .borrow_mut() .await; @@ -276,11 +291,7 @@ pub async fn op_http2_poll_client_connection( state: Rc>, #[smi] rid: ResourceId, ) -> Result<(), Http2Error> { - let resource = state - .borrow() - .resource_table - .get::(rid) - .map_err(Http2Error::Resource)?; + let resource = state.borrow().resource_table.get::(rid)?; let cancel_handle = RcRef::map(resource.clone(), |this| &this.cancel_handle); let mut conn = RcRef::map(resource, |this| &this.conn).borrow_mut().await; @@ -310,8 +321,7 @@ pub async fn op_http2_client_request( let resource = state .borrow() .resource_table - .get::(client_rid) - .map_err(Http2Error::Resource)?; + .get::(client_rid)?; let url = resource.url.clone(); @@ -344,10 +354,7 @@ pub async fn op_http2_client_request( let resource = { let state = state.borrow(); - state - .resource_table - .get::(client_rid) - .map_err(Http2Error::Resource)? + state.resource_table.get::(client_rid)? }; let mut client = RcRef::map(&resource, |r| &r.client).borrow_mut().await; poll_fn(|cx| client.poll_ready(cx)).await?; @@ -370,8 +377,7 @@ pub async fn op_http2_client_send_data( let resource = state .borrow() .resource_table - .get::(stream_rid) - .map_err(Http2Error::Resource)?; + .get::(stream_rid)?; let mut stream = RcRef::map(&resource, |r| &r.stream).borrow_mut().await; stream.send_data(data.to_vec().into(), end_of_stream)?; @@ -383,7 +389,7 @@ pub async fn op_http2_client_reset_stream( state: Rc>, #[smi] stream_rid: ResourceId, #[smi] code: u32, -) -> Result<(), deno_core::error::AnyError> { +) -> Result<(), ResourceError> { let resource = state .borrow() .resource_table @@ -402,8 +408,7 @@ pub async fn op_http2_client_send_trailers( let resource = state .borrow() .resource_table - .get::(stream_rid) - .map_err(Http2Error::Resource)?; + .get::(stream_rid)?; let mut stream = RcRef::map(&resource, |r| &r.stream).borrow_mut().await; let mut trailers_map = http::HeaderMap::new(); @@ -435,8 +440,7 @@ pub async fn op_http2_client_get_response( let resource = state .borrow() .resource_table - .get::(stream_rid) - .map_err(Http2Error::Resource)?; + .get::(stream_rid)?; let mut response_future = RcRef::map(&resource, |r| &r.response).borrow_mut().await; @@ -506,8 +510,7 @@ pub async fn op_http2_client_get_response_body_chunk( let resource = state .borrow() .resource_table - .get::(body_rid) - .map_err(Http2Error::Resource)?; + .get::(body_rid)?; let mut body = RcRef::map(&resource, |r| &r.body).borrow_mut().await; loop { @@ -550,7 +553,7 @@ pub async fn op_http2_client_get_response_body_chunk( pub async fn op_http2_client_get_response_trailers( state: Rc>, #[smi] body_rid: ResourceId, -) -> Result>, deno_core::error::AnyError> { +) -> Result>, ResourceError> { let resource = state .borrow() .resource_table diff --git a/ext/node/ops/idna.rs b/ext/node/ops/idna.rs index a3d85e77c2..24bcb97c63 100644 --- a/ext/node/ops/idna.rs +++ b/ext/node/ops/idna.rs @@ -1,24 +1,29 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. - -use deno_core::op2; +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; +use deno_core::op2; + // map_domain, to_ascii and to_unicode are based on the punycode implementation in node.js // https://github.com/nodejs/node/blob/73025c4dec042e344eeea7912ed39f7b7c4a3991/lib/punycode.js const PUNY_PREFIX: &str = "xn--"; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum IdnaError { + #[class(range)] #[error("Invalid input")] InvalidInput, + #[class(generic)] #[error("Input would take more than 63 characters to encode")] InputTooLong, + #[class(range)] #[error("Illegal input >= 0x80 (not a basic code point)")] IllegalInput, } +deno_error::js_error_wrapper!(idna::Errors, JsIdnaErrors, "Error"); + /// map a domain by mapping each label with the given function fn map_domain( domain: &str, @@ -113,8 +118,8 @@ pub fn op_node_idna_punycode_to_unicode( #[string] pub fn op_node_idna_domain_to_ascii( #[string] domain: String, -) -> Result { - idna::domain_to_ascii(&domain) +) -> Result { + idna::domain_to_ascii(&domain).map_err(Into::into) } /// Converts a domain to Unicode as per the IDNA spec diff --git a/ext/node/ops/inspector.rs b/ext/node/ops/inspector.rs index 9986aeb197..c462523715 100644 --- a/ext/node/ops/inspector.rs +++ b/ext/node/ops/inspector.rs @@ -1,8 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::cell::RefCell; +use std::rc::Rc; -use crate::NodePermissions; -use deno_core::anyhow::Error; -use deno_core::error::generic_error; use deno_core::futures::channel::mpsc; use deno_core::op2; use deno_core::v8; @@ -11,8 +11,9 @@ use deno_core::InspectorSessionKind; use deno_core::InspectorSessionOptions; use deno_core::JsRuntimeInspector; use deno_core::OpState; -use std::cell::RefCell; -use std::rc::Rc; +use deno_error::JsErrorBox; + +use crate::NodePermissions; #[op2(fast)] pub fn op_inspector_enabled() -> bool { @@ -25,7 +26,7 @@ pub fn op_inspector_open

( _state: &mut OpState, _port: Option, #[string] _host: Option, -) -> Result<(), Error> +) -> Result<(), JsErrorBox> where P: NodePermissions + 'static, { @@ -85,6 +86,20 @@ struct JSInspectorSession { impl GarbageCollected for JSInspectorSession {} +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum InspectorConnectError { + #[class(inherit)] + #[error(transparent)] + Permission( + #[from] + #[inherit] + deno_permissions::PermissionCheckError, + ), + #[class(generic)] + #[error("connectToMainThread not supported")] + ConnectToMainThreadUnsupported, +} + #[op2(stack_trace)] #[cppgc] pub fn op_inspector_connect<'s, P>( @@ -93,7 +108,7 @@ pub fn op_inspector_connect<'s, P>( state: &mut OpState, connect_to_main_thread: bool, callback: v8::Local<'s, v8::Function>, -) -> Result +) -> Result where P: NodePermissions + 'static, { @@ -102,7 +117,7 @@ where .check_sys("inspector", "inspector.Session.connect")?; if connect_to_main_thread { - return Err(generic_error("connectToMainThread not supported")); + return Err(InspectorConnectError::ConnectToMainThreadUnsupported); } let context = scope.get_current_context(); diff --git a/ext/node/ops/ipc.rs b/ext/node/ops/ipc.rs index 672cf0d707..0213295c5a 100644 --- a/ext/node/ops/ipc.rs +++ b/ext/node/ops/ipc.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. pub use impl_::*; @@ -8,38 +8,24 @@ mod impl_ { use std::cell::RefCell; use std::future::Future; use std::io; - use std::mem; - use std::pin::Pin; use std::rc::Rc; - use std::sync::atomic::AtomicBool; - use std::sync::atomic::AtomicUsize; - use std::task::ready; - use std::task::Context; - use std::task::Poll; use deno_core::op2; use deno_core::serde; use deno_core::serde::Serializer; use deno_core::serde_json; use deno_core::v8; - use deno_core::AsyncRefCell; use deno_core::CancelFuture; - use deno_core::CancelHandle; - use deno_core::ExternalOpsTracker; use deno_core::OpState; use deno_core::RcRef; use deno_core::ResourceId; use deno_core::ToV8; - use memchr::memchr; - use pin_project_lite::pin_project; + use deno_error::JsErrorBox; + use deno_process::ipc::IpcJsonStreamError; + pub use deno_process::ipc::IpcJsonStreamResource; + pub use deno_process::ipc::IpcRefTracker; + pub use deno_process::ipc::INITIAL_CAPACITY; use serde::Serialize; - use tokio::io::AsyncRead; - use tokio::io::AsyncWriteExt; - use tokio::io::ReadBuf; - - use deno_io::BiPipe; - use deno_io::BiPipeRead; - use deno_io::BiPipeWrite; /// Wrapper around v8 value that implements Serialize. struct SerializeWrapper<'a, 'b>( @@ -80,7 +66,7 @@ mod impl_ { } else if value.is_string_object() { let str = deno_core::serde_v8::to_utf8( value.to_string(scope).ok_or_else(|| { - S::Error::custom(deno_core::error::generic_error( + S::Error::custom(deno_error::JsErrorBox::generic( "toString on string object failed", )) })?, @@ -153,7 +139,7 @@ mod impl_ { map.end() } else { // TODO(nathanwhit): better error message - Err(S::Error::custom(deno_core::error::type_error(format!( + Err(S::Error::custom(JsErrorBox::type_error(format!( "Unsupported type: {}", value.type_repr() )))) @@ -178,14 +164,18 @@ mod impl_ { )) } - #[derive(Debug, thiserror::Error)] + #[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum IpcError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] deno_core::error::ResourceError), + #[class(inherit)] #[error(transparent)] IpcJsonStream(#[from] IpcJsonStreamError), + #[class(inherit)] #[error(transparent)] Canceled(#[from] deno_core::Canceled), + #[class(inherit)] #[error("failed to serialize json value: {0}")] SerdeJson(serde_json::Error), } @@ -211,8 +201,7 @@ mod impl_ { let stream = state .borrow() .resource_table - .get::(rid) - .map_err(IpcError::Resource)?; + .get::(rid)?; let old = stream .queued_bytes .fetch_add(serialized.len(), std::sync::atomic::Ordering::Relaxed); @@ -256,8 +245,7 @@ mod impl_ { let stream = state .borrow() .resource_table - .get::(rid) - .map_err(IpcError::Resource)?; + .get::(rid)?; let cancel = stream.cancel.clone(); let mut stream = RcRef::map(stream, |r| &r.read_half).borrow_mut().await; @@ -287,529 +275,11 @@ mod impl_ { stream.ref_tracker.unref(); } - /// Tracks whether the IPC resources is currently - /// refed, and allows refing/unrefing it. - pub struct IpcRefTracker { - refed: AtomicBool, - tracker: OpsTracker, - } - - /// A little wrapper so we don't have to get an - /// `ExternalOpsTracker` for tests. When we aren't - /// cfg(test), this will get optimized out. - enum OpsTracker { - External(ExternalOpsTracker), - #[cfg(test)] - Test, - } - - impl OpsTracker { - fn ref_(&self) { - match self { - Self::External(tracker) => tracker.ref_op(), - #[cfg(test)] - Self::Test => {} - } - } - - fn unref(&self) { - match self { - Self::External(tracker) => tracker.unref_op(), - #[cfg(test)] - Self::Test => {} - } - } - } - - impl IpcRefTracker { - pub fn new(tracker: ExternalOpsTracker) -> Self { - Self { - refed: AtomicBool::new(false), - tracker: OpsTracker::External(tracker), - } - } - - #[cfg(test)] - fn new_test() -> Self { - Self { - refed: AtomicBool::new(false), - tracker: OpsTracker::Test, - } - } - - fn ref_(&self) { - if !self.refed.swap(true, std::sync::atomic::Ordering::AcqRel) { - self.tracker.ref_(); - } - } - - fn unref(&self) { - if self.refed.swap(false, std::sync::atomic::Ordering::AcqRel) { - self.tracker.unref(); - } - } - } - - pub struct IpcJsonStreamResource { - read_half: AsyncRefCell, - write_half: AsyncRefCell, - cancel: Rc, - queued_bytes: AtomicUsize, - ref_tracker: IpcRefTracker, - } - - impl deno_core::Resource for IpcJsonStreamResource { - fn close(self: Rc) { - self.cancel.cancel(); - } - } - - impl IpcJsonStreamResource { - pub fn new( - stream: i64, - ref_tracker: IpcRefTracker, - ) -> Result { - let (read_half, write_half) = BiPipe::from_raw(stream as _)?.split(); - Ok(Self { - read_half: AsyncRefCell::new(IpcJsonStream::new(read_half)), - write_half: AsyncRefCell::new(write_half), - cancel: Default::default(), - queued_bytes: Default::default(), - ref_tracker, - }) - } - - #[cfg(all(unix, test))] - fn from_stream( - stream: tokio::net::UnixStream, - ref_tracker: IpcRefTracker, - ) -> Self { - let (read_half, write_half) = stream.into_split(); - Self { - read_half: AsyncRefCell::new(IpcJsonStream::new(read_half.into())), - write_half: AsyncRefCell::new(write_half.into()), - cancel: Default::default(), - queued_bytes: Default::default(), - ref_tracker, - } - } - - #[cfg(all(windows, test))] - fn from_stream( - pipe: tokio::net::windows::named_pipe::NamedPipeClient, - ref_tracker: IpcRefTracker, - ) -> Self { - let (read_half, write_half) = tokio::io::split(pipe); - Self { - read_half: AsyncRefCell::new(IpcJsonStream::new(read_half.into())), - write_half: AsyncRefCell::new(write_half.into()), - cancel: Default::default(), - queued_bytes: Default::default(), - ref_tracker, - } - } - - /// writes _newline terminated_ JSON message to the IPC pipe. - async fn write_msg_bytes( - self: Rc, - msg: &[u8], - ) -> Result<(), io::Error> { - let mut write_half = - RcRef::map(self, |r| &r.write_half).borrow_mut().await; - write_half.write_all(msg).await?; - Ok(()) - } - } - - // Initial capacity of the buffered reader and the JSON backing buffer. - // - // This is a tradeoff between memory usage and performance on large messages. - // - // 64kb has been chosen after benchmarking 64 to 66536 << 6 - 1 bytes per message. - const INITIAL_CAPACITY: usize = 1024 * 64; - - /// A buffer for reading from the IPC pipe. - /// Similar to the internal buffer of `tokio::io::BufReader`. - /// - /// This exists to provide buffered reading while granting mutable access - /// to the internal buffer (which isn't exposed through `tokio::io::BufReader` - /// or the `AsyncBufRead` trait). `simd_json` requires mutable access to an input - /// buffer for parsing, so this allows us to use the read buffer directly as the - /// input buffer without a copy (provided the message fits). - struct ReadBuffer { - buffer: Box<[u8]>, - pos: usize, - cap: usize, - } - - impl ReadBuffer { - fn new() -> Self { - Self { - buffer: vec![0; INITIAL_CAPACITY].into_boxed_slice(), - pos: 0, - cap: 0, - } - } - - fn get_mut(&mut self) -> &mut [u8] { - &mut self.buffer - } - - fn available_mut(&mut self) -> &mut [u8] { - &mut self.buffer[self.pos..self.cap] - } - - fn consume(&mut self, n: usize) { - self.pos = std::cmp::min(self.pos + n, self.cap); - } - - fn needs_fill(&self) -> bool { - self.pos >= self.cap - } - } - - #[derive(Debug, thiserror::Error)] - pub enum IpcJsonStreamError { - #[error("{0}")] - Io(#[source] std::io::Error), - #[error("{0}")] - SimdJson(#[source] simd_json::Error), - } - - // JSON serialization stream over IPC pipe. - // - // `\n` is used as a delimiter between messages. - struct IpcJsonStream { - pipe: BiPipeRead, - buffer: Vec, - read_buffer: ReadBuffer, - } - - impl IpcJsonStream { - fn new(pipe: BiPipeRead) -> Self { - Self { - pipe, - buffer: Vec::with_capacity(INITIAL_CAPACITY), - read_buffer: ReadBuffer::new(), - } - } - - async fn read_msg( - &mut self, - ) -> Result, IpcJsonStreamError> { - let mut json = None; - let nread = read_msg_inner( - &mut self.pipe, - &mut self.buffer, - &mut json, - &mut self.read_buffer, - ) - .await - .map_err(IpcJsonStreamError::Io)?; - if nread == 0 { - // EOF. - return Ok(None); - } - - let json = match json { - Some(v) => v, - None => { - // Took more than a single read and some buffering. - simd_json::from_slice(&mut self.buffer[..nread]) - .map_err(IpcJsonStreamError::SimdJson)? - } - }; - - // Safety: Same as `Vec::clear` but without the `drop_in_place` for - // each element (nop for u8). Capacity remains the same. - unsafe { - self.buffer.set_len(0); - } - - Ok(Some(json)) - } - } - - pin_project! { - #[must_use = "futures do nothing unless you `.await` or poll them"] - struct ReadMsgInner<'a, R: ?Sized> { - reader: &'a mut R, - buf: &'a mut Vec, - json: &'a mut Option, - // The number of bytes appended to buf. This can be less than buf.len() if - // the buffer was not empty when the operation was started. - read: usize, - read_buffer: &'a mut ReadBuffer, - } - } - - fn read_msg_inner<'a, R>( - reader: &'a mut R, - buf: &'a mut Vec, - json: &'a mut Option, - read_buffer: &'a mut ReadBuffer, - ) -> ReadMsgInner<'a, R> - where - R: AsyncRead + ?Sized + Unpin, - { - ReadMsgInner { - reader, - buf, - json, - read: 0, - read_buffer, - } - } - - fn read_msg_internal( - mut reader: Pin<&mut R>, - cx: &mut Context<'_>, - buf: &mut Vec, - read_buffer: &mut ReadBuffer, - json: &mut Option, - read: &mut usize, - ) -> Poll> { - loop { - let (done, used) = { - // effectively a tiny `poll_fill_buf`, but allows us to get a mutable reference to the buffer. - if read_buffer.needs_fill() { - let mut read_buf = ReadBuf::new(read_buffer.get_mut()); - ready!(reader.as_mut().poll_read(cx, &mut read_buf))?; - read_buffer.cap = read_buf.filled().len(); - read_buffer.pos = 0; - } - let available = read_buffer.available_mut(); - if let Some(i) = memchr(b'\n', available) { - if *read == 0 { - // Fast path: parse and put into the json slot directly. - json.replace( - simd_json::from_slice(&mut available[..i + 1]) - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?, - ); - } else { - // This is not the first read, so we have to copy the data - // to make it contiguous. - buf.extend_from_slice(&available[..=i]); - } - (true, i + 1) - } else { - buf.extend_from_slice(available); - (false, available.len()) - } - }; - - read_buffer.consume(used); - *read += used; - if done || used == 0 { - return Poll::Ready(Ok(mem::replace(read, 0))); - } - } - } - - impl Future for ReadMsgInner<'_, R> { - type Output = io::Result; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let me = self.project(); - read_msg_internal( - Pin::new(*me.reader), - cx, - me.buf, - me.read_buffer, - me.json, - me.read, - ) - } - } - #[cfg(test)] mod tests { - use super::IpcJsonStreamResource; - use deno_core::serde_json::json; use deno_core::v8; use deno_core::JsRuntime; - use deno_core::RcRef; use deno_core::RuntimeOptions; - use std::rc::Rc; - - #[allow(clippy::unused_async)] - #[cfg(unix)] - pub async fn pair() -> (Rc, tokio::net::UnixStream) { - let (a, b) = tokio::net::UnixStream::pair().unwrap(); - - /* Similar to how ops would use the resource */ - let a = Rc::new(IpcJsonStreamResource::from_stream( - a, - super::IpcRefTracker::new_test(), - )); - (a, b) - } - - #[cfg(windows)] - pub async fn pair() -> ( - Rc, - tokio::net::windows::named_pipe::NamedPipeServer, - ) { - use tokio::net::windows::named_pipe::ClientOptions; - use tokio::net::windows::named_pipe::ServerOptions; - - let name = - format!(r"\\.\pipe\deno-named-pipe-test-{}", rand::random::()); - - let server = ServerOptions::new().create(name.clone()).unwrap(); - let client = ClientOptions::new().open(name).unwrap(); - - server.connect().await.unwrap(); - /* Similar to how ops would use the resource */ - let client = Rc::new(IpcJsonStreamResource::from_stream( - client, - super::IpcRefTracker::new_test(), - )); - (client, server) - } - - #[allow(clippy::print_stdout)] - #[tokio::test] - async fn bench_ipc() -> Result<(), Box> { - // A simple round trip benchmark for quick dev feedback. - // - // Only ran when the env var is set. - if std::env::var_os("BENCH_IPC_DENO").is_none() { - return Ok(()); - } - - let (ipc, mut fd2) = pair().await; - let child = tokio::spawn(async move { - use tokio::io::AsyncWriteExt; - - let size = 1024 * 1024; - - let stri = "x".repeat(size); - let data = format!("\"{}\"\n", stri); - for _ in 0..100 { - fd2.write_all(data.as_bytes()).await?; - } - Ok::<_, std::io::Error>(()) - }); - - let start = std::time::Instant::now(); - let mut bytes = 0; - - let mut ipc = RcRef::map(ipc, |r| &r.read_half).borrow_mut().await; - loop { - let Some(msgs) = ipc.read_msg().await? else { - break; - }; - bytes += msgs.as_str().unwrap().len(); - if start.elapsed().as_secs() > 5 { - break; - } - } - let elapsed = start.elapsed(); - let mb = bytes as f64 / 1024.0 / 1024.0; - println!("{} mb/s", mb / elapsed.as_secs_f64()); - - child.await??; - - Ok(()) - } - - #[tokio::test] - async fn unix_ipc_json() -> Result<(), Box> { - let (ipc, mut fd2) = pair().await; - let child = tokio::spawn(async move { - use tokio::io::AsyncReadExt; - use tokio::io::AsyncWriteExt; - - const EXPECTED: &[u8] = b"\"hello\"\n"; - let mut buf = [0u8; EXPECTED.len()]; - let n = fd2.read_exact(&mut buf).await?; - assert_eq!(&buf[..n], EXPECTED); - fd2.write_all(b"\"world\"\n").await?; - - Ok::<_, std::io::Error>(()) - }); - - ipc - .clone() - .write_msg_bytes(&json_to_bytes(json!("hello"))) - .await?; - - let mut ipc = RcRef::map(ipc, |r| &r.read_half).borrow_mut().await; - let msgs = ipc.read_msg().await?.unwrap(); - assert_eq!(msgs, json!("world")); - - child.await??; - - Ok(()) - } - - fn json_to_bytes(v: deno_core::serde_json::Value) -> Vec { - let mut buf = deno_core::serde_json::to_vec(&v).unwrap(); - buf.push(b'\n'); - buf - } - - #[tokio::test] - async fn unix_ipc_json_multi() -> Result<(), Box> { - let (ipc, mut fd2) = pair().await; - let child = tokio::spawn(async move { - use tokio::io::AsyncReadExt; - use tokio::io::AsyncWriteExt; - - const EXPECTED: &[u8] = b"\"hello\"\n\"world\"\n"; - let mut buf = [0u8; EXPECTED.len()]; - let n = fd2.read_exact(&mut buf).await?; - assert_eq!(&buf[..n], EXPECTED); - fd2.write_all(b"\"foo\"\n\"bar\"\n").await?; - Ok::<_, std::io::Error>(()) - }); - - ipc - .clone() - .write_msg_bytes(&json_to_bytes(json!("hello"))) - .await?; - ipc - .clone() - .write_msg_bytes(&json_to_bytes(json!("world"))) - .await?; - - let mut ipc = RcRef::map(ipc, |r| &r.read_half).borrow_mut().await; - let msgs = ipc.read_msg().await?.unwrap(); - assert_eq!(msgs, json!("foo")); - - child.await??; - - Ok(()) - } - - #[tokio::test] - async fn unix_ipc_json_invalid() -> Result<(), Box> { - let (ipc, mut fd2) = pair().await; - let child = tokio::spawn(async move { - tokio::io::AsyncWriteExt::write_all(&mut fd2, b"\n\n").await?; - Ok::<_, std::io::Error>(()) - }); - - let mut ipc = RcRef::map(ipc, |r| &r.read_half).borrow_mut().await; - let _err = ipc.read_msg().await.unwrap_err(); - - child.await??; - - Ok(()) - } - - #[test] - fn memchr() { - let str = b"hello world"; - assert_eq!(super::memchr(b'h', str), Some(0)); - assert_eq!(super::memchr(b'w', str), Some(6)); - assert_eq!(super::memchr(b'd', str), Some(10)); - assert_eq!(super::memchr(b'x', str), None); - - let empty = b""; - assert_eq!(super::memchr(b'\n', empty), None); - } fn wrap_expr(s: &str) -> String { format!("(function () {{ return {s}; }})()") diff --git a/ext/node/ops/mod.rs b/ext/node/ops/mod.rs index 2ecc8dfd75..8dae6aeff6 100644 --- a/ext/node/ops/mod.rs +++ b/ext/node/ops/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. pub mod blocklist; pub mod buffer; diff --git a/ext/node/ops/os/cpus.rs b/ext/node/ops/os/cpus.rs index 2b931884c3..4dd0e59a17 100644 --- a/ext/node/ops/os/cpus.rs +++ b/ext/node/ops/os/cpus.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::serde::Serialize; @@ -127,13 +127,13 @@ pub fn cpu_info() -> Option> { #[cfg(target_os = "windows")] pub fn cpu_info() -> Option> { + use std::os::windows::ffi::OsStrExt; + use std::os::windows::ffi::OsStringExt; + use windows_sys::Wdk::System::SystemInformation::NtQuerySystemInformation; use windows_sys::Wdk::System::SystemInformation::SystemProcessorPerformanceInformation; use windows_sys::Win32::System::WindowsProgramming::SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; - use std::os::windows::ffi::OsStrExt; - use std::os::windows::ffi::OsStringExt; - fn encode_wide(s: &str) -> Vec { std::ffi::OsString::from(s) .encode_wide() @@ -264,13 +264,16 @@ pub fn cpu_info() -> Option> { let nice = fields.next()?.parse::().ok()?; let sys = fields.next()?.parse::().ok()?; let idle = fields.next()?.parse::().ok()?; + let _iowait = fields.next()?.parse::().ok()?; let irq = fields.next()?.parse::().ok()?; - cpus[i].times.user = user; - cpus[i].times.nice = nice; - cpus[i].times.sys = sys; - cpus[i].times.idle = idle; - cpus[i].times.irq = irq; + // sysconf(_SC_CLK_TCK) is fixed at 100 Hz, therefore the + // multiplier is always 1000/100 = 10 + cpus[i].times.user = user * 10; + cpus[i].times.nice = nice * 10; + cpus[i].times.sys = sys * 10; + cpus[i].times.idle = idle * 10; + cpus[i].times.irq = irq * 10; } let fp = std::fs::File::open("/proc/cpuinfo").ok()?; @@ -287,6 +290,18 @@ pub fn cpu_info() -> Option> { let model = fields.next()?.trim(); cpus[j].model = model.to_string(); + + if let Ok(fp) = std::fs::File::open(format!( + "/sys/devices/system/cpu/cpu{}/cpufreq/scaling_cur_freq", + j + )) { + let mut reader = std::io::BufReader::new(fp); + let mut speed = String::new(); + reader.read_line(&mut speed).ok()?; + + cpus[j].speed = speed.trim().parse::().ok()? / 1000; + } + j += 1; } diff --git a/ext/node/ops/os/mod.rs b/ext/node/ops/os/mod.rs index ddb2a70c64..ad0be8200e 100644 --- a/ext/node/ops/os/mod.rs +++ b/ext/node/ops/os/mod.rs @@ -1,24 +1,39 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::mem::MaybeUninit; -use crate::NodePermissions; use deno_core::op2; use deno_core::OpState; +use deno_permissions::PermissionCheckError; +use sys_traits::EnvHomeDir; + +use crate::NodePermissions; mod cpus; pub mod priority; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum OsError { + #[class(inherit)] #[error(transparent)] - Priority(priority::PriorityError), + Priority(#[inherit] priority::PriorityError), + #[class(inherit)] #[error(transparent)] - Permission(#[from] deno_permissions::PermissionCheckError), + Permission( + #[from] + #[inherit] + PermissionCheckError, + ), + #[class(type)] #[error("Failed to get cpu info")] FailedToGetCpuInfo, + #[class(inherit)] #[error("Failed to get user info")] - FailedToGetUserInfo(#[source] std::io::Error), + FailedToGetUserInfo( + #[source] + #[inherit] + std::io::Error, + ), } #[op2(fast, stack_trace)] @@ -213,9 +228,7 @@ where } #[op2(fast, stack_trace)] -pub fn op_geteuid

( - state: &mut OpState, -) -> Result +pub fn op_geteuid

(state: &mut OpState) -> Result where P: NodePermissions + 'static, { @@ -234,9 +247,7 @@ where } #[op2(fast, stack_trace)] -pub fn op_getegid

( - state: &mut OpState, -) -> Result +pub fn op_getegid

(state: &mut OpState) -> Result where P: NodePermissions + 'static, { @@ -272,7 +283,7 @@ where #[string] pub fn op_homedir

( state: &mut OpState, -) -> Result, deno_core::error::AnyError> +) -> Result, PermissionCheckError> where P: NodePermissions + 'static, { @@ -281,5 +292,9 @@ where permissions.check_sys("homedir", "node:os.homedir()")?; } - Ok(home::home_dir().map(|path| path.to_string_lossy().to_string())) + Ok( + sys_traits::impls::RealSys + .env_home_dir() + .map(|path| path.to_string_lossy().to_string()), + ) } diff --git a/ext/node/ops/os/priority.rs b/ext/node/ops/os/priority.rs index 9a1ebcca70..10640e4942 100644 --- a/ext/node/ops/os/priority.rs +++ b/ext/node/ops/os/priority.rs @@ -1,12 +1,14 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. pub use impl_::*; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum PriorityError { + #[class(inherit)] #[error("{0}")] Io(#[from] std::io::Error), #[cfg(windows)] + #[class(type)] #[error("Invalid priority")] InvalidPriority, } diff --git a/ext/node/ops/perf_hooks.rs b/ext/node/ops/perf_hooks.rs index 636d0b2adb..9c0fd01385 100644 --- a/ext/node/ops/perf_hooks.rs +++ b/ext/node/ops/perf_hooks.rs @@ -1,12 +1,13 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::cell::Cell; use deno_core::op2; use deno_core::GarbageCollected; -use std::cell::Cell; - -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum PerfHooksError { + #[class(generic)] #[error(transparent)] TokioEld(#[from] tokio_eld::Error), } diff --git a/ext/node/ops/process.rs b/ext/node/ops/process.rs index 45c599bee2..f28e452437 100644 --- a/ext/node/ops/process.rs +++ b/ext/node/ops/process.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::op2; use deno_core::OpState; @@ -50,7 +50,7 @@ pub fn op_node_process_kill( state: &mut OpState, #[smi] pid: i32, #[smi] sig: i32, -) -> Result { +) -> Result { state .borrow_mut::() .check_run_all("process.kill")?; diff --git a/ext/node/ops/require.rs b/ext/node/ops/require.rs index c5e3afa87d..bff0cd79ed 100644 --- a/ext/node/ops/require.rs +++ b/ext/node/ops/require.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::cell::RefCell; @@ -7,19 +7,21 @@ use std::path::PathBuf; use std::rc::Rc; use boxed_error::Boxed; -use deno_core::error::AnyError; use deno_core::op2; use deno_core::url::Url; use deno_core::v8; use deno_core::FastString; use deno_core::JsRuntimeInspector; use deno_core::OpState; +use deno_error::JsErrorBox; use deno_package_json::PackageJsonRc; use deno_path_util::normalize_path; use deno_path_util::url_from_file_path; use deno_path_util::url_to_file_path; use node_resolver::errors::ClosestPkgJsonError; +use node_resolver::InNpmPackageChecker; use node_resolver::NodeResolutionKind; +use node_resolver::NpmPackageFolderResolver; use node_resolver::ResolutionMode; use node_resolver::REQUIRE_CONDITIONS; use sys_traits::FsCanonicalize; @@ -30,14 +32,13 @@ use crate::ExtNodeSys; use crate::NodePermissions; use crate::NodeRequireLoaderRc; use crate::NodeResolverRc; -use crate::NpmPackageFolderResolverRc; use crate::PackageJsonResolverRc; #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] fn ensure_read_permission<'a, P>( state: &mut OpState, file_path: &'a Path, -) -> Result, deno_core::error::AnyError> +) -> Result, JsErrorBox> where P: NodePermissions + 'static, { @@ -46,37 +47,67 @@ where loader.ensure_read_permission(permissions, file_path) } -#[derive(Debug, Boxed)] +#[derive(Debug, Boxed, deno_error::JsError)] pub struct RequireError(pub Box); -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum RequireErrorKind { + #[class(inherit)] #[error(transparent)] - UrlParse(#[from] url::ParseError), + UrlParse( + #[from] + #[inherit] + url::ParseError, + ), + #[class(inherit)] #[error(transparent)] - Permission(deno_core::error::AnyError), + Permission(#[inherit] JsErrorBox), + #[class(generic)] #[error(transparent)] PackageExportsResolve( #[from] node_resolver::errors::PackageExportsResolveError, ), + #[class(generic)] #[error(transparent)] PackageJsonLoad(#[from] node_resolver::errors::PackageJsonLoadError), + #[class(generic)] #[error(transparent)] - ClosestPkgJson(#[from] node_resolver::errors::ClosestPkgJsonError), + ClosestPkgJson(#[from] ClosestPkgJsonError), + #[class(generic)] #[error(transparent)] PackageImportsResolve( #[from] node_resolver::errors::PackageImportsResolveError, ), + #[class(generic)] #[error(transparent)] FilePathConversion(#[from] deno_path_util::UrlToFilePathError), + #[class(generic)] #[error(transparent)] UrlConversion(#[from] deno_path_util::PathToUrlError), + #[class(inherit)] #[error(transparent)] - Fs(#[from] std::io::Error), + Fs( + #[from] + #[inherit] + deno_io::fs::FsError, + ), + #[class(inherit)] #[error(transparent)] - ReadModule(deno_core::error::AnyError), + Io( + #[from] + #[inherit] + std::io::Error, + ), + #[class(inherit)] + #[error(transparent)] + ReadModule( + #[from] + #[inherit] + JsErrorBox, + ), + #[class(inherit)] #[error("Unable to get CWD: {0}")] - UnableToGetCwd(std::io::Error), + UnableToGetCwd(#[inherit] std::io::Error), } #[op2] @@ -226,12 +257,21 @@ pub fn op_require_is_request_relative(#[string] request: String) -> bool { #[op2] #[string] -pub fn op_require_resolve_deno_dir( +pub fn op_require_resolve_deno_dir< + TInNpmPackageChecker: InNpmPackageChecker + 'static, + TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static, + TSys: ExtNodeSys + 'static, +>( state: &mut OpState, #[string] request: String, #[string] parent_filename: String, -) -> Result, AnyError> { - let resolver = state.borrow::(); +) -> Result, deno_path_util::PathToUrlError> { + let resolver = state.borrow::>(); + Ok( resolver .resolve_package_folder_from_package( @@ -244,11 +284,19 @@ pub fn op_require_resolve_deno_dir( } #[op2(fast)] -pub fn op_require_is_deno_dir_package( +pub fn op_require_is_deno_dir_package< + TInNpmPackageChecker: InNpmPackageChecker + 'static, + TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static, + TSys: ExtNodeSys + 'static, +>( state: &mut OpState, #[string] path: String, ) -> bool { - let resolver = state.borrow::>(); + let resolver = state.borrow::>(); match deno_path_util::url_from_file_path(&PathBuf::from(path)) { Ok(specifier) => resolver.in_npm_package(&specifier), Err(_) => false, @@ -309,7 +357,7 @@ pub fn op_require_stat< >( state: &mut OpState, #[string] path: String, -) -> Result { +) -> Result { let path = PathBuf::from(path); let path = ensure_read_permission::

(state, &path)?; let sys = state.borrow::(); @@ -337,8 +385,9 @@ pub fn op_require_real_path< let path = ensure_read_permission::

(state, &path) .map_err(RequireErrorKind::Permission)?; let sys = state.borrow::(); - let canonicalized_path = - deno_path_util::strip_unc_prefix(sys.fs_canonicalize(&path)?); + let canonicalized_path = deno_path_util::strip_unc_prefix( + sys.fs_canonicalize(&path).map_err(RequireErrorKind::Io)?, + ); Ok(canonicalized_path.to_string_lossy().into_owned()) } @@ -362,14 +411,12 @@ pub fn op_require_path_resolve(#[serde] parts: Vec) -> String { #[string] pub fn op_require_path_dirname( #[string] request: String, -) -> Result { +) -> Result { let p = PathBuf::from(request); if let Some(parent) = p.parent() { Ok(parent.to_string_lossy().into_owned()) } else { - Err(deno_core::error::generic_error( - "Path doesn't have a parent", - )) + Err(JsErrorBox::generic("Path doesn't have a parent")) } } @@ -377,14 +424,12 @@ pub fn op_require_path_dirname( #[string] pub fn op_require_path_basename( #[string] request: String, -) -> Result { +) -> Result { let p = PathBuf::from(request); if let Some(path) = p.file_name() { Ok(path.to_string_lossy().into_owned()) } else { - Err(deno_core::error::generic_error( - "Path doesn't have a file name", - )) + Err(JsErrorBox::generic("Path doesn't have a file name")) } } @@ -398,7 +443,7 @@ pub fn op_require_try_self_parent_path< has_parent: bool, #[string] maybe_parent_filename: Option, #[string] maybe_parent_id: Option, -) -> Result, deno_core::error::AnyError> { +) -> Result, JsErrorBox> { if !has_parent { return Ok(None); } @@ -423,6 +468,8 @@ pub fn op_require_try_self_parent_path< #[string] pub fn op_require_try_self< P: NodePermissions + 'static, + TInNpmPackageChecker: InNpmPackageChecker + 'static, + TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static, TSys: ExtNodeSys + 'static, >( state: &mut OpState, @@ -465,7 +512,11 @@ pub fn op_require_try_self< let referrer = deno_core::url::Url::from_file_path(&pkg.path).unwrap(); if let Some(exports) = &pkg.exports { - let node_resolver = state.borrow::>(); + let node_resolver = state.borrow::>(); let r = node_resolver.package_exports_resolve( &pkg.path, &expansion, @@ -524,6 +575,8 @@ pub fn op_require_as_file_path(#[string] file_or_url: String) -> String { #[string] pub fn op_require_resolve_exports< P: NodePermissions + 'static, + TInNpmPackageChecker: InNpmPackageChecker + 'static, + TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static, TSys: ExtNodeSys + 'static, >( state: &mut OpState, @@ -535,7 +588,11 @@ pub fn op_require_resolve_exports< #[string] parent_path: String, ) -> Result, RequireError> { let sys = state.borrow::(); - let node_resolver = state.borrow::>(); + let node_resolver = state.borrow::>(); let pkg_json_resolver = state.borrow::>(); let modules_path = PathBuf::from(&modules_path_str); @@ -583,17 +640,23 @@ pub fn op_require_resolve_exports< })) } +deno_error::js_error_wrapper!( + ClosestPkgJsonError, + JsClosestPkgJsonError, + "Error" +); + #[op2(fast)] pub fn op_require_is_maybe_cjs( state: &mut OpState, #[string] filename: String, -) -> Result { +) -> Result { let filename = PathBuf::from(filename); let Ok(url) = url_from_file_path(&filename) else { return Ok(false); }; let loader = state.borrow::(); - loader.is_maybe_cjs(&url) + loader.is_maybe_cjs(&url).map_err(Into::into) } #[op2(stack_trace)] @@ -621,6 +684,8 @@ pub fn op_require_read_package_scope< #[string] pub fn op_require_package_imports_resolve< P: NodePermissions + 'static, + TInNpmPackageChecker: InNpmPackageChecker + 'static, + TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static, TSys: ExtNodeSys + 'static, >( state: &mut OpState, @@ -638,7 +703,11 @@ pub fn op_require_package_imports_resolve< }; if pkg.imports.is_some() { - let node_resolver = state.borrow::>(); + let node_resolver = state.borrow::>(); let referrer_url = Url::from_file_path(&referrer_filename).unwrap(); let url = node_resolver.package_imports_resolve( &request, diff --git a/ext/node/ops/tls.rs b/ext/node/ops/tls.rs index 86b1779601..8b2845e023 100644 --- a/ext/node/ops/tls.rs +++ b/ext/node/ops/tls.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use base64::Engine; use deno_core::op2; use webpki_root_certs; diff --git a/ext/node/ops/util.rs b/ext/node/ops/util.rs index 1c177ac043..1af4f7edbd 100644 --- a/ext/node/ops/util.rs +++ b/ext/node/ops/util.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::op2; use deno_core::OpState; @@ -21,7 +21,7 @@ enum HandleType { pub fn op_node_guess_handle_type( state: &mut OpState, rid: u32, -) -> Result { +) -> Result { let handle = state.resource_table.get_handle(rid)?; let handle_type = match handle { diff --git a/ext/node/ops/v8.rs b/ext/node/ops/v8.rs index 8f09314d1d..c268d41925 100644 --- a/ext/node/ops/v8.rs +++ b/ext/node/ops/v8.rs @@ -1,11 +1,13 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::ptr::NonNull; use deno_core::op2; use deno_core::v8; use deno_core::FastString; use deno_core::GarbageCollected; use deno_core::ToJsBuffer; -use std::ptr::NonNull; +use deno_error::JsErrorBox; use v8::ValueDeserializerHelper; use v8::ValueSerializerHelper; @@ -273,13 +275,11 @@ pub fn op_v8_new_deserializer( scope: &mut v8::HandleScope, obj: v8::Local, buffer: v8::Local, -) -> Result, deno_core::error::AnyError> { +) -> Result, JsErrorBox> { let offset = buffer.byte_offset(); let len = buffer.byte_length(); let backing_store = buffer.get_backing_store().ok_or_else(|| { - deno_core::error::generic_error( - "deserialization buffer has no backing store", - ) + JsErrorBox::generic("deserialization buffer has no backing store") })?; let (buf_slice, buf_ptr) = if let Some(data) = backing_store.data() { // SAFETY: the offset is valid for the underlying buffer because we're getting it directly from v8 @@ -321,10 +321,10 @@ pub fn op_v8_transfer_array_buffer_de( #[op2(fast)] pub fn op_v8_read_double( #[cppgc] deser: &Deserializer, -) -> Result { +) -> Result { let mut double = 0f64; if !deser.inner.read_double(&mut double) { - return Err(deno_core::error::type_error("ReadDouble() failed")); + return Err(JsErrorBox::type_error("ReadDouble() failed")); } Ok(double) } @@ -359,10 +359,10 @@ pub fn op_v8_read_raw_bytes( #[op2(fast)] pub fn op_v8_read_uint32( #[cppgc] deser: &Deserializer, -) -> Result { +) -> Result { let mut value = 0; if !deser.inner.read_uint32(&mut value) { - return Err(deno_core::error::type_error("ReadUint32() failed")); + return Err(JsErrorBox::type_error("ReadUint32() failed")); } Ok(value) @@ -372,10 +372,10 @@ pub fn op_v8_read_uint32( #[serde] pub fn op_v8_read_uint64( #[cppgc] deser: &Deserializer, -) -> Result<(u32, u32), deno_core::error::AnyError> { +) -> Result<(u32, u32), JsErrorBox> { let mut val = 0; if !deser.inner.read_uint64(&mut val) { - return Err(deno_core::error::type_error("ReadUint64() failed")); + return Err(JsErrorBox::type_error("ReadUint64() failed")); } Ok(((val >> 32) as u32, val as u32)) diff --git a/ext/node/ops/vm.rs b/ext/node/ops/vm.rs index 25881cbaed..34eff8865c 100644 --- a/ext/node/ops/vm.rs +++ b/ext/node/ops/vm.rs @@ -1,14 +1,16 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::sync::atomic::AtomicBool; +use std::sync::atomic::Ordering; +use std::time::Duration; -use crate::create_host_defined_options; use deno_core::op2; use deno_core::serde_v8; use deno_core::v8; use deno_core::v8::MapFnTo; use deno_core::JsBuffer; -use std::sync::atomic::AtomicBool; -use std::sync::atomic::Ordering; -use std::time::Duration; + +use crate::create_host_defined_options; pub const PRIVATE_SYMBOL_NAME: v8::OneByteConst = v8::String::create_external_onebyte_const(b"node:contextify:context"); diff --git a/ext/node/ops/vm_internal.rs b/ext/node/ops/vm_internal.rs index 815f570ead..2219d05cd0 100644 --- a/ext/node/ops/vm_internal.rs +++ b/ext/node/ops/vm_internal.rs @@ -1,10 +1,10 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::create_host_defined_options; -use deno_core::error::type_error; -use deno_core::error::AnyError; use deno_core::v8; use deno_core::v8::MapFnTo; +use deno_error::JsErrorBox; + +use crate::create_host_defined_options; pub const PRIVATE_SYMBOL_NAME: v8::OneByteConst = v8::String::create_external_onebyte_const(b"node:contextify:context"); @@ -19,7 +19,7 @@ impl ContextifyScript { pub fn new( scope: &mut v8::HandleScope, source_str: v8::Local, - ) -> Result { + ) -> Result { let resource_name = v8::undefined(scope); let host_defined_options = create_host_defined_options(scope); let origin = v8::ScriptOrigin::new( @@ -44,7 +44,7 @@ impl ContextifyScript { v8::script_compiler::CompileOptions::NoCompileOptions, v8::script_compiler::NoCacheReason::NoReason, ) - .ok_or_else(|| type_error("Failed to compile script"))?; + .ok_or_else(|| JsErrorBox::type_error("Failed to compile script"))?; let script = v8::Global::new(scope, unbound_script); Ok(Self { script }) } diff --git a/ext/node/ops/winerror.rs b/ext/node/ops/winerror.rs index cb053774ef..5cbeddc5ae 100644 --- a/ext/node/ops/winerror.rs +++ b/ext/node/ops/winerror.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/ext/node/ops/worker_threads.rs b/ext/node/ops/worker_threads.rs index 48683be1e7..ae3c28ef35 100644 --- a/ext/node/ops/worker_threads.rs +++ b/ext/node/ops/worker_threads.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::path::Path; @@ -7,6 +7,7 @@ use std::path::PathBuf; use deno_core::op2; use deno_core::url::Url; use deno_core::OpState; +use deno_error::JsErrorBox; use sys_traits::FsCanonicalize; use sys_traits::FsMetadata; @@ -18,7 +19,7 @@ use crate::NodeRequireLoaderRc; fn ensure_read_permission<'a, P>( state: &mut OpState, file_path: &'a Path, -) -> Result, deno_core::error::AnyError> +) -> Result, JsErrorBox> where P: NodePermissions + 'static, { @@ -27,24 +28,47 @@ where loader.ensure_read_permission(permissions, file_path) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum WorkerThreadsFilenameError { + #[class(inherit)] #[error(transparent)] - Permission(deno_core::error::AnyError), + Permission(JsErrorBox), + #[class(inherit)] #[error("{0}")] - UrlParse(#[from] url::ParseError), + UrlParse( + #[from] + #[inherit] + url::ParseError, + ), + #[class(generic)] #[error("Relative path entries must start with '.' or '..'")] InvalidRelativeUrl, + #[class(generic)] #[error("URL from Path-String")] UrlFromPathString, + #[class(generic)] #[error("URL to Path-String")] UrlToPathString, + #[class(generic)] #[error("URL to Path")] UrlToPath, + #[class(generic)] #[error("File not found [{0:?}]")] FileNotFound(PathBuf), + #[class(inherit)] #[error(transparent)] - Fs(#[from] std::io::Error), + Fs( + #[from] + #[inherit] + deno_io::fs::FsError, + ), + #[class(inherit)] + #[error(transparent)] + Io( + #[from] + #[inherit] + std::io::Error, + ), } // todo(dsherret): we should remove this and do all this work inside op_create_worker diff --git a/ext/node/ops/zlib/alloc.rs b/ext/node/ops/zlib/alloc.rs index d425a18d5e..6066ab6a8e 100644 --- a/ext/node/ops/zlib/alloc.rs +++ b/ext/node/ops/zlib/alloc.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Workaround for https://github.com/rust-lang/libz-sys/issues/55 // See https://github.com/rust-lang/flate2-rs/blob/31fb07820345691352aaa64f367c1e482ad9cfdc/src/ffi/c.rs#L60 diff --git a/ext/node/ops/zlib/brotli.rs b/ext/node/ops/zlib/brotli.rs index 1a681ff7f7..5e4c1d16e6 100644 --- a/ext/node/ops/zlib/brotli.rs +++ b/ext/node/ops/zlib/brotli.rs @@ -1,4 +1,7 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. +use std::cell::RefCell; +use std::io::Read; + use brotli::enc::backward_references::BrotliEncoderMode; use brotli::enc::encode::BrotliEncoderCompress; use brotli::enc::encode::BrotliEncoderOperation; @@ -14,23 +17,35 @@ use deno_core::JsBuffer; use deno_core::OpState; use deno_core::Resource; use deno_core::ToJsBuffer; -use std::cell::RefCell; -use std::io::Read; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum BrotliError { + #[class(type)] #[error("Invalid encoder mode")] InvalidEncoderMode, + #[class(type)] #[error("Failed to compress")] CompressFailed, + #[class(type)] #[error("Failed to decompress")] DecompressFailed, + #[class(inherit)] #[error(transparent)] - Join(#[from] tokio::task::JoinError), + Join( + #[from] + #[inherit] + tokio::task::JoinError, + ), + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource( + #[from] + #[inherit] + deno_core::error::ResourceError, + ), + #[class(inherit)] #[error("{0}")] - Io(std::io::Error), + Io(#[inherit] std::io::Error), } fn encoder_mode(mode: u32) -> Result { @@ -166,10 +181,7 @@ pub fn op_brotli_compress_stream( #[buffer] input: &[u8], #[buffer] output: &mut [u8], ) -> Result { - let ctx = state - .resource_table - .get::(rid) - .map_err(BrotliError::Resource)?; + let ctx = state.resource_table.get::(rid)?; let mut inst = ctx.inst.borrow_mut(); let mut output_offset = 0; @@ -198,10 +210,7 @@ pub fn op_brotli_compress_stream_end( #[smi] rid: u32, #[buffer] output: &mut [u8], ) -> Result { - let ctx = state - .resource_table - .get::(rid) - .map_err(BrotliError::Resource)?; + let ctx = state.resource_table.get::(rid)?; let mut inst = ctx.inst.borrow_mut(); let mut output_offset = 0; @@ -276,10 +285,7 @@ pub fn op_brotli_decompress_stream( #[buffer] input: &[u8], #[buffer] output: &mut [u8], ) -> Result { - let ctx = state - .resource_table - .get::(rid) - .map_err(BrotliError::Resource)?; + let ctx = state.resource_table.get::(rid)?; let mut inst = ctx.inst.borrow_mut(); let mut output_offset = 0; @@ -307,10 +313,7 @@ pub fn op_brotli_decompress_stream_end( #[smi] rid: u32, #[buffer] output: &mut [u8], ) -> Result { - let ctx = state - .resource_table - .get::(rid) - .map_err(BrotliError::Resource)?; + let ctx = state.resource_table.get::(rid)?; let mut inst = ctx.inst.borrow_mut(); let mut output_offset = 0; diff --git a/ext/node/ops/zlib/mod.rs b/ext/node/ops/zlib/mod.rs index 991c0925d2..892944bcea 100644 --- a/ext/node/ops/zlib/mod.rs +++ b/ext/node/ops/zlib/mod.rs @@ -1,9 +1,11 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use deno_core::op2; -use libc::c_ulong; use std::borrow::Cow; use std::cell::RefCell; + +use deno_core::op2; +use deno_error::JsErrorBox; +use libc::c_ulong; use zlib::*; mod alloc; @@ -17,11 +19,11 @@ use mode::Mode; use self::stream::StreamWrapper; #[inline] -fn check(condition: bool, msg: &str) -> Result<(), deno_core::error::AnyError> { +fn check(condition: bool, msg: &str) -> Result<(), JsErrorBox> { if condition { Ok(()) } else { - Err(deno_core::error::type_error(msg.to_string())) + Err(JsErrorBox::type_error(msg.to_string())) } } @@ -56,7 +58,7 @@ impl ZlibInner { out_off: u32, out_len: u32, flush: Flush, - ) -> Result<(), deno_core::error::AnyError> { + ) -> Result<(), JsErrorBox> { check(self.init_done, "write before init")?; check(!self.write_in_progress, "write already in progress")?; check(!self.pending_close, "close already in progress")?; @@ -65,11 +67,11 @@ impl ZlibInner { let next_in = input .get(in_off as usize..in_off as usize + in_len as usize) - .ok_or_else(|| deno_core::error::type_error("invalid input range"))? + .ok_or_else(|| JsErrorBox::type_error("invalid input range"))? .as_ptr() as *mut _; let next_out = out .get_mut(out_off as usize..out_off as usize + out_len as usize) - .ok_or_else(|| deno_core::error::type_error("invalid output range"))? + .ok_or_else(|| JsErrorBox::type_error("invalid output range"))? .as_mut_ptr(); self.strm.avail_in = in_len; @@ -81,10 +83,7 @@ impl ZlibInner { Ok(()) } - fn do_write( - &mut self, - flush: Flush, - ) -> Result<(), deno_core::error::AnyError> { + fn do_write(&mut self, flush: Flush) -> Result<(), JsErrorBox> { self.flush = flush; match self.mode { Mode::Deflate | Mode::Gzip | Mode::DeflateRaw => { @@ -130,7 +129,7 @@ impl ZlibInner { self.mode = Mode::Inflate; } } else if next_expected_header_byte.is_some() { - return Err(deno_core::error::type_error( + return Err(JsErrorBox::type_error( "invalid number of gzip magic number bytes read", )); } @@ -184,7 +183,7 @@ impl ZlibInner { Ok(()) } - fn init_stream(&mut self) -> Result<(), deno_core::error::AnyError> { + fn init_stream(&mut self) -> Result<(), JsErrorBox> { match self.mode { Mode::Gzip | Mode::Gunzip => self.window_bits += 16, Mode::Unzip => self.window_bits += 32, @@ -202,7 +201,7 @@ impl ZlibInner { Mode::Inflate | Mode::Gunzip | Mode::InflateRaw | Mode::Unzip => { self.strm.inflate_init(self.window_bits) } - Mode::None => return Err(deno_core::error::type_error("Unknown mode")), + Mode::None => return Err(JsErrorBox::type_error("Unknown mode")), }; self.write_in_progress = false; @@ -211,7 +210,7 @@ impl ZlibInner { Ok(()) } - fn close(&mut self) -> Result { + fn close(&mut self) -> Result { if self.write_in_progress { self.pending_close = true; return Ok(false); @@ -257,14 +256,25 @@ pub fn op_zlib_new(#[smi] mode: i32) -> Result { }) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum ZlibError { + #[class(type)] #[error("zlib not initialized")] NotInitialized, + #[class(inherit)] #[error(transparent)] - Mode(#[from] mode::ModeError), + Mode( + #[from] + #[inherit] + mode::ModeError, + ), + #[class(inherit)] #[error(transparent)] - Other(#[from] deno_core::error::AnyError), + Other( + #[from] + #[inherit] + JsErrorBox, + ), } #[op2(fast)] diff --git a/ext/node/ops/zlib/mode.rs b/ext/node/ops/zlib/mode.rs index 41565f9b11..5fa2e501dc 100644 --- a/ext/node/ops/zlib/mode.rs +++ b/ext/node/ops/zlib/mode.rs @@ -1,6 +1,7 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(generic)] #[error("bad argument")] pub struct ModeError; diff --git a/ext/node/ops/zlib/stream.rs b/ext/node/ops/zlib/stream.rs index afcdcc4d70..de7abcacbd 100644 --- a/ext/node/ops/zlib/stream.rs +++ b/ext/node/ops/zlib/stream.rs @@ -1,11 +1,12 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use super::mode::Flush; -use super::mode::Mode; use std::ffi::c_int; use std::ops::Deref; use std::ops::DerefMut; +use super::mode::Flush; +use super::mode::Mode; + pub struct StreamWrapper { pub strm: zlib::z_stream, } diff --git a/ext/node/polyfill.rs b/ext/node/polyfill.rs index f16f16dea3..295053b434 100644 --- a/ext/node/polyfill.rs +++ b/ext/node/polyfill.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// e.g. `is_builtin_node_module("assert")` pub fn is_builtin_node_module(module_name: &str) -> bool { diff --git a/ext/node/polyfills/00_globals.js b/ext/node/polyfills/00_globals.js index efe491acc1..8a896412bc 100644 --- a/ext/node/polyfills/00_globals.js +++ b/ext/node/polyfills/00_globals.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file diff --git a/ext/node/polyfills/01_require.js b/ext/node/polyfills/01_require.js index 9709487ad3..3353da7ef7 100644 --- a/ext/node/polyfills/01_require.js +++ b/ext/node/polyfills/01_require.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file @@ -948,7 +948,7 @@ Module.prototype.require = function (id) { // wrapper function we run the users code in. The only observable difference is // that in Deno `arguments.callee` is not null. Module.wrapper = [ - "(function (exports, require, module, __filename, __dirname, Buffer, clearImmediate, clearInterval, clearTimeout, global, setImmediate, setInterval, setTimeout, performance) { (function (exports, require, module, __filename, __dirname) {", + "(function (exports, require, module, __filename, __dirname, Buffer, clearImmediate, clearInterval, clearTimeout, global, process, setImmediate, setInterval, setTimeout, performance) { (function (exports, require, module, __filename, __dirname) {", "\n}).call(this, exports, require, module, __filename, __dirname); })", ]; Module.wrap = function (script) { @@ -1033,6 +1033,7 @@ Module.prototype._compile = function (content, filename, format) { clearInterval, clearTimeout, global, + process, setImmediate, setInterval, setTimeout, @@ -1051,6 +1052,7 @@ Module.prototype._compile = function (content, filename, format) { clearInterval, clearTimeout, global, + process, setImmediate, setInterval, setTimeout, diff --git a/ext/node/polyfills/02_init.js b/ext/node/polyfills/02_init.js index b25f7ad574..a069bd828c 100644 --- a/ext/node/polyfills/02_init.js +++ b/ext/node/polyfills/02_init.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file diff --git a/ext/node/polyfills/_brotli.js b/ext/node/polyfills/_brotli.js index 108e5319a9..308cad42ad 100644 --- a/ext/node/polyfills/_brotli.js +++ b/ext/node/polyfills/_brotli.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, primordials } from "ext:core/mod.js"; const { diff --git a/ext/node/polyfills/_events.d.ts b/ext/node/polyfills/_events.d.ts index 1b765041e5..98a6b9d2f4 100644 --- a/ext/node/polyfills/_events.d.ts +++ b/ext/node/polyfills/_events.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-explicit-any // Forked from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/9b9cd671114a2a5178809798d8e7f4d8ca6c2671/types/node/events.d.ts diff --git a/ext/node/polyfills/_events.mjs b/ext/node/polyfills/_events.mjs index ce7a8ebf24..feecad2743 100644 --- a/ext/node/polyfills/_events.mjs +++ b/ext/node/polyfills/_events.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/_fs/_fs_access.ts b/ext/node/polyfills/_fs/_fs_access.ts index 824386e64b..561e023cd8 100644 --- a/ext/node/polyfills/_fs/_fs_access.ts +++ b/ext/node/polyfills/_fs/_fs_access.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_appendFile.ts b/ext/node/polyfills/_fs/_fs_appendFile.ts index 7077898623..ed47ea5a83 100644 --- a/ext/node/polyfills/_fs/_fs_appendFile.ts +++ b/ext/node/polyfills/_fs/_fs_appendFile.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { CallbackWithError, diff --git a/ext/node/polyfills/_fs/_fs_chmod.ts b/ext/node/polyfills/_fs/_fs_chmod.ts index eec8c7a8a9..195b4f810a 100644 --- a/ext/node/polyfills/_fs/_fs_chmod.ts +++ b/ext/node/polyfills/_fs/_fs_chmod.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_chown.ts b/ext/node/polyfills/_fs/_fs_chown.ts index 56364109d5..0056502f20 100644 --- a/ext/node/polyfills/_fs/_fs_chown.ts +++ b/ext/node/polyfills/_fs/_fs_chown.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_close.ts b/ext/node/polyfills/_fs/_fs_close.ts index fd01a0336a..476b3912be 100644 --- a/ext/node/polyfills/_fs/_fs_close.ts +++ b/ext/node/polyfills/_fs/_fs_close.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_common.ts b/ext/node/polyfills/_fs/_fs_common.ts index a29548bb36..8358f0271c 100644 --- a/ext/node/polyfills/_fs/_fs_common.ts +++ b/ext/node/polyfills/_fs/_fs_common.ts @@ -1,8 +1,12 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. - -// TODO(petamoriken): enable prefer-primordials for node polyfills -// deno-lint-ignore-file prefer-primordials +// Copyright 2018-2025 the Deno authors. MIT license. +import { primordials } from "ext:core/mod.js"; +const { + StringPrototypeToLowerCase, + ArrayPrototypeIncludes, + ReflectApply, + Error, +} = primordials; import { O_APPEND, O_CREAT, @@ -85,8 +89,10 @@ export function getEncoding( export function checkEncoding(encoding: Encodings | null): Encodings | null { if (!encoding) return null; - encoding = encoding.toLowerCase() as Encodings; - if (["utf8", "hex", "base64", "ascii"].includes(encoding)) return encoding; + encoding = StringPrototypeToLowerCase(encoding) as Encodings; + if (ArrayPrototypeIncludes(["utf8", "hex", "base64", "ascii"], encoding)) { + return encoding; + } if (encoding === "utf-8") { return "utf8"; @@ -99,7 +105,7 @@ export function checkEncoding(encoding: Encodings | null): Encodings | null { const notImplementedEncodings = ["utf16le", "latin1", "ucs2"]; - if (notImplementedEncodings.includes(encoding as string)) { + if (ArrayPrototypeIncludes(notImplementedEncodings, encoding as string)) { notImplemented(`"${encoding}" encoding`); } @@ -241,5 +247,5 @@ export function makeCallback( ) { validateFunction(cb, "cb"); - return (...args: unknown[]) => Reflect.apply(cb!, this, args); + return (...args: unknown[]) => ReflectApply(cb!, this, args); } diff --git a/ext/node/polyfills/_fs/_fs_constants.ts b/ext/node/polyfills/_fs/_fs_constants.ts index 0af75f072c..3d5d0b5898 100644 --- a/ext/node/polyfills/_fs/_fs_constants.ts +++ b/ext/node/polyfills/_fs/_fs_constants.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { fs } from "ext:deno_node/internal_binding/constants.ts"; diff --git a/ext/node/polyfills/_fs/_fs_copy.ts b/ext/node/polyfills/_fs/_fs_copy.ts index 0434bff4d1..87204e348c 100644 --- a/ext/node/polyfills/_fs/_fs_copy.ts +++ b/ext/node/polyfills/_fs/_fs_copy.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_cp.js b/ext/node/polyfills/_fs/_fs_cp.js index 52dd8f5056..29bc633224 100644 --- a/ext/node/polyfills/_fs/_fs_cp.js +++ b/ext/node/polyfills/_fs/_fs_cp.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { primordials } from "ext:core/mod.js"; import { op_node_cp, op_node_cp_sync } from "ext:core/ops"; import { diff --git a/ext/node/polyfills/_fs/_fs_dir.ts b/ext/node/polyfills/_fs/_fs_dir.ts index ed051fb0bf..2a496562d6 100644 --- a/ext/node/polyfills/_fs/_fs_dir.ts +++ b/ext/node/polyfills/_fs/_fs_dir.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { primordials } from "ext:core/mod.js"; import Dirent from "ext:deno_node/_fs/_fs_dirent.ts"; diff --git a/ext/node/polyfills/_fs/_fs_dirent.ts b/ext/node/polyfills/_fs/_fs_dirent.ts index d4ad6bb430..fce7a6e72d 100644 --- a/ext/node/polyfills/_fs/_fs_dirent.ts +++ b/ext/node/polyfills/_fs/_fs_dirent.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { notImplemented } from "ext:deno_node/_utils.ts"; export default class Dirent { diff --git a/ext/node/polyfills/_fs/_fs_exists.ts b/ext/node/polyfills/_fs/_fs_exists.ts index b5bbe235a4..6a285f5e60 100644 --- a/ext/node/polyfills/_fs/_fs_exists.ts +++ b/ext/node/polyfills/_fs/_fs_exists.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_fdatasync.ts b/ext/node/polyfills/_fs/_fs_fdatasync.ts index 0c3f50f1c6..02226e1c96 100644 --- a/ext/node/polyfills/_fs/_fs_fdatasync.ts +++ b/ext/node/polyfills/_fs/_fs_fdatasync.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_fstat.ts b/ext/node/polyfills/_fs/_fs_fstat.ts index 1a845dfff4..37c057c378 100644 --- a/ext/node/polyfills/_fs/_fs_fstat.ts +++ b/ext/node/polyfills/_fs/_fs_fstat.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_fsync.ts b/ext/node/polyfills/_fs/_fs_fsync.ts index 75d4b37569..a07f440778 100644 --- a/ext/node/polyfills/_fs/_fs_fsync.ts +++ b/ext/node/polyfills/_fs/_fs_fsync.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_ftruncate.ts b/ext/node/polyfills/_fs/_fs_ftruncate.ts index 79320137f9..6a8614b734 100644 --- a/ext/node/polyfills/_fs/_fs_ftruncate.ts +++ b/ext/node/polyfills/_fs/_fs_ftruncate.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_futimes.ts b/ext/node/polyfills/_fs/_fs_futimes.ts index 98cd1066c3..be274f4d11 100644 --- a/ext/node/polyfills/_fs/_fs_futimes.ts +++ b/ext/node/polyfills/_fs/_fs_futimes.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_lchown.ts b/ext/node/polyfills/_fs/_fs_lchown.ts index 8611c8021d..293155f9d0 100644 --- a/ext/node/polyfills/_fs/_fs_lchown.ts +++ b/ext/node/polyfills/_fs/_fs_lchown.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_link.ts b/ext/node/polyfills/_fs/_fs_link.ts index a10860c12f..73ed890d36 100644 --- a/ext/node/polyfills/_fs/_fs_link.ts +++ b/ext/node/polyfills/_fs/_fs_link.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_lstat.ts b/ext/node/polyfills/_fs/_fs_lstat.ts index 6ce401444f..b9f80bfc51 100644 --- a/ext/node/polyfills/_fs/_fs_lstat.ts +++ b/ext/node/polyfills/_fs/_fs_lstat.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_lutimes.ts b/ext/node/polyfills/_fs/_fs_lutimes.ts index 2475c57149..3f8dd167c0 100644 --- a/ext/node/polyfills/_fs/_fs_lutimes.ts +++ b/ext/node/polyfills/_fs/_fs_lutimes.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_mkdir.ts b/ext/node/polyfills/_fs/_fs_mkdir.ts index 06a8b35221..03d36629e5 100644 --- a/ext/node/polyfills/_fs/_fs_mkdir.ts +++ b/ext/node/polyfills/_fs/_fs_mkdir.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_mkdtemp.ts b/ext/node/polyfills/_fs/_fs_mkdtemp.ts index 5498828b5b..46060971a8 100644 --- a/ext/node/polyfills/_fs/_fs_mkdtemp.ts +++ b/ext/node/polyfills/_fs/_fs_mkdtemp.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Node.js contributors. All rights reserved. MIT License. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/_fs/_fs_open.ts b/ext/node/polyfills/_fs/_fs_open.ts index 31ca4bb619..12f8ed7035 100644 --- a/ext/node/polyfills/_fs/_fs_open.ts +++ b/ext/node/polyfills/_fs/_fs_open.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials @@ -153,7 +153,7 @@ export function openPromise( return new Promise((resolve, reject) => { open(path, flags, mode, (err, fd) => { if (err) reject(err); - else resolve(new FileHandle(fd)); + else resolve(new FileHandle(fd, path)); }); }); } diff --git a/ext/node/polyfills/_fs/_fs_opendir.ts b/ext/node/polyfills/_fs/_fs_opendir.ts index 3280f0fd5c..51379fd451 100644 --- a/ext/node/polyfills/_fs/_fs_opendir.ts +++ b/ext/node/polyfills/_fs/_fs_opendir.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_read.ts b/ext/node/polyfills/_fs/_fs_read.ts index df4f5e375d..c7f3acf4d8 100644 --- a/ext/node/polyfills/_fs/_fs_read.ts +++ b/ext/node/polyfills/_fs/_fs_read.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_readFile.ts b/ext/node/polyfills/_fs/_fs_readFile.ts index b1bc53675d..752a683ca7 100644 --- a/ext/node/polyfills/_fs/_fs_readFile.ts +++ b/ext/node/polyfills/_fs/_fs_readFile.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_readdir.ts b/ext/node/polyfills/_fs/_fs_readdir.ts index 59c802e424..4b34451a38 100644 --- a/ext/node/polyfills/_fs/_fs_readdir.ts +++ b/ext/node/polyfills/_fs/_fs_readdir.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_readlink.ts b/ext/node/polyfills/_fs/_fs_readlink.ts index 08bea843fa..084dbc2d09 100644 --- a/ext/node/polyfills/_fs/_fs_readlink.ts +++ b/ext/node/polyfills/_fs/_fs_readlink.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_readv.ts b/ext/node/polyfills/_fs/_fs_readv.ts index 2259f029ae..4486959b76 100644 --- a/ext/node/polyfills/_fs/_fs_readv.ts +++ b/ext/node/polyfills/_fs/_fs_readv.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_realpath.ts b/ext/node/polyfills/_fs/_fs_realpath.ts index 4568748ba7..12f5f10a43 100644 --- a/ext/node/polyfills/_fs/_fs_realpath.ts +++ b/ext/node/polyfills/_fs/_fs_realpath.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_rename.ts b/ext/node/polyfills/_fs/_fs_rename.ts index 41569c80f3..7a84cf8d98 100644 --- a/ext/node/polyfills/_fs/_fs_rename.ts +++ b/ext/node/polyfills/_fs/_fs_rename.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_rm.ts b/ext/node/polyfills/_fs/_fs_rm.ts index 5730f8c413..cce2ab95c0 100644 --- a/ext/node/polyfills/_fs/_fs_rm.ts +++ b/ext/node/polyfills/_fs/_fs_rm.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_rmdir.ts b/ext/node/polyfills/_fs/_fs_rmdir.ts index 00c085ebd5..6a78e9e467 100644 --- a/ext/node/polyfills/_fs/_fs_rmdir.ts +++ b/ext/node/polyfills/_fs/_fs_rmdir.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_stat.ts b/ext/node/polyfills/_fs/_fs_stat.ts index f264746686..031c8dbb50 100644 --- a/ext/node/polyfills/_fs/_fs_stat.ts +++ b/ext/node/polyfills/_fs/_fs_stat.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_statfs.js b/ext/node/polyfills/_fs/_fs_statfs.js index 51da1ed684..90953c12b5 100644 --- a/ext/node/polyfills/_fs/_fs_statfs.js +++ b/ext/node/polyfills/_fs/_fs_statfs.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { BigInt } from "ext:deno_node/internal/primordials.mjs"; import { op_node_statfs } from "ext:core/ops"; diff --git a/ext/node/polyfills/_fs/_fs_symlink.ts b/ext/node/polyfills/_fs/_fs_symlink.ts index 350263423a..953697e44c 100644 --- a/ext/node/polyfills/_fs/_fs_symlink.ts +++ b/ext/node/polyfills/_fs/_fs_symlink.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_truncate.ts b/ext/node/polyfills/_fs/_fs_truncate.ts index a7e79b9c30..47b87eecdc 100644 --- a/ext/node/polyfills/_fs/_fs_truncate.ts +++ b/ext/node/polyfills/_fs/_fs_truncate.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_unlink.ts b/ext/node/polyfills/_fs/_fs_unlink.ts index 1d9aefa46f..d046c40f35 100644 --- a/ext/node/polyfills/_fs/_fs_unlink.ts +++ b/ext/node/polyfills/_fs/_fs_unlink.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_utimes.ts b/ext/node/polyfills/_fs/_fs_utimes.ts index 3fff4a4623..ff25fffed8 100644 --- a/ext/node/polyfills/_fs/_fs_utimes.ts +++ b/ext/node/polyfills/_fs/_fs_utimes.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_watch.ts b/ext/node/polyfills/_fs/_fs_watch.ts index eb2cd8bfa2..8b92e9aa44 100644 --- a/ext/node/polyfills/_fs/_fs_watch.ts +++ b/ext/node/polyfills/_fs/_fs_watch.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_write.d.ts b/ext/node/polyfills/_fs/_fs_write.d.ts index 7171ec6dbd..cd8257ec35 100644 --- a/ext/node/polyfills/_fs/_fs_write.d.ts +++ b/ext/node/polyfills/_fs/_fs_write.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Forked from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/d9df51e34526f48bef4e2546a006157b391ad96c/types/node/fs.d.ts import { BufferEncoding, ErrnoException } from "ext:deno_node/_global.d.ts"; diff --git a/ext/node/polyfills/_fs/_fs_write.mjs b/ext/node/polyfills/_fs/_fs_write.mjs index 254094c9ad..a0d0af6017 100644 --- a/ext/node/polyfills/_fs/_fs_write.mjs +++ b/ext/node/polyfills/_fs/_fs_write.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/_fs/_fs_writeFile.ts b/ext/node/polyfills/_fs/_fs_writeFile.ts index dd324815b9..c76be8a6b8 100644 --- a/ext/node/polyfills/_fs/_fs_writeFile.ts +++ b/ext/node/polyfills/_fs/_fs_writeFile.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/_fs/_fs_writev.d.ts b/ext/node/polyfills/_fs/_fs_writev.d.ts deleted file mode 100644 index daa4dbbcf4..0000000000 --- a/ext/node/polyfills/_fs/_fs_writev.d.ts +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -// Forked from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/d9df51e34526f48bef4e2546a006157b391ad96c/types/node/fs.d.ts - -import { ErrnoException } from "ext:deno_node/_global.d.ts"; - -/** - * Write an array of `ArrayBufferView`s to the file specified by `fd` using`writev()`. - * - * `position` is the offset from the beginning of the file where this data - * should be written. If `typeof position !== 'number'`, the data will be written - * at the current position. - * - * The callback will be given three arguments: `err`, `bytesWritten`, and`buffers`. `bytesWritten` is how many bytes were written from `buffers`. - * - * If this method is `util.promisify()` ed, it returns a promise for an`Object` with `bytesWritten` and `buffers` properties. - * - * It is unsafe to use `fs.writev()` multiple times on the same file without - * waiting for the callback. For this scenario, use {@link createWriteStream}. - * - * On Linux, positional writes don't work when the file is opened in append mode. - * The kernel ignores the position argument and always appends the data to - * the end of the file. - * @since v12.9.0 - */ -export function writev( - fd: number, - buffers: ReadonlyArray, - cb: ( - err: ErrnoException | null, - bytesWritten: number, - buffers: ArrayBufferView[], - ) => void, -): void; -export function writev( - fd: number, - buffers: ReadonlyArray, - position: number | null, - cb: ( - err: ErrnoException | null, - bytesWritten: number, - buffers: ArrayBufferView[], - ) => void, -): void; -export interface WriteVResult { - bytesWritten: number; - buffers: ArrayBufferView[]; -} -export namespace writev { - function __promisify__( - fd: number, - buffers: ReadonlyArray, - position?: number, - ): Promise; -} -/** - * For detailed information, see the documentation of the asynchronous version of - * this API: {@link writev}. - * @since v12.9.0 - * @return The number of bytes written. - */ -export function writevSync( - fd: number, - buffers: ReadonlyArray, - position?: number, -): number; diff --git a/ext/node/polyfills/_fs/_fs_writev.mjs b/ext/node/polyfills/_fs/_fs_writev.ts similarity index 50% rename from ext/node/polyfills/_fs/_fs_writev.mjs rename to ext/node/polyfills/_fs/_fs_writev.ts index 055bce0b24..e38b44b19a 100644 --- a/ext/node/polyfills/_fs/_fs_writev.mjs +++ b/ext/node/polyfills/_fs/_fs_writev.ts @@ -1,19 +1,57 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials import { Buffer } from "node:buffer"; +import process from "node:process"; +import { ErrnoException } from "ext:deno_node/_global.d.ts"; import { validateBufferArray } from "ext:deno_node/internal/fs/utils.mjs"; import { getValidatedFd } from "ext:deno_node/internal/fs/utils.mjs"; +import { WriteVResult } from "ext:deno_node/internal/fs/handle.ts"; import { maybeCallback } from "ext:deno_node/_fs/_fs_common.ts"; import * as io from "ext:deno_io/12_io.js"; import { op_fs_seek_async, op_fs_seek_sync } from "ext:core/ops"; -export function writev(fd, buffers, position, callback) { +export interface WriteVResult { + bytesWritten: number; + buffers: ReadonlyArray; +} + +type writeVCallback = ( + err: ErrnoException | null, + bytesWritten: number, + buffers: ReadonlyArray, +) => void; + +/** + * Write an array of `ArrayBufferView`s to the file specified by `fd` using`writev()`. + * + * `position` is the offset from the beginning of the file where this data + * should be written. If `typeof position !== 'number'`, the data will be written + * at the current position. + * + * The callback will be given three arguments: `err`, `bytesWritten`, and`buffers`. `bytesWritten` is how many bytes were written from `buffers`. + * + * If this method is `util.promisify()` ed, it returns a promise for an`Object` with `bytesWritten` and `buffers` properties. + * + * It is unsafe to use `fs.writev()` multiple times on the same file without + * waiting for the callback. For this scenario, use {@link createWriteStream}. + * + * On Linux, positional writes don't work when the file is opened in append mode. + * The kernel ignores the position argument and always appends the data to + * the end of the file. + * @since v12.9.0 + */ +export function writev( + fd: number, + buffers: ReadonlyArray, + position?: number | null, + callback?: writeVCallback, +): void { const innerWritev = async (fd, buffers, position) => { - const chunks = []; + const chunks: Buffer[] = []; const offset = 0; for (let i = 0; i < buffers.length; i++) { if (Buffer.isBuffer(buffers[i])) { @@ -45,16 +83,24 @@ export function writev(fd, buffers, position, callback) { if (typeof position !== "number") position = null; innerWritev(fd, buffers, position).then( - (nwritten) => { - callback(null, nwritten, buffers); - }, + (nwritten) => callback(null, nwritten, buffers), (err) => callback(err), ); } -export function writevSync(fd, buffers, position) { +/** + * For detailed information, see the documentation of the asynchronous version of + * this API: {@link writev}. + * @since v12.9.0 + * @return The number of bytes written. + */ +export function writevSync( + fd: number, + buffers: ArrayBufferView[], + position?: number | null, +): number { const innerWritev = (fd, buffers, position) => { - const chunks = []; + const chunks: Buffer[] = []; const offset = 0; for (let i = 0; i < buffers.length; i++) { if (Buffer.isBuffer(buffers[i])) { @@ -85,3 +131,16 @@ export function writevSync(fd, buffers, position) { return innerWritev(fd, buffers, position); } + +export function writevPromise( + fd: number, + buffers: ArrayBufferView[], + position?: number, +): Promise { + return new Promise((resolve, reject) => { + writev(fd, buffers, position, (err, bytesWritten, buffers) => { + if (err) reject(err); + else resolve({ bytesWritten, buffers }); + }); + }); +} diff --git a/ext/node/polyfills/_global.d.ts b/ext/node/polyfills/_global.d.ts index 8587acbbb2..1e610de08d 100644 --- a/ext/node/polyfills/_global.d.ts +++ b/ext/node/polyfills/_global.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { EventEmitter } from "ext:deno_node/_events.d.ts"; import { Buffer } from "node:buffer"; diff --git a/ext/node/polyfills/_http_agent.mjs b/ext/node/polyfills/_http_agent.mjs index 53bb64ed53..4de58cb406 100644 --- a/ext/node/polyfills/_http_agent.mjs +++ b/ext/node/polyfills/_http_agent.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/_http_common.ts b/ext/node/polyfills/_http_common.ts index 86143b4dea..f2ca75ec1c 100644 --- a/ext/node/polyfills/_http_common.ts +++ b/ext/node/polyfills/_http_common.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. import { primordials } from "ext:core/mod.js"; diff --git a/ext/node/polyfills/_http_outgoing.ts b/ext/node/polyfills/_http_outgoing.ts index 5a9a8ad7e6..fcc6394eb8 100644 --- a/ext/node/polyfills/_http_outgoing.ts +++ b/ext/node/polyfills/_http_outgoing.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/_http_server.ts b/ext/node/polyfills/_http_server.ts index c2867de0c6..cf80f1e6e0 100644 --- a/ext/node/polyfills/_http_server.ts +++ b/ext/node/polyfills/_http_server.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. export enum STATUS_CODES { /** RFC 7231, 6.2.1 */ diff --git a/ext/node/polyfills/_next_tick.ts b/ext/node/polyfills/_next_tick.ts index af306a29c8..355b6ca6ba 100644 --- a/ext/node/polyfills/_next_tick.ts +++ b/ext/node/polyfills/_next_tick.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/_process/exiting.ts b/ext/node/polyfills/_process/exiting.ts index 01991e9c96..c1a032b643 100644 --- a/ext/node/polyfills/_process/exiting.ts +++ b/ext/node/polyfills/_process/exiting.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore prefer-const export let _exiting = false; diff --git a/ext/node/polyfills/_process/process.ts b/ext/node/polyfills/_process/process.ts index 6f69139c98..06e48160de 100644 --- a/ext/node/polyfills/_process/process.ts +++ b/ext/node/polyfills/_process/process.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. // The following are all the process APIs that don't depend on the stream module diff --git a/ext/node/polyfills/_process/streams.mjs b/ext/node/polyfills/_process/streams.mjs index 3573956c9d..9a838e7d38 100644 --- a/ext/node/polyfills/_process/streams.mjs +++ b/ext/node/polyfills/_process/streams.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. import { primordials } from "ext:core/mod.js"; diff --git a/ext/node/polyfills/_readline.d.ts b/ext/node/polyfills/_readline.d.ts index fcaa327a05..256cb87887 100644 --- a/ext/node/polyfills/_readline.d.ts +++ b/ext/node/polyfills/_readline.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-explicit-any // Forked from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/cd61f5b4d3d143108569ec3f88adc0eb34b961c4/types/node/readline.d.ts diff --git a/ext/node/polyfills/_readline.mjs b/ext/node/polyfills/_readline.mjs index 2af717152b..3943736ea9 100644 --- a/ext/node/polyfills/_readline.mjs +++ b/ext/node/polyfills/_readline.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/_readline_shared_types.d.ts b/ext/node/polyfills/_readline_shared_types.d.ts index b58ad035e7..f88de9091c 100644 --- a/ext/node/polyfills/_readline_shared_types.d.ts +++ b/ext/node/polyfills/_readline_shared_types.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Part of https://github.com/DefinitelyTyped/DefinitelyTyped/blob/cd61f5b4d3d143108569ec3f88adc0eb34b961c4/types/node/readline.d.ts diff --git a/ext/node/polyfills/_stream.d.ts b/ext/node/polyfills/_stream.d.ts index d251d9bee2..6ae3494118 100644 --- a/ext/node/polyfills/_stream.d.ts +++ b/ext/node/polyfills/_stream.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-explicit-any // Forked from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/4f538975138678878fed5b2555c0672aa578ab7d/types/node/stream.d.ts diff --git a/ext/node/polyfills/_stream.mjs b/ext/node/polyfills/_stream.mjs index 02640abcd9..3fc79b69df 100644 --- a/ext/node/polyfills/_stream.mjs +++ b/ext/node/polyfills/_stream.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // deno-fmt-ignore-file // deno-lint-ignore-file diff --git a/ext/node/polyfills/_tls_common.ts b/ext/node/polyfills/_tls_common.ts index d00c3629e1..4e5904b971 100644 --- a/ext/node/polyfills/_tls_common.ts +++ b/ext/node/polyfills/_tls_common.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // deno-lint-ignore-file no-explicit-any diff --git a/ext/node/polyfills/_tls_wrap.ts b/ext/node/polyfills/_tls_wrap.ts index 9e5def9f2b..dc7dac77ac 100644 --- a/ext/node/polyfills/_tls_wrap.ts +++ b/ext/node/polyfills/_tls_wrap.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills @@ -154,7 +154,7 @@ export class TLSSocket extends net.Socket { const afterConnect = handle.afterConnect; handle.afterConnect = async (req: any, status: number) => { options.hostname ??= undefined; // coerce to undefined if null, startTls expects hostname to be undefined - if (tlssock._isNpmAgent) { + if (tlssock._needsSockInitWorkaround) { // skips the TLS handshake for @npmcli/agent as it's handled by // onSocket handler of ClientRequest object. tlssock.emit("secure"); diff --git a/ext/node/polyfills/_util/_util_callbackify.js b/ext/node/polyfills/_util/_util_callbackify.js index cb30f79150..ae83850bc0 100644 --- a/ext/node/polyfills/_util/_util_callbackify.js +++ b/ext/node/polyfills/_util/_util_callbackify.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // // Adapted from Node.js. Copyright Joyent, Inc. and other Node contributors. // diff --git a/ext/node/polyfills/_util/asserts.ts b/ext/node/polyfills/_util/asserts.ts index 8f90cf168a..71c3cc863d 100644 --- a/ext/node/polyfills/_util/asserts.ts +++ b/ext/node/polyfills/_util/asserts.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { primordials } from "ext:core/mod.js"; const { diff --git a/ext/node/polyfills/_util/async.ts b/ext/node/polyfills/_util/async.ts index 0cacccacc7..445febcaaf 100644 --- a/ext/node/polyfills/_util/async.ts +++ b/ext/node/polyfills/_util/async.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // This module is vendored from std/async/delay.ts // (with some modifications) diff --git a/ext/node/polyfills/_util/os.ts b/ext/node/polyfills/_util/os.ts index 421d5d9da0..f72dc662d9 100644 --- a/ext/node/polyfills/_util/os.ts +++ b/ext/node/polyfills/_util/os.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { op_node_build_os } from "ext:core/ops"; diff --git a/ext/node/polyfills/_util/std_asserts.ts b/ext/node/polyfills/_util/std_asserts.ts index 78b749f549..7623741379 100644 --- a/ext/node/polyfills/_util/std_asserts.ts +++ b/ext/node/polyfills/_util/std_asserts.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // vendored from std/assert/mod.ts import { primordials } from "ext:core/mod.js"; diff --git a/ext/node/polyfills/_util/std_fmt_colors.ts b/ext/node/polyfills/_util/std_fmt_colors.ts index 5072b298ee..f1dc97f6ca 100644 --- a/ext/node/polyfills/_util/std_fmt_colors.ts +++ b/ext/node/polyfills/_util/std_fmt_colors.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // This file is vendored from std/fmt/colors.ts import { primordials } from "ext:core/mod.js"; diff --git a/ext/node/polyfills/_util/std_testing_diff.ts b/ext/node/polyfills/_util/std_testing_diff.ts index 5155fd242c..1b680c6cca 100644 --- a/ext/node/polyfills/_util/std_testing_diff.ts +++ b/ext/node/polyfills/_util/std_testing_diff.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // This file was vendored from std/testing/_diff.ts import { primordials } from "ext:core/mod.js"; diff --git a/ext/node/polyfills/_utils.ts b/ext/node/polyfills/_utils.ts index 79d84e00f0..7f20782e2b 100644 --- a/ext/node/polyfills/_utils.ts +++ b/ext/node/polyfills/_utils.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { primordials } from "ext:core/mod.js"; const { diff --git a/ext/node/polyfills/_zlib.mjs b/ext/node/polyfills/_zlib.mjs index 07fc440ef5..bb6bac1bd0 100644 --- a/ext/node/polyfills/_zlib.mjs +++ b/ext/node/polyfills/_zlib.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright (c) 2014-2015 Devon Govett // Forked from https://github.com/browserify/browserify-zlib diff --git a/ext/node/polyfills/_zlib_binding.mjs b/ext/node/polyfills/_zlib_binding.mjs index 069b7f8351..37125b88ac 100644 --- a/ext/node/polyfills/_zlib_binding.mjs +++ b/ext/node/polyfills/_zlib_binding.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file diff --git a/ext/node/polyfills/assert.ts b/ext/node/polyfills/assert.ts index 188c7a0c2f..48b4627044 100644 --- a/ext/node/polyfills/assert.ts +++ b/ext/node/polyfills/assert.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file ban-types prefer-primordials diff --git a/ext/node/polyfills/assert/strict.ts b/ext/node/polyfills/assert/strict.ts index 9837167627..883deaf087 100644 --- a/ext/node/polyfills/assert/strict.ts +++ b/ext/node/polyfills/assert/strict.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { strict } from "node:assert"; export { diff --git a/ext/node/polyfills/assertion_error.ts b/ext/node/polyfills/assertion_error.ts index ff1168dc30..b56cec2c1d 100644 --- a/ext/node/polyfills/assertion_error.ts +++ b/ext/node/polyfills/assertion_error.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Adapted from Node.js. Copyright Joyent, Inc. and other Node contributors. diff --git a/ext/node/polyfills/async_hooks.ts b/ext/node/polyfills/async_hooks.ts index 7a2f153dac..e01110bd3b 100644 --- a/ext/node/polyfills/async_hooks.ts +++ b/ext/node/polyfills/async_hooks.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/buffer.ts b/ext/node/polyfills/buffer.ts index efe3b07a97..38000c6edb 100644 --- a/ext/node/polyfills/buffer.ts +++ b/ext/node/polyfills/buffer.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @deno-types="./internal/buffer.d.ts" export { atob, diff --git a/ext/node/polyfills/child_process.ts b/ext/node/polyfills/child_process.ts index eda718ff34..2bd8614275 100644 --- a/ext/node/polyfills/child_process.ts +++ b/ext/node/polyfills/child_process.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // This module implements 'child_process' module of Node.JS API. // ref: https://nodejs.org/api/child_process.html @@ -53,7 +53,7 @@ import { convertToValidSignal, kEmptyObject, } from "ext:deno_node/internal/util.mjs"; -import { kNeedsNpmProcessState } from "ext:runtime/40_process.js"; +import { kNeedsNpmProcessState } from "ext:deno_process/40_process.js"; const MAX_BUFFER = 1024 * 1024; diff --git a/ext/node/polyfills/cluster.ts b/ext/node/polyfills/cluster.ts index 8abc2fedcd..67534676b4 100644 --- a/ext/node/polyfills/cluster.ts +++ b/ext/node/polyfills/cluster.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. import { notImplemented } from "ext:deno_node/_utils.ts"; diff --git a/ext/node/polyfills/console.ts b/ext/node/polyfills/console.ts index f74c9af165..1189d95064 100644 --- a/ext/node/polyfills/console.ts +++ b/ext/node/polyfills/console.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { primordials } from "ext:core/mod.js"; import { Console } from "ext:deno_node/internal/console/constructor.mjs"; diff --git a/ext/node/polyfills/constants.ts b/ext/node/polyfills/constants.ts index e5004039b1..421c8b641a 100644 --- a/ext/node/polyfills/constants.ts +++ b/ext/node/polyfills/constants.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Based on: https://github.com/nodejs/node/blob/0646eda/lib/constants.js diff --git a/ext/node/polyfills/crypto.ts b/ext/node/polyfills/crypto.ts index 908d21b006..ff3bdc7752 100644 --- a/ext/node/polyfills/crypto.ts +++ b/ext/node/polyfills/crypto.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/dgram.ts b/ext/node/polyfills/dgram.ts index 99f4940ec2..56fb8d8f32 100644 --- a/ext/node/polyfills/dgram.ts +++ b/ext/node/polyfills/dgram.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/diagnostics_channel.js b/ext/node/polyfills/diagnostics_channel.js index 807c33e475..65533e0803 100644 --- a/ext/node/polyfills/diagnostics_channel.js +++ b/ext/node/polyfills/diagnostics_channel.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/dns.ts b/ext/node/polyfills/dns.ts index 78b934e602..b8e4af6eec 100644 --- a/ext/node/polyfills/dns.ts +++ b/ext/node/polyfills/dns.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/dns/promises.ts b/ext/node/polyfills/dns/promises.ts index 6bc539cba9..422ae05c64 100644 --- a/ext/node/polyfills/dns/promises.ts +++ b/ext/node/polyfills/dns/promises.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/domain.ts b/ext/node/polyfills/domain.ts index 7093779966..daa613ede0 100644 --- a/ext/node/polyfills/domain.ts +++ b/ext/node/polyfills/domain.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // This code has been inspired by https://github.com/bevry/domain-browser/commit/8bce7f4a093966ca850da75b024239ad5d0b33c6 diff --git a/ext/node/polyfills/events.ts b/ext/node/polyfills/events.ts index 78f3d8768c..891f3d3b8d 100644 --- a/ext/node/polyfills/events.ts +++ b/ext/node/polyfills/events.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @deno-types="./_events.d.ts" export { addAbortListener, diff --git a/ext/node/polyfills/fs.ts b/ext/node/polyfills/fs.ts index cbdc36afe5..a6e43b5baa 100644 --- a/ext/node/polyfills/fs.ts +++ b/ext/node/polyfills/fs.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { access, accessPromise, @@ -119,7 +119,7 @@ import { // @deno-types="./_fs/_fs_write.d.ts" import { write, writeSync } from "ext:deno_node/_fs/_fs_write.mjs"; // @deno-types="./_fs/_fs_writev.d.ts" -import { writev, writevSync } from "ext:deno_node/_fs/_fs_writev.mjs"; +import { writev, writevSync } from "ext:deno_node/_fs/_fs_writev.ts"; import { readv, readvSync } from "ext:deno_node/_fs/_fs_readv.ts"; import { writeFile, diff --git a/ext/node/polyfills/fs/promises.ts b/ext/node/polyfills/fs/promises.ts index a5125dac8d..f8d63e94e0 100644 --- a/ext/node/polyfills/fs/promises.ts +++ b/ext/node/polyfills/fs/promises.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { promises as fsPromises } from "node:fs"; export const access = fsPromises.access; diff --git a/ext/node/polyfills/http.ts b/ext/node/polyfills/http.ts index e911535be5..ff85a61531 100644 --- a/ext/node/polyfills/http.ts +++ b/ext/node/polyfills/http.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials @@ -455,8 +455,13 @@ class ClientRequest extends OutgoingMessage { (async () => { try { const parsedUrl = new URL(url); - let baseConnRid = - this.socket._handle[kStreamBaseField][internalRidSymbol]; + const handle = this.socket._handle; + if (!handle) { + // Using non-standard socket. There's no way to handle this type of socket. + // This should be only happening in artificial test cases + return; + } + let baseConnRid = handle[kStreamBaseField][internalRidSymbol]; if (this._encrypted) { [baseConnRid] = op_tls_start({ rid: baseConnRid, @@ -637,6 +642,12 @@ class ClientRequest extends OutgoingMessage { }; this.socket = socket; this.emit("socket", socket); + socket.once("error", (err) => { + // This callback loosely follow `socketErrorListener` in Node.js + // https://github.com/nodejs/node/blob/f16cd10946ca9ad272f42b94f00cf960571c9181/lib/_http_client.js#L509 + emitErrorEvent(this, err); + socket.destroy(err); + }); if (socket.readyState === "opening") { socket.on("connect", onConnect); } else { diff --git a/ext/node/polyfills/http2.ts b/ext/node/polyfills/http2.ts index 1b3f74f6f6..ab2faa2d08 100644 --- a/ext/node/polyfills/http2.ts +++ b/ext/node/polyfills/http2.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/https.ts b/ext/node/polyfills/https.ts index fd700173eb..d958d8e746 100644 --- a/ext/node/polyfills/https.ts +++ b/ext/node/polyfills/https.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/inspector.js b/ext/node/polyfills/inspector.js index 7eb15ce917..bb2661b9cd 100644 --- a/ext/node/polyfills/inspector.js +++ b/ext/node/polyfills/inspector.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. import process from "node:process"; diff --git a/ext/node/polyfills/inspector/promises.js b/ext/node/polyfills/inspector/promises.js index 3483e53f5e..a075eba001 100644 --- a/ext/node/polyfills/inspector/promises.js +++ b/ext/node/polyfills/inspector/promises.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. import inspector from "node:inspector"; diff --git a/ext/node/polyfills/internal/assert.mjs b/ext/node/polyfills/internal/assert.mjs index 20ed511e02..01b5fad460 100644 --- a/ext/node/polyfills/internal/assert.mjs +++ b/ext/node/polyfills/internal/assert.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { ERR_INTERNAL_ASSERTION } from "ext:deno_node/internal/errors.ts"; function assert(value, message) { diff --git a/ext/node/polyfills/internal/async_hooks.ts b/ext/node/polyfills/internal/async_hooks.ts index a5d6728e33..a2f52e6979 100644 --- a/ext/node/polyfills/internal/async_hooks.ts +++ b/ext/node/polyfills/internal/async_hooks.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal/blocklist.mjs b/ext/node/polyfills/internal/blocklist.mjs index 8a7c9c376a..d45592a8ff 100644 --- a/ext/node/polyfills/internal/blocklist.mjs +++ b/ext/node/polyfills/internal/blocklist.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. import { primordials } from "ext:core/mod.js"; diff --git a/ext/node/polyfills/internal/buffer.d.ts b/ext/node/polyfills/internal/buffer.d.ts index 2008dc2432..125deb0ef2 100644 --- a/ext/node/polyfills/internal/buffer.d.ts +++ b/ext/node/polyfills/internal/buffer.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright DefinitelyTyped contributors. All rights reserved. MIT license. /** diff --git a/ext/node/polyfills/internal/buffer.mjs b/ext/node/polyfills/internal/buffer.mjs index dd549221fa..033d8a1e1e 100644 --- a/ext/node/polyfills/internal/buffer.mjs +++ b/ext/node/polyfills/internal/buffer.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // Copyright Feross Aboukhadijeh, and other contributors. All rights reserved. MIT license. diff --git a/ext/node/polyfills/internal/child_process.ts b/ext/node/polyfills/internal/child_process.ts index cfff1079ff..9c9e084787 100644 --- a/ext/node/polyfills/internal/child_process.ts +++ b/ext/node/polyfills/internal/child_process.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // This module implements 'child_process' module of Node.JS API. // ref: https://nodejs.org/api/child_process.html @@ -61,7 +61,7 @@ import { kExtraStdio, kIpc, kNeedsNpmProcessState, -} from "ext:runtime/40_process.js"; +} from "ext:deno_process/40_process.js"; export function mapValues( record: Readonly>, @@ -277,6 +277,7 @@ export class ChildProcess extends EventEmitter { try { this.#process = new Deno.Command(cmd, { args: cmdArgs, + clearEnv: true, cwd, env: stringEnv, stdin: toDenoStdio(stdin), @@ -839,6 +840,7 @@ export function normalizeSpawnArguments( args, cwd, detached: !!options.detached, + env, envPairs, file, windowsHide: !!options.windowsHide, diff --git a/ext/node/polyfills/internal/cli_table.ts b/ext/node/polyfills/internal/cli_table.ts index 9826e524f6..c6991ed06d 100644 --- a/ext/node/polyfills/internal/cli_table.ts +++ b/ext/node/polyfills/internal/cli_table.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal/console/constructor.mjs b/ext/node/polyfills/internal/console/constructor.mjs index ebf5cbec4f..0736fd4c47 100644 --- a/ext/node/polyfills/internal/console/constructor.mjs +++ b/ext/node/polyfills/internal/console/constructor.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal/constants.ts b/ext/node/polyfills/internal/constants.ts index 521cea987c..3c83c0f0ef 100644 --- a/ext/node/polyfills/internal/constants.ts +++ b/ext/node/polyfills/internal/constants.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. import { isWindows } from "ext:deno_node/_util/os.ts"; diff --git a/ext/node/polyfills/internal/crypto/_keys.ts b/ext/node/polyfills/internal/crypto/_keys.ts index e799862458..9a097f82e3 100644 --- a/ext/node/polyfills/internal/crypto/_keys.ts +++ b/ext/node/polyfills/internal/crypto/_keys.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // This file is here because to break a circular dependency between streams and // crypto. diff --git a/ext/node/polyfills/internal/crypto/_randomBytes.ts b/ext/node/polyfills/internal/crypto/_randomBytes.ts index e1dc5c5ac8..c8608a7c53 100644 --- a/ext/node/polyfills/internal/crypto/_randomBytes.ts +++ b/ext/node/polyfills/internal/crypto/_randomBytes.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/internal/crypto/_randomFill.mjs b/ext/node/polyfills/internal/crypto/_randomFill.mjs index 8ef864562f..20a6e1c022 100644 --- a/ext/node/polyfills/internal/crypto/_randomFill.mjs +++ b/ext/node/polyfills/internal/crypto/_randomFill.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/internal/crypto/_randomInt.ts b/ext/node/polyfills/internal/crypto/_randomInt.ts index e08b3e9639..65a8bacf13 100644 --- a/ext/node/polyfills/internal/crypto/_randomInt.ts +++ b/ext/node/polyfills/internal/crypto/_randomInt.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { op_node_random_int } from "ext:core/ops"; import { primordials } from "ext:core/mod.js"; diff --git a/ext/node/polyfills/internal/crypto/certificate.ts b/ext/node/polyfills/internal/crypto/certificate.ts index c15236c5cb..cd64ba36d9 100644 --- a/ext/node/polyfills/internal/crypto/certificate.ts +++ b/ext/node/polyfills/internal/crypto/certificate.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. import { notImplemented } from "ext:deno_node/_utils.ts"; diff --git a/ext/node/polyfills/internal/crypto/cipher.ts b/ext/node/polyfills/internal/crypto/cipher.ts index c1c5ce8901..dd1698f46e 100644 --- a/ext/node/polyfills/internal/crypto/cipher.ts +++ b/ext/node/polyfills/internal/crypto/cipher.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal/crypto/constants.ts b/ext/node/polyfills/internal/crypto/constants.ts index d9c0b2d63b..77fe9bbf43 100644 --- a/ext/node/polyfills/internal/crypto/constants.ts +++ b/ext/node/polyfills/internal/crypto/constants.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal/crypto/diffiehellman.ts b/ext/node/polyfills/internal/crypto/diffiehellman.ts index a439306a97..fb0da4e60b 100644 --- a/ext/node/polyfills/internal/crypto/diffiehellman.ts +++ b/ext/node/polyfills/internal/crypto/diffiehellman.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal/crypto/hash.ts b/ext/node/polyfills/internal/crypto/hash.ts index c42ca39892..3b3ec928fb 100644 --- a/ext/node/polyfills/internal/crypto/hash.ts +++ b/ext/node/polyfills/internal/crypto/hash.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal/crypto/hkdf.ts b/ext/node/polyfills/internal/crypto/hkdf.ts index cb1dbee46b..282633ba26 100644 --- a/ext/node/polyfills/internal/crypto/hkdf.ts +++ b/ext/node/polyfills/internal/crypto/hkdf.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal/crypto/keygen.ts b/ext/node/polyfills/internal/crypto/keygen.ts index b023ab1060..8d9a98e324 100644 --- a/ext/node/polyfills/internal/crypto/keygen.ts +++ b/ext/node/polyfills/internal/crypto/keygen.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal/crypto/keys.ts b/ext/node/polyfills/internal/crypto/keys.ts index 932856df0e..a6ef6b156d 100644 --- a/ext/node/polyfills/internal/crypto/keys.ts +++ b/ext/node/polyfills/internal/crypto/keys.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal/crypto/pbkdf2.ts b/ext/node/polyfills/internal/crypto/pbkdf2.ts index 4e58cb68b3..84a3032c75 100644 --- a/ext/node/polyfills/internal/crypto/pbkdf2.ts +++ b/ext/node/polyfills/internal/crypto/pbkdf2.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/internal/crypto/random.ts b/ext/node/polyfills/internal/crypto/random.ts index a41b868190..9d8864aabc 100644 --- a/ext/node/polyfills/internal/crypto/random.ts +++ b/ext/node/polyfills/internal/crypto/random.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal/crypto/scrypt.ts b/ext/node/polyfills/internal/crypto/scrypt.ts index ce8649bbe2..e20ad33011 100644 --- a/ext/node/polyfills/internal/crypto/scrypt.ts +++ b/ext/node/polyfills/internal/crypto/scrypt.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /* MIT License diff --git a/ext/node/polyfills/internal/crypto/sig.ts b/ext/node/polyfills/internal/crypto/sig.ts index a05f16478d..d75f522f37 100644 --- a/ext/node/polyfills/internal/crypto/sig.ts +++ b/ext/node/polyfills/internal/crypto/sig.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal/crypto/types.ts b/ext/node/polyfills/internal/crypto/types.ts index 17b15127ef..60f913ca2d 100644 --- a/ext/node/polyfills/internal/crypto/types.ts +++ b/ext/node/polyfills/internal/crypto/types.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. import { BufferEncoding } from "ext:deno_node/_global.d.ts"; diff --git a/ext/node/polyfills/internal/crypto/util.ts b/ext/node/polyfills/internal/crypto/util.ts index 6c925f6577..7e6f4a9b40 100644 --- a/ext/node/polyfills/internal/crypto/util.ts +++ b/ext/node/polyfills/internal/crypto/util.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal/crypto/x509.ts b/ext/node/polyfills/internal/crypto/x509.ts index 699e45a51b..a37db7365e 100644 --- a/ext/node/polyfills/internal/crypto/x509.ts +++ b/ext/node/polyfills/internal/crypto/x509.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal/dgram.ts b/ext/node/polyfills/internal/dgram.ts index e34f92f1ea..d69baa7ef2 100644 --- a/ext/node/polyfills/internal/dgram.ts +++ b/ext/node/polyfills/internal/dgram.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal/dns/promises.ts b/ext/node/polyfills/internal/dns/promises.ts index ee4248163d..b431c4502f 100644 --- a/ext/node/polyfills/internal/dns/promises.ts +++ b/ext/node/polyfills/internal/dns/promises.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal/dns/utils.ts b/ext/node/polyfills/internal/dns/utils.ts index 226fce93dd..a405d3f509 100644 --- a/ext/node/polyfills/internal/dns/utils.ts +++ b/ext/node/polyfills/internal/dns/utils.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal/dtrace.ts b/ext/node/polyfills/internal/dtrace.ts index 3443aec7ff..716c48c7cc 100644 --- a/ext/node/polyfills/internal/dtrace.ts +++ b/ext/node/polyfills/internal/dtrace.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal/error_codes.ts b/ext/node/polyfills/internal/error_codes.ts index 0603e9e114..638c0584c2 100644 --- a/ext/node/polyfills/internal/error_codes.ts +++ b/ext/node/polyfills/internal/error_codes.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Lazily initializes the error classes in this object. // This trick is necessary for avoiding circular dendencies between diff --git a/ext/node/polyfills/internal/errors.ts b/ext/node/polyfills/internal/errors.ts index d79232aed7..5d35f07dd8 100644 --- a/ext/node/polyfills/internal/errors.ts +++ b/ext/node/polyfills/internal/errors.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Node.js contributors. All rights reserved. MIT License. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal/event_target.mjs b/ext/node/polyfills/internal/event_target.mjs index 4409b00ed4..80c6041c57 100644 --- a/ext/node/polyfills/internal/event_target.mjs +++ b/ext/node/polyfills/internal/event_target.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Node.js contributors. All rights reserved. MIT License. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal/events/abort_listener.mjs b/ext/node/polyfills/internal/events/abort_listener.mjs index f1430489fa..0407b93595 100644 --- a/ext/node/polyfills/internal/events/abort_listener.mjs +++ b/ext/node/polyfills/internal/events/abort_listener.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. import { primordials } from "ext:deno_node/internal/test/binding.ts"; diff --git a/ext/node/polyfills/internal/fixed_queue.ts b/ext/node/polyfills/internal/fixed_queue.ts index 0a2209c8d5..d9355e73c5 100644 --- a/ext/node/polyfills/internal/fixed_queue.ts +++ b/ext/node/polyfills/internal/fixed_queue.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. import { primordials } from "ext:core/mod.js"; diff --git a/ext/node/polyfills/internal/fs/handle.ts b/ext/node/polyfills/internal/fs/handle.ts index ee035f2f5c..e22c3e0ae6 100644 --- a/ext/node/polyfills/internal/fs/handle.ts +++ b/ext/node/polyfills/internal/fs/handle.ts @@ -1,12 +1,12 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials import { EventEmitter } from "node:events"; import { Buffer } from "node:buffer"; -import { promises, read, write } from "node:fs"; -export type { BigIntStats, Stats } from "ext:deno_node/_fs/_fs_stat.ts"; +import { Mode, promises, read, write } from "node:fs"; +import { core } from "ext:core/mod.js"; import { BinaryOptionsArgument, FileOptionsArgument, @@ -14,7 +14,8 @@ import { TextOptionsArgument, } from "ext:deno_node/_fs/_fs_common.ts"; import { ftruncatePromise } from "ext:deno_node/_fs/_fs_ftruncate.ts"; -import { core } from "ext:core/mod.js"; +export type { BigIntStats, Stats } from "ext:deno_node/_fs/_fs_stat.ts"; +import { writevPromise, WriteVResult } from "ext:deno_node/_fs/_fs_writev.ts"; interface WriteResult { bytesWritten: number; @@ -26,11 +27,15 @@ interface ReadResult { buffer: Buffer; } +type Path = string | Buffer | URL; export class FileHandle extends EventEmitter { #rid: number; - constructor(rid: number) { + #path: Path; + + constructor(rid: number, path: Path) { super(); this.#rid = rid; + this.#path = path; } get fd() { @@ -60,7 +65,7 @@ export class FileHandle extends EventEmitter { position, (err, bytesRead, buffer) => { if (err) reject(err); - else resolve({ buffer: buffer, bytesRead: bytesRead }); + else resolve({ buffer, bytesRead }); }, ); }); @@ -68,7 +73,7 @@ export class FileHandle extends EventEmitter { return new Promise((resolve, reject) => { read(this.fd, bufferOrOpt, (err, bytesRead, buffer) => { if (err) reject(err); - else resolve({ buffer: buffer, bytesRead: bytesRead }); + else resolve({ buffer, bytesRead }); }); }); } @@ -133,6 +138,10 @@ export class FileHandle extends EventEmitter { return fsCall(promises.writeFile, this, data, options); } + writev(buffers: ArrayBufferView[], position?: number): Promise { + return fsCall(writevPromise, this, buffers, position); + } + close(): Promise { // Note that Deno.close is not async return Promise.resolve(core.close(this.fd)); @@ -144,17 +153,37 @@ export class FileHandle extends EventEmitter { stat(options?: { bigint: boolean }): Promise { return fsCall(promises.fstat, this, options); } + chmod(mode: Mode): Promise { + assertNotClosed(this, promises.chmod.name); + return promises.chmod(this.#path, mode); + } + + utimes( + atime: number | string | Date, + mtime: number | string | Date, + ): Promise { + assertNotClosed(this, promises.utimes.name); + return promises.utimes(this.#path, atime, mtime); + } + + chown(uid: number, gid: number): Promise { + assertNotClosed(this, promises.chown.name); + return promises.chown(this.#path, uid, gid); + } } -function fsCall(fn, handle, ...args) { +function assertNotClosed(handle: FileHandle, syscall: string) { if (handle.fd === -1) { const err = new Error("file closed"); throw Object.assign(err, { code: "EBADF", - syscall: fn.name, + syscall, }); } +} +function fsCall(fn, handle, ...args) { + assertNotClosed(handle, fn.name); return fn(handle.fd, ...args); } diff --git a/ext/node/polyfills/internal/fs/streams.d.ts b/ext/node/polyfills/internal/fs/streams.d.ts index b4c235f9b5..8459120573 100644 --- a/ext/node/polyfills/internal/fs/streams.d.ts +++ b/ext/node/polyfills/internal/fs/streams.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright DefinitelyTyped contributors. All rights reserved. MIT license. // deno-lint-ignore-file no-explicit-any diff --git a/ext/node/polyfills/internal/fs/streams.mjs b/ext/node/polyfills/internal/fs/streams.mjs index 3b4409c4cf..d2ebecbe9a 100644 --- a/ext/node/polyfills/internal/fs/streams.mjs +++ b/ext/node/polyfills/internal/fs/streams.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills @@ -18,7 +18,7 @@ import { errorOrDestroy } from "ext:deno_node/internal/streams/destroy.mjs"; import { open as fsOpen } from "ext:deno_node/_fs/_fs_open.ts"; import { read as fsRead } from "ext:deno_node/_fs/_fs_read.ts"; import { write as fsWrite } from "ext:deno_node/_fs/_fs_write.mjs"; -import { writev as fsWritev } from "ext:deno_node/_fs/_fs_writev.mjs"; +import { writev as fsWritev } from "ext:deno_node/_fs/_fs_writev.ts"; import { close as fsClose } from "ext:deno_node/_fs/_fs_close.ts"; import { Buffer } from "node:buffer"; import { diff --git a/ext/node/polyfills/internal/fs/utils.mjs b/ext/node/polyfills/internal/fs/utils.mjs index b0ef34873e..9e8558dea2 100644 --- a/ext/node/polyfills/internal/fs/utils.mjs +++ b/ext/node/polyfills/internal/fs/utils.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/internal/hide_stack_frames.ts b/ext/node/polyfills/internal/hide_stack_frames.ts index 4145189fff..93d7aca095 100644 --- a/ext/node/polyfills/internal/hide_stack_frames.ts +++ b/ext/node/polyfills/internal/hide_stack_frames.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/internal/http.ts b/ext/node/polyfills/internal/http.ts index ddf082f451..d559442bbc 100644 --- a/ext/node/polyfills/internal/http.ts +++ b/ext/node/polyfills/internal/http.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal/idna.ts b/ext/node/polyfills/internal/idna.ts index 93ed065cce..8a53b7e721 100644 --- a/ext/node/polyfills/internal/idna.ts +++ b/ext/node/polyfills/internal/idna.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal/net.ts b/ext/node/polyfills/internal/net.ts index a3dcb3ed21..a14dcae9b8 100644 --- a/ext/node/polyfills/internal/net.ts +++ b/ext/node/polyfills/internal/net.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal/normalize_encoding.mjs b/ext/node/polyfills/internal/normalize_encoding.mjs index a367337880..6ae322f118 100644 --- a/ext/node/polyfills/internal/normalize_encoding.mjs +++ b/ext/node/polyfills/internal/normalize_encoding.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/internal/options.ts b/ext/node/polyfills/internal/options.ts index 4b62a11285..16ac62a69f 100644 --- a/ext/node/polyfills/internal/options.ts +++ b/ext/node/polyfills/internal/options.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal/primordials.mjs b/ext/node/polyfills/internal/primordials.mjs index cddd1aa66d..027994a3d2 100644 --- a/ext/node/polyfills/internal/primordials.mjs +++ b/ext/node/polyfills/internal/primordials.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/internal/process/per_thread.mjs b/ext/node/polyfills/internal/process/per_thread.mjs index b4db3f3691..9d784be153 100644 --- a/ext/node/polyfills/internal/process/per_thread.mjs +++ b/ext/node/polyfills/internal/process/per_thread.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal/process/report.ts b/ext/node/polyfills/internal/process/report.ts index c4a1ff5616..5374c449fc 100644 --- a/ext/node/polyfills/internal/process/report.ts +++ b/ext/node/polyfills/internal/process/report.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { primordials } from "ext:core/mod.js"; const { diff --git a/ext/node/polyfills/internal/querystring.ts b/ext/node/polyfills/internal/querystring.ts index a34e4e4b76..1824203c60 100644 --- a/ext/node/polyfills/internal/querystring.ts +++ b/ext/node/polyfills/internal/querystring.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/internal/readline/callbacks.mjs b/ext/node/polyfills/internal/readline/callbacks.mjs index 5e3d7382fc..4f860776e0 100644 --- a/ext/node/polyfills/internal/readline/callbacks.mjs +++ b/ext/node/polyfills/internal/readline/callbacks.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal/readline/emitKeypressEvents.mjs b/ext/node/polyfills/internal/readline/emitKeypressEvents.mjs index e016fd1533..27a010b420 100644 --- a/ext/node/polyfills/internal/readline/emitKeypressEvents.mjs +++ b/ext/node/polyfills/internal/readline/emitKeypressEvents.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal/readline/interface.mjs b/ext/node/polyfills/internal/readline/interface.mjs index bdb832f881..9988f6c46b 100644 --- a/ext/node/polyfills/internal/readline/interface.mjs +++ b/ext/node/polyfills/internal/readline/interface.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal/readline/promises.mjs b/ext/node/polyfills/internal/readline/promises.mjs index f1de6a2d31..21ab8b6d93 100644 --- a/ext/node/polyfills/internal/readline/promises.mjs +++ b/ext/node/polyfills/internal/readline/promises.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal/readline/symbols.mjs b/ext/node/polyfills/internal/readline/symbols.mjs index 299cc8c9a7..7b935d1243 100644 --- a/ext/node/polyfills/internal/readline/symbols.mjs +++ b/ext/node/polyfills/internal/readline/symbols.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal/readline/utils.mjs b/ext/node/polyfills/internal/readline/utils.mjs index b9372ab0ea..495c373638 100644 --- a/ext/node/polyfills/internal/readline/utils.mjs +++ b/ext/node/polyfills/internal/readline/utils.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal/stream_base_commons.ts b/ext/node/polyfills/internal/stream_base_commons.ts index 1fabb73f47..050658d4f5 100644 --- a/ext/node/polyfills/internal/stream_base_commons.ts +++ b/ext/node/polyfills/internal/stream_base_commons.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal/streams/add-abort-signal.mjs b/ext/node/polyfills/internal/streams/add-abort-signal.mjs index 2e66c86643..d6a3ca099e 100644 --- a/ext/node/polyfills/internal/streams/add-abort-signal.mjs +++ b/ext/node/polyfills/internal/streams/add-abort-signal.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // deno-lint-ignore-file diff --git a/ext/node/polyfills/internal/streams/buffer_list.mjs b/ext/node/polyfills/internal/streams/buffer_list.mjs index db3a703388..cb9dba563b 100644 --- a/ext/node/polyfills/internal/streams/buffer_list.mjs +++ b/ext/node/polyfills/internal/streams/buffer_list.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // deno-lint-ignore-file diff --git a/ext/node/polyfills/internal/streams/destroy.mjs b/ext/node/polyfills/internal/streams/destroy.mjs index 27420e78bf..6e60e20ace 100644 --- a/ext/node/polyfills/internal/streams/destroy.mjs +++ b/ext/node/polyfills/internal/streams/destroy.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // deno-lint-ignore-file diff --git a/ext/node/polyfills/internal/streams/duplex.mjs b/ext/node/polyfills/internal/streams/duplex.mjs index b7c0b077ff..0424c3d17b 100644 --- a/ext/node/polyfills/internal/streams/duplex.mjs +++ b/ext/node/polyfills/internal/streams/duplex.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // deno-lint-ignore-file diff --git a/ext/node/polyfills/internal/streams/end-of-stream.mjs b/ext/node/polyfills/internal/streams/end-of-stream.mjs index aebdb90bf3..be9bf0a50c 100644 --- a/ext/node/polyfills/internal/streams/end-of-stream.mjs +++ b/ext/node/polyfills/internal/streams/end-of-stream.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // deno-lint-ignore-file diff --git a/ext/node/polyfills/internal/streams/lazy_transform.mjs b/ext/node/polyfills/internal/streams/lazy_transform.mjs index 3033ee6d4c..f5cf8ac48a 100644 --- a/ext/node/polyfills/internal/streams/lazy_transform.mjs +++ b/ext/node/polyfills/internal/streams/lazy_transform.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // deno-lint-ignore-file diff --git a/ext/node/polyfills/internal/streams/passthrough.mjs b/ext/node/polyfills/internal/streams/passthrough.mjs index 8c7d4f3560..aa3f26a52c 100644 --- a/ext/node/polyfills/internal/streams/passthrough.mjs +++ b/ext/node/polyfills/internal/streams/passthrough.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // deno-lint-ignore-file diff --git a/ext/node/polyfills/internal/streams/readable.mjs b/ext/node/polyfills/internal/streams/readable.mjs index c5411d6451..7c291f3932 100644 --- a/ext/node/polyfills/internal/streams/readable.mjs +++ b/ext/node/polyfills/internal/streams/readable.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // deno-lint-ignore-file diff --git a/ext/node/polyfills/internal/streams/state.mjs b/ext/node/polyfills/internal/streams/state.mjs index 428492306b..599620ce7a 100644 --- a/ext/node/polyfills/internal/streams/state.mjs +++ b/ext/node/polyfills/internal/streams/state.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // deno-lint-ignore-file diff --git a/ext/node/polyfills/internal/streams/transform.mjs b/ext/node/polyfills/internal/streams/transform.mjs index af368365cb..ac2bf6acc9 100644 --- a/ext/node/polyfills/internal/streams/transform.mjs +++ b/ext/node/polyfills/internal/streams/transform.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // deno-lint-ignore-file diff --git a/ext/node/polyfills/internal/streams/utils.mjs b/ext/node/polyfills/internal/streams/utils.mjs index a2506bd5de..65551b129d 100644 --- a/ext/node/polyfills/internal/streams/utils.mjs +++ b/ext/node/polyfills/internal/streams/utils.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // deno-lint-ignore-file diff --git a/ext/node/polyfills/internal/streams/writable.mjs b/ext/node/polyfills/internal/streams/writable.mjs index c02e4e0e1d..7f1679e372 100644 --- a/ext/node/polyfills/internal/streams/writable.mjs +++ b/ext/node/polyfills/internal/streams/writable.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // deno-lint-ignore-file diff --git a/ext/node/polyfills/internal/test/binding.ts b/ext/node/polyfills/internal/test/binding.ts index cce56b922c..bbd78ec471 100644 --- a/ext/node/polyfills/internal/test/binding.ts +++ b/ext/node/polyfills/internal/test/binding.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. import { getBinding } from "ext:deno_node/internal_binding/mod.ts"; import type { BindingName } from "ext:deno_node/internal_binding/mod.ts"; diff --git a/ext/node/polyfills/internal/timers.mjs b/ext/node/polyfills/internal/timers.mjs index 363f55f693..84dd165e26 100644 --- a/ext/node/polyfills/internal/timers.mjs +++ b/ext/node/polyfills/internal/timers.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal/url.ts b/ext/node/polyfills/internal/url.ts index 4b9da49ec0..82d7a8b4bf 100644 --- a/ext/node/polyfills/internal/url.ts +++ b/ext/node/polyfills/internal/url.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/internal/util.mjs b/ext/node/polyfills/internal/util.mjs index a603a975ad..91de868920 100644 --- a/ext/node/polyfills/internal/util.mjs +++ b/ext/node/polyfills/internal/util.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/internal/util/comparisons.ts b/ext/node/polyfills/internal/util/comparisons.ts index 39e30c69aa..44f0bef007 100644 --- a/ext/node/polyfills/internal/util/comparisons.ts +++ b/ext/node/polyfills/internal/util/comparisons.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // deno-lint-ignore-file diff --git a/ext/node/polyfills/internal/util/debuglog.ts b/ext/node/polyfills/internal/util/debuglog.ts index bbaba7b6fc..dc05aff825 100644 --- a/ext/node/polyfills/internal/util/debuglog.ts +++ b/ext/node/polyfills/internal/util/debuglog.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal/util/inspect.mjs b/ext/node/polyfills/internal/util/inspect.mjs index ae797449bf..0587059122 100644 --- a/ext/node/polyfills/internal/util/inspect.mjs +++ b/ext/node/polyfills/internal/util/inspect.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal/util/parse_args/parse_args.js b/ext/node/polyfills/internal/util/parse_args/parse_args.js index 742f2a1f0d..c4a60bcd35 100644 --- a/ext/node/polyfills/internal/util/parse_args/parse_args.js +++ b/ext/node/polyfills/internal/util/parse_args/parse_args.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. import { primordials } from "ext:core/mod.js"; diff --git a/ext/node/polyfills/internal/util/parse_args/utils.js b/ext/node/polyfills/internal/util/parse_args/utils.js index 1ceed0b9e8..dd76fa1512 100644 --- a/ext/node/polyfills/internal/util/parse_args/utils.js +++ b/ext/node/polyfills/internal/util/parse_args/utils.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. import { primordials } from "ext:core/mod.js"; diff --git a/ext/node/polyfills/internal/util/types.ts b/ext/node/polyfills/internal/util/types.ts index b8aca59680..9415c9db5f 100644 --- a/ext/node/polyfills/internal/util/types.ts +++ b/ext/node/polyfills/internal/util/types.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // // Adapted from Node.js. Copyright Joyent, Inc. and other Node contributors. // diff --git a/ext/node/polyfills/internal/validators.mjs b/ext/node/polyfills/internal/validators.mjs index 12962b8432..0529dca546 100644 --- a/ext/node/polyfills/internal/validators.mjs +++ b/ext/node/polyfills/internal/validators.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/internal_binding/_libuv_winerror.ts b/ext/node/polyfills/internal_binding/_libuv_winerror.ts index 3ba7d9cdae..b84c60226c 100644 --- a/ext/node/polyfills/internal_binding/_libuv_winerror.ts +++ b/ext/node/polyfills/internal_binding/_libuv_winerror.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { op_node_sys_to_uv_error } from "ext:core/ops"; diff --git a/ext/node/polyfills/internal_binding/_listen.ts b/ext/node/polyfills/internal_binding/_listen.ts index 613fdd999d..06e13af79f 100644 --- a/ext/node/polyfills/internal_binding/_listen.ts +++ b/ext/node/polyfills/internal_binding/_listen.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/internal_binding/_node.ts b/ext/node/polyfills/internal_binding/_node.ts index bf6b776130..1e4f1d257e 100644 --- a/ext/node/polyfills/internal_binding/_node.ts +++ b/ext/node/polyfills/internal_binding/_node.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // This file contains C++ node globals accessed in internal binding calls /** diff --git a/ext/node/polyfills/internal_binding/_timingSafeEqual.ts b/ext/node/polyfills/internal_binding/_timingSafeEqual.ts index d9811c5505..f24e70b723 100644 --- a/ext/node/polyfills/internal_binding/_timingSafeEqual.ts +++ b/ext/node/polyfills/internal_binding/_timingSafeEqual.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/internal_binding/_utils.ts b/ext/node/polyfills/internal_binding/_utils.ts index 74dc3cbcd6..c3e5ca7adb 100644 --- a/ext/node/polyfills/internal_binding/_utils.ts +++ b/ext/node/polyfills/internal_binding/_utils.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/internal_binding/ares.ts b/ext/node/polyfills/internal_binding/ares.ts index 46afdfb195..807617aa94 100644 --- a/ext/node/polyfills/internal_binding/ares.ts +++ b/ext/node/polyfills/internal_binding/ares.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /* Copyright 1998 by the Massachusetts Institute of Technology. * * Permission to use, copy, modify, and distribute this diff --git a/ext/node/polyfills/internal_binding/async_wrap.ts b/ext/node/polyfills/internal_binding/async_wrap.ts index affee03fab..4480e1a0a7 100644 --- a/ext/node/polyfills/internal_binding/async_wrap.ts +++ b/ext/node/polyfills/internal_binding/async_wrap.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal_binding/buffer.ts b/ext/node/polyfills/internal_binding/buffer.ts index 4b8e5388b2..7a543e6f03 100644 --- a/ext/node/polyfills/internal_binding/buffer.ts +++ b/ext/node/polyfills/internal_binding/buffer.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/internal_binding/cares_wrap.ts b/ext/node/polyfills/internal_binding/cares_wrap.ts index cbd0bb8ef6..6a864e5855 100644 --- a/ext/node/polyfills/internal_binding/cares_wrap.ts +++ b/ext/node/polyfills/internal_binding/cares_wrap.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal_binding/connection_wrap.ts b/ext/node/polyfills/internal_binding/connection_wrap.ts index ef07025e29..036d7a3e5b 100644 --- a/ext/node/polyfills/internal_binding/connection_wrap.ts +++ b/ext/node/polyfills/internal_binding/connection_wrap.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal_binding/constants.ts b/ext/node/polyfills/internal_binding/constants.ts index ccb0ba5702..5e1afb7222 100644 --- a/ext/node/polyfills/internal_binding/constants.ts +++ b/ext/node/polyfills/internal_binding/constants.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { op_node_build_os } from "ext:core/ops"; diff --git a/ext/node/polyfills/internal_binding/crypto.ts b/ext/node/polyfills/internal_binding/crypto.ts index 3aabbbf344..e3d03a4b1a 100644 --- a/ext/node/polyfills/internal_binding/crypto.ts +++ b/ext/node/polyfills/internal_binding/crypto.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. import { notImplemented } from "ext:deno_node/_utils.ts"; diff --git a/ext/node/polyfills/internal_binding/handle_wrap.ts b/ext/node/polyfills/internal_binding/handle_wrap.ts index 1b3036a7ef..61a34fbc06 100644 --- a/ext/node/polyfills/internal_binding/handle_wrap.ts +++ b/ext/node/polyfills/internal_binding/handle_wrap.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal_binding/http_parser.ts b/ext/node/polyfills/internal_binding/http_parser.ts index bad10d9851..ac087e24de 100644 --- a/ext/node/polyfills/internal_binding/http_parser.ts +++ b/ext/node/polyfills/internal_binding/http_parser.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal_binding/mod.ts b/ext/node/polyfills/internal_binding/mod.ts index ebbfc629f1..25a5a2c7c2 100644 --- a/ext/node/polyfills/internal_binding/mod.ts +++ b/ext/node/polyfills/internal_binding/mod.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/internal_binding/node_file.ts b/ext/node/polyfills/internal_binding/node_file.ts index 6c134ec4bc..1e97ee5cf7 100644 --- a/ext/node/polyfills/internal_binding/node_file.ts +++ b/ext/node/polyfills/internal_binding/node_file.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal_binding/node_options.ts b/ext/node/polyfills/internal_binding/node_options.ts index ddacb28b6d..927fd39b94 100644 --- a/ext/node/polyfills/internal_binding/node_options.ts +++ b/ext/node/polyfills/internal_binding/node_options.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal_binding/pipe_wrap.ts b/ext/node/polyfills/internal_binding/pipe_wrap.ts index 3e366b3c76..3917be36ee 100644 --- a/ext/node/polyfills/internal_binding/pipe_wrap.ts +++ b/ext/node/polyfills/internal_binding/pipe_wrap.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal_binding/stream_wrap.ts b/ext/node/polyfills/internal_binding/stream_wrap.ts index 19c9357ce8..e66c737be0 100644 --- a/ext/node/polyfills/internal_binding/stream_wrap.ts +++ b/ext/node/polyfills/internal_binding/stream_wrap.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal_binding/string_decoder.ts b/ext/node/polyfills/internal_binding/string_decoder.ts index 7f8c954a35..4825ea0aa9 100644 --- a/ext/node/polyfills/internal_binding/string_decoder.ts +++ b/ext/node/polyfills/internal_binding/string_decoder.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { Encodings } from "ext:deno_node/internal_binding/_node.ts"; const encodings = []; diff --git a/ext/node/polyfills/internal_binding/symbols.ts b/ext/node/polyfills/internal_binding/symbols.ts index 2b0656b0ea..affc63eb84 100644 --- a/ext/node/polyfills/internal_binding/symbols.ts +++ b/ext/node/polyfills/internal_binding/symbols.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal_binding/tcp_wrap.ts b/ext/node/polyfills/internal_binding/tcp_wrap.ts index d9f1c5356a..6c19e2dd29 100644 --- a/ext/node/polyfills/internal_binding/tcp_wrap.ts +++ b/ext/node/polyfills/internal_binding/tcp_wrap.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal_binding/types.ts b/ext/node/polyfills/internal_binding/types.ts index 2d301ba1b2..a0fd338600 100644 --- a/ext/node/polyfills/internal_binding/types.ts +++ b/ext/node/polyfills/internal_binding/types.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // // Adapted from Node.js. Copyright Joyent, Inc. and other Node contributors. // diff --git a/ext/node/polyfills/internal_binding/udp_wrap.ts b/ext/node/polyfills/internal_binding/udp_wrap.ts index db6961ddb7..337dfe75c2 100644 --- a/ext/node/polyfills/internal_binding/udp_wrap.ts +++ b/ext/node/polyfills/internal_binding/udp_wrap.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal_binding/util.ts b/ext/node/polyfills/internal_binding/util.ts index c8fb32d8ca..9297e1b20c 100644 --- a/ext/node/polyfills/internal_binding/util.ts +++ b/ext/node/polyfills/internal_binding/util.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/internal_binding/uv.ts b/ext/node/polyfills/internal_binding/uv.ts index 6cd70a7e85..cd868cb395 100644 --- a/ext/node/polyfills/internal_binding/uv.ts +++ b/ext/node/polyfills/internal_binding/uv.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/net.ts b/ext/node/polyfills/net.ts index b2b0c9857c..2d57507c1b 100644 --- a/ext/node/polyfills/net.ts +++ b/ext/node/polyfills/net.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -1157,6 +1157,13 @@ function _emitCloseNT(s: Socket | Server) { s.emit("close"); } +// The packages that need socket initialization workaround +const pkgsNeedsSockInitWorkaround = [ + "@npmcli/agent", + "npm-check-updates", + "playwright-core", +]; + /** * This class is an abstraction of a TCP socket or a streaming `IPC` endpoint * (uses named pipes on Windows, and Unix domain sockets otherwise). It is also @@ -1201,9 +1208,11 @@ export class Socket extends Duplex { _host: string | null = null; // deno-lint-ignore no-explicit-any _parent: any = null; - // The flag for detecting if it's called in @npmcli/agent + // Skip some initialization (initial read and tls handshake if it's tls socket). + // If this flag is true, it's used as connection for http(s) request, and + // the reading and TLS handshake is done by the http client. // See discussions in https://github.com/denoland/deno/pull/25470 for more details. - _isNpmAgent = false; + _needsSockInitWorkaround = false; autoSelectFamilyAttemptedAddresses: AddressInfo[] | undefined = undefined; constructor(options: SocketOptions | number) { @@ -1224,16 +1233,20 @@ export class Socket extends Duplex { super(options); - // Note: If the socket is created from @npmcli/agent, the 'socket' event - // on ClientRequest object happens after 'connect' event on Socket object. + // Note: If the socket is created from one of `pkgNeedsSockInitWorkaround`, + // the 'socket' event on ClientRequest object happens after 'connect' event on Socket object. // That swaps the sequence of op_node_http_request_with_conn() call and // initial socket read. That causes op_node_http_request_with_conn() not // working. // To avoid the above situation, we detect the socket created from - // @npmcli/agent and pause the socket (and also skips the startTls call - // if it's TLSSocket) - this._isNpmAgent = new Error().stack?.includes("@npmcli/agent") || false; - if (this._isNpmAgent) { + // one of those packages using stack trace and pause the socket + // (and also skips the startTls call if it's TLSSocket) + // TODO(kt3k): Remove this workaround + const errorStack = new Error().stack; + this._needsSockInitWorkaround = pkgsNeedsSockInitWorkaround.some((pkg) => + errorStack?.includes(pkg) + ); + if (this._needsSockInitWorkaround) { this.pause(); } diff --git a/ext/node/polyfills/os.ts b/ext/node/polyfills/os.ts index edc89ed2c3..4901b20fa8 100644 --- a/ext/node/polyfills/os.ts +++ b/ext/node/polyfills/os.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -35,7 +35,7 @@ import { validateIntegerRange } from "ext:deno_node/_utils.ts"; import process from "node:process"; import { isWindows } from "ext:deno_node/_util/os.ts"; import { os } from "ext:deno_node/internal_binding/constants.ts"; -import { osUptime } from "ext:runtime/30_os.js"; +import { osUptime } from "ext:deno_os/30_os.js"; import { Buffer } from "ext:deno_node/internal/buffer.mjs"; import { primordials } from "ext:core/mod.js"; const { StringPrototypeEndsWith, StringPrototypeSlice } = primordials; diff --git a/ext/node/polyfills/path.ts b/ext/node/polyfills/path.ts index 19ba2e26d3..255f9592a0 100644 --- a/ext/node/polyfills/path.ts +++ b/ext/node/polyfills/path.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. export * from "ext:deno_node/path/mod.ts"; import m from "ext:deno_node/path/mod.ts"; export default m; diff --git a/ext/node/polyfills/path/_constants.ts b/ext/node/polyfills/path/_constants.ts index 3407515169..b18f90601f 100644 --- a/ext/node/polyfills/path/_constants.ts +++ b/ext/node/polyfills/path/_constants.ts @@ -1,6 +1,6 @@ // Copyright the Browserify authors. MIT License. // Ported from https://github.com/browserify/path-browserify/ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Alphabet chars. export const CHAR_UPPERCASE_A = 65; /* A */ diff --git a/ext/node/polyfills/path/_interface.ts b/ext/node/polyfills/path/_interface.ts index cb40bae12e..e37933962b 100644 --- a/ext/node/polyfills/path/_interface.ts +++ b/ext/node/polyfills/path/_interface.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /** * A parsed path object generated by path.parse() or consumed by path.format(). diff --git a/ext/node/polyfills/path/_posix.ts b/ext/node/polyfills/path/_posix.ts index bf0b91d488..6a4aa2117a 100644 --- a/ext/node/polyfills/path/_posix.ts +++ b/ext/node/polyfills/path/_posix.ts @@ -1,6 +1,6 @@ // Copyright the Browserify authors. MIT License. // Ported from https://github.com/browserify/path-browserify/ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/path/_util.ts b/ext/node/polyfills/path/_util.ts index 9248c68ae5..1e95faea41 100644 --- a/ext/node/polyfills/path/_util.ts +++ b/ext/node/polyfills/path/_util.ts @@ -1,6 +1,6 @@ // Copyright the Browserify authors. MIT License. // Ported from https://github.com/browserify/path-browserify/ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/path/_win32.ts b/ext/node/polyfills/path/_win32.ts index 11c82e0eee..70a0d8a006 100644 --- a/ext/node/polyfills/path/_win32.ts +++ b/ext/node/polyfills/path/_win32.ts @@ -1,6 +1,6 @@ // Copyright the Browserify authors. MIT License. // Ported from https://github.com/browserify/path-browserify/ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/path/common.ts b/ext/node/polyfills/path/common.ts index ee2987307e..9c1c91a650 100644 --- a/ext/node/polyfills/path/common.ts +++ b/ext/node/polyfills/path/common.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // This module is browser compatible. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/path/mod.ts b/ext/node/polyfills/path/mod.ts index e74c1da4db..5fd5e34e57 100644 --- a/ext/node/polyfills/path/mod.ts +++ b/ext/node/polyfills/path/mod.ts @@ -1,6 +1,6 @@ // Copyright the Browserify authors. MIT License. // Ported mostly from https://github.com/browserify/path-browserify/ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { isWindows } from "ext:deno_node/_util/os.ts"; import _win32 from "ext:deno_node/path/_win32.ts"; diff --git a/ext/node/polyfills/path/posix.ts b/ext/node/polyfills/path/posix.ts index 2b6582ff6d..474d74afaf 100644 --- a/ext/node/polyfills/path/posix.ts +++ b/ext/node/polyfills/path/posix.ts @@ -1,6 +1,6 @@ // Copyright the Browserify authors. MIT License. // Ported from https://github.com/browserify/path-browserify/ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import path from "ext:deno_node/path/mod.ts"; diff --git a/ext/node/polyfills/path/separator.ts b/ext/node/polyfills/path/separator.ts index 36dce7df99..bb9eaf7bb4 100644 --- a/ext/node/polyfills/path/separator.ts +++ b/ext/node/polyfills/path/separator.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/path/win32.ts b/ext/node/polyfills/path/win32.ts index 02e6f97c5a..740a346508 100644 --- a/ext/node/polyfills/path/win32.ts +++ b/ext/node/polyfills/path/win32.ts @@ -1,6 +1,6 @@ // Copyright the Browserify authors. MIT License. // Ported from https://github.com/browserify/path-browserify/ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import path from "ext:deno_node/path/mod.ts"; diff --git a/ext/node/polyfills/perf_hooks.ts b/ext/node/polyfills/perf_hooks.ts index ec76b3ce2d..af4e7b261f 100644 --- a/ext/node/polyfills/perf_hooks.ts +++ b/ext/node/polyfills/perf_hooks.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/process.ts b/ext/node/polyfills/process.ts index 647376d5cf..b3fe0883dc 100644 --- a/ext/node/polyfills/process.ts +++ b/ext/node/polyfills/process.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills @@ -58,7 +58,7 @@ import { } from "ext:deno_node/_next_tick.ts"; import { isWindows } from "ext:deno_node/_util/os.ts"; import * as io from "ext:deno_io/12_io.js"; -import * as denoOs from "ext:runtime/30_os.js"; +import * as denoOs from "ext:deno_os/30_os.js"; export let argv0 = ""; diff --git a/ext/node/polyfills/punycode.ts b/ext/node/polyfills/punycode.ts index adecdf4f9a..6e29dd81f9 100644 --- a/ext/node/polyfills/punycode.ts +++ b/ext/node/polyfills/punycode.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { op_node_idna_punycode_decode, diff --git a/ext/node/polyfills/querystring.js b/ext/node/polyfills/querystring.js index 5eb6a077aa..206c3f5f82 100644 --- a/ext/node/polyfills/querystring.js +++ b/ext/node/polyfills/querystring.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials diff --git a/ext/node/polyfills/readline.ts b/ext/node/polyfills/readline.ts index 5813dd3d9b..6b7e51fe9d 100644 --- a/ext/node/polyfills/readline.ts +++ b/ext/node/polyfills/readline.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @deno-types="./_readline.d.ts" import { diff --git a/ext/node/polyfills/readline/promises.ts b/ext/node/polyfills/readline/promises.ts index 76c8b350d4..0e5ae6b8bb 100644 --- a/ext/node/polyfills/readline/promises.ts +++ b/ext/node/polyfills/readline/promises.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/repl.ts b/ext/node/polyfills/repl.ts index a7acc5b19a..c0e69d93eb 100644 --- a/ext/node/polyfills/repl.ts +++ b/ext/node/polyfills/repl.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. import { primordials } from "ext:core/mod.js"; diff --git a/ext/node/polyfills/stream.ts b/ext/node/polyfills/stream.ts index 96262428f0..2c9821dee6 100644 --- a/ext/node/polyfills/stream.ts +++ b/ext/node/polyfills/stream.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // compose, destroy and isDisturbed are experimental APIs without // typings. They can be exposed once they are released as stable in Node diff --git a/ext/node/polyfills/stream/consumers.mjs b/ext/node/polyfills/stream/consumers.mjs index dc5d29f611..5f436c3e17 100644 --- a/ext/node/polyfills/stream/consumers.mjs +++ b/ext/node/polyfills/stream/consumers.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/stream/promises.mjs b/ext/node/polyfills/stream/promises.mjs index 1282ca8963..007000d883 100644 --- a/ext/node/polyfills/stream/promises.mjs +++ b/ext/node/polyfills/stream/promises.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. import { Stream } from "ext:deno_node/_stream.mjs"; diff --git a/ext/node/polyfills/stream/web.ts b/ext/node/polyfills/stream/web.ts index 9cb361f862..c0594c0cb7 100644 --- a/ext/node/polyfills/stream/web.ts +++ b/ext/node/polyfills/stream/web.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { ByteLengthQueuingStrategy, diff --git a/ext/node/polyfills/string_decoder.ts b/ext/node/polyfills/string_decoder.ts index b4a422e4b6..f8dfe8d9a8 100644 --- a/ext/node/polyfills/string_decoder.ts +++ b/ext/node/polyfills/string_decoder.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/sys.ts b/ext/node/polyfills/sys.ts index 4ee112caea..e10f174b6d 100644 --- a/ext/node/polyfills/sys.ts +++ b/ext/node/polyfills/sys.ts @@ -1,3 +1,3 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. export * from "node:util"; export { default } from "node:util"; diff --git a/ext/node/polyfills/testing.ts b/ext/node/polyfills/testing.ts index 901c38ed36..39014533a5 100644 --- a/ext/node/polyfills/testing.ts +++ b/ext/node/polyfills/testing.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { primordials } from "ext:core/mod.js"; const { PromisePrototypeThen } = primordials; diff --git a/ext/node/polyfills/timers.ts b/ext/node/polyfills/timers.ts index fa5f7a2042..9ef704a0b3 100644 --- a/ext/node/polyfills/timers.ts +++ b/ext/node/polyfills/timers.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { primordials } from "ext:core/mod.js"; const { diff --git a/ext/node/polyfills/timers/promises.ts b/ext/node/polyfills/timers/promises.ts index b2896fe809..2ec2327330 100644 --- a/ext/node/polyfills/timers/promises.ts +++ b/ext/node/polyfills/timers/promises.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import timers from "node:timers"; export const setTimeout = timers.promises.setTimeout; diff --git a/ext/node/polyfills/tls.ts b/ext/node/polyfills/tls.ts index 4cfe9ebd63..345994236e 100644 --- a/ext/node/polyfills/tls.ts +++ b/ext/node/polyfills/tls.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. // TODO(petamoriken): enable prefer-primordials for node polyfills diff --git a/ext/node/polyfills/trace_events.ts b/ext/node/polyfills/trace_events.ts index bb3ea97459..4df631a4c5 100644 --- a/ext/node/polyfills/trace_events.ts +++ b/ext/node/polyfills/trace_events.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { ERR_INVALID_ARG_TYPE } from "ext:deno_node/internal/errors.ts"; diff --git a/ext/node/polyfills/tty.js b/ext/node/polyfills/tty.js index e906c5f677..1545ab12ec 100644 --- a/ext/node/polyfills/tty.js +++ b/ext/node/polyfills/tty.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { op_bootstrap_color_depth } from "ext:core/ops"; import { core, primordials } from "ext:core/mod.js"; diff --git a/ext/node/polyfills/url.ts b/ext/node/polyfills/url.ts index 4eeb0381f6..b2744ff6cc 100644 --- a/ext/node/polyfills/url.ts +++ b/ext/node/polyfills/url.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/ext/node/polyfills/util.ts b/ext/node/polyfills/util.ts index d82b288b03..06c75ef79a 100644 --- a/ext/node/polyfills/util.ts +++ b/ext/node/polyfills/util.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { primordials } from "ext:core/mod.js"; const { diff --git a/ext/node/polyfills/util/types.ts b/ext/node/polyfills/util/types.ts index 5f2ead19bb..fbf9092d9d 100644 --- a/ext/node/polyfills/util/types.ts +++ b/ext/node/polyfills/util/types.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import * as types from "ext:deno_node/internal/util/types.ts"; export * from "ext:deno_node/internal/util/types.ts"; export default { ...types }; diff --git a/ext/node/polyfills/v8.ts b/ext/node/polyfills/v8.ts index e24a79ab5a..6d7892a724 100644 --- a/ext/node/polyfills/v8.ts +++ b/ext/node/polyfills/v8.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. /// diff --git a/ext/node/polyfills/vm.js b/ext/node/polyfills/vm.js index b64c847c58..72279abcf8 100644 --- a/ext/node/polyfills/vm.js +++ b/ext/node/polyfills/vm.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license. import { Buffer } from "node:buffer"; diff --git a/ext/node/polyfills/wasi.ts b/ext/node/polyfills/wasi.ts index 4bdc776a4c..b948b0e35c 100644 --- a/ext/node/polyfills/wasi.ts +++ b/ext/node/polyfills/wasi.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { primordials } from "ext:core/mod.js"; diff --git a/ext/node/polyfills/worker_threads.ts b/ext/node/polyfills/worker_threads.ts index dc844169c5..87de9a5a5c 100644 --- a/ext/node/polyfills/worker_threads.ts +++ b/ext/node/polyfills/worker_threads.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. import { core, internals, primordials } from "ext:core/mod.js"; diff --git a/ext/node/polyfills/zlib.ts b/ext/node/polyfills/zlib.ts index 6e5d02b5be..08a9238bd5 100644 --- a/ext/node/polyfills/zlib.ts +++ b/ext/node/polyfills/zlib.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { notImplemented } from "ext:deno_node/_utils.ts"; import { zlib as constants } from "ext:deno_node/internal_binding/constants.ts"; import { diff --git a/runtime/js/30_os.js b/ext/os/30_os.js similarity index 97% rename from runtime/js/30_os.js rename to ext/os/30_os.js index f3dfda886d..166b983f45 100644 --- a/runtime/js/30_os.js +++ b/ext/os/30_os.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { primordials } from "ext:core/mod.js"; import { diff --git a/runtime/js/40_signals.js b/ext/os/40_signals.js similarity index 96% rename from runtime/js/40_signals.js rename to ext/os/40_signals.js index 41f25af677..161adfabbc 100644 --- a/runtime/js/40_signals.js +++ b/ext/os/40_signals.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, primordials } from "ext:core/mod.js"; import { op_signal_bind, op_signal_poll, op_signal_unbind } from "ext:core/ops"; diff --git a/ext/os/Cargo.toml b/ext/os/Cargo.toml new file mode 100644 index 0000000000..bc809f3485 --- /dev/null +++ b/ext/os/Cargo.toml @@ -0,0 +1,33 @@ +# Copyright 2018-2025 the Deno authors. MIT license. + +[package] +name = "deno_os" +version = "0.3.0" +authors.workspace = true +edition.workspace = true +license.workspace = true +readme = "README.md" +repository.workspace = true +description = "OS specific APIs for Deno" + +[lib] +path = "lib.rs" + +[dependencies] +deno_core.workspace = true +deno_error.workspace = true +deno_path_util.workspace = true +deno_permissions.workspace = true +deno_telemetry.workspace = true +libc.workspace = true +netif = "0.1.6" +once_cell.workspace = true +serde.workspace = true +signal-hook = "0.3.17" +signal-hook-registry = "1.4.0" +thiserror.workspace = true +tokio.workspace = true + +[target.'cfg(windows)'.dependencies] +winapi = { workspace = true, features = ["commapi", "knownfolders", "mswsock", "objbase", "psapi", "shlobj", "tlhelp32", "winbase", "winerror", "winuser", "winsock2"] } +ntapi = "0.4.0" diff --git a/runtime/ops/os/README.md b/ext/os/README.md similarity index 97% rename from runtime/ops/os/README.md rename to ext/os/README.md index ae1a5958e4..f308ed3d2b 100644 --- a/runtime/ops/os/README.md +++ b/ext/os/README.md @@ -1,4 +1,6 @@ -## `os` ops +# deno_os + +This crate implements OS specific APIs for Deno `loadavg` diff --git a/runtime/ops/os/mod.rs b/ext/os/lib.rs similarity index 82% rename from runtime/ops/os/mod.rs rename to ext/os/lib.rs index 71169217a7..f084601678 100644 --- a/runtime/ops/os/mod.rs +++ b/ext/os/lib.rs @@ -1,16 +1,54 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::collections::HashMap; +use std::collections::HashSet; +use std::env; +use std::sync::atomic::AtomicI32; +use std::sync::atomic::Ordering; +use std::sync::Arc; -use crate::sys_info; -use crate::worker::ExitCode; use deno_core::op2; use deno_core::v8; use deno_core::OpState; -use deno_node::NODE_ENV_VAR_ALLOWLIST; use deno_path_util::normalize_path; +use deno_permissions::PermissionCheckError; use deno_permissions::PermissionsContainer; +use once_cell::sync::Lazy; use serde::Serialize; -use std::collections::HashMap; -use std::env; + +mod ops; +pub mod signal; +pub mod sys_info; + +pub use ops::signal::SignalError; + +pub static NODE_ENV_VAR_ALLOWLIST: Lazy> = Lazy::new(|| { + // The full list of environment variables supported by Node.js is available + // at https://nodejs.org/api/cli.html#environment-variables + let mut set = HashSet::new(); + set.insert("NODE_DEBUG".to_string()); + set.insert("NODE_OPTIONS".to_string()); + set +}); + +#[derive(Clone, Default)] +pub struct ExitCode(Arc); + +impl ExitCode { + pub fn get(&self) -> i32 { + self.0.load(Ordering::Relaxed) + } + + pub fn set(&mut self, code: i32) { + self.0.store(code, Ordering::Relaxed); + } +} + +pub fn exit(code: i32) -> ! { + deno_telemetry::flush(); + #[allow(clippy::disallowed_methods)] + std::process::exit(code); +} deno_core::extension!( deno_os, @@ -32,13 +70,21 @@ deno_core::extension!( op_system_memory_info, op_uid, op_runtime_memory_usage, + ops::signal::op_signal_bind, + ops::signal::op_signal_unbind, + ops::signal::op_signal_poll, ], + esm = ["30_os.js", "40_signals.js"], options = { exit_code: ExitCode, }, state = |state, options| { state.put::(options.exit_code); - }, + #[cfg(unix)] + { + state.put(ops::signal::SignalState::default()); + } + } ); deno_core::extension!( @@ -61,28 +107,39 @@ deno_core::extension!( op_system_memory_info, op_uid, op_runtime_memory_usage, + ops::signal::op_signal_bind, + ops::signal::op_signal_unbind, + ops::signal::op_signal_poll, ], + esm = ["30_os.js", "40_signals.js"], middleware = |op| match op.name { "op_exit" | "op_set_exit_code" | "op_get_exit_code" => op.with_implementation_from(&deno_core::op_void_sync()), _ => op, - }, + } ); -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum OsError { + #[class(inherit)] #[error(transparent)] - Permission(#[from] deno_permissions::PermissionCheckError), + Permission(#[from] PermissionCheckError), + #[class("InvalidData")] #[error("File name or path {0:?} is not valid UTF-8")] InvalidUtf8(std::ffi::OsString), + #[class(type)] #[error("Key is an empty string.")] EnvEmptyKey, + #[class(type)] #[error("Key contains invalid characters: {0:?}")] EnvInvalidKey(String), + #[class(type)] #[error("Value contains invalid characters: {0:?}")] EnvInvalidValue(String), + #[class(inherit)] #[error(transparent)] Var(#[from] env::VarError), + #[class(inherit)] #[error("{0}")] Io(#[from] std::io::Error), } @@ -127,7 +184,7 @@ fn op_set_env( #[serde] fn op_env( state: &mut OpState, -) -> Result, deno_core::error::AnyError> { +) -> Result, PermissionCheckError> { state.borrow_mut::().check_env_all()?; Ok(env::vars().collect()) } @@ -186,14 +243,14 @@ fn op_get_exit_code(state: &mut OpState) -> i32 { #[op2(fast)] fn op_exit(state: &mut OpState) { let code = state.borrow::().get(); - crate::exit(code) + exit(code) } #[op2(stack_trace)] #[serde] fn op_loadavg( state: &mut OpState, -) -> Result<(f64, f64, f64), deno_core::error::AnyError> { +) -> Result<(f64, f64, f64), PermissionCheckError> { state .borrow_mut::() .check_sys("loadavg", "Deno.loadavg()")?; @@ -202,9 +259,7 @@ fn op_loadavg( #[op2(stack_trace, stack_trace)] #[string] -fn op_hostname( - state: &mut OpState, -) -> Result { +fn op_hostname(state: &mut OpState) -> Result { state .borrow_mut::() .check_sys("hostname", "Deno.hostname()")?; @@ -213,9 +268,7 @@ fn op_hostname( #[op2(stack_trace)] #[string] -fn op_os_release( - state: &mut OpState, -) -> Result { +fn op_os_release(state: &mut OpState) -> Result { state .borrow_mut::() .check_sys("osRelease", "Deno.osRelease()")?; @@ -233,7 +286,7 @@ fn op_network_interfaces( Ok(netif::up()?.map(NetworkInterface::from).collect()) } -#[derive(serde::Serialize)] +#[derive(Serialize)] struct NetworkInterface { family: &'static str, name: String, @@ -278,7 +331,7 @@ impl From for NetworkInterface { #[serde] fn op_system_memory_info( state: &mut OpState, -) -> Result, deno_core::error::AnyError> { +) -> Result, PermissionCheckError> { state .borrow_mut::() .check_sys("systemMemoryInfo", "Deno.systemMemoryInfo()")?; @@ -288,9 +341,7 @@ fn op_system_memory_info( #[cfg(not(windows))] #[op2(stack_trace)] #[smi] -fn op_gid( - state: &mut OpState, -) -> Result, deno_core::error::AnyError> { +fn op_gid(state: &mut OpState) -> Result, PermissionCheckError> { state .borrow_mut::() .check_sys("gid", "Deno.gid()")?; @@ -304,9 +355,7 @@ fn op_gid( #[cfg(windows)] #[op2(stack_trace)] #[smi] -fn op_gid( - state: &mut OpState, -) -> Result, deno_core::error::AnyError> { +fn op_gid(state: &mut OpState) -> Result, PermissionCheckError> { state .borrow_mut::() .check_sys("gid", "Deno.gid()")?; @@ -316,9 +365,7 @@ fn op_gid( #[cfg(not(windows))] #[op2(stack_trace)] #[smi] -fn op_uid( - state: &mut OpState, -) -> Result, deno_core::error::AnyError> { +fn op_uid(state: &mut OpState) -> Result, PermissionCheckError> { state .borrow_mut::() .check_sys("uid", "Deno.uid()")?; @@ -332,9 +379,7 @@ fn op_uid( #[cfg(windows)] #[op2(stack_trace)] #[smi] -fn op_uid( - state: &mut OpState, -) -> Result, deno_core::error::AnyError> { +fn op_uid(state: &mut OpState) -> Result, PermissionCheckError> { state .borrow_mut::() .check_sys("uid", "Deno.uid()")?; @@ -515,7 +560,7 @@ fn rss() -> usize { } } -fn os_uptime(state: &mut OpState) -> Result { +fn os_uptime(state: &mut OpState) -> Result { state .borrow_mut::() .check_sys("osUptime", "Deno.osUptime()")?; @@ -524,8 +569,6 @@ fn os_uptime(state: &mut OpState) -> Result { #[op2(fast, stack_trace)] #[number] -fn op_os_uptime( - state: &mut OpState, -) -> Result { +fn op_os_uptime(state: &mut OpState) -> Result { os_uptime(state) } diff --git a/ext/os/ops/mod.rs b/ext/os/ops/mod.rs new file mode 100644 index 0000000000..857d4688c7 --- /dev/null +++ b/ext/os/ops/mod.rs @@ -0,0 +1,3 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +pub mod signal; diff --git a/runtime/ops/signal.rs b/ext/os/ops/signal.rs similarity index 92% rename from runtime/ops/signal.rs rename to ext/os/ops/signal.rs index ef87c37297..5b556e3a2c 100644 --- a/runtime/ops/signal.rs +++ b/ext/os/ops/signal.rs @@ -1,13 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_core::op2; -use deno_core::AsyncRefCell; -use deno_core::CancelFuture; -use deno_core::CancelHandle; -use deno_core::OpState; -use deno_core::RcRef; -use deno_core::Resource; -use deno_core::ResourceId; - +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::cell::RefCell; #[cfg(unix)] @@ -18,6 +9,15 @@ use std::sync::atomic::AtomicBool; #[cfg(unix)] use std::sync::Arc; +use deno_core::error::ResourceError; +use deno_core::op2; +use deno_core::AsyncRefCell; +use deno_core::CancelFuture; +use deno_core::CancelHandle; +use deno_core::OpState; +use deno_core::RcRef; +use deno_core::Resource; +use deno_core::ResourceId; #[cfg(unix)] use tokio::signal::unix::signal; #[cfg(unix)] @@ -33,32 +33,25 @@ use tokio::signal::windows::CtrlBreak; #[cfg(windows)] use tokio::signal::windows::CtrlC; -deno_core::extension!( - deno_signal, - ops = [op_signal_bind, op_signal_unbind, op_signal_poll], - state = |state| { - #[cfg(unix)] - { - state.put(SignalState::default()); - } - } -); - -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum SignalError { + #[class(type)] #[error(transparent)] InvalidSignalStr(#[from] crate::signal::InvalidSignalStrError), + #[class(type)] #[error(transparent)] InvalidSignalInt(#[from] crate::signal::InvalidSignalIntError), + #[class(type)] #[error("Binding to signal '{0}' is not allowed")] SignalNotAllowed(String), + #[class(inherit)] #[error("{0}")] Io(#[from] std::io::Error), } #[cfg(unix)] #[derive(Default)] -struct SignalState { +pub struct SignalState { enable_default_handlers: BTreeMap>, } @@ -160,7 +153,7 @@ impl Resource for SignalStreamResource { #[cfg(unix)] #[op2(fast)] #[smi] -fn op_signal_bind( +pub fn op_signal_bind( state: &mut OpState, #[string] sig: &str, ) -> Result { @@ -197,7 +190,7 @@ fn op_signal_bind( #[cfg(windows)] #[op2(fast)] #[smi] -fn op_signal_bind( +pub fn op_signal_bind( state: &mut OpState, #[string] sig: &str, ) -> Result { @@ -221,10 +214,10 @@ fn op_signal_bind( } #[op2(async)] -async fn op_signal_poll( +pub async fn op_signal_poll( state: Rc>, #[smi] rid: ResourceId, -) -> Result { +) -> Result { let resource = state .borrow_mut() .resource_table @@ -243,7 +236,7 @@ async fn op_signal_poll( pub fn op_signal_unbind( state: &mut OpState, #[smi] rid: ResourceId, -) -> Result<(), deno_core::error::AnyError> { +) -> Result<(), ResourceError> { let resource = state.resource_table.take::(rid)?; #[cfg(unix)] diff --git a/runtime/signal.rs b/ext/os/signal.rs similarity index 98% rename from runtime/signal.rs rename to ext/os/signal.rs index 0ef83d7de8..b11353b3b2 100644 --- a/runtime/signal.rs +++ b/ext/os/signal.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. #[cfg(target_os = "windows")] #[derive(Debug, thiserror::Error)] diff --git a/runtime/sys_info.rs b/ext/os/sys_info.rs similarity index 99% rename from runtime/sys_info.rs rename to ext/os/sys_info.rs index 99bfcfe103..e6bd16c0f3 100644 --- a/runtime/sys_info.rs +++ b/ext/os/sys_info.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. #[cfg(target_family = "windows")] use std::sync::Once; @@ -159,6 +159,7 @@ pub fn hostname() -> String { use std::ffi::OsString; use std::mem; use std::os::windows::ffi::OsStringExt; + use winapi::shared::minwindef::MAKEWORD; use winapi::um::winsock2::GetHostNameW; use winapi::um::winsock2::WSAStartup; @@ -307,6 +308,7 @@ pub fn mem_info() -> Option { // - `dwLength` is set to the size of the struct. unsafe { use std::mem; + use winapi::shared::minwindef; use winapi::um::psapi::GetPerformanceInfo; use winapi::um::psapi::PERFORMANCE_INFORMATION; diff --git a/runtime/js/40_process.js b/ext/process/40_process.js similarity index 99% rename from runtime/js/40_process.js rename to ext/process/40_process.js index e2cb1d95b2..fde97fac64 100644 --- a/runtime/js/40_process.js +++ b/ext/process/40_process.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, internals, primordials } from "ext:core/mod.js"; import { diff --git a/ext/process/Cargo.toml b/ext/process/Cargo.toml new file mode 100644 index 0000000000..26f7a41a5e --- /dev/null +++ b/ext/process/Cargo.toml @@ -0,0 +1,41 @@ +# Copyright 2018-2025 the Deno authors. MIT license. + +[package] +name = "deno_process" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license.workspace = true +readme = "README.md" +repository.workspace = true +description = "Subprocess APIs for Deno" + +[lib] +path = "lib.rs" + +[dependencies] +deno_core.workspace = true +deno_error.workspace = true +deno_fs.workspace = true +deno_io.workspace = true +deno_os.workspace = true +deno_path_util.workspace = true +deno_permissions.workspace = true +libc.workspace = true +log.workspace = true +memchr = "2.7.4" +pin-project-lite = "0.2.13" +rand.workspace = true +serde.workspace = true +simd-json = "0.14.0" +tempfile.workspace = true +thiserror.workspace = true +tokio.workspace = true +which.workspace = true + +[target.'cfg(unix)'.dependencies] +nix = { workspace = true, features = ["signal", "process"] } + +[target.'cfg(windows)'.dependencies] +winapi = { workspace = true, features = [] } +windows-sys.workspace = true diff --git a/ext/process/README.md b/ext/process/README.md new file mode 100644 index 0000000000..ac39ab83d6 --- /dev/null +++ b/ext/process/README.md @@ -0,0 +1,3 @@ +# deno_process + +This crate implements subprocess APIs for Deno diff --git a/ext/process/ipc.rs b/ext/process/ipc.rs new file mode 100644 index 0000000000..3728943457 --- /dev/null +++ b/ext/process/ipc.rs @@ -0,0 +1,558 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +#![allow(unused)] + +use std::cell::RefCell; +use std::future::Future; +use std::io; +use std::mem; +use std::pin::Pin; +use std::rc::Rc; +use std::sync::atomic::AtomicBool; +use std::sync::atomic::AtomicUsize; +use std::task::ready; +use std::task::Context; +use std::task::Poll; + +use deno_core::serde; +use deno_core::serde_json; +use deno_core::AsyncRefCell; +use deno_core::CancelHandle; +use deno_core::ExternalOpsTracker; +use deno_core::RcRef; +use deno_io::BiPipe; +use deno_io::BiPipeRead; +use deno_io::BiPipeWrite; +use memchr::memchr; +use pin_project_lite::pin_project; +use tokio::io::AsyncRead; +use tokio::io::AsyncWriteExt; +use tokio::io::ReadBuf; + +/// Tracks whether the IPC resources is currently +/// refed, and allows refing/unrefing it. +pub struct IpcRefTracker { + refed: AtomicBool, + tracker: OpsTracker, +} + +/// A little wrapper so we don't have to get an +/// `ExternalOpsTracker` for tests. When we aren't +/// cfg(test), this will get optimized out. +enum OpsTracker { + External(ExternalOpsTracker), + #[cfg(test)] + Test, +} + +impl OpsTracker { + fn ref_(&self) { + match self { + Self::External(tracker) => tracker.ref_op(), + #[cfg(test)] + Self::Test => {} + } + } + + fn unref(&self) { + match self { + Self::External(tracker) => tracker.unref_op(), + #[cfg(test)] + Self::Test => {} + } + } +} + +impl IpcRefTracker { + pub fn new(tracker: ExternalOpsTracker) -> Self { + Self { + refed: AtomicBool::new(false), + tracker: OpsTracker::External(tracker), + } + } + + #[cfg(test)] + fn new_test() -> Self { + Self { + refed: AtomicBool::new(false), + tracker: OpsTracker::Test, + } + } + + pub fn ref_(&self) { + if !self.refed.swap(true, std::sync::atomic::Ordering::AcqRel) { + self.tracker.ref_(); + } + } + + pub fn unref(&self) { + if self.refed.swap(false, std::sync::atomic::Ordering::AcqRel) { + self.tracker.unref(); + } + } +} + +pub struct IpcJsonStreamResource { + pub read_half: AsyncRefCell, + pub write_half: AsyncRefCell, + pub cancel: Rc, + pub queued_bytes: AtomicUsize, + pub ref_tracker: IpcRefTracker, +} + +impl deno_core::Resource for IpcJsonStreamResource { + fn close(self: Rc) { + self.cancel.cancel(); + } +} + +impl IpcJsonStreamResource { + pub fn new( + stream: i64, + ref_tracker: IpcRefTracker, + ) -> Result { + let (read_half, write_half) = BiPipe::from_raw(stream as _)?.split(); + Ok(Self { + read_half: AsyncRefCell::new(IpcJsonStream::new(read_half)), + write_half: AsyncRefCell::new(write_half), + cancel: Default::default(), + queued_bytes: Default::default(), + ref_tracker, + }) + } + + #[cfg(all(unix, test))] + pub fn from_stream( + stream: tokio::net::UnixStream, + ref_tracker: IpcRefTracker, + ) -> Self { + let (read_half, write_half) = stream.into_split(); + Self { + read_half: AsyncRefCell::new(IpcJsonStream::new(read_half.into())), + write_half: AsyncRefCell::new(write_half.into()), + cancel: Default::default(), + queued_bytes: Default::default(), + ref_tracker, + } + } + + #[cfg(all(windows, test))] + pub fn from_stream( + pipe: tokio::net::windows::named_pipe::NamedPipeClient, + ref_tracker: IpcRefTracker, + ) -> Self { + let (read_half, write_half) = tokio::io::split(pipe); + Self { + read_half: AsyncRefCell::new(IpcJsonStream::new(read_half.into())), + write_half: AsyncRefCell::new(write_half.into()), + cancel: Default::default(), + queued_bytes: Default::default(), + ref_tracker, + } + } + + /// writes _newline terminated_ JSON message to the IPC pipe. + pub async fn write_msg_bytes( + self: Rc, + msg: &[u8], + ) -> Result<(), io::Error> { + let mut write_half = RcRef::map(self, |r| &r.write_half).borrow_mut().await; + write_half.write_all(msg).await?; + Ok(()) + } +} + +// Initial capacity of the buffered reader and the JSON backing buffer. +// +// This is a tradeoff between memory usage and performance on large messages. +// +// 64kb has been chosen after benchmarking 64 to 66536 << 6 - 1 bytes per message. +pub const INITIAL_CAPACITY: usize = 1024 * 64; + +/// A buffer for reading from the IPC pipe. +/// Similar to the internal buffer of `tokio::io::BufReader`. +/// +/// This exists to provide buffered reading while granting mutable access +/// to the internal buffer (which isn't exposed through `tokio::io::BufReader` +/// or the `AsyncBufRead` trait). `simd_json` requires mutable access to an input +/// buffer for parsing, so this allows us to use the read buffer directly as the +/// input buffer without a copy (provided the message fits). +struct ReadBuffer { + buffer: Box<[u8]>, + pos: usize, + cap: usize, +} + +impl ReadBuffer { + fn new() -> Self { + Self { + buffer: vec![0; INITIAL_CAPACITY].into_boxed_slice(), + pos: 0, + cap: 0, + } + } + + fn get_mut(&mut self) -> &mut [u8] { + &mut self.buffer + } + + fn available_mut(&mut self) -> &mut [u8] { + &mut self.buffer[self.pos..self.cap] + } + + fn consume(&mut self, n: usize) { + self.pos = std::cmp::min(self.pos + n, self.cap); + } + + fn needs_fill(&self) -> bool { + self.pos >= self.cap + } +} + +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum IpcJsonStreamError { + #[class(inherit)] + #[error("{0}")] + Io(#[source] std::io::Error), + #[class(generic)] + #[error("{0}")] + SimdJson(#[source] simd_json::Error), +} + +// JSON serialization stream over IPC pipe. +// +// `\n` is used as a delimiter between messages. +pub struct IpcJsonStream { + pipe: BiPipeRead, + buffer: Vec, + read_buffer: ReadBuffer, +} + +impl IpcJsonStream { + fn new(pipe: BiPipeRead) -> Self { + Self { + pipe, + buffer: Vec::with_capacity(INITIAL_CAPACITY), + read_buffer: ReadBuffer::new(), + } + } + + pub async fn read_msg( + &mut self, + ) -> Result, IpcJsonStreamError> { + let mut json = None; + let nread = read_msg_inner( + &mut self.pipe, + &mut self.buffer, + &mut json, + &mut self.read_buffer, + ) + .await + .map_err(IpcJsonStreamError::Io)?; + if nread == 0 { + // EOF. + return Ok(None); + } + + let json = match json { + Some(v) => v, + None => { + // Took more than a single read and some buffering. + simd_json::from_slice(&mut self.buffer[..nread]) + .map_err(IpcJsonStreamError::SimdJson)? + } + }; + + // Safety: Same as `Vec::clear` but without the `drop_in_place` for + // each element (nop for u8). Capacity remains the same. + unsafe { + self.buffer.set_len(0); + } + + Ok(Some(json)) + } +} + +pin_project! { + #[must_use = "futures do nothing unless you `.await` or poll them"] + struct ReadMsgInner<'a, R: ?Sized> { + reader: &'a mut R, + buf: &'a mut Vec, + json: &'a mut Option, + // The number of bytes appended to buf. This can be less than buf.len() if + // the buffer was not empty when the operation was started. + read: usize, + read_buffer: &'a mut ReadBuffer, + } +} + +fn read_msg_inner<'a, R>( + reader: &'a mut R, + buf: &'a mut Vec, + json: &'a mut Option, + read_buffer: &'a mut ReadBuffer, +) -> ReadMsgInner<'a, R> +where + R: AsyncRead + ?Sized + Unpin, +{ + ReadMsgInner { + reader, + buf, + json, + read: 0, + read_buffer, + } +} + +fn read_msg_internal( + mut reader: Pin<&mut R>, + cx: &mut Context<'_>, + buf: &mut Vec, + read_buffer: &mut ReadBuffer, + json: &mut Option, + read: &mut usize, +) -> Poll> { + loop { + let (done, used) = { + // effectively a tiny `poll_fill_buf`, but allows us to get a mutable reference to the buffer. + if read_buffer.needs_fill() { + let mut read_buf = ReadBuf::new(read_buffer.get_mut()); + ready!(reader.as_mut().poll_read(cx, &mut read_buf))?; + read_buffer.cap = read_buf.filled().len(); + read_buffer.pos = 0; + } + let available = read_buffer.available_mut(); + if let Some(i) = memchr(b'\n', available) { + if *read == 0 { + // Fast path: parse and put into the json slot directly. + json.replace( + simd_json::from_slice(&mut available[..i + 1]) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?, + ); + } else { + // This is not the first read, so we have to copy the data + // to make it contiguous. + buf.extend_from_slice(&available[..=i]); + } + (true, i + 1) + } else { + buf.extend_from_slice(available); + (false, available.len()) + } + }; + + read_buffer.consume(used); + *read += used; + if done || used == 0 { + return Poll::Ready(Ok(mem::replace(read, 0))); + } + } +} + +impl Future for ReadMsgInner<'_, R> { + type Output = io::Result; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let me = self.project(); + read_msg_internal( + Pin::new(*me.reader), + cx, + me.buf, + me.read_buffer, + me.json, + me.read, + ) + } +} + +#[cfg(test)] +mod tests { + use std::rc::Rc; + + use deno_core::serde_json::json; + use deno_core::v8; + use deno_core::JsRuntime; + use deno_core::RcRef; + use deno_core::RuntimeOptions; + + use super::IpcJsonStreamResource; + + #[allow(clippy::unused_async)] + #[cfg(unix)] + pub async fn pair() -> (Rc, tokio::net::UnixStream) { + let (a, b) = tokio::net::UnixStream::pair().unwrap(); + + /* Similar to how ops would use the resource */ + let a = Rc::new(IpcJsonStreamResource::from_stream( + a, + super::IpcRefTracker::new_test(), + )); + (a, b) + } + + #[cfg(windows)] + pub async fn pair() -> ( + Rc, + tokio::net::windows::named_pipe::NamedPipeServer, + ) { + use tokio::net::windows::named_pipe::ClientOptions; + use tokio::net::windows::named_pipe::ServerOptions; + + let name = + format!(r"\\.\pipe\deno-named-pipe-test-{}", rand::random::()); + + let server = ServerOptions::new().create(name.clone()).unwrap(); + let client = ClientOptions::new().open(name).unwrap(); + + server.connect().await.unwrap(); + /* Similar to how ops would use the resource */ + let client = Rc::new(IpcJsonStreamResource::from_stream( + client, + super::IpcRefTracker::new_test(), + )); + (client, server) + } + + #[allow(clippy::print_stdout)] + #[tokio::test] + async fn bench_ipc() -> Result<(), Box> { + // A simple round trip benchmark for quick dev feedback. + // + // Only ran when the env var is set. + if std::env::var_os("BENCH_IPC_DENO").is_none() { + return Ok(()); + } + + let (ipc, mut fd2) = pair().await; + let child = tokio::spawn(async move { + use tokio::io::AsyncWriteExt; + + let size = 1024 * 1024; + + let stri = "x".repeat(size); + let data = format!("\"{}\"\n", stri); + for _ in 0..100 { + fd2.write_all(data.as_bytes()).await?; + } + Ok::<_, std::io::Error>(()) + }); + + let start = std::time::Instant::now(); + let mut bytes = 0; + + let mut ipc = RcRef::map(ipc, |r| &r.read_half).borrow_mut().await; + loop { + let Some(msgs) = ipc.read_msg().await? else { + break; + }; + bytes += msgs.as_str().unwrap().len(); + if start.elapsed().as_secs() > 5 { + break; + } + } + let elapsed = start.elapsed(); + let mb = bytes as f64 / 1024.0 / 1024.0; + println!("{} mb/s", mb / elapsed.as_secs_f64()); + + child.await??; + + Ok(()) + } + + #[tokio::test] + async fn unix_ipc_json() -> Result<(), Box> { + let (ipc, mut fd2) = pair().await; + let child = tokio::spawn(async move { + use tokio::io::AsyncReadExt; + use tokio::io::AsyncWriteExt; + + const EXPECTED: &[u8] = b"\"hello\"\n"; + let mut buf = [0u8; EXPECTED.len()]; + let n = fd2.read_exact(&mut buf).await?; + assert_eq!(&buf[..n], EXPECTED); + fd2.write_all(b"\"world\"\n").await?; + + Ok::<_, std::io::Error>(()) + }); + + ipc + .clone() + .write_msg_bytes(&json_to_bytes(json!("hello"))) + .await?; + + let mut ipc = RcRef::map(ipc, |r| &r.read_half).borrow_mut().await; + let msgs = ipc.read_msg().await?.unwrap(); + assert_eq!(msgs, json!("world")); + + child.await??; + + Ok(()) + } + + fn json_to_bytes(v: deno_core::serde_json::Value) -> Vec { + let mut buf = deno_core::serde_json::to_vec(&v).unwrap(); + buf.push(b'\n'); + buf + } + + #[tokio::test] + async fn unix_ipc_json_multi() -> Result<(), Box> { + let (ipc, mut fd2) = pair().await; + let child = tokio::spawn(async move { + use tokio::io::AsyncReadExt; + use tokio::io::AsyncWriteExt; + + const EXPECTED: &[u8] = b"\"hello\"\n\"world\"\n"; + let mut buf = [0u8; EXPECTED.len()]; + let n = fd2.read_exact(&mut buf).await?; + assert_eq!(&buf[..n], EXPECTED); + fd2.write_all(b"\"foo\"\n\"bar\"\n").await?; + Ok::<_, std::io::Error>(()) + }); + + ipc + .clone() + .write_msg_bytes(&json_to_bytes(json!("hello"))) + .await?; + ipc + .clone() + .write_msg_bytes(&json_to_bytes(json!("world"))) + .await?; + + let mut ipc = RcRef::map(ipc, |r| &r.read_half).borrow_mut().await; + let msgs = ipc.read_msg().await?.unwrap(); + assert_eq!(msgs, json!("foo")); + + child.await??; + + Ok(()) + } + + #[tokio::test] + async fn unix_ipc_json_invalid() -> Result<(), Box> { + let (ipc, mut fd2) = pair().await; + let child = tokio::spawn(async move { + tokio::io::AsyncWriteExt::write_all(&mut fd2, b"\n\n").await?; + Ok::<_, std::io::Error>(()) + }); + + let mut ipc = RcRef::map(ipc, |r| &r.read_half).borrow_mut().await; + let _err = ipc.read_msg().await.unwrap_err(); + + child.await??; + + Ok(()) + } + + #[test] + fn memchr() { + let str = b"hello world"; + assert_eq!(super::memchr(b'h', str), Some(0)); + assert_eq!(super::memchr(b'w', str), Some(6)); + assert_eq!(super::memchr(b'd', str), Some(10)); + assert_eq!(super::memchr(b'x', str), None); + + let empty = b""; + assert_eq!(super::memchr(b'\n', empty), None); + } +} diff --git a/runtime/ops/process.rs b/ext/process/lib.rs similarity index 92% rename from runtime/ops/process.rs rename to ext/process/lib.rs index 422f229632..24985a8048 100644 --- a/runtime/ops/process.rs +++ b/ext/process/lib.rs @@ -1,4 +1,20 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::borrow::Cow; +use std::cell::RefCell; +use std::collections::HashMap; +use std::ffi::OsString; +use std::io::Write; +#[cfg(unix)] +use std::os::unix::prelude::ExitStatusExt; +#[cfg(unix)] +use std::os::unix::process::CommandExt; +#[cfg(windows)] +use std::os::windows::process::CommandExt; +use std::path::Path; +use std::path::PathBuf; +use std::process::ExitStatus; +use std::rc::Rc; use deno_core::op2; use deno_core::serde_json; @@ -9,34 +25,22 @@ use deno_core::RcRef; use deno_core::Resource; use deno_core::ResourceId; use deno_core::ToJsBuffer; +use deno_error::JsErrorBox; use deno_io::fs::FileResource; use deno_io::ChildStderrResource; use deno_io::ChildStdinResource; use deno_io::ChildStdoutResource; use deno_io::IntoRawIoHandle; +use deno_os::SignalError; use deno_permissions::PermissionsContainer; use deno_permissions::RunQueryDescriptor; use serde::Deserialize; use serde::Serialize; -use std::borrow::Cow; -use std::cell::RefCell; -use std::collections::HashMap; -use std::ffi::OsString; -use std::io::Write; -use std::path::Path; -use std::path::PathBuf; -use std::process::ExitStatus; -use std::rc::Rc; use tokio::process::Command; -#[cfg(windows)] -use std::os::windows::process::CommandExt; - -use crate::ops::signal::SignalError; -#[cfg(unix)] -use std::os::unix::prelude::ExitStatusExt; -#[cfg(unix)] -use std::os::unix::process::CommandExt; +pub mod ipc; +use ipc::IpcJsonStreamResource; +use ipc::IpcRefTracker; pub const UNSTABLE_FEATURE_NAME: &str = "process"; @@ -107,8 +111,9 @@ impl StdioOrRid { match &self { StdioOrRid::Stdio(val) => Ok(val.as_stdio()), StdioOrRid::Rid(rid) => { - FileResource::with_file(state, *rid, |file| Ok(file.as_stdio()?)) - .map_err(ProcessError::Resource) + Ok(FileResource::with_file(state, *rid, |file| { + file.as_stdio().map_err(deno_error::JsErrorBox::from_err) + })?) } } } @@ -138,7 +143,9 @@ pub trait NpmProcessStateProvider: #[derive(Debug)] pub struct EmptyNpmProcessStateProvider; + impl NpmProcessStateProvider for EmptyNpmProcessStateProvider {} + deno_core::extension!( deno_process, ops = [ @@ -150,6 +157,7 @@ deno_core::extension!( deprecated::op_run_status, deprecated::op_kill, ], + esm = ["40_process.js"], options = { get_npm_process_state: Option }, state = |state, options| { state.put::(options.get_npm_process_state.unwrap_or(deno_fs::sync::MaybeArc::new(EmptyNpmProcessStateProvider))); @@ -190,37 +198,73 @@ pub struct SpawnArgs { needs_npm_process_state: bool, } -#[derive(Debug, thiserror::Error)] +#[cfg(unix)] +deno_error::js_error_wrapper!(nix::Error, JsNixError, |err| { + match err { + nix::Error::ECHILD => "NotFound", + nix::Error::EINVAL => "TypeError", + nix::Error::ENOENT => "NotFound", + nix::Error::ENOTTY => "BadResource", + nix::Error::EPERM => "PermissionDenied", + nix::Error::ESRCH => "NotFound", + nix::Error::ELOOP => "FilesystemLoop", + nix::Error::ENOTDIR => "NotADirectory", + nix::Error::ENETUNREACH => "NetworkUnreachable", + nix::Error::EISDIR => "IsADirectory", + nix::Error::UnknownErrno => "Error", + &nix::Error::ENOTSUP => unreachable!(), + _ => "Error", + } +}); + +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum ProcessError { + #[class(inherit)] #[error("Failed to spawn '{command}': {error}")] SpawnFailed { command: String, #[source] + #[inherit] error: Box, }, + #[class(inherit)] #[error("{0}")] Io(#[from] std::io::Error), #[cfg(unix)] + #[class(inherit)] #[error(transparent)] - Nix(nix::Error), + Nix(JsNixError), + #[class(inherit)] #[error("failed resolving cwd: {0}")] FailedResolvingCwd(#[source] std::io::Error), + #[class(inherit)] #[error(transparent)] Permission(#[from] deno_permissions::PermissionCheckError), + #[class(inherit)] #[error(transparent)] RunPermission(#[from] CheckRunPermissionError), + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(deno_core::error::ResourceError), + #[class(generic)] #[error(transparent)] BorrowMut(std::cell::BorrowMutError), + #[class(generic)] #[error(transparent)] Which(which::Error), + #[class(type)] #[error("Child process has already terminated.")] ChildProcessAlreadyTerminated, + #[class(type)] #[error("Invalid pid")] InvalidPid, + #[class(inherit)] #[error(transparent)] Signal(#[from] SignalError), + #[class(inherit)] + #[error(transparent)] + Other(#[from] JsErrorBox), + #[class(type)] #[error("Missing cmd")] MissingCmd, // only for Deno.run } @@ -256,7 +300,7 @@ impl TryFrom for ChildStatus { success: false, code: 128 + signal, #[cfg(unix)] - signal: Some(crate::signal::signal_int_to_str(signal)?.to_string()), + signal: Some(deno_os::signal::signal_int_to_str(signal)?.to_string()), #[cfg(not(unix))] signal: None, } @@ -423,13 +467,10 @@ fn create_command( fds_to_dup.push((ipc_fd2, ipc)); fds_to_close.push(ipc_fd2); /* One end returned to parent process (this) */ - let pipe_rid = - state - .resource_table - .add(deno_node::IpcJsonStreamResource::new( - ipc_fd1 as _, - deno_node::IpcRefTracker::new(state.external_ops_tracker.clone()), - )?); + let pipe_rid = state.resource_table.add(IpcJsonStreamResource::new( + ipc_fd1 as _, + IpcRefTracker::new(state.external_ops_tracker.clone()), + )?); /* The other end passed to child process via NODE_CHANNEL_FD */ command.env("NODE_CHANNEL_FD", format!("{}", ipc)); ipc_rid = Some(pipe_rid); @@ -493,12 +534,11 @@ fn create_command( let (hd1, hd2) = deno_io::bi_pipe_pair_raw()?; /* One end returned to parent process (this) */ - let pipe_rid = Some(state.resource_table.add( - deno_node::IpcJsonStreamResource::new( + let pipe_rid = + Some(state.resource_table.add(IpcJsonStreamResource::new( hd1 as i64, - deno_node::IpcRefTracker::new(state.external_ops_tracker.clone()), - )?, - )); + IpcRefTracker::new(state.external_ops_tracker.clone()), + )?)); /* The other end passed to child process via NODE_CHANNEL_FD */ command.env("NODE_CHANNEL_FD", format!("{}", hd2 as i64)); @@ -733,12 +773,14 @@ fn resolve_path(path: &str, cwd: &Path) -> PathBuf { deno_path_util::normalize_path(cwd.join(path)) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum CheckRunPermissionError { + #[class(inherit)] #[error(transparent)] Permission(#[from] deno_permissions::PermissionCheckError), + #[class(inherit)] #[error("{0}")] - Other(deno_core::error::AnyError), + Other(JsErrorBox), } fn check_run_permission( @@ -755,7 +797,7 @@ fn check_run_permission( // we don't allow users to launch subprocesses with any LD_ or DYLD_* // env vars set because this allows executing code (ex. LD_PRELOAD) return Err(CheckRunPermissionError::Other( - deno_core::error::custom_error( + JsErrorBox::new( "NotCapable", format!( "Requires --allow-run permissions to spawn subprocess with {0} environment variable{1}. Alternatively, spawn with {2} environment variable{1} unset.", @@ -1074,19 +1116,22 @@ mod deprecated { #[cfg(unix)] pub fn kill(pid: i32, signal: &str) -> Result<(), ProcessError> { - let signo = crate::signal::signal_str_to_int(signal) + let signo = deno_os::signal::signal_str_to_int(signal) .map_err(SignalError::InvalidSignalStr)?; use nix::sys::signal::kill as unix_kill; use nix::sys::signal::Signal; use nix::unistd::Pid; - let sig = Signal::try_from(signo).map_err(ProcessError::Nix)?; - unix_kill(Pid::from_raw(pid), Some(sig)).map_err(ProcessError::Nix) + let sig = + Signal::try_from(signo).map_err(|e| ProcessError::Nix(JsNixError(e)))?; + unix_kill(Pid::from_raw(pid), Some(sig)) + .map_err(|e| ProcessError::Nix(JsNixError(e))) } #[cfg(not(unix))] pub fn kill(pid: i32, signal: &str) -> Result<(), ProcessError> { use std::io::Error; use std::io::ErrorKind::NotFound; + use winapi::shared::minwindef::DWORD; use winapi::shared::minwindef::FALSE; use winapi::shared::minwindef::TRUE; @@ -1099,7 +1144,7 @@ mod deprecated { if !matches!(signal, "SIGKILL" | "SIGTERM") { Err( - SignalError::InvalidSignalStr(crate::signal::InvalidSignalStrError( + SignalError::InvalidSignalStr(deno_os::signal::InvalidSignalStrError( signal.to_string(), )) .into(), diff --git a/ext/telemetry/Cargo.toml b/ext/telemetry/Cargo.toml index fedaed6656..4d00b82909 100644 --- a/ext/telemetry/Cargo.toml +++ b/ext/telemetry/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_telemetry" -version = "0.6.0" +version = "0.8.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -16,6 +16,7 @@ path = "lib.rs" [dependencies] async-trait.workspace = true deno_core.workspace = true +deno_error.workspace = true http-body-util.workspace = true hyper.workspace = true hyper-util.workspace = true @@ -28,4 +29,5 @@ opentelemetry-semantic-conventions.workspace = true opentelemetry_sdk.workspace = true pin-project.workspace = true serde.workspace = true +thiserror.workspace = true tokio.workspace = true diff --git a/ext/telemetry/lib.rs b/ext/telemetry/lib.rs index 8018843dc4..ce3f34a0af 100644 --- a/ext/telemetry/lib.rs +++ b/ext/telemetry/lib.rs @@ -1,7 +1,23 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +#![allow(clippy::too_many_arguments)] + +use std::borrow::Cow; +use std::cell::RefCell; +use std::collections::HashMap; +use std::env; +use std::fmt::Debug; +use std::pin::Pin; +use std::rc::Rc; +use std::sync::atomic::AtomicU64; +use std::sync::Arc; +use std::sync::Mutex; +use std::task::Context; +use std::task::Poll; +use std::thread; +use std::time::Duration; +use std::time::SystemTime; -use deno_core::anyhow; -use deno_core::anyhow::anyhow; use deno_core::futures::channel::mpsc; use deno_core::futures::channel::mpsc::UnboundedSender; use deno_core::futures::future::BoxFuture; @@ -11,8 +27,11 @@ use deno_core::futures::Stream; use deno_core::futures::StreamExt; use deno_core::op2; use deno_core::v8; +use deno_core::v8::DataError; use deno_core::GarbageCollected; use deno_core::OpState; +use deno_error::JsError; +use deno_error::JsErrorBox; use once_cell::sync::Lazy; use once_cell::sync::OnceCell; use opentelemetry::logs::AnyValue; @@ -20,7 +39,7 @@ use opentelemetry::logs::LogRecord as LogRecordTrait; use opentelemetry::logs::Severity; use opentelemetry::metrics::AsyncInstrumentBuilder; use opentelemetry::metrics::InstrumentBuilder; -use opentelemetry::metrics::MeterProvider; +use opentelemetry::metrics::MeterProvider as _; use opentelemetry::otel_debug; use opentelemetry::otel_error; use opentelemetry::trace::SpanContext; @@ -29,6 +48,8 @@ use opentelemetry::trace::SpanKind; use opentelemetry::trace::Status as SpanStatus; use opentelemetry::trace::TraceFlags; use opentelemetry::trace::TraceId; +use opentelemetry::trace::TraceState; +use opentelemetry::InstrumentationScope; use opentelemetry::Key; use opentelemetry::KeyValue; use opentelemetry::StringValue; @@ -48,7 +69,11 @@ use opentelemetry_sdk::metrics::MetricResult; use opentelemetry_sdk::metrics::SdkMeterProvider; use opentelemetry_sdk::metrics::Temporality; use opentelemetry_sdk::trace::BatchSpanProcessor; -use opentelemetry_sdk::trace::SpanProcessor; +use opentelemetry_sdk::trace::IdGenerator; +use opentelemetry_sdk::trace::RandomIdGenerator; +use opentelemetry_sdk::trace::SpanEvents; +use opentelemetry_sdk::trace::SpanLinks; +use opentelemetry_sdk::trace::SpanProcessor as _; use opentelemetry_sdk::Resource; use opentelemetry_semantic_conventions::resource::PROCESS_RUNTIME_NAME; use opentelemetry_semantic_conventions::resource::PROCESS_RUNTIME_VERSION; @@ -57,20 +82,7 @@ use opentelemetry_semantic_conventions::resource::TELEMETRY_SDK_NAME; use opentelemetry_semantic_conventions::resource::TELEMETRY_SDK_VERSION; use serde::Deserialize; use serde::Serialize; -use std::borrow::Cow; -use std::cell::RefCell; -use std::collections::HashMap; -use std::env; -use std::fmt::Debug; -use std::pin::Pin; -use std::rc::Rc; -use std::sync::Arc; -use std::sync::Mutex; -use std::task::Context; -use std::task::Poll; -use std::thread; -use std::time::Duration; -use std::time::SystemTime; +use thiserror::Error; use tokio::sync::oneshot; use tokio::task::JoinSet; @@ -78,23 +90,11 @@ deno_core::extension!( deno_telemetry, ops = [ op_otel_log, - op_otel_instrumentation_scope_create_and_enter, - op_otel_instrumentation_scope_enter, - op_otel_instrumentation_scope_enter_builtin, - op_otel_span_start, - op_otel_span_continue, - op_otel_span_attribute, + op_otel_log_foreign, + op_otel_span_attribute1, op_otel_span_attribute2, op_otel_span_attribute3, - op_otel_span_set_dropped, - op_otel_span_flush, - op_otel_metric_create_counter, - op_otel_metric_create_up_down_counter, - op_otel_metric_create_gauge, - op_otel_metric_create_histogram, - op_otel_metric_create_observable_counter, - op_otel_metric_create_observable_gauge, - op_otel_metric_create_observable_up_down_counter, + op_otel_span_update_name, op_otel_metric_attribute3, op_otel_metric_record0, op_otel_metric_record1, @@ -107,6 +107,7 @@ deno_core::extension!( op_otel_metric_wait_to_observe, op_otel_metric_observation_done, ], + objects = [OtelTracer, OtelMeter, OtelSpan], esm = ["telemetry.ts", "util.ts"], ); @@ -469,6 +470,11 @@ impl DenoPeriodicReader { } mod hyper_client { + use std::fmt::Debug; + use std::pin::Pin; + use std::task::Poll; + use std::task::{self}; + use http_body_util::BodyExt; use http_body_util::Full; use hyper::body::Body as HttpBody; @@ -480,10 +486,6 @@ mod hyper_client { use opentelemetry_http::Request; use opentelemetry_http::Response; use opentelemetry_http::ResponseExt; - use std::fmt::Debug; - use std::pin::Pin; - use std::task::Poll; - use std::task::{self}; use super::OtelSharedRuntime; @@ -548,19 +550,20 @@ mod hyper_client { } } -struct Processors { - spans: BatchSpanProcessor, - logs: BatchLogProcessor, +struct OtelGlobals { + span_processor: BatchSpanProcessor, + log_processor: BatchLogProcessor, + id_generator: DenoIdGenerator, meter_provider: SdkMeterProvider, + builtin_instrumentation_scope: InstrumentationScope, } -static OTEL_PROCESSORS: OnceCell = OnceCell::new(); +static OTEL_GLOBALS: OnceCell = OnceCell::new(); -static BUILT_IN_INSTRUMENTATION_SCOPE: OnceCell< - opentelemetry::InstrumentationScope, -> = OnceCell::new(); - -pub fn init(rt_config: OtelRuntimeConfig) -> anyhow::Result<()> { +pub fn init( + rt_config: OtelRuntimeConfig, + config: &OtelConfig, +) -> deno_core::anyhow::Result<()> { // Parse the `OTEL_EXPORTER_OTLP_PROTOCOL` variable. The opentelemetry_* // crates don't do this automatically. // TODO(piscisaureus): enable GRPC support. @@ -569,13 +572,13 @@ pub fn init(rt_config: OtelRuntimeConfig) -> anyhow::Result<()> { Ok("http/json") => Protocol::HttpJson, Ok("") | Err(env::VarError::NotPresent) => Protocol::HttpBinary, Ok(protocol) => { - return Err(anyhow!( + return Err(deno_core::anyhow::anyhow!( "Env var OTEL_EXPORTER_OTLP_PROTOCOL specifies an unsupported protocol: {}", protocol )); } Err(err) => { - return Err(anyhow!( + return Err(deno_core::anyhow::anyhow!( "Failed to read env var OTEL_EXPORTER_OTLP_PROTOCOL: {}", err )); @@ -642,7 +645,7 @@ pub fn init(rt_config: OtelRuntimeConfig) -> anyhow::Result<()> { Some("delta") => Temporality::Delta, Some("lowmemory") => Temporality::LowMemory, Some(other) => { - return Err(anyhow!( + return Err(deno_core::anyhow::anyhow!( "Invalid value for OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE: {}", other )); @@ -666,21 +669,26 @@ pub fn init(rt_config: OtelRuntimeConfig) -> anyhow::Result<()> { BatchLogProcessor::builder(log_exporter, OtelSharedRuntime).build(); log_processor.set_resource(&resource); - OTEL_PROCESSORS - .set(Processors { - spans: span_processor, - logs: log_processor, - meter_provider, - }) - .map_err(|_| anyhow!("failed to init otel"))?; - let builtin_instrumentation_scope = opentelemetry::InstrumentationScope::builder("deno") .with_version(rt_config.runtime_version.clone()) .build(); - BUILT_IN_INSTRUMENTATION_SCOPE - .set(builtin_instrumentation_scope) - .map_err(|_| anyhow!("failed to init otel"))?; + + let id_generator = if config.deterministic { + DenoIdGenerator::deterministic() + } else { + DenoIdGenerator::random() + }; + + OTEL_GLOBALS + .set(OtelGlobals { + log_processor, + span_processor, + id_generator, + meter_provider, + builtin_instrumentation_scope, + }) + .map_err(|_| deno_core::anyhow::anyhow!("failed to set otel globals"))?; Ok(()) } @@ -689,11 +697,12 @@ pub fn init(rt_config: OtelRuntimeConfig) -> anyhow::Result<()> { /// `process::exit()`, to ensure that all OpenTelemetry logs are properly /// flushed before the process terminates. pub fn flush() { - if let Some(Processors { - spans, - logs, + if let Some(OtelGlobals { + span_processor: spans, + log_processor: logs, meter_provider, - }) = OTEL_PROCESSORS.get() + .. + }) = OTEL_GLOBALS.get() { let _ = spans.force_flush(); let _ = logs.force_flush(); @@ -704,7 +713,12 @@ pub fn flush() { pub fn handle_log(record: &log::Record) { use log::Level; - let Some(Processors { logs, .. }) = OTEL_PROCESSORS.get() else { + let Some(OtelGlobals { + log_processor: logs, + builtin_instrumentation_scope, + .. + }) = OTEL_GLOBALS.get() + else { return; }; @@ -754,10 +768,58 @@ pub fn handle_log(record: &log::Record) { let _ = record.key_values().visit(&mut Visitor(&mut log_record)); - logs.emit( - &mut log_record, - BUILT_IN_INSTRUMENTATION_SCOPE.get().unwrap(), - ); + logs.emit(&mut log_record, builtin_instrumentation_scope); +} + +#[derive(Debug)] +enum DenoIdGenerator { + Random(RandomIdGenerator), + Deterministic { + next_trace_id: AtomicU64, + next_span_id: AtomicU64, + }, +} + +impl IdGenerator for DenoIdGenerator { + fn new_trace_id(&self) -> TraceId { + match self { + Self::Random(generator) => generator.new_trace_id(), + Self::Deterministic { next_trace_id, .. } => { + let id = + next_trace_id.fetch_add(1, std::sync::atomic::Ordering::Relaxed); + let bytes = id.to_be_bytes(); + let bytes = [ + 0, 0, 0, 0, 0, 0, 0, 0, bytes[0], bytes[1], bytes[2], bytes[3], + bytes[4], bytes[5], bytes[6], bytes[7], + ]; + TraceId::from_bytes(bytes) + } + } + } + + fn new_span_id(&self) -> SpanId { + match self { + Self::Random(generator) => generator.new_span_id(), + Self::Deterministic { next_span_id, .. } => { + let id = + next_span_id.fetch_add(1, std::sync::atomic::Ordering::Relaxed); + SpanId::from_bytes(id.to_be_bytes()) + } + } + } +} + +impl DenoIdGenerator { + fn random() -> Self { + Self::Random(RandomIdGenerator::default()) + } + + fn deterministic() -> Self { + Self::Deterministic { + next_trace_id: AtomicU64::new(1), + next_span_id: AtomicU64::new(1), + } + } } fn parse_trace_id( @@ -849,6 +911,9 @@ macro_rules! attr_raw { } else if let Ok(bigint) = $value.try_cast::() { let (i64_value, _lossless) = bigint.i64_value(); Some(Value::I64(i64_value)) + } else if let Ok(_array) = $value.try_cast::() { + // TODO: implement array attributes + None } else { None }; @@ -874,48 +939,66 @@ macro_rules! attr { }; } -#[derive(Debug, Clone)] -struct InstrumentationScope(opentelemetry::InstrumentationScope); - -impl deno_core::GarbageCollected for InstrumentationScope {} - -#[op2] -#[cppgc] -fn op_otel_instrumentation_scope_create_and_enter( - state: &mut OpState, - #[string] name: String, - #[string] version: Option, - #[string] schema_url: Option, -) -> InstrumentationScope { - let mut builder = opentelemetry::InstrumentationScope::builder(name); - if let Some(version) = version { - builder = builder.with_version(version); - } - if let Some(schema_url) = schema_url { - builder = builder.with_schema_url(schema_url); - } - let scope = InstrumentationScope(builder.build()); - state.put(scope.clone()); - scope -} - #[op2(fast)] -fn op_otel_instrumentation_scope_enter( - state: &mut OpState, - #[cppgc] scope: &InstrumentationScope, +fn op_otel_log<'s>( + scope: &mut v8::HandleScope<'s>, + message: v8::Local<'s, v8::Value>, + #[smi] level: i32, + span: v8::Local<'s, v8::Value>, ) { - state.put(scope.clone()); -} + let Some(OtelGlobals { + log_processor, + builtin_instrumentation_scope, + .. + }) = OTEL_GLOBALS.get() + else { + return; + }; -#[op2(fast)] -fn op_otel_instrumentation_scope_enter_builtin(state: &mut OpState) { - if let Some(scope) = BUILT_IN_INSTRUMENTATION_SCOPE.get() { - state.put(InstrumentationScope(scope.clone())); + // Convert the integer log level that ext/console uses to the corresponding + // OpenTelemetry log severity. + let severity = match level { + ..=0 => Severity::Debug, + 1 => Severity::Info, + 2 => Severity::Warn, + 3.. => Severity::Error, + }; + + let mut log_record = LogRecord::default(); + log_record.set_observed_timestamp(SystemTime::now()); + let Ok(message) = message.try_cast() else { + return; + }; + log_record.set_body(owned_string(scope, message).into()); + log_record.set_severity_number(severity); + log_record.set_severity_text(severity.name()); + if let Some(span) = + deno_core::_ops::try_unwrap_cppgc_object::(scope, span) + { + let state = span.0.borrow(); + match &**state { + OtelSpanState::Recording(span) => { + log_record.set_trace_context( + span.span_context.trace_id(), + span.span_context.span_id(), + Some(span.span_context.trace_flags()), + ); + } + OtelSpanState::Done(span_context) => { + log_record.set_trace_context( + span_context.trace_id(), + span_context.span_id(), + Some(span_context.trace_flags()), + ); + } + } } + + log_processor.emit(&mut log_record, builtin_instrumentation_scope); } #[op2(fast)] -fn op_otel_log( +fn op_otel_log_foreign( scope: &mut v8::HandleScope<'_>, #[string] message: String, #[smi] level: i32, @@ -923,10 +1006,12 @@ fn op_otel_log( span_id: v8::Local<'_, v8::Value>, #[smi] trace_flags: u8, ) { - let Some(Processors { logs, .. }) = OTEL_PROCESSORS.get() else { - return; - }; - let Some(instrumentation_scope) = BUILT_IN_INSTRUMENTATION_SCOPE.get() else { + let Some(OtelGlobals { + log_processor, + builtin_instrumentation_scope, + .. + }) = OTEL_GLOBALS.get() + else { return; }; @@ -956,7 +1041,7 @@ fn op_otel_log( ); } - logs.emit(&mut log_record, instrumentation_scope); + log_processor.emit(&mut log_record, builtin_instrumentation_scope); } fn owned_string<'s>( @@ -972,136 +1057,348 @@ fn owned_string<'s>( } } -struct TemporarySpan(SpanData); +struct OtelTracer(InstrumentationScope); -#[allow(clippy::too_many_arguments)] -#[op2(fast)] -fn op_otel_span_start<'s>( - scope: &mut v8::HandleScope<'s>, - state: &mut OpState, - trace_id: v8::Local<'s, v8::Value>, - span_id: v8::Local<'s, v8::Value>, - parent_span_id: v8::Local<'s, v8::Value>, - #[smi] span_kind: u8, - name: v8::Local<'s, v8::Value>, - start_time: f64, - end_time: f64, -) -> Result<(), anyhow::Error> { - if let Some(temporary_span) = state.try_take::() { - let Some(Processors { spans, .. }) = OTEL_PROCESSORS.get() else { - return Ok(()); - }; - spans.on_end(temporary_span.0); - }; +impl deno_core::GarbageCollected for OtelTracer {} - let Some(InstrumentationScope(instrumentation_scope)) = - state.try_borrow::() - else { - return Err(anyhow!("instrumentation scope not available")); - }; - - let trace_id = parse_trace_id(scope, trace_id); - if trace_id == TraceId::INVALID { - return Err(anyhow!("invalid trace_id")); +#[op2] +impl OtelTracer { + #[constructor] + #[cppgc] + fn new( + #[string] name: String, + #[string] version: Option, + #[string] schema_url: Option, + ) -> OtelTracer { + let mut builder = opentelemetry::InstrumentationScope::builder(name); + if let Some(version) = version { + builder = builder.with_version(version); + } + if let Some(schema_url) = schema_url { + builder = builder.with_schema_url(schema_url); + } + let scope = builder.build(); + OtelTracer(scope) } - let span_id = parse_span_id(scope, span_id); - if span_id == SpanId::INVALID { - return Err(anyhow!("invalid span_id")); + #[static_method] + #[cppgc] + fn builtin() -> OtelTracer { + let OtelGlobals { + builtin_instrumentation_scope, + .. + } = OTEL_GLOBALS.get().unwrap(); + OtelTracer(builtin_instrumentation_scope.clone()) } - let parent_span_id = parse_span_id(scope, parent_span_id); - - let name = owned_string(scope, name.try_cast()?); - - let temporary_span = TemporarySpan(SpanData { - span_context: SpanContext::new( - trace_id, - span_id, - TraceFlags::SAMPLED, - false, - Default::default(), - ), - parent_span_id, - span_kind: match span_kind { + #[cppgc] + fn start_span<'s>( + &self, + scope: &mut v8::HandleScope<'s>, + #[cppgc] parent: Option<&OtelSpan>, + name: v8::Local<'s, v8::Value>, + #[smi] span_kind: u8, + start_time: Option, + #[smi] attribute_count: usize, + ) -> Result { + let OtelGlobals { id_generator, .. } = OTEL_GLOBALS.get().unwrap(); + let span_context; + let parent_span_id; + match parent { + Some(parent) => { + let parent = parent.0.borrow(); + let parent_span_context = match &**parent { + OtelSpanState::Recording(span) => &span.span_context, + OtelSpanState::Done(span_context) => span_context, + }; + span_context = SpanContext::new( + parent_span_context.trace_id(), + id_generator.new_span_id(), + TraceFlags::SAMPLED, + false, + parent_span_context.trace_state().clone(), + ); + parent_span_id = parent_span_context.span_id(); + } + None => { + span_context = SpanContext::new( + id_generator.new_trace_id(), + id_generator.new_span_id(), + TraceFlags::SAMPLED, + false, + TraceState::NONE, + ); + parent_span_id = SpanId::INVALID; + } + } + let name = owned_string( + scope, + name + .try_cast() + .map_err(|e: DataError| JsErrorBox::generic(e.to_string()))?, + ); + let span_kind = match span_kind { 0 => SpanKind::Internal, 1 => SpanKind::Server, 2 => SpanKind::Client, 3 => SpanKind::Producer, 4 => SpanKind::Consumer, - _ => return Err(anyhow!("invalid span kind")), - }, - name: Cow::Owned(name), - start_time: SystemTime::UNIX_EPOCH - .checked_add(std::time::Duration::from_secs_f64(start_time)) - .ok_or_else(|| anyhow!("invalid start time"))?, - end_time: SystemTime::UNIX_EPOCH - .checked_add(std::time::Duration::from_secs_f64(end_time)) - .ok_or_else(|| anyhow!("invalid start time"))?, - attributes: Vec::new(), - dropped_attributes_count: 0, - events: Default::default(), - links: Default::default(), - status: SpanStatus::Unset, - instrumentation_scope: instrumentation_scope.clone(), - }); - state.put(temporary_span); + _ => return Err(JsErrorBox::generic("invalid span kind")), + }; + let start_time = start_time + .map(|start_time| { + SystemTime::UNIX_EPOCH + .checked_add(std::time::Duration::from_secs_f64(start_time)) + .ok_or_else(|| JsErrorBox::generic("invalid start time")) + }) + .unwrap_or_else(|| Ok(SystemTime::now()))?; + let span_data = SpanData { + span_context, + parent_span_id, + span_kind, + name: Cow::Owned(name), + start_time, + end_time: SystemTime::UNIX_EPOCH, + attributes: Vec::with_capacity(attribute_count), + dropped_attributes_count: 0, + status: SpanStatus::Unset, + events: SpanEvents::default(), + links: SpanLinks::default(), + instrumentation_scope: self.0.clone(), + }; + Ok(OtelSpan(RefCell::new(Box::new(OtelSpanState::Recording( + span_data, + ))))) + } - Ok(()) + #[cppgc] + fn start_span_foreign<'s>( + &self, + scope: &mut v8::HandleScope<'s>, + parent_trace_id: v8::Local<'s, v8::Value>, + parent_span_id: v8::Local<'s, v8::Value>, + name: v8::Local<'s, v8::Value>, + #[smi] span_kind: u8, + start_time: Option, + #[smi] attribute_count: usize, + ) -> Result { + let parent_trace_id = parse_trace_id(scope, parent_trace_id); + if parent_trace_id == TraceId::INVALID { + return Err(JsErrorBox::generic("invalid trace id")); + }; + let parent_span_id = parse_span_id(scope, parent_span_id); + if parent_span_id == SpanId::INVALID { + return Err(JsErrorBox::generic("invalid span id")); + }; + let OtelGlobals { id_generator, .. } = OTEL_GLOBALS.get().unwrap(); + let span_context = SpanContext::new( + parent_trace_id, + id_generator.new_span_id(), + TraceFlags::SAMPLED, + false, + TraceState::NONE, + ); + let name = owned_string( + scope, + name + .try_cast() + .map_err(|e: DataError| JsErrorBox::generic(e.to_string()))?, + ); + let span_kind = match span_kind { + 0 => SpanKind::Internal, + 1 => SpanKind::Server, + 2 => SpanKind::Client, + 3 => SpanKind::Producer, + 4 => SpanKind::Consumer, + _ => return Err(JsErrorBox::generic("invalid span kind")), + }; + let start_time = start_time + .map(|start_time| { + SystemTime::UNIX_EPOCH + .checked_add(std::time::Duration::from_secs_f64(start_time)) + .ok_or_else(|| JsErrorBox::generic("invalid start time")) + }) + .unwrap_or_else(|| Ok(SystemTime::now()))?; + let span_data = SpanData { + span_context, + parent_span_id, + span_kind, + name: Cow::Owned(name), + start_time, + end_time: SystemTime::UNIX_EPOCH, + attributes: Vec::with_capacity(attribute_count), + dropped_attributes_count: 0, + status: SpanStatus::Unset, + events: SpanEvents::default(), + links: SpanLinks::default(), + instrumentation_scope: self.0.clone(), + }; + Ok(OtelSpan(RefCell::new(Box::new(OtelSpanState::Recording( + span_data, + ))))) + } } -#[op2(fast)] -fn op_otel_span_continue( - state: &mut OpState, - #[smi] status: u8, - #[string] error_description: Cow<'_, str>, -) { - if let Some(temporary_span) = state.try_borrow_mut::() { - temporary_span.0.status = match status { +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct JsSpanContext { + trace_id: Box, + span_id: Box, + trace_flags: u8, +} + +#[derive(Debug, Error, JsError)] +#[error("OtelSpan cannot be constructed.")] +#[class(type)] +struct OtelSpanCannotBeConstructedError; + +#[derive(Debug, Error, JsError)] +#[error("invalid span status code")] +#[class(type)] +struct InvalidSpanStatusCodeError; + +// boxed because of https://github.com/denoland/rusty_v8/issues/1676 +#[derive(Debug)] +struct OtelSpan(RefCell>); + +#[derive(Debug)] +#[allow(clippy::large_enum_variant)] +enum OtelSpanState { + Recording(SpanData), + Done(SpanContext), +} + +impl deno_core::GarbageCollected for OtelSpan {} + +#[op2] +impl OtelSpan { + #[constructor] + #[cppgc] + fn new() -> Result { + Err(OtelSpanCannotBeConstructedError) + } + + #[serde] + fn span_context(&self) -> JsSpanContext { + let state = self.0.borrow(); + let span_context = match &**state { + OtelSpanState::Recording(span) => &span.span_context, + OtelSpanState::Done(span_context) => span_context, + }; + JsSpanContext { + trace_id: format!("{:?}", span_context.trace_id()).into(), + span_id: format!("{:?}", span_context.span_id()).into(), + trace_flags: span_context.trace_flags().to_u8(), + } + } + + #[fast] + fn set_status<'s>( + &self, + #[smi] status: u8, + #[string] error_description: String, + ) -> Result<(), InvalidSpanStatusCodeError> { + let mut state = self.0.borrow_mut(); + let OtelSpanState::Recording(span) = &mut **state else { + return Ok(()); + }; + span.status = match status { 0 => SpanStatus::Unset, 1 => SpanStatus::Ok, 2 => SpanStatus::Error { - description: Cow::Owned(error_description.into_owned()), + description: Cow::Owned(error_description), }, - _ => return, + _ => return Err(InvalidSpanStatusCodeError), }; + Ok(()) + } + + #[fast] + fn drop_event(&self) { + let mut state = self.0.borrow_mut(); + match &mut **state { + OtelSpanState::Recording(span) => { + span.events.dropped_count += 1; + } + OtelSpanState::Done(_) => {} + } + } + + #[fast] + fn drop_link(&self) { + let mut state = self.0.borrow_mut(); + match &mut **state { + OtelSpanState::Recording(span) => { + span.links.dropped_count += 1; + } + OtelSpanState::Done(_) => {} + } + } + + #[fast] + fn end(&self, end_time: f64) { + let end_time = if end_time.is_nan() { + SystemTime::now() + } else { + SystemTime::UNIX_EPOCH + .checked_add(Duration::from_secs_f64(end_time)) + .unwrap() + }; + + let mut state = self.0.borrow_mut(); + if let OtelSpanState::Recording(span) = &mut **state { + let span_context = span.span_context.clone(); + if let OtelSpanState::Recording(mut span) = *std::mem::replace( + &mut *state, + Box::new(OtelSpanState::Done(span_context)), + ) { + span.end_time = end_time; + let Some(OtelGlobals { span_processor, .. }) = OTEL_GLOBALS.get() + else { + return; + }; + span_processor.on_end(span); + } + } } } #[op2(fast)] -fn op_otel_span_attribute<'s>( +fn op_otel_span_attribute1<'s>( scope: &mut v8::HandleScope<'s>, - state: &mut OpState, - #[smi] capacity: u32, + span: v8::Local<'_, v8::Value>, key: v8::Local<'s, v8::Value>, value: v8::Local<'s, v8::Value>, ) { - if let Some(temporary_span) = state.try_borrow_mut::() { - temporary_span.0.attributes.reserve_exact( - (capacity as usize) - .saturating_sub(temporary_span.0.attributes.capacity()), - ); - attr!(scope, temporary_span.0.attributes => temporary_span.0.dropped_attributes_count, key, value); + let Some(span) = + deno_core::_ops::try_unwrap_cppgc_object::(scope, span) + else { + return; + }; + let mut state = span.0.borrow_mut(); + if let OtelSpanState::Recording(span) = &mut **state { + attr!(scope, span.attributes => span.dropped_attributes_count, key, value); } } #[op2(fast)] fn op_otel_span_attribute2<'s>( scope: &mut v8::HandleScope<'s>, - state: &mut OpState, - #[smi] capacity: u32, + span: v8::Local<'_, v8::Value>, key1: v8::Local<'s, v8::Value>, value1: v8::Local<'s, v8::Value>, key2: v8::Local<'s, v8::Value>, value2: v8::Local<'s, v8::Value>, ) { - if let Some(temporary_span) = state.try_borrow_mut::() { - temporary_span.0.attributes.reserve_exact( - (capacity as usize) - .saturating_sub(temporary_span.0.attributes.capacity()), - ); - attr!(scope, temporary_span.0.attributes => temporary_span.0.dropped_attributes_count, key1, value1); - attr!(scope, temporary_span.0.attributes => temporary_span.0.dropped_attributes_count, key2, value2); + let Some(span) = + deno_core::_ops::try_unwrap_cppgc_object::(scope, span) + else { + return; + }; + let mut state = span.0.borrow_mut(); + if let OtelSpanState::Recording(span) = &mut **state { + attr!(scope, span.attributes => span.dropped_attributes_count, key1, value1); + attr!(scope, span.attributes => span.dropped_attributes_count, key2, value2); } } @@ -1109,8 +1406,7 @@ fn op_otel_span_attribute2<'s>( #[op2(fast)] fn op_otel_span_attribute3<'s>( scope: &mut v8::HandleScope<'s>, - state: &mut OpState, - #[smi] capacity: u32, + span: v8::Local<'_, v8::Value>, key1: v8::Local<'s, v8::Value>, value1: v8::Local<'s, v8::Value>, key2: v8::Local<'s, v8::Value>, @@ -1118,42 +1414,229 @@ fn op_otel_span_attribute3<'s>( key3: v8::Local<'s, v8::Value>, value3: v8::Local<'s, v8::Value>, ) { - if let Some(temporary_span) = state.try_borrow_mut::() { - temporary_span.0.attributes.reserve_exact( - (capacity as usize) - .saturating_sub(temporary_span.0.attributes.capacity()), - ); - attr!(scope, temporary_span.0.attributes => temporary_span.0.dropped_attributes_count, key1, value1); - attr!(scope, temporary_span.0.attributes => temporary_span.0.dropped_attributes_count, key2, value2); - attr!(scope, temporary_span.0.attributes => temporary_span.0.dropped_attributes_count, key3, value3); + let Some(span) = + deno_core::_ops::try_unwrap_cppgc_object::(scope, span) + else { + return; + }; + let mut state = span.0.borrow_mut(); + if let OtelSpanState::Recording(span) = &mut **state { + attr!(scope, span.attributes => span.dropped_attributes_count, key1, value1); + attr!(scope, span.attributes => span.dropped_attributes_count, key2, value2); + attr!(scope, span.attributes => span.dropped_attributes_count, key3, value3); } } #[op2(fast)] -fn op_otel_span_set_dropped( - state: &mut OpState, - #[smi] dropped_attributes_count: u32, - #[smi] dropped_links_count: u32, - #[smi] dropped_events_count: u32, +fn op_otel_span_update_name<'s>( + scope: &mut v8::HandleScope<'s>, + span: v8::Local<'s, v8::Value>, + name: v8::Local<'s, v8::Value>, ) { - if let Some(temporary_span) = state.try_borrow_mut::() { - temporary_span.0.dropped_attributes_count += dropped_attributes_count; - temporary_span.0.links.dropped_count += dropped_links_count; - temporary_span.0.events.dropped_count += dropped_events_count; + let Ok(name) = name.try_cast() else { + return; + }; + let name = owned_string(scope, name); + let Some(span) = + deno_core::_ops::try_unwrap_cppgc_object::(scope, span) + else { + return; + }; + let mut state = span.0.borrow_mut(); + if let OtelSpanState::Recording(span) = &mut **state { + span.name = Cow::Owned(name) } } -#[op2(fast)] -fn op_otel_span_flush(state: &mut OpState) { - let Some(temporary_span) = state.try_take::() else { - return; - }; +struct OtelMeter(opentelemetry::metrics::Meter); - let Some(Processors { spans, .. }) = OTEL_PROCESSORS.get() else { - return; - }; +impl deno_core::GarbageCollected for OtelMeter {} - spans.on_end(temporary_span.0); +#[op2] +impl OtelMeter { + #[constructor] + #[cppgc] + fn new( + #[string] name: String, + #[string] version: Option, + #[string] schema_url: Option, + ) -> OtelMeter { + let mut builder = opentelemetry::InstrumentationScope::builder(name); + if let Some(version) = version { + builder = builder.with_version(version); + } + if let Some(schema_url) = schema_url { + builder = builder.with_schema_url(schema_url); + } + let scope = builder.build(); + let meter = OTEL_GLOBALS + .get() + .unwrap() + .meter_provider + .meter_with_scope(scope); + OtelMeter(meter) + } + + #[cppgc] + fn create_counter<'s>( + &self, + scope: &mut v8::HandleScope<'s>, + name: v8::Local<'s, v8::Value>, + description: v8::Local<'s, v8::Value>, + unit: v8::Local<'s, v8::Value>, + ) -> Result { + create_instrument( + |name| self.0.f64_counter(name), + |i| Instrument::Counter(i.build()), + scope, + name, + description, + unit, + ) + .map_err(|e| JsErrorBox::generic(e.to_string())) + } + + #[cppgc] + fn create_up_down_counter<'s>( + &self, + scope: &mut v8::HandleScope<'s>, + name: v8::Local<'s, v8::Value>, + description: v8::Local<'s, v8::Value>, + unit: v8::Local<'s, v8::Value>, + ) -> Result { + create_instrument( + |name| self.0.f64_up_down_counter(name), + |i| Instrument::UpDownCounter(i.build()), + scope, + name, + description, + unit, + ) + .map_err(|e| JsErrorBox::generic(e.to_string())) + } + + #[cppgc] + fn create_gauge<'s>( + &self, + scope: &mut v8::HandleScope<'s>, + name: v8::Local<'s, v8::Value>, + description: v8::Local<'s, v8::Value>, + unit: v8::Local<'s, v8::Value>, + ) -> Result { + create_instrument( + |name| self.0.f64_gauge(name), + |i| Instrument::Gauge(i.build()), + scope, + name, + description, + unit, + ) + .map_err(|e| JsErrorBox::generic(e.to_string())) + } + + #[cppgc] + fn create_histogram<'s>( + &self, + scope: &mut v8::HandleScope<'s>, + name: v8::Local<'s, v8::Value>, + description: v8::Local<'s, v8::Value>, + unit: v8::Local<'s, v8::Value>, + #[serde] boundaries: Option>, + ) -> Result { + let name = owned_string( + scope, + name + .try_cast() + .map_err(|e: DataError| JsErrorBox::generic(e.to_string()))?, + ); + let mut builder = self.0.f64_histogram(name); + if !description.is_null_or_undefined() { + let description = owned_string( + scope, + description + .try_cast() + .map_err(|e: DataError| JsErrorBox::generic(e.to_string()))?, + ); + builder = builder.with_description(description); + }; + if !unit.is_null_or_undefined() { + let unit = owned_string( + scope, + unit + .try_cast() + .map_err(|e: DataError| JsErrorBox::generic(e.to_string()))?, + ); + builder = builder.with_unit(unit); + }; + if let Some(boundaries) = boundaries { + builder = builder.with_boundaries(boundaries); + } + + Ok(Instrument::Histogram(builder.build())) + } + + #[cppgc] + fn create_observable_counter<'s>( + &self, + scope: &mut v8::HandleScope<'s>, + name: v8::Local<'s, v8::Value>, + description: v8::Local<'s, v8::Value>, + unit: v8::Local<'s, v8::Value>, + ) -> Result { + create_async_instrument( + |name| self.0.f64_observable_counter(name), + |i| { + i.build(); + }, + scope, + name, + description, + unit, + ) + .map_err(|e| JsErrorBox::generic(e.to_string())) + } + + #[cppgc] + fn create_observable_up_down_counter<'s>( + &self, + scope: &mut v8::HandleScope<'s>, + name: v8::Local<'s, v8::Value>, + description: v8::Local<'s, v8::Value>, + unit: v8::Local<'s, v8::Value>, + ) -> Result { + create_async_instrument( + |name| self.0.f64_observable_up_down_counter(name), + |i| { + i.build(); + }, + scope, + name, + description, + unit, + ) + .map_err(|e| JsErrorBox::generic(e.to_string())) + } + + #[cppgc] + fn create_observable_gauge<'s>( + &self, + scope: &mut v8::HandleScope<'s>, + name: v8::Local<'s, v8::Value>, + description: v8::Local<'s, v8::Value>, + unit: v8::Local<'s, v8::Value>, + ) -> Result { + create_async_instrument( + |name| self.0.f64_observable_gauge(name), + |i| { + i.build(); + }, + scope, + name, + description, + unit, + ) + .map_err(|e| JsErrorBox::generic(e.to_string())) + } } enum Instrument { @@ -1166,32 +1649,16 @@ enum Instrument { impl GarbageCollected for Instrument {} -fn create_instrument<'a, T>( - cb: impl FnOnce( - &'_ opentelemetry::metrics::Meter, - String, - ) -> InstrumentBuilder<'_, T>, - cb2: impl FnOnce(InstrumentBuilder<'_, T>) -> Instrument, - state: &mut OpState, +fn create_instrument<'a, 'b, T>( + cb: impl FnOnce(String) -> InstrumentBuilder<'b, T>, + cb2: impl FnOnce(InstrumentBuilder<'b, T>) -> Instrument, scope: &mut v8::HandleScope<'a>, name: v8::Local<'a, v8::Value>, description: v8::Local<'a, v8::Value>, unit: v8::Local<'a, v8::Value>, -) -> Result { - let Some(InstrumentationScope(instrumentation_scope)) = - state.try_borrow::() - else { - return Err(anyhow!("instrumentation scope not available")); - }; - - let meter = OTEL_PROCESSORS - .get() - .unwrap() - .meter_provider - .meter_with_scope(instrumentation_scope.clone()); - +) -> Result { let name = owned_string(scope, name.try_cast()?); - let mut builder = cb(&meter, name); + let mut builder = cb(name); if !description.is_null_or_undefined() { let description = owned_string(scope, description.try_cast()?); builder = builder.with_description(description); @@ -1204,131 +1671,16 @@ fn create_instrument<'a, T>( Ok(cb2(builder)) } -#[op2] -#[cppgc] -fn op_otel_metric_create_counter<'s>( - state: &mut OpState, - scope: &mut v8::HandleScope<'s>, - name: v8::Local<'s, v8::Value>, - description: v8::Local<'s, v8::Value>, - unit: v8::Local<'s, v8::Value>, -) -> Result { - create_instrument( - |meter, name| meter.f64_counter(name), - |i| Instrument::Counter(i.build()), - state, - scope, - name, - description, - unit, - ) -} - -#[op2] -#[cppgc] -fn op_otel_metric_create_up_down_counter<'s>( - state: &mut OpState, - scope: &mut v8::HandleScope<'s>, - name: v8::Local<'s, v8::Value>, - description: v8::Local<'s, v8::Value>, - unit: v8::Local<'s, v8::Value>, -) -> Result { - create_instrument( - |meter, name| meter.f64_up_down_counter(name), - |i| Instrument::UpDownCounter(i.build()), - state, - scope, - name, - description, - unit, - ) -} - -#[op2] -#[cppgc] -fn op_otel_metric_create_gauge<'s>( - state: &mut OpState, - scope: &mut v8::HandleScope<'s>, - name: v8::Local<'s, v8::Value>, - description: v8::Local<'s, v8::Value>, - unit: v8::Local<'s, v8::Value>, -) -> Result { - create_instrument( - |meter, name| meter.f64_gauge(name), - |i| Instrument::Gauge(i.build()), - state, - scope, - name, - description, - unit, - ) -} - -#[op2] -#[cppgc] -fn op_otel_metric_create_histogram<'s>( - state: &mut OpState, - scope: &mut v8::HandleScope<'s>, - name: v8::Local<'s, v8::Value>, - description: v8::Local<'s, v8::Value>, - unit: v8::Local<'s, v8::Value>, - #[serde] boundaries: Option>, -) -> Result { - let Some(InstrumentationScope(instrumentation_scope)) = - state.try_borrow::() - else { - return Err(anyhow!("instrumentation scope not available")); - }; - - let meter = OTEL_PROCESSORS - .get() - .unwrap() - .meter_provider - .meter_with_scope(instrumentation_scope.clone()); - - let name = owned_string(scope, name.try_cast()?); - let mut builder = meter.f64_histogram(name); - if !description.is_null_or_undefined() { - let description = owned_string(scope, description.try_cast()?); - builder = builder.with_description(description); - }; - if !unit.is_null_or_undefined() { - let unit = owned_string(scope, unit.try_cast()?); - builder = builder.with_unit(unit); - }; - if let Some(boundaries) = boundaries { - builder = builder.with_boundaries(boundaries); - } - - Ok(Instrument::Histogram(builder.build())) -} - -fn create_async_instrument<'a, T>( - cb: impl FnOnce( - &'_ opentelemetry::metrics::Meter, - String, - ) -> AsyncInstrumentBuilder<'_, T, f64>, - cb2: impl FnOnce(AsyncInstrumentBuilder<'_, T, f64>), - state: &mut OpState, +fn create_async_instrument<'a, 'b, T>( + cb: impl FnOnce(String) -> AsyncInstrumentBuilder<'b, T, f64>, + cb2: impl FnOnce(AsyncInstrumentBuilder<'b, T, f64>), scope: &mut v8::HandleScope<'a>, name: v8::Local<'a, v8::Value>, description: v8::Local<'a, v8::Value>, unit: v8::Local<'a, v8::Value>, -) -> Result { - let Some(InstrumentationScope(instrumentation_scope)) = - state.try_borrow::() - else { - return Err(anyhow!("instrumentation scope not available")); - }; - - let meter = OTEL_PROCESSORS - .get() - .unwrap() - .meter_provider - .meter_with_scope(instrumentation_scope.clone()); - +) -> Result { let name = owned_string(scope, name.try_cast()?); - let mut builder = cb(&meter, name); + let mut builder = cb(name); if !description.is_null_or_undefined() { let description = owned_string(scope, description.try_cast()?); builder = builder.with_description(description); @@ -1354,72 +1706,6 @@ fn create_async_instrument<'a, T>( Ok(Instrument::Observable(data_share)) } -#[op2] -#[cppgc] -fn op_otel_metric_create_observable_counter<'s>( - state: &mut OpState, - scope: &mut v8::HandleScope<'s>, - name: v8::Local<'s, v8::Value>, - description: v8::Local<'s, v8::Value>, - unit: v8::Local<'s, v8::Value>, -) -> Result { - create_async_instrument( - |meter, name| meter.f64_observable_counter(name), - |i| { - i.build(); - }, - state, - scope, - name, - description, - unit, - ) -} - -#[op2] -#[cppgc] -fn op_otel_metric_create_observable_up_down_counter<'s>( - state: &mut OpState, - scope: &mut v8::HandleScope<'s>, - name: v8::Local<'s, v8::Value>, - description: v8::Local<'s, v8::Value>, - unit: v8::Local<'s, v8::Value>, -) -> Result { - create_async_instrument( - |meter, name| meter.f64_observable_up_down_counter(name), - |i| { - i.build(); - }, - state, - scope, - name, - description, - unit, - ) -} - -#[op2] -#[cppgc] -fn op_otel_metric_create_observable_gauge<'s>( - state: &mut OpState, - scope: &mut v8::HandleScope<'s>, - name: v8::Local<'s, v8::Value>, - description: v8::Local<'s, v8::Value>, - unit: v8::Local<'s, v8::Value>, -) -> Result { - create_async_instrument( - |meter, name| meter.f64_observable_gauge(name), - |i| { - i.build(); - }, - state, - scope, - name, - description, - unit, - ) -} - struct MetricAttributes { attributes: Vec, } diff --git a/ext/telemetry/telemetry.ts b/ext/telemetry/telemetry.ts index 86b4fe059d..bea16f49d4 100644 --- a/ext/telemetry/telemetry.ts +++ b/ext/telemetry/telemetry.ts @@ -1,20 +1,10 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, primordials } from "ext:core/mod.js"; import { - op_crypto_get_random_values, - op_otel_instrumentation_scope_create_and_enter, - op_otel_instrumentation_scope_enter, - op_otel_instrumentation_scope_enter_builtin, op_otel_log, + op_otel_log_foreign, op_otel_metric_attribute3, - op_otel_metric_create_counter, - op_otel_metric_create_gauge, - op_otel_metric_create_histogram, - op_otel_metric_create_observable_counter, - op_otel_metric_create_observable_gauge, - op_otel_metric_create_observable_up_down_counter, - op_otel_metric_create_up_down_counter, op_otel_metric_observable_record0, op_otel_metric_observable_record1, op_otel_metric_observable_record2, @@ -25,45 +15,39 @@ import { op_otel_metric_record2, op_otel_metric_record3, op_otel_metric_wait_to_observe, - op_otel_span_attribute, + op_otel_span_attribute1, op_otel_span_attribute2, op_otel_span_attribute3, - op_otel_span_continue, - op_otel_span_flush, - op_otel_span_set_dropped, - op_otel_span_start, + op_otel_span_update_name, + OtelMeter, + OtelSpan, + OtelTracer, } from "ext:core/ops"; import { Console } from "ext:deno_console/01_console.js"; -import { performance } from "ext:deno_web/15_performance.js"; const { - Array, + ArrayIsArray, ArrayPrototypePush, + DatePrototype, + DatePrototypeGetTime, Error, - ObjectAssign, ObjectDefineProperty, ObjectEntries, + ObjectKeys, ObjectPrototypeIsPrototypeOf, ReflectApply, SafeIterator, SafeMap, SafePromiseAll, SafeSet, - SafeWeakMap, - SafeWeakRef, SafeWeakSet, - String, - StringPrototypePadStart, SymbolFor, - TypedArrayPrototypeSubarray, - Uint8Array, - WeakRefPrototypeDeref, + TypeError, } = primordials; const { AsyncVariable, setAsyncContext } = core; export let TRACING_ENABLED = false; export let METRICS_ENABLED = false; -let DETERMINISTIC = false; // Note: These start at 0 in the JS library, // but start at 1 when serialized with JSON. @@ -90,8 +74,6 @@ interface SpanContext { traceState?: TraceState; } -type HrTime = [number, number]; - enum SpanStatusCode { UNSET = 0, OK = 1, @@ -103,7 +85,7 @@ interface SpanStatus { message?: string; } -export type AttributeValue = +type AttributeValue = | string | number | boolean @@ -117,9 +99,14 @@ interface Attributes { type SpanAttributes = Attributes; +type TimeInput = [number, number] | number | Date; + interface SpanOptions { - attributes?: Attributes; kind?: SpanKind; + attributes?: Attributes; + links?: Link[]; + startTime?: TimeInput; + root?: boolean; } interface Link { @@ -128,13 +115,6 @@ interface Link { droppedAttributesCount?: number; } -interface TimedEvent { - time: HrTime; - name: string; - attributes?: SpanAttributes; - droppedAttributesCount?: number; -} - interface IArrayValue { values: IAnyValue[]; } @@ -157,482 +137,322 @@ interface IKeyValue { key: string; value: IAnyValue; } -interface IResource { - attributes: IKeyValue[]; - droppedAttributesCount: number; -} - -interface InstrumentationLibrary { - readonly name: string; - readonly version?: string; - readonly schemaUrl?: string; -} - -interface ReadableSpan { - readonly name: string; - readonly kind: SpanKind; - readonly spanContext: () => SpanContext; - readonly parentSpanId?: string; - readonly startTime: HrTime; - readonly endTime: HrTime; - readonly status: SpanStatus; - readonly attributes: SpanAttributes; - readonly links: Link[]; - readonly events: TimedEvent[]; - readonly duration: HrTime; - readonly ended: boolean; - readonly resource: IResource; - readonly instrumentationLibrary: InstrumentationLibrary; - readonly droppedAttributesCount: number; - readonly droppedEventsCount: number; - readonly droppedLinksCount: number; -} - -enum ExportResultCode { - SUCCESS = 0, - FAILED = 1, -} - -interface ExportResult { - code: ExportResultCode; - error?: Error; -} function hrToSecs(hr: [number, number]): number { - return ((hr[0] * 1e3 + hr[1] / 1e6) / 1000); + return (hr[0] * 1e3 + hr[1] / 1e6) / 1000; } -const TRACE_FLAG_SAMPLED = 1 << 0; +export function enterSpan(span: Span): Context | undefined { + if (!span.isRecording()) return undefined; + const context = (CURRENT.get() || ROOT_CONTEXT).setValue(SPAN_KEY, span); + return CURRENT.enter(context); +} -const instrumentationScopes = new SafeWeakMap< - InstrumentationLibrary, - { __key: "instrumentation-library" } ->(); -let activeInstrumentationLibrary: WeakRef | null = null; +export function restoreContext(context: Context): void { + setAsyncContext(context); +} -function activateInstrumentationLibrary( - instrumentationLibrary: InstrumentationLibrary, -) { - if ( - !activeInstrumentationLibrary || - WeakRefPrototypeDeref(activeInstrumentationLibrary) !== - instrumentationLibrary +function isDate(value: unknown): value is Date { + return ObjectPrototypeIsPrototypeOf(value, DatePrototype); +} + +interface OtelTracer { + __key: "tracer"; + + // deno-lint-ignore no-misused-new + new (name: string, version?: string, schemaUrl?: string): OtelTracer; + + startSpan( + parent: OtelSpan | undefined, + name: string, + spanKind: SpanKind, + startTime: number | undefined, + attributeCount: number, + ): OtelSpan; + + startSpanForeign( + parentTraceId: string, + parentSpanId: string, + name: string, + spanKind: SpanKind, + startTime: number | undefined, + attributeCount: number, + ): OtelSpan; +} + +interface OtelSpan { + __key: "span"; + + spanContext(): SpanContext; + setStatus(status: SpanStatusCode, errorDescription: string): void; + dropEvent(): void; + dropLink(): void; + end(endTime: number): void; +} + +interface TracerOptions { + schemaUrl?: string; +} + +class TracerProvider { + constructor() { + throw new TypeError("TracerProvider can not be constructed"); + } + + static getTracer( + name: string, + version?: string, + options?: TracerOptions, + ): Tracer { + const tracer = new OtelTracer(name, version, options?.schemaUrl); + return new Tracer(tracer); + } +} + +class Tracer { + #tracer: OtelTracer; + + constructor(tracer: OtelTracer) { + this.#tracer = tracer; + } + + startActiveSpan unknown>( + name: string, + fn: F, + ): ReturnType; + startActiveSpan unknown>( + name: string, + options: SpanOptions, + fn: F, + ): ReturnType; + startActiveSpan unknown>( + name: string, + options: SpanOptions, + context: Context, + fn: F, + ): ReturnType; + startActiveSpan unknown>( + name: string, + optionsOrFn: SpanOptions | F, + fnOrContext?: F | Context, + maybeFn?: F, ) { - activeInstrumentationLibrary = new SafeWeakRef(instrumentationLibrary); - if (instrumentationLibrary === BUILTIN_INSTRUMENTATION_LIBRARY) { - op_otel_instrumentation_scope_enter_builtin(); + let options; + let context; + let fn; + if (typeof optionsOrFn === "function") { + options = undefined; + fn = optionsOrFn; + } else if (typeof fnOrContext === "function") { + options = optionsOrFn; + fn = fnOrContext; + } else if (typeof maybeFn === "function") { + options = optionsOrFn; + context = fnOrContext; + fn = maybeFn; } else { - let instrumentationScope = instrumentationScopes - .get(instrumentationLibrary); - - if (instrumentationScope === undefined) { - instrumentationScope = op_otel_instrumentation_scope_create_and_enter( - instrumentationLibrary.name, - instrumentationLibrary.version, - instrumentationLibrary.schemaUrl, - ) as { __key: "instrumentation-library" }; - instrumentationScopes.set( - instrumentationLibrary, - instrumentationScope, - ); - } else { - op_otel_instrumentation_scope_enter( - instrumentationScope, - ); - } + throw new Error("startActiveSpan requires a function argument"); } - } -} - -function submitSpan( - spanId: string | Uint8Array, - traceId: string | Uint8Array, - traceFlags: number, - parentSpanId: string | Uint8Array | null, - span: Omit< - ReadableSpan, - | "spanContext" - | "startTime" - | "endTime" - | "parentSpanId" - | "duration" - | "ended" - | "resource" - >, - startTime: number, - endTime: number, -) { - if (!TRACING_ENABLED) return; - if (!(traceFlags & TRACE_FLAG_SAMPLED)) return; - - // TODO(@lucacasonato): `resource` is ignored for now, should we implement it? - - activateInstrumentationLibrary(span.instrumentationLibrary); - - op_otel_span_start( - traceId, - spanId, - parentSpanId, - span.kind, - span.name, - startTime, - endTime, - ); - - const status = span.status; - if (status !== null && status.code !== 0) { - op_otel_span_continue(status.code, status.message ?? ""); - } - - const attributeKvs = ObjectEntries(span.attributes); - let i = 0; - while (i < attributeKvs.length) { - if (i + 2 < attributeKvs.length) { - op_otel_span_attribute3( - attributeKvs.length, - attributeKvs[i][0], - attributeKvs[i][1], - attributeKvs[i + 1][0], - attributeKvs[i + 1][1], - attributeKvs[i + 2][0], - attributeKvs[i + 2][1], - ); - i += 3; - } else if (i + 1 < attributeKvs.length) { - op_otel_span_attribute2( - attributeKvs.length, - attributeKvs[i][0], - attributeKvs[i][1], - attributeKvs[i + 1][0], - attributeKvs[i + 1][1], - ); - i += 2; + if (options?.root) { + context = undefined; } else { - op_otel_span_attribute( - attributeKvs.length, - attributeKvs[i][0], - attributeKvs[i][1], + context = context ?? CURRENT.get(); + } + const span = this.startSpan(name, options, context); + const ctx = CURRENT.enter(context.setValue(SPAN_KEY, span)); + try { + return ReflectApply(fn, undefined, [span]); + } finally { + setAsyncContext(ctx); + } + } + + startSpan(name: string, options?: SpanOptions, context?: Context): Span { + if (options?.root) { + context = undefined; + } else { + context = context ?? CURRENT.get(); + } + + let startTime = options?.startTime; + if (startTime && ArrayIsArray(startTime)) { + startTime = hrToSecs(startTime); + } else if (startTime && isDate(startTime)) { + startTime = DatePrototypeGetTime(startTime); + } + + const parentSpan = context?.getValue(SPAN_KEY) as + | Span + | { spanContext(): SpanContext } + | undefined; + const attributesCount = options?.attributes + ? ObjectKeys(options.attributes).length + : 0; + const parentOtelSpan: OtelSpan | null | undefined = parentSpan !== undefined + ? getOtelSpan(parentSpan) ?? undefined + : undefined; + let otelSpan: OtelSpan; + if (parentOtelSpan || !parentSpan) { + otelSpan = this.#tracer.startSpan( + parentOtelSpan, + name, + options?.kind ?? 0, + startTime, + attributesCount, + ); + } else { + const spanContext = parentSpan.spanContext(); + otelSpan = this.#tracer.startSpanForeign( + spanContext.traceId, + spanContext.spanId, + name, + options?.kind ?? 0, + startTime, + attributesCount, ); - i += 1; } + const span = new Span(otelSpan); + if (options?.links) span.addLinks(options?.links); + if (options?.attributes) span.setAttributes(options?.attributes); + return span; } - - // TODO(@lucacasonato): implement links - // TODO(@lucacasonato): implement events - - const droppedAttributesCount = span.droppedAttributesCount; - const droppedLinksCount = span.droppedLinksCount + span.links.length; - const droppedEventsCount = span.droppedEventsCount + span.events.length; - if ( - droppedAttributesCount > 0 || droppedLinksCount > 0 || - droppedEventsCount > 0 - ) { - op_otel_span_set_dropped( - droppedAttributesCount, - droppedLinksCount, - droppedEventsCount, - ); - } - - op_otel_span_flush(); -} - -const now = () => (performance.timeOrigin + performance.now()) / 1000; - -const SPAN_ID_BYTES = 8; -const TRACE_ID_BYTES = 16; - -const INVALID_TRACE_ID = new Uint8Array(TRACE_ID_BYTES); -const INVALID_SPAN_ID = new Uint8Array(SPAN_ID_BYTES); - -const NO_ASYNC_CONTEXT = {}; - -let otelLog: (message: string, level: number) => void; - -const hexSliceLookupTable = (function () { - const alphabet = "0123456789abcdef"; - const table = new Array(256); - for (let i = 0; i < 16; ++i) { - const i16 = i * 16; - for (let j = 0; j < 16; ++j) { - table[i16 + j] = alphabet[i] + alphabet[j]; - } - } - return table; -})(); - -function bytesToHex(bytes: Uint8Array): string { - let out = ""; - for (let i = 0; i < bytes.length; i += 1) { - out += hexSliceLookupTable[bytes[i]]; - } - return out; } const SPAN_KEY = SymbolFor("OpenTelemetry Context Key SPAN"); -const BUILTIN_INSTRUMENTATION_LIBRARY: InstrumentationLibrary = {} as never; +let getOtelSpan: (span: object) => OtelSpan | null | undefined; -let COUNTER = 1; - -export let enterSpan: (span: Span) => void; -export let exitSpan: (span: Span) => void; -export let endSpan: (span: Span) => void; - -export class Span { - #traceId: string | Uint8Array; - #spanId: string | Uint8Array; - #traceFlags = TRACE_FLAG_SAMPLED; - - #spanContext: SpanContext | null = null; - - #parentSpanId: string | Uint8Array | null = null; - #parentSpanIdString: string | null = null; - - #recording = TRACING_ENABLED; - - #kind: number = SpanKind.INTERNAL; - #name: string; - #startTime: number; - #status: { code: number; message?: string } | null = null; - #attributes: Attributes = { __proto__: null } as never; - - #droppedEventsCount = 0; - #droppedLinksCount = 0; - - #asyncContext = NO_ASYNC_CONTEXT; +class Span { + #otelSpan: OtelSpan | null; + #spanContext: SpanContext | undefined; static { - otelLog = function otelLog(message, level) { - let traceId = null; - let spanId = null; - let traceFlags = 0; - const span = CURRENT.get()?.getValue(SPAN_KEY); - if (span) { - // The lint is wrong, we can not use anything but `in` here because this - // is a private field. - // deno-lint-ignore prefer-primordials - if (#traceId in span) { - traceId = span.#traceId; - spanId = span.#spanId; - traceFlags = span.#traceFlags; - } else { - const context = span.spanContext(); - traceId = context.traceId; - spanId = context.spanId; - traceFlags = context.traceFlags; - } - } - return op_otel_log(message, level, traceId, spanId, traceFlags); - }; - - enterSpan = (span: Span) => { - if (!span.#recording) return; - const context = (CURRENT.get() || ROOT_CONTEXT).setValue(SPAN_KEY, span); - span.#asyncContext = CURRENT.enter(context); - }; - - exitSpan = (span: Span) => { - if (!span.#recording) return; - if (span.#asyncContext === NO_ASYNC_CONTEXT) return; - setAsyncContext(span.#asyncContext); - span.#asyncContext = NO_ASYNC_CONTEXT; - }; - - endSpan = (span: Span) => { - const endTime = now(); - submitSpan( - span.#spanId, - span.#traceId, - span.#traceFlags, - span.#parentSpanId, - { - name: span.#name, - kind: span.#kind, - status: span.#status ?? { code: 0 }, - attributes: span.#attributes, - events: [], - links: [], - droppedAttributesCount: 0, - droppedEventsCount: span.#droppedEventsCount, - droppedLinksCount: span.#droppedLinksCount, - instrumentationLibrary: BUILTIN_INSTRUMENTATION_LIBRARY, - }, - span.#startTime, - endTime, - ); - }; + // deno-lint-ignore prefer-primordials + getOtelSpan = (span) => (#otelSpan in span ? span.#otelSpan : undefined); } - constructor( - name: string, - options?: SpanOptions, - ) { - if (!this.isRecording) { - this.#name = ""; - this.#startTime = 0; - this.#traceId = INVALID_TRACE_ID; - this.#spanId = INVALID_SPAN_ID; - this.#traceFlags = 0; - return; - } - - this.#name = name; - this.#startTime = now(); - this.#attributes = options?.attributes ?? { __proto__: null } as never; - this.#kind = options?.kind ?? SpanKind.INTERNAL; - - const currentSpan: Span | { - spanContext(): { traceId: string; spanId: string }; - } = CURRENT.get()?.getValue(SPAN_KEY); - if (currentSpan) { - if (DETERMINISTIC) { - this.#spanId = StringPrototypePadStart(String(COUNTER++), 16, "0"); - } else { - this.#spanId = new Uint8Array(SPAN_ID_BYTES); - op_crypto_get_random_values(this.#spanId); - } - // deno-lint-ignore prefer-primordials - if (#traceId in currentSpan) { - this.#traceId = currentSpan.#traceId; - this.#parentSpanId = currentSpan.#spanId; - } else { - const context = currentSpan.spanContext(); - this.#traceId = context.traceId; - this.#parentSpanId = context.spanId; - } - } else { - if (DETERMINISTIC) { - this.#traceId = StringPrototypePadStart(String(COUNTER++), 32, "0"); - this.#spanId = StringPrototypePadStart(String(COUNTER++), 16, "0"); - } else { - const buffer = new Uint8Array(TRACE_ID_BYTES + SPAN_ID_BYTES); - op_crypto_get_random_values(buffer); - this.#traceId = TypedArrayPrototypeSubarray(buffer, 0, TRACE_ID_BYTES); - this.#spanId = TypedArrayPrototypeSubarray(buffer, TRACE_ID_BYTES); - } - } + constructor(otelSpan: OtelSpan | null) { + this.#otelSpan = otelSpan; } spanContext() { if (!this.#spanContext) { - this.#spanContext = { - traceId: typeof this.#traceId === "string" - ? this.#traceId - : bytesToHex(this.#traceId), - spanId: typeof this.#spanId === "string" - ? this.#spanId - : bytesToHex(this.#spanId), - traceFlags: this.#traceFlags, - }; + if (this.#otelSpan) { + this.#spanContext = this.#otelSpan.spanContext(); + } else { + this.#spanContext = { + traceId: "00000000000000000000000000000000", + spanId: "0000000000000000", + traceFlags: 0, + }; + } } return this.#spanContext; } - get parentSpanId() { - if (!this.#parentSpanIdString && this.#parentSpanId) { - if (typeof this.#parentSpanId === "string") { - this.#parentSpanIdString = this.#parentSpanId; - } else { - this.#parentSpanIdString = bytesToHex(this.#parentSpanId); - } - } - return this.#parentSpanIdString; - } - - setAttribute(name: string, value: AttributeValue) { - if (this.#recording) this.#attributes[name] = value; + addEvent( + _name: string, + _attributesOrStartTime?: Attributes | TimeInput, + _startTime?: TimeInput, + ): Span { + this.#otelSpan?.dropEvent(); return this; } - setAttributes(attributes: Attributes) { - if (this.#recording) ObjectAssign(this.#attributes, attributes); + addLink(_link: Link): Span { + this.#otelSpan?.dropLink(); return this; } - setStatus(status: { code: number; message?: string }) { - if (this.#recording) { - if (status.code === 0) { - this.#status = null; - } else if (status.code > 2) { - throw new Error("Invalid status code"); - } else { - this.#status = status; - } + addLinks(links: Link[]): Span { + for (let i = 0; i < links.length; i++) { + this.#otelSpan?.dropLink(); } return this; } - updateName(name: string) { - if (this.#recording) this.#name = name; + end(endTime?: TimeInput): void { + if (endTime && ArrayIsArray(endTime)) { + endTime = hrToSecs(endTime); + } else if (endTime && isDate(endTime)) { + endTime = DatePrototypeGetTime(endTime); + } + this.#otelSpan?.end(endTime || NaN); + } + + isRecording(): boolean { + return this.#otelSpan !== undefined; + } + + // deno-lint-ignore no-explicit-any + recordException(_exception: any, _time?: TimeInput): Span { + this.#otelSpan?.dropEvent(); return this; } - addEvent(_name: never) { - // TODO(@lucacasonato): implement events - if (this.#recording) this.#droppedEventsCount += 1; + setAttribute(key: string, value: AttributeValue): Span { + if (!this.#otelSpan) return this; + op_otel_span_attribute1(this.#otelSpan, key, value); return this; } - addLink(_link: never) { - // TODO(@lucacasonato): implement links - if (this.#recording) this.#droppedLinksCount += 1; - return this; - } - - addLinks(links: never[]) { - // TODO(@lucacasonato): implement links - if (this.#recording) this.#droppedLinksCount += links.length; - return this; - } - - isRecording() { - return this.#recording; - } -} - -// Exporter compatible with opentelemetry js library -class SpanExporter { - export( - spans: ReadableSpan[], - resultCallback: (result: ExportResult) => void, - ) { - try { - for (let i = 0; i < spans.length; i += 1) { - const span = spans[i]; - const context = span.spanContext(); - submitSpan( - context.spanId, - context.traceId, - context.traceFlags, - span.parentSpanId ?? null, - span, - hrToSecs(span.startTime), - hrToSecs(span.endTime), + setAttributes(attributes: Attributes): Span { + if (!this.#otelSpan) return this; + const attributeKvs = ObjectEntries(attributes); + let i = 0; + while (i < attributeKvs.length) { + if (i + 2 < attributeKvs.length) { + op_otel_span_attribute3( + this.#otelSpan, + attributeKvs[i][0], + attributeKvs[i][1], + attributeKvs[i + 1][0], + attributeKvs[i + 1][1], + attributeKvs[i + 2][0], + attributeKvs[i + 2][1], ); + i += 3; + } else if (i + 1 < attributeKvs.length) { + op_otel_span_attribute2( + this.#otelSpan, + attributeKvs[i][0], + attributeKvs[i][1], + attributeKvs[i + 1][0], + attributeKvs[i + 1][1], + ); + i += 2; + } else { + op_otel_span_attribute1( + this.#otelSpan, + attributeKvs[i][0], + attributeKvs[i][1], + ); + i += 1; } - resultCallback({ code: 0 }); - } catch (error) { - resultCallback({ - code: 1, - error: ObjectPrototypeIsPrototypeOf(error, Error) - ? error as Error - : new Error(String(error)), - }); } + return this; } - async shutdown() {} + setStatus(status: SpanStatus): Span { + this.#otelSpan?.setStatus(status.code, status.message ?? ""); + return this; + } - async forceFlush() {} + updateName(name: string): Span { + if (!this.#otelSpan) return this; + op_otel_span_update_name(this.#otelSpan, name); + return this; + } } const CURRENT = new AsyncVariable(); class Context { + // @ts-ignore __proto__ is not supported in TypeScript #data: Record = { __proto__: null }; constructor(data?: Record | null | undefined) { + // @ts-ignore __proto__ is not supported in TypeScript this.#data = { __proto__: null, ...data }; } @@ -658,11 +478,15 @@ const ROOT_CONTEXT = new Context(); // Context manager for opentelemetry js library class ContextManager { - active(): Context { + constructor() { + throw new TypeError("ContextManager can not be constructed"); + } + + static active(): Context { return CURRENT.get() ?? ROOT_CONTEXT; } - with ReturnType>( + static with ReturnType>( context: Context, fn: F, thisArg?: ThisParameterType, @@ -677,7 +501,7 @@ class ContextManager { } // deno-lint-ignore no-explicit-any - bind any>( + static bind any>( context: Context, target: T, ): T { @@ -691,11 +515,11 @@ class ContextManager { }) as T; } - enable() { + static enable() { return this; } - disable() { + static disable() { return this; } } @@ -729,9 +553,50 @@ interface MetricAdvice { explicitBucketBoundaries?: number[]; } -export class MeterProvider { - getMeter(name: string, version?: string, options?: MeterOptions): Meter { - return new Meter({ name, version, schemaUrl: options?.schemaUrl }); +interface OtelMeter { + __key: "meter"; + createCounter(name: string, description?: string, unit?: string): Instrument; + createUpDownCounter( + name: string, + description?: string, + unit?: string, + ): Instrument; + createGauge(name: string, description?: string, unit?: string): Instrument; + createHistogram( + name: string, + description?: string, + unit?: string, + explicitBucketBoundaries?: number[], + ): Instrument; + createObservableCounter( + name: string, + description?: string, + unit?: string, + ): Instrument; + createObservableUpDownCounter( + name: string, + description?: string, + unit?: string, + ): Instrument; + createObservableGauge( + name: string, + description?: string, + unit?: string, + ): Instrument; +} + +class MeterProvider { + constructor() { + throw new TypeError("MeterProvider can not be constructed"); + } + + static getMeter( + name: string, + version?: string, + options?: MeterOptions, + ): Meter { + const meter = new OtelMeter(name, version, options?.schemaUrl); + return new Meter(meter); } } @@ -777,22 +642,18 @@ const BATCH_CALLBACKS = new SafeMap< const INDIVIDUAL_CALLBACKS = new SafeMap>(); class Meter { - #instrumentationLibrary: InstrumentationLibrary; + #meter: OtelMeter; - constructor(instrumentationLibrary: InstrumentationLibrary) { - this.#instrumentationLibrary = instrumentationLibrary; + constructor(meter: OtelMeter) { + this.#meter = meter; } - createCounter( - name: string, - options?: MetricOptions, - ): Counter { + createCounter(name: string, options?: MetricOptions): Counter { if (options?.valueType !== undefined && options?.valueType !== 1) { throw new Error("Only valueType: DOUBLE is supported"); } if (!METRICS_ENABLED) return new Counter(null, false); - activateInstrumentationLibrary(this.#instrumentationLibrary); - const instrument = op_otel_metric_create_counter( + const instrument = this.#meter.createCounter( name, // deno-lint-ignore prefer-primordials options?.description, @@ -801,16 +662,12 @@ class Meter { return new Counter(instrument, false); } - createUpDownCounter( - name: string, - options?: MetricOptions, - ): Counter { + createUpDownCounter(name: string, options?: MetricOptions): Counter { if (options?.valueType !== undefined && options?.valueType !== 1) { throw new Error("Only valueType: DOUBLE is supported"); } if (!METRICS_ENABLED) return new Counter(null, true); - activateInstrumentationLibrary(this.#instrumentationLibrary); - const instrument = op_otel_metric_create_up_down_counter( + const instrument = this.#meter.createUpDownCounter( name, // deno-lint-ignore prefer-primordials options?.description, @@ -819,16 +676,12 @@ class Meter { return new Counter(instrument, true); } - createGauge( - name: string, - options?: MetricOptions, - ): Gauge { + createGauge(name: string, options?: MetricOptions): Gauge { if (options?.valueType !== undefined && options?.valueType !== 1) { throw new Error("Only valueType: DOUBLE is supported"); } if (!METRICS_ENABLED) return new Gauge(null); - activateInstrumentationLibrary(this.#instrumentationLibrary); - const instrument = op_otel_metric_create_gauge( + const instrument = this.#meter.createGauge( name, // deno-lint-ignore prefer-primordials options?.description, @@ -837,16 +690,12 @@ class Meter { return new Gauge(instrument); } - createHistogram( - name: string, - options?: MetricOptions, - ): Histogram { + createHistogram(name: string, options?: MetricOptions): Histogram { if (options?.valueType !== undefined && options?.valueType !== 1) { throw new Error("Only valueType: DOUBLE is supported"); } if (!METRICS_ENABLED) return new Histogram(null); - activateInstrumentationLibrary(this.#instrumentationLibrary); - const instrument = op_otel_metric_create_histogram( + const instrument = this.#meter.createHistogram( name, // deno-lint-ignore prefer-primordials options?.description, @@ -856,16 +705,12 @@ class Meter { return new Histogram(instrument); } - createObservableCounter( - name: string, - options?: MetricOptions, - ): Observable { + createObservableCounter(name: string, options?: MetricOptions): Observable { if (options?.valueType !== undefined && options?.valueType !== 1) { throw new Error("Only valueType: DOUBLE is supported"); } if (!METRICS_ENABLED) new Observable(new ObservableResult(null, true)); - activateInstrumentationLibrary(this.#instrumentationLibrary); - const instrument = op_otel_metric_create_observable_counter( + const instrument = this.#meter.createObservableCounter( name, // deno-lint-ignore prefer-primordials options?.description, @@ -874,24 +719,6 @@ class Meter { return new Observable(new ObservableResult(instrument, true)); } - createObservableGauge( - name: string, - options?: MetricOptions, - ): Observable { - if (options?.valueType !== undefined && options?.valueType !== 1) { - throw new Error("Only valueType: DOUBLE is supported"); - } - if (!METRICS_ENABLED) new Observable(new ObservableResult(null, false)); - activateInstrumentationLibrary(this.#instrumentationLibrary); - const instrument = op_otel_metric_create_observable_gauge( - name, - // deno-lint-ignore prefer-primordials - options?.description, - options?.unit, - ) as Instrument; - return new Observable(new ObservableResult(instrument, false)); - } - createObservableUpDownCounter( name: string, options?: MetricOptions, @@ -900,8 +727,21 @@ class Meter { throw new Error("Only valueType: DOUBLE is supported"); } if (!METRICS_ENABLED) new Observable(new ObservableResult(null, false)); - activateInstrumentationLibrary(this.#instrumentationLibrary); - const instrument = op_otel_metric_create_observable_up_down_counter( + const instrument = this.#meter.createObservableUpDownCounter( + name, + // deno-lint-ignore prefer-primordials + options?.description, + options?.unit, + ) as Instrument; + return new Observable(new ObservableResult(instrument, false)); + } + + createObservableGauge(name: string, options?: MetricOptions): Observable { + if (options?.valueType !== undefined && options?.valueType !== 1) { + throw new Error("Only valueType: DOUBLE is supported"); + } + if (!METRICS_ENABLED) new Observable(new ObservableResult(null, false)); + const instrument = this.#meter.createObservableGauge( name, // deno-lint-ignore prefer-primordials options?.description, @@ -987,12 +827,7 @@ function record( ); i += 2; } else if (remaining === 1) { - op_otel_metric_record1( - instrument, - value, - attrs[i][0], - attrs[i][1], - ); + op_otel_metric_record1(instrument, value, attrs[i][0], attrs[i][1]); i += 1; } } @@ -1212,24 +1047,51 @@ const otelConsoleConfig = { replace: 2, }; +function otelLog(message: string, level: number) { + const currentSpan = CURRENT.get()?.getValue(SPAN_KEY); + const otelSpan = currentSpan !== undefined + ? getOtelSpan(currentSpan) + : undefined; + if (otelSpan || currentSpan === undefined) { + op_otel_log(message, level, otelSpan); + } else { + const spanContext = currentSpan.spanContext(); + op_otel_log_foreign( + message, + level, + spanContext.traceId, + spanContext.spanId, + spanContext.traceFlags, + ); + } +} + +let builtinTracerCache: Tracer; + +export function builtinTracer(): Tracer { + if (!builtinTracerCache) { + builtinTracerCache = new Tracer(OtelTracer.builtin()); + } + return builtinTracerCache; +} + +// We specify a very high version number, to allow any `@opentelemetry/api` +// version to load this module. This does cause @opentelemetry/api to not be +// able to register anything itself with the global registration methods. +const OTEL_API_COMPAT_VERSION = "1.999.999"; + export function bootstrap( config: [ 0 | 1, 0 | 1, - typeof otelConsoleConfig[keyof typeof otelConsoleConfig], + (typeof otelConsoleConfig)[keyof typeof otelConsoleConfig], 0 | 1, ], ): void { - const { - 0: tracingEnabled, - 1: metricsEnabled, - 2: consoleConfig, - 3: deterministic, - } = config; + const { 0: tracingEnabled, 1: metricsEnabled, 2: consoleConfig } = config; TRACING_ENABLED = tracingEnabled === 1; METRICS_ENABLED = metricsEnabled === 1; - DETERMINISTIC = deterministic === 1; switch (consoleConfig) { case otelConsoleConfig.capture: @@ -1245,10 +1107,23 @@ export function bootstrap( default: break; } + + if (TRACING_ENABLED || METRICS_ENABLED) { + const otel = globalThis[SymbolFor("opentelemetry.js.api.1")] ??= { + version: OTEL_API_COMPAT_VERSION, + }; + if (TRACING_ENABLED) { + otel.trace = TracerProvider; + otel.context = ContextManager; + } + if (METRICS_ENABLED) { + otel.metrics = MeterProvider; + } + } } export const telemetry = { - SpanExporter, - ContextManager, - MeterProvider, + tracerProvider: TracerProvider, + contextManager: ContextManager, + meterProvider: MeterProvider, }; diff --git a/ext/telemetry/util.ts b/ext/telemetry/util.ts index 7e30d5d859..ac233f7a9f 100644 --- a/ext/telemetry/util.ts +++ b/ext/telemetry/util.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { primordials } from "ext:core/mod.js"; import type { Span } from "ext:deno_telemetry/telemetry.ts"; diff --git a/ext/tls/Cargo.toml b/ext/tls/Cargo.toml index 6bf1b8ea03..8a9fdb00c0 100644 --- a/ext/tls/Cargo.toml +++ b/ext/tls/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_tls" -version = "0.171.0" +version = "0.173.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -15,6 +15,7 @@ path = "lib.rs" [dependencies] deno_core.workspace = true +deno_error.workspace = true deno_native_certs = "0.3.0" rustls.workspace = true rustls-pemfile.workspace = true diff --git a/ext/tls/lib.rs b/ext/tls/lib.rs index 883d2995e4..a3e386052e 100644 --- a/ext/tls/lib.rs +++ b/ext/tls/lib.rs @@ -1,47 +1,54 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -pub use deno_native_certs; -pub use rustls; -use rustls::pki_types::CertificateDer; -use rustls::pki_types::PrivateKeyDer; -use rustls::pki_types::ServerName; -pub use rustls_pemfile; -pub use rustls_tokio_stream::*; -pub use webpki; -pub use webpki_roots; - -use rustls::client::danger::HandshakeSignatureValid; -use rustls::client::danger::ServerCertVerified; -use rustls::client::danger::ServerCertVerifier; -use rustls::client::WebPkiServerVerifier; -use rustls::ClientConfig; -use rustls::DigitallySignedStruct; -use rustls::RootCertStore; -use rustls_pemfile::certs; -use rustls_pemfile::ec_private_keys; -use rustls_pemfile::pkcs8_private_keys; -use rustls_pemfile::rsa_private_keys; -use serde::Deserialize; +// Copyright 2018-2025 the Deno authors. MIT license. use std::io::BufRead; use std::io::BufReader; use std::io::Cursor; use std::net::IpAddr; use std::sync::Arc; +use deno_error::JsErrorBox; +pub use deno_native_certs; +pub use rustls; +use rustls::client::danger::HandshakeSignatureValid; +use rustls::client::danger::ServerCertVerified; +use rustls::client::danger::ServerCertVerifier; +use rustls::client::WebPkiServerVerifier; +use rustls::pki_types::CertificateDer; +use rustls::pki_types::PrivateKeyDer; +use rustls::pki_types::ServerName; +use rustls::ClientConfig; +use rustls::DigitallySignedStruct; +use rustls::RootCertStore; +pub use rustls_pemfile; +use rustls_pemfile::certs; +use rustls_pemfile::ec_private_keys; +use rustls_pemfile::pkcs8_private_keys; +use rustls_pemfile::rsa_private_keys; +pub use rustls_tokio_stream::*; +use serde::Deserialize; +pub use webpki; +pub use webpki_roots; + mod tls_key; pub use tls_key::*; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum TlsError { + #[class(generic)] #[error(transparent)] Rustls(#[from] rustls::Error), + #[class(inherit)] #[error("Unable to add pem file to certificate store: {0}")] UnableAddPemFileToCert(std::io::Error), + #[class("InvalidData")] #[error("Unable to decode certificate")] CertInvalid, + #[class("InvalidData")] #[error("No certificates found in certificate data")] CertsNotFound, + #[class("InvalidData")] #[error("No keys found in key data")] KeysNotFound, + #[class("InvalidData")] #[error("Unable to decode key")] KeyDecode, } @@ -51,9 +58,7 @@ pub enum TlsError { /// This was done because the root cert store is not needed in all cases /// and takes a bit of time to initialize. pub trait RootCertStoreProvider: Send + Sync { - fn get_or_try_init( - &self, - ) -> Result<&RootCertStore, deno_core::error::AnyError>; + fn get_or_try_init(&self) -> Result<&RootCertStore, JsErrorBox>; } // This extension has no runtime apis, it only exports some shared native functions. diff --git a/ext/tls/tls_key.rs b/ext/tls/tls_key.rs index b7baa604b9..dfd2863e5e 100644 --- a/ext/tls/tls_key.rs +++ b/ext/tls/tls_key.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. //! These represent the various types of TLS keys we support for both client and server //! connections. @@ -11,12 +11,6 @@ //! key lookup can handle closing one end of the pair, in which case they will just //! attempt to clean up the associated resources. -use deno_core::futures::future::poll_fn; -use deno_core::futures::future::Either; -use deno_core::futures::FutureExt; -use deno_core::unsync::spawn; -use rustls::ServerConfig; -use rustls_tokio_stream::ServerConfigProvider; use std::cell::RefCell; use std::collections::HashMap; use std::fmt::Debug; @@ -25,6 +19,13 @@ use std::future::Future; use std::io::ErrorKind; use std::rc::Rc; use std::sync::Arc; + +use deno_core::futures::future::poll_fn; +use deno_core::futures::future::Either; +use deno_core::futures::FutureExt; +use deno_core::unsync::spawn; +use rustls::ServerConfig; +use rustls_tokio_stream::ServerConfigProvider; use tokio::sync::broadcast; use tokio::sync::mpsc; use tokio::sync::oneshot; @@ -269,9 +270,10 @@ impl TlsKeyLookup { #[cfg(test)] pub mod tests { - use super::*; use deno_core::unsync::spawn; + use super::*; + fn tls_key_for_test(sni: &str) -> TlsKey { let manifest_dir = std::path::PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()); diff --git a/ext/url/00_url.js b/ext/url/00_url.js index ec875da768..c853430d1a 100644 --- a/ext/url/00_url.js +++ b/ext/url/00_url.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/url/01_urlpattern.js b/ext/url/01_urlpattern.js index 6e27563089..5febef3332 100644 --- a/ext/url/01_urlpattern.js +++ b/ext/url/01_urlpattern.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/url/Cargo.toml b/ext/url/Cargo.toml index 9ca3ce6752..b4500aad3c 100644 --- a/ext/url/Cargo.toml +++ b/ext/url/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_url" -version = "0.184.0" +version = "0.186.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -15,6 +15,7 @@ path = "lib.rs" [dependencies] deno_core.workspace = true +deno_error.workspace = true thiserror.workspace = true urlpattern = "0.3.0" diff --git a/ext/url/benches/url_ops.rs b/ext/url/benches/url_ops.rs index 70afb96db2..9295a08d51 100644 --- a/ext/url/benches/url_ops.rs +++ b/ext/url/benches/url_ops.rs @@ -1,10 +1,9 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_bench_util::bench_js_sync; use deno_bench_util::bench_or_profile; use deno_bench_util::bencher::benchmark_group; use deno_bench_util::bencher::Bencher; - use deno_core::Extension; fn setup() -> Vec { diff --git a/ext/url/internal.d.ts b/ext/url/internal.d.ts index 11bacb0e1b..69e0472e8e 100644 --- a/ext/url/internal.d.ts +++ b/ext/url/internal.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// /// diff --git a/ext/url/lib.deno_url.d.ts b/ext/url/lib.deno_url.d.ts index 946c70607f..08fe74cd66 100644 --- a/ext/url/lib.deno_url.d.ts +++ b/ext/url/lib.deno_url.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-explicit-any no-var diff --git a/ext/url/lib.rs b/ext/url/lib.rs index f8946532ae..dd74239d93 100644 --- a/ext/url/lib.rs +++ b/ext/url/lib.rs @@ -1,22 +1,20 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. mod urlpattern; -use deno_core::error::type_error; -use deno_core::error::AnyError; +use std::path::PathBuf; + use deno_core::op2; use deno_core::url::form_urlencoded; use deno_core::url::quirks; use deno_core::url::Url; use deno_core::JsBuffer; use deno_core::OpState; -use std::path::PathBuf; +use deno_error::JsErrorBox; use crate::urlpattern::op_urlpattern_parse; use crate::urlpattern::op_urlpattern_process_match_input; -pub use urlpattern::UrlPatternError; - deno_core::extension!( deno_url, deps = [deno_webidl], @@ -220,7 +218,7 @@ pub fn op_url_reparse( pub fn op_url_parse_search_params( #[string] args: Option, #[buffer] zero_copy: Option, -) -> Result, AnyError> { +) -> Result, JsErrorBox> { let params = match (args, zero_copy) { (None, Some(zero_copy)) => form_urlencoded::parse(&zero_copy) .into_iter() @@ -230,7 +228,7 @@ pub fn op_url_parse_search_params( .into_iter() .map(|(k, v)| (k.as_ref().to_owned(), v.as_ref().to_owned())) .collect(), - _ => return Err(type_error("invalid parameters")), + _ => return Err(JsErrorBox::type_error("invalid parameters")), }; Ok(params) } diff --git a/ext/url/urlpattern.rs b/ext/url/urlpattern.rs index 7d4e8ee71b..02034332cf 100644 --- a/ext/url/urlpattern.rs +++ b/ext/url/urlpattern.rs @@ -1,15 +1,12 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::op2; - use urlpattern::quirks; use urlpattern::quirks::MatchInput; use urlpattern::quirks::StringOrInit; use urlpattern::quirks::UrlPattern; -#[derive(Debug, thiserror::Error)] -#[error(transparent)] -pub struct UrlPatternError(urlpattern::Error); +deno_error::js_error_wrapper!(urlpattern::Error, UrlPatternError, "TypeError"); #[op2] #[serde] @@ -19,11 +16,9 @@ pub fn op_urlpattern_parse( #[serde] options: urlpattern::UrlPatternOptions, ) -> Result { let init = - quirks::process_construct_pattern_input(input, base_url.as_deref()) - .map_err(UrlPatternError)?; + quirks::process_construct_pattern_input(input, base_url.as_deref())?; - let pattern = - quirks::parse_pattern(init, options).map_err(UrlPatternError)?; + let pattern = quirks::parse_pattern(init, options)?; Ok(pattern) } @@ -34,8 +29,7 @@ pub fn op_urlpattern_process_match_input( #[serde] input: StringOrInit, #[string] base_url: Option, ) -> Result, UrlPatternError> { - let res = quirks::process_match_input(input, base_url.as_deref()) - .map_err(UrlPatternError)?; + let res = quirks::process_match_input(input, base_url.as_deref())?; let (input, inputs) = match res { Some((input, inputs)) => (input, inputs), diff --git a/ext/web/00_infra.js b/ext/web/00_infra.js index 9a75f8fa58..8ca42e86c2 100644 --- a/ext/web/00_infra.js +++ b/ext/web/00_infra.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/web/01_dom_exception.js b/ext/web/01_dom_exception.js index db2996e0c6..730fda860f 100644 --- a/ext/web/01_dom_exception.js +++ b/ext/web/01_dom_exception.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/web/01_mimesniff.js b/ext/web/01_mimesniff.js index e60783bbe1..9a687a8305 100644 --- a/ext/web/01_mimesniff.js +++ b/ext/web/01_mimesniff.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/web/02_event.js b/ext/web/02_event.js index f6351c4b9e..810e48537d 100644 --- a/ext/web/02_event.js +++ b/ext/web/02_event.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // This module follows most of the WHATWG Living Standard for the DOM logic. // Many parts of the DOM are not implemented in Deno, but the logic for those diff --git a/ext/web/02_structured_clone.js b/ext/web/02_structured_clone.js index 776a8ee96e..453700fc41 100644 --- a/ext/web/02_structured_clone.js +++ b/ext/web/02_structured_clone.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/web/02_timers.js b/ext/web/02_timers.js index 6058febd59..c74f9baff9 100644 --- a/ext/web/02_timers.js +++ b/ext/web/02_timers.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, primordials } from "ext:core/mod.js"; import { op_defer } from "ext:core/ops"; diff --git a/ext/web/03_abort_signal.js b/ext/web/03_abort_signal.js index 93b3cf0522..1f9ce42e1e 100644 --- a/ext/web/03_abort_signal.js +++ b/ext/web/03_abort_signal.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/web/04_global_interfaces.js b/ext/web/04_global_interfaces.js index 7c7f83b431..bda695b530 100644 --- a/ext/web/04_global_interfaces.js +++ b/ext/web/04_global_interfaces.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/web/05_base64.js b/ext/web/05_base64.js index e6796e1dc3..155201f853 100644 --- a/ext/web/05_base64.js +++ b/ext/web/05_base64.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index f3ac711fc7..950d46e829 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// @@ -908,7 +908,7 @@ const _original = Symbol("[[original]]"); * @param {boolean=} autoClose If the resource should be auto-closed when the stream closes. Defaults to true. * @returns {ReadableStream} */ -function readableStreamForRid(rid, autoClose = true, Super) { +function readableStreamForRid(rid, autoClose = true, Super, onError) { const stream = new (Super ?? ReadableStream)(_brand); stream[_resourceBacking] = { rid, autoClose }; @@ -947,7 +947,11 @@ function readableStreamForRid(rid, autoClose = true, Super) { controller.byobRequest.respond(bytesRead); } } catch (e) { - controller.error(e); + if (onError) { + onError(controller, e); + } else { + controller.error(e); + } tryClose(); } }, diff --git a/ext/web/06_streams_types.d.ts b/ext/web/06_streams_types.d.ts index fe05ee6e65..0a6cb6503a 100644 --- a/ext/web/06_streams_types.d.ts +++ b/ext/web/06_streams_types.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // ** Internal Interfaces ** diff --git a/ext/web/08_text_encoding.js b/ext/web/08_text_encoding.js index 3163c96282..8988c06c36 100644 --- a/ext/web/08_text_encoding.js +++ b/ext/web/08_text_encoding.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/web/09_file.js b/ext/web/09_file.js index 7c1d79ce31..cdad0b7396 100644 --- a/ext/web/09_file.js +++ b/ext/web/09_file.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/web/10_filereader.js b/ext/web/10_filereader.js index 2718606380..cecc6484a6 100644 --- a/ext/web/10_filereader.js +++ b/ext/web/10_filereader.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/web/12_location.js b/ext/web/12_location.js index ba0c47e2d1..cc1afb3d05 100644 --- a/ext/web/12_location.js +++ b/ext/web/12_location.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// diff --git a/ext/web/13_message_port.js b/ext/web/13_message_port.js index 79fec9de2f..f96cd193f4 100644 --- a/ext/web/13_message_port.js +++ b/ext/web/13_message_port.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/web/14_compression.js b/ext/web/14_compression.js index 1adb205b22..de49d7ad3d 100644 --- a/ext/web/14_compression.js +++ b/ext/web/14_compression.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/web/15_performance.js b/ext/web/15_performance.js index f23e851246..967cdda470 100644 --- a/ext/web/15_performance.js +++ b/ext/web/15_performance.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { primordials } from "ext:core/mod.js"; import { op_now, op_time_origin } from "ext:core/ops"; diff --git a/ext/web/16_image_data.js b/ext/web/16_image_data.js index 13df0d07be..bd69da7903 100644 --- a/ext/web/16_image_data.js +++ b/ext/web/16_image_data.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { primordials } from "ext:core/mod.js"; import * as webidl from "ext:deno_webidl/00_webidl.js"; diff --git a/ext/web/Cargo.toml b/ext/web/Cargo.toml index 44fb2e46bf..dda1e98b4b 100644 --- a/ext/web/Cargo.toml +++ b/ext/web/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_web" -version = "0.215.0" +version = "0.217.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -18,6 +18,7 @@ async-trait.workspace = true base64-simd = "0.8" bytes.workspace = true deno_core.workspace = true +deno_error.workspace = true deno_permissions.workspace = true encoding_rs.workspace = true flate2 = { workspace = true, features = ["default"] } diff --git a/ext/web/benches/encoding.rs b/ext/web/benches/encoding.rs index d0738c6452..42497ef3ce 100644 --- a/ext/web/benches/encoding.rs +++ b/ext/web/benches/encoding.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_bench_util::bench_js_sync; use deno_bench_util::bench_or_profile; diff --git a/ext/web/benches/timers_ops.rs b/ext/web/benches/timers_ops.rs index d39ee4eeae..a8a52ad916 100644 --- a/ext/web/benches/timers_ops.rs +++ b/ext/web/benches/timers_ops.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_bench_util::bench_js_async; use deno_bench_util::bench_or_profile; diff --git a/ext/web/blob.rs b/ext/web/blob.rs index bc64a0f27e..555e6da1cf 100644 --- a/ext/web/blob.rs +++ b/ext/web/blob.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::cell::RefCell; use std::collections::HashMap; @@ -17,14 +17,18 @@ use serde::Deserialize; use serde::Serialize; use uuid::Uuid; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum BlobError { + #[class(type)] #[error("Blob part not found")] BlobPartNotFound, + #[class(type)] #[error("start + len can not be larger than blob part size")] SizeLargerThanBlobPart, + #[class(type)] #[error("Blob URLs are not supported in this context")] BlobURLsNotSupported, + #[class(generic)] #[error(transparent)] Url(#[from] deno_core::url::ParseError), } diff --git a/ext/web/compression.rs b/ext/web/compression.rs index 6967009915..66662de74a 100644 --- a/ext/web/compression.rs +++ b/ext/web/compression.rs @@ -1,4 +1,7 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::cell::RefCell; +use std::io::Write; use deno_core::op2; use flate2::write::DeflateDecoder; @@ -8,17 +11,19 @@ use flate2::write::GzEncoder; use flate2::write::ZlibDecoder; use flate2::write::ZlibEncoder; use flate2::Compression; -use std::cell::RefCell; -use std::io::Write; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum CompressionError { + #[class(type)] #[error("Unsupported format")] UnsupportedFormat, + #[class(type)] #[error("resource is closed")] ResourceClosed, + #[class(type)] #[error(transparent)] IoTypeError(std::io::Error), + #[class(inherit)] #[error(transparent)] Io(std::io::Error), } diff --git a/ext/web/internal.d.ts b/ext/web/internal.d.ts index b2aea80d9f..64a8633854 100644 --- a/ext/web/internal.d.ts +++ b/ext/web/internal.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// /// diff --git a/ext/web/lib.deno_web.d.ts b/ext/web/lib.deno_web.d.ts index 8aafbad535..1fb003b66f 100644 --- a/ext/web/lib.deno_web.d.ts +++ b/ext/web/lib.deno_web.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-explicit-any no-var diff --git a/ext/web/lib.rs b/ext/web/lib.rs index af0fc2c276..7d22fa3b2a 100644 --- a/ext/web/lib.rs +++ b/ext/web/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. mod blob; mod compression; @@ -6,17 +6,6 @@ mod message_port; mod stream_resource; mod timers; -use deno_core::op2; -use deno_core::url::Url; -use deno_core::v8; -use deno_core::ByteString; -use deno_core::ToJsBuffer; -use deno_core::U16String; - -use encoding_rs::CoderResult; -use encoding_rs::Decoder; -use encoding_rs::DecoderResult; -use encoding_rs::Encoding; use std::borrow::Cow; use std::cell::RefCell; use std::path::PathBuf; @@ -24,6 +13,16 @@ use std::sync::Arc; pub use blob::BlobError; pub use compression::CompressionError; +use deno_core::op2; +use deno_core::url::Url; +use deno_core::v8; +use deno_core::ByteString; +use deno_core::ToJsBuffer; +use deno_core::U16String; +use encoding_rs::CoderResult; +use encoding_rs::Decoder; +use encoding_rs::DecoderResult; +use encoding_rs::Encoding; pub use message_port::MessagePortError; pub use stream_resource::StreamResourceError; @@ -38,7 +37,6 @@ pub use crate::blob::Blob; pub use crate::blob::BlobPart; pub use crate::blob::BlobStore; pub use crate::blob::InMemoryBlobPart; - pub use crate::message_port::create_entangled_message_port; pub use crate::message_port::deserialize_js_transferables; use crate::message_port::op_message_port_create_entangled; @@ -49,7 +47,6 @@ pub use crate::message_port::serialize_transferables; pub use crate::message_port::JsMessageData; pub use crate::message_port::MessagePort; pub use crate::message_port::Transferable; - use crate::timers::op_defer; use crate::timers::op_now; use crate::timers::op_time_origin; @@ -129,20 +126,27 @@ deno_core::extension!(deno_web, } ); -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum WebError { + #[class("DOMExceptionInvalidCharacterError")] #[error("Failed to decode base64")] Base64Decode, + #[class(range)] #[error("The encoding label provided ('{0}') is invalid.")] InvalidEncodingLabel(String), + #[class(type)] #[error("buffer exceeds maximum length")] BufferTooLong, + #[class(range)] #[error("Value too large to decode")] ValueTooLarge, + #[class(range)] #[error("Provided buffer too small")] BufferTooSmall, + #[class(type)] #[error("The encoded data is not valid")] DataInvalid, + #[class(generic)] #[error(transparent)] DataError(#[from] v8::DataError), } diff --git a/ext/web/message_port.rs b/ext/web/message_port.rs index 1a4a09073d..3d656fdea2 100644 --- a/ext/web/message_port.rs +++ b/ext/web/message_port.rs @@ -1,11 +1,10 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::cell::RefCell; use std::rc::Rc; use deno_core::op2; - use deno_core::CancelFuture; use deno_core::CancelHandle; use deno_core::DetachedBuffer; @@ -21,18 +20,23 @@ use tokio::sync::mpsc::unbounded_channel; use tokio::sync::mpsc::UnboundedReceiver; use tokio::sync::mpsc::UnboundedSender; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum MessagePortError { + #[class(type)] #[error("Invalid message port transfer")] InvalidTransfer, + #[class(type)] #[error("Message port is not ready for transfer")] NotReady, + #[class(type)] #[error("Can not transfer self message port")] TransferSelf, + #[class(inherit)] #[error(transparent)] Canceled(#[from] deno_core::Canceled), + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(deno_core::error::ResourceError), } pub enum Transferable { diff --git a/ext/web/stream_resource.rs b/ext/web/stream_resource.rs index c44a385ea9..edc842ff4d 100644 --- a/ext/web/stream_resource.rs +++ b/ext/web/stream_resource.rs @@ -1,4 +1,17 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. +use std::borrow::Cow; +use std::cell::RefCell; +use std::cell::RefMut; +use std::ffi::c_void; +use std::future::Future; +use std::marker::PhantomData; +use std::mem::MaybeUninit; +use std::pin::Pin; +use std::rc::Rc; +use std::task::Context; +use std::task::Poll; +use std::task::Waker; + use bytes::BytesMut; use deno_core::external; use deno_core::op2; @@ -17,23 +30,13 @@ use deno_core::Resource; use deno_core::ResourceId; use futures::future::poll_fn; use futures::TryFutureExt; -use std::borrow::Cow; -use std::cell::RefCell; -use std::cell::RefMut; -use std::ffi::c_void; -use std::future::Future; -use std::marker::PhantomData; -use std::mem::MaybeUninit; -use std::pin::Pin; -use std::rc::Rc; -use std::task::Context; -use std::task::Poll; -use std::task::Waker; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum StreamResourceError { + #[class(inherit)] #[error(transparent)] Canceled(#[from] deno_core::Canceled), + #[class(type)] #[error("{0}")] Js(String), } @@ -403,7 +406,10 @@ impl Resource for ReadableStreamResource { } fn read(self: Rc, limit: usize) -> AsyncResult { - Box::pin(ReadableStreamResource::read(self, limit).map_err(|e| e.into())) + Box::pin( + ReadableStreamResource::read(self, limit) + .map_err(deno_error::JsErrorBox::from_err), + ) } fn close(self: Rc) { @@ -607,13 +613,15 @@ impl Drop for ReadableStreamResourceData { #[cfg(test)] mod tests { - use super::*; - use deno_core::v8; use std::cell::OnceCell; use std::sync::atomic::AtomicUsize; use std::sync::OnceLock; use std::time::Duration; + use deno_core::v8; + + use super::*; + static V8_GLOBAL: OnceLock<()> = OnceLock::new(); thread_local! { diff --git a/ext/web/timers.rs b/ext/web/timers.rs index 06444ed34f..7929b6050e 100644 --- a/ext/web/timers.rs +++ b/ext/web/timers.rs @@ -1,14 +1,15 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. //! This module helps deno implement timers and performance APIs. -use deno_core::op2; -use deno_core::OpState; use std::time::Duration; use std::time::Instant; use std::time::SystemTime; use std::time::UNIX_EPOCH; +use deno_core::op2; +use deno_core::OpState; + pub trait TimersPermission { fn allow_hrtime(&mut self) -> bool; } diff --git a/ext/webgpu/00_init.js b/ext/webgpu/00_init.js index 0f10847cef..81bb27286d 100644 --- a/ext/webgpu/00_init.js +++ b/ext/webgpu/00_init.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core } from "ext:core/mod.js"; diff --git a/ext/webgpu/01_webgpu.js b/ext/webgpu/01_webgpu.js index d371f49ea1..5ce34a5e7b 100644 --- a/ext/webgpu/01_webgpu.js +++ b/ext/webgpu/01_webgpu.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/webgpu/02_surface.js b/ext/webgpu/02_surface.js index ce723b891f..b0561469a9 100644 --- a/ext/webgpu/02_surface.js +++ b/ext/webgpu/02_surface.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check /// diff --git a/ext/webgpu/Cargo.toml b/ext/webgpu/Cargo.toml index 3a491afcf8..7e8973cadd 100644 --- a/ext/webgpu/Cargo.toml +++ b/ext/webgpu/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_webgpu" -version = "0.151.0" +version = "0.153.0" authors = ["the Deno authors"] edition.workspace = true license = "MIT" @@ -21,6 +21,7 @@ vulkan-portability = [] # so the whole workspace can built as wasm. [target.'cfg(not(target_arch = "wasm32"))'.dependencies] deno_core.workspace = true +deno_error.workspace = true serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["full"] } wgpu-types = { workspace = true, features = ["serde"] } diff --git a/ext/webgpu/binding.rs b/ext/webgpu/binding.rs index 41708acc7f..c8441c64af 100644 --- a/ext/webgpu/binding.rs +++ b/ext/webgpu/binding.rs @@ -1,13 +1,14 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use deno_core::error::AnyError; +use std::borrow::Cow; +use std::rc::Rc; + +use deno_core::error::ResourceError; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; use serde::Deserialize; -use std::borrow::Cow; -use std::rc::Rc; use super::error::WebGpuResult; @@ -169,7 +170,7 @@ pub fn op_webgpu_create_bind_group_layout( #[smi] device_rid: ResourceId, #[string] label: Cow, #[serde] entries: Vec, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table @@ -208,7 +209,7 @@ pub fn op_webgpu_create_pipeline_layout( #[smi] device_rid: ResourceId, #[string] label: Cow, #[serde] bind_group_layouts: Vec, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table @@ -222,7 +223,7 @@ pub fn op_webgpu_create_pipeline_layout( state.resource_table.get::(rid)?; Ok(bind_group_layout.1) }) - .collect::, AnyError>>()?; + .collect::, ResourceError>>()?; let descriptor = wgpu_core::binding_model::PipelineLayoutDescriptor { label: Some(label), @@ -255,7 +256,7 @@ pub fn op_webgpu_create_bind_group( #[string] label: Cow, #[smi] layout: ResourceId, #[serde] entries: Vec, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table @@ -303,7 +304,7 @@ pub fn op_webgpu_create_bind_group( }, }) }) - .collect::, AnyError>>()?; + .collect::, ResourceError>>()?; let bind_group_layout = state.resource_table.get::(layout)?; diff --git a/ext/webgpu/buffer.rs b/ext/webgpu/buffer.rs index c2b53890e0..25a5606e12 100644 --- a/ext/webgpu/buffer.rs +++ b/ext/webgpu/buffer.rs @@ -1,9 +1,5 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use deno_core::op2; -use deno_core::OpState; -use deno_core::Resource; -use deno_core::ResourceId; use std::borrow::Cow; use std::cell::RefCell; use std::rc::Rc; @@ -11,14 +7,26 @@ use std::sync::Arc; use std::sync::Mutex; use std::time::Duration; +use deno_core::op2; +use deno_core::OpState; +use deno_core::Resource; +use deno_core::ResourceId; + use super::error::WebGpuResult; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum BufferError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource( + #[from] + #[inherit] + deno_core::error::ResourceError, + ), + #[class(type)] #[error("usage is not valid")] InvalidUsage, + #[class("DOMExceptionOperationError")] #[error(transparent)] Access(wgpu_core::resource::BufferAccessError), } @@ -57,8 +65,7 @@ pub fn op_webgpu_create_buffer( let instance = state.borrow::(); let device_resource = state .resource_table - .get::(device_rid) - .map_err(BufferError::Resource)?; + .get::(device_rid)?; let device = device_resource.1; let descriptor = wgpu_core::resource::BufferDescriptor { @@ -91,15 +98,12 @@ pub async fn op_webgpu_buffer_get_map_async( { let state_ = state.borrow(); let instance = state_.borrow::(); - let buffer_resource = state_ - .resource_table - .get::(buffer_rid) - .map_err(BufferError::Resource)?; + let buffer_resource = + state_.resource_table.get::(buffer_rid)?; let buffer = buffer_resource.1; let device_resource = state_ .resource_table - .get::(device_rid) - .map_err(BufferError::Resource)?; + .get::(device_rid)?; device = device_resource.1; let done_ = done.clone(); @@ -154,10 +158,7 @@ pub fn op_webgpu_buffer_get_mapped_range( #[buffer] buf: &mut [u8], ) -> Result { let instance = state.borrow::(); - let buffer_resource = state - .resource_table - .get::(buffer_rid) - .map_err(BufferError::Resource)?; + let buffer_resource = state.resource_table.get::(buffer_rid)?; let buffer = buffer_resource.1; let (slice_pointer, range_size) = @@ -191,13 +192,9 @@ pub fn op_webgpu_buffer_unmap( ) -> Result { let mapped_resource = state .resource_table - .take::(mapped_rid) - .map_err(BufferError::Resource)?; + .take::(mapped_rid)?; let instance = state.borrow::(); - let buffer_resource = state - .resource_table - .get::(buffer_rid) - .map_err(BufferError::Resource)?; + let buffer_resource = state.resource_table.get::(buffer_rid)?; let buffer = buffer_resource.1; if let Some(buf) = buf { diff --git a/ext/webgpu/bundle.rs b/ext/webgpu/bundle.rs index d9a5b29539..73c3c9f221 100644 --- a/ext/webgpu/bundle.rs +++ b/ext/webgpu/bundle.rs @@ -1,20 +1,28 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. +use std::borrow::Cow; +use std::cell::RefCell; +use std::rc::Rc; + +use deno_core::error::ResourceError; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; use serde::Deserialize; -use std::borrow::Cow; -use std::cell::RefCell; -use std::rc::Rc; use super::error::WebGpuResult; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum BundleError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource( + #[from] + #[inherit] + ResourceError, + ), + #[class(type)] #[error("size must be larger than 0")] InvalidSize, } @@ -59,7 +67,7 @@ pub struct CreateRenderBundleEncoderArgs { pub fn op_webgpu_create_render_bundle_encoder( state: &mut OpState, #[serde] args: CreateRenderBundleEncoderArgs, -) -> Result { +) -> Result { let device_resource = state .resource_table .get::(args.device_rid)?; @@ -106,7 +114,7 @@ pub fn op_webgpu_render_bundle_encoder_finish( state: &mut OpState, #[smi] render_bundle_encoder_rid: ResourceId, #[string] label: Cow, -) -> Result { +) -> Result { let render_bundle_encoder_resource = state .resource_table @@ -137,7 +145,7 @@ pub fn op_webgpu_render_bundle_encoder_set_bind_group( #[buffer] dynamic_offsets_data: &[u32], #[number] dynamic_offsets_data_start: usize, #[number] dynamic_offsets_data_length: usize, -) -> Result { +) -> Result { let bind_group_resource = state .resource_table @@ -177,7 +185,7 @@ pub fn op_webgpu_render_bundle_encoder_push_debug_group( state: &mut OpState, #[smi] render_bundle_encoder_rid: ResourceId, #[string] group_label: &str, -) -> Result { +) -> Result { let render_bundle_encoder_resource = state .resource_table @@ -201,7 +209,7 @@ pub fn op_webgpu_render_bundle_encoder_push_debug_group( pub fn op_webgpu_render_bundle_encoder_pop_debug_group( state: &mut OpState, #[smi] render_bundle_encoder_rid: ResourceId, -) -> Result { +) -> Result { let render_bundle_encoder_resource = state .resource_table @@ -220,7 +228,7 @@ pub fn op_webgpu_render_bundle_encoder_insert_debug_marker( state: &mut OpState, #[smi] render_bundle_encoder_rid: ResourceId, #[string] marker_label: &str, -) -> Result { +) -> Result { let render_bundle_encoder_resource = state .resource_table @@ -245,7 +253,7 @@ pub fn op_webgpu_render_bundle_encoder_set_pipeline( state: &mut OpState, #[smi] render_bundle_encoder_rid: ResourceId, #[smi] pipeline: ResourceId, -) -> Result { +) -> Result { let render_pipeline_resource = state .resource_table @@ -275,12 +283,11 @@ pub fn op_webgpu_render_bundle_encoder_set_index_buffer( ) -> Result { let buffer_resource = state .resource_table - .get::(buffer) - .map_err(BundleError::Resource)?; - let render_bundle_encoder_resource = state - .resource_table - .get::(render_bundle_encoder_rid) - .map_err(BundleError::Resource)?; + .get::(buffer)?; + let render_bundle_encoder_resource = + state + .resource_table + .get::(render_bundle_encoder_rid)?; let size = Some(std::num::NonZeroU64::new(size).ok_or(BundleError::InvalidSize)?); @@ -304,12 +311,11 @@ pub fn op_webgpu_render_bundle_encoder_set_vertex_buffer( ) -> Result { let buffer_resource = state .resource_table - .get::(buffer) - .map_err(BundleError::Resource)?; - let render_bundle_encoder_resource = state - .resource_table - .get::(render_bundle_encoder_rid) - .map_err(BundleError::Resource)?; + .get::(buffer)?; + let render_bundle_encoder_resource = + state + .resource_table + .get::(render_bundle_encoder_rid)?; let size = if let Some(size) = size { Some(std::num::NonZeroU64::new(size).ok_or(BundleError::InvalidSize)?) } else { @@ -336,7 +342,7 @@ pub fn op_webgpu_render_bundle_encoder_draw( instance_count: u32, first_vertex: u32, first_instance: u32, -) -> Result { +) -> Result { let render_bundle_encoder_resource = state .resource_table @@ -363,7 +369,7 @@ pub fn op_webgpu_render_bundle_encoder_draw_indexed( first_index: u32, base_vertex: i32, first_instance: u32, -) -> Result { +) -> Result { let render_bundle_encoder_resource = state .resource_table @@ -388,7 +394,7 @@ pub fn op_webgpu_render_bundle_encoder_draw_indirect( #[smi] render_bundle_encoder_rid: ResourceId, #[smi] indirect_buffer: ResourceId, #[number] indirect_offset: u64, -) -> Result { +) -> Result { let buffer_resource = state .resource_table .get::(indirect_buffer)?; diff --git a/ext/webgpu/byow.rs b/ext/webgpu/byow.rs index c9e1177b1e..e911e1402b 100644 --- a/ext/webgpu/byow.rs +++ b/ext/webgpu/byow.rs @@ -1,8 +1,5 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use deno_core::op2; -use deno_core::OpState; -use deno_core::ResourceId; use std::ffi::c_void; #[cfg(any( target_os = "linux", @@ -12,20 +9,29 @@ use std::ffi::c_void; ))] use std::ptr::NonNull; +use deno_core::op2; +use deno_core::OpState; +use deno_core::ResourceId; + use crate::surface::WebGpuSurface; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum ByowError { + #[class(type)] #[error("Cannot create surface outside of WebGPU context. Did you forget to call `navigator.gpu.requestAdapter()`?")] WebGPUNotInitiated, + #[class(type)] #[error("Invalid parameters")] InvalidParameters, + #[class(generic)] #[error(transparent)] CreateSurface(wgpu_core::instance::CreateSurfaceError), #[cfg(target_os = "windows")] + #[class(type)] #[error("Invalid system on Windows")] InvalidSystem, #[cfg(target_os = "macos")] + #[class(type)] #[error("Invalid system on macOS")] InvalidSystem, #[cfg(any( @@ -33,6 +39,7 @@ pub enum ByowError { target_os = "freebsd", target_os = "openbsd" ))] + #[class(type)] #[error("Invalid system on Linux/BSD")] InvalidSystem, #[cfg(any( @@ -41,6 +48,7 @@ pub enum ByowError { target_os = "freebsd", target_os = "openbsd" ))] + #[class(type)] #[error("window is null")] NullWindow, #[cfg(any( @@ -48,9 +56,11 @@ pub enum ByowError { target_os = "freebsd", target_os = "openbsd" ))] + #[class(type)] #[error("display is null")] NullDisplay, #[cfg(target_os = "macos")] + #[class(type)] #[error("ns_view is null")] NSViewDisplay, } @@ -198,6 +208,6 @@ fn raw_window( _system: &str, _window: *const c_void, _display: *const c_void, -) -> Result { - Err(deno_core::error::type_error("Unsupported platform")) +) -> Result { + Err(deno_error::JsErrorBox::type_error("Unsupported platform")) } diff --git a/ext/webgpu/command_encoder.rs b/ext/webgpu/command_encoder.rs index 4bee7aac30..9b6bb44ae8 100644 --- a/ext/webgpu/command_encoder.rs +++ b/ext/webgpu/command_encoder.rs @@ -1,17 +1,18 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::WebGpuQuerySet; -use deno_core::error::AnyError; +use std::borrow::Cow; +use std::cell::RefCell; +use std::rc::Rc; + +use deno_core::error::ResourceError; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; use serde::Deserialize; -use std::borrow::Cow; -use std::cell::RefCell; -use std::rc::Rc; use super::error::WebGpuResult; +use crate::WebGpuQuerySet; pub(crate) struct WebGpuCommandEncoder( pub(crate) super::Instance, @@ -49,7 +50,7 @@ pub fn op_webgpu_create_command_encoder( state: &mut OpState, #[smi] device_rid: ResourceId, #[string] label: Cow, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table @@ -109,7 +110,7 @@ pub fn op_webgpu_command_encoder_begin_render_pass( >, #[smi] occlusion_query_set: Option, #[serde] timestamp_writes: Option, -) -> Result { +) -> Result { let command_encoder_resource = state .resource_table .get::(command_encoder_rid)?; @@ -148,7 +149,7 @@ pub fn op_webgpu_command_encoder_begin_render_pass( }; Ok(rp_at) }) - .collect::, AnyError>>()?; + .collect::, ResourceError>>()?; let mut processed_depth_stencil_attachment = None; @@ -244,7 +245,7 @@ pub fn op_webgpu_command_encoder_begin_compute_pass( #[smi] command_encoder_rid: ResourceId, #[string] label: Cow, #[serde] timestamp_writes: Option, -) -> Result { +) -> Result { let command_encoder_resource = state .resource_table .get::(command_encoder_rid)?; @@ -294,7 +295,7 @@ pub fn op_webgpu_command_encoder_copy_buffer_to_buffer( #[smi] destination: ResourceId, #[number] destination_offset: u64, #[number] size: u64, -) -> Result { +) -> Result { let instance = state.borrow::(); let command_encoder_resource = state .resource_table @@ -346,7 +347,7 @@ pub fn op_webgpu_command_encoder_copy_buffer_to_texture( #[serde] source: GpuImageCopyBuffer, #[serde] destination: GpuImageCopyTexture, #[serde] copy_size: wgpu_types::Extent3d, -) -> Result { +) -> Result { let instance = state.borrow::(); let command_encoder_resource = state .resource_table @@ -391,7 +392,7 @@ pub fn op_webgpu_command_encoder_copy_texture_to_buffer( #[serde] source: GpuImageCopyTexture, #[serde] destination: GpuImageCopyBuffer, #[serde] copy_size: wgpu_types::Extent3d, -) -> Result { +) -> Result { let instance = state.borrow::(); let command_encoder_resource = state .resource_table @@ -436,7 +437,7 @@ pub fn op_webgpu_command_encoder_copy_texture_to_texture( #[serde] source: GpuImageCopyTexture, #[serde] destination: GpuImageCopyTexture, #[serde] copy_size: wgpu_types::Extent3d, -) -> Result { +) -> Result { let instance = state.borrow::(); let command_encoder_resource = state .resource_table @@ -479,7 +480,7 @@ pub fn op_webgpu_command_encoder_clear_buffer( #[smi] buffer_rid: ResourceId, #[number] offset: u64, #[number] size: u64, -) -> Result { +) -> Result { let instance = state.borrow::(); let command_encoder_resource = state .resource_table @@ -503,7 +504,7 @@ pub fn op_webgpu_command_encoder_push_debug_group( state: &mut OpState, #[smi] command_encoder_rid: ResourceId, #[string] group_label: &str, -) -> Result { +) -> Result { let instance = state.borrow::(); let command_encoder_resource = state .resource_table @@ -518,7 +519,7 @@ pub fn op_webgpu_command_encoder_push_debug_group( pub fn op_webgpu_command_encoder_pop_debug_group( state: &mut OpState, #[smi] command_encoder_rid: ResourceId, -) -> Result { +) -> Result { let instance = state.borrow::(); let command_encoder_resource = state .resource_table @@ -534,7 +535,7 @@ pub fn op_webgpu_command_encoder_insert_debug_marker( state: &mut OpState, #[smi] command_encoder_rid: ResourceId, #[string] marker_label: &str, -) -> Result { +) -> Result { let instance = state.borrow::(); let command_encoder_resource = state .resource_table @@ -554,7 +555,7 @@ pub fn op_webgpu_command_encoder_write_timestamp( #[smi] command_encoder_rid: ResourceId, #[smi] query_set: ResourceId, query_index: u32, -) -> Result { +) -> Result { let instance = state.borrow::(); let command_encoder_resource = state .resource_table @@ -581,7 +582,7 @@ pub fn op_webgpu_command_encoder_resolve_query_set( query_count: u32, #[smi] destination: ResourceId, #[number] destination_offset: u64, -) -> Result { +) -> Result { let instance = state.borrow::(); let command_encoder_resource = state .resource_table @@ -610,7 +611,7 @@ pub fn op_webgpu_command_encoder_finish( state: &mut OpState, #[smi] command_encoder_rid: ResourceId, #[string] label: Cow, -) -> Result { +) -> Result { let command_encoder_resource = state .resource_table .take::(command_encoder_rid)?; diff --git a/ext/webgpu/compute_pass.rs b/ext/webgpu/compute_pass.rs index 17043c7671..afa19b3fac 100644 --- a/ext/webgpu/compute_pass.rs +++ b/ext/webgpu/compute_pass.rs @@ -1,12 +1,13 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use deno_core::error::AnyError; +use std::borrow::Cow; +use std::cell::RefCell; + +use deno_core::error::ResourceError; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; -use std::borrow::Cow; -use std::cell::RefCell; use super::error::WebGpuResult; @@ -25,7 +26,7 @@ pub fn op_webgpu_compute_pass_set_pipeline( state: &mut OpState, #[smi] compute_pass_rid: ResourceId, #[smi] pipeline: ResourceId, -) -> Result { +) -> Result { let compute_pipeline_resource = state .resource_table @@ -50,7 +51,7 @@ pub fn op_webgpu_compute_pass_dispatch_workgroups( x: u32, y: u32, z: u32, -) -> Result { +) -> Result { let compute_pass_resource = state .resource_table .get::(compute_pass_rid)?; @@ -72,7 +73,7 @@ pub fn op_webgpu_compute_pass_dispatch_workgroups_indirect( #[smi] compute_pass_rid: ResourceId, #[smi] indirect_buffer: ResourceId, #[number] indirect_offset: u64, -) -> Result { +) -> Result { let buffer_resource = state .resource_table .get::(indirect_buffer)?; @@ -95,7 +96,7 @@ pub fn op_webgpu_compute_pass_end( state: &mut OpState, #[smi] command_encoder_rid: ResourceId, #[smi] compute_pass_rid: ResourceId, -) -> Result { +) -> Result { let command_encoder_resource = state .resource_table .get::( @@ -124,7 +125,7 @@ pub fn op_webgpu_compute_pass_set_bind_group( #[buffer] dynamic_offsets_data: &[u32], #[number] dynamic_offsets_data_start: usize, #[number] dynamic_offsets_data_length: usize, -) -> Result { +) -> Result { let bind_group_resource = state .resource_table @@ -158,7 +159,7 @@ pub fn op_webgpu_compute_pass_push_debug_group( state: &mut OpState, #[smi] compute_pass_rid: ResourceId, #[string] group_label: &str, -) -> Result { +) -> Result { let compute_pass_resource = state .resource_table .get::(compute_pass_rid)?; @@ -177,7 +178,7 @@ pub fn op_webgpu_compute_pass_push_debug_group( pub fn op_webgpu_compute_pass_pop_debug_group( state: &mut OpState, #[smi] compute_pass_rid: ResourceId, -) -> Result { +) -> Result { let compute_pass_resource = state .resource_table .get::(compute_pass_rid)?; @@ -195,7 +196,7 @@ pub fn op_webgpu_compute_pass_insert_debug_marker( state: &mut OpState, #[smi] compute_pass_rid: ResourceId, #[string] marker_label: &str, -) -> Result { +) -> Result { let compute_pass_resource = state .resource_table .get::(compute_pass_rid)?; diff --git a/ext/webgpu/error.rs b/ext/webgpu/error.rs index f08f765386..f022a56916 100644 --- a/ext/webgpu/error.rs +++ b/ext/webgpu/error.rs @@ -1,9 +1,10 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::convert::From; +use std::error::Error; use deno_core::ResourceId; use serde::Serialize; -use std::convert::From; -use std::error::Error; use wgpu_core::binding_model::CreateBindGroupError; use wgpu_core::binding_model::CreateBindGroupLayoutError; use wgpu_core::binding_model::CreatePipelineLayoutError; diff --git a/ext/webgpu/lib.rs b/ext/webgpu/lib.rs index 5dc8278e41..afcd808f74 100644 --- a/ext/webgpu/lib.rs +++ b/ext/webgpu/lib.rs @@ -1,22 +1,22 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. #![cfg(not(target_arch = "wasm32"))] #![warn(unsafe_op_in_unsafe_fn)] +use std::borrow::Cow; +use std::cell::RefCell; +use std::collections::HashSet; +use std::rc::Rc; + use deno_core::op2; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; +use error::WebGpuResult; use serde::Deserialize; use serde::Serialize; -use std::borrow::Cow; -use std::cell::RefCell; -use std::collections::HashSet; -use std::rc::Rc; pub use wgpu_core; pub use wgpu_types; -use error::WebGpuResult; - pub const UNSTABLE_FEATURE_NAME: &str = "webgpu"; #[macro_use] @@ -83,14 +83,22 @@ pub mod shader; pub mod surface; pub mod texture; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum InitError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource( + #[from] + #[inherit] + deno_core::error::ResourceError, + ), + #[class(generic)] #[error(transparent)] InvalidAdapter(wgpu_core::instance::InvalidAdapter), + #[class("DOMExceptionOperationError")] #[error(transparent)] RequestDevice(wgpu_core::instance::RequestDeviceError), + #[class(generic)] #[error(transparent)] InvalidDevice(wgpu_core::device::InvalidDevice), } @@ -676,10 +684,8 @@ pub fn op_webgpu_request_device( #[serde] required_limits: Option, ) -> Result { let mut state = state.borrow_mut(); - let adapter_resource = state - .resource_table - .take::(adapter_rid) - .map_err(InitError::Resource)?; + let adapter_resource = + state.resource_table.take::(adapter_rid)?; let adapter = adapter_resource.1; let instance = state.borrow::(); @@ -738,10 +744,8 @@ pub fn op_webgpu_request_adapter_info( #[smi] adapter_rid: ResourceId, ) -> Result { let state = state.borrow_mut(); - let adapter_resource = state - .resource_table - .get::(adapter_rid) - .map_err(InitError::Resource)?; + let adapter_resource = + state.resource_table.get::(adapter_rid)?; let adapter = adapter_resource.1; let instance = state.borrow::(); @@ -788,10 +792,8 @@ pub fn op_webgpu_create_query_set( state: &mut OpState, #[serde] args: CreateQuerySetArgs, ) -> Result { - let device_resource = state - .resource_table - .get::(args.device_rid) - .map_err(InitError::Resource)?; + let device_resource = + state.resource_table.get::(args.device_rid)?; let device = device_resource.1; let instance = state.borrow::(); diff --git a/ext/webgpu/pipeline.rs b/ext/webgpu/pipeline.rs index a6b0cb8cec..07452a1caf 100644 --- a/ext/webgpu/pipeline.rs +++ b/ext/webgpu/pipeline.rs @@ -1,15 +1,16 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use deno_core::error::AnyError; +use std::borrow::Cow; +use std::collections::HashMap; +use std::rc::Rc; + +use deno_core::error::ResourceError; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; use serde::Deserialize; use serde::Serialize; -use std::borrow::Cow; -use std::collections::HashMap; -use std::rc::Rc; use super::error::WebGpuError; use super::error::WebGpuResult; @@ -87,7 +88,7 @@ pub fn op_webgpu_create_compute_pipeline( #[string] label: Cow, #[serde] layout: GPUPipelineLayoutOrGPUAutoLayoutMode, #[serde] compute: GpuProgrammableStage, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table @@ -155,7 +156,7 @@ pub fn op_webgpu_compute_pipeline_get_bind_group_layout( state: &mut OpState, #[smi] compute_pipeline_rid: ResourceId, index: u32, -) -> Result { +) -> Result { let instance = state.borrow::(); let compute_pipeline_resource = state .resource_table @@ -334,7 +335,7 @@ pub struct CreateRenderPipelineArgs { pub fn op_webgpu_create_render_pipeline( state: &mut OpState, #[serde] args: CreateRenderPipelineArgs, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table @@ -433,7 +434,7 @@ pub fn op_webgpu_render_pipeline_get_bind_group_layout( state: &mut OpState, #[smi] render_pipeline_rid: ResourceId, index: u32, -) -> Result { +) -> Result { let instance = state.borrow::(); let render_pipeline_resource = state .resource_table diff --git a/ext/webgpu/queue.rs b/ext/webgpu/queue.rs index 8c8bbec95e..51f4c4e009 100644 --- a/ext/webgpu/queue.rs +++ b/ext/webgpu/queue.rs @@ -1,17 +1,18 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::command_encoder::WebGpuCommandBuffer; -use crate::Instance; -use deno_core::error::AnyError; +use std::borrow::Cow; +use std::rc::Rc; + +use deno_core::error::ResourceError; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; use serde::Deserialize; -use std::borrow::Cow; -use std::rc::Rc; use super::error::WebGpuResult; +use crate::command_encoder::WebGpuCommandBuffer; +use crate::Instance; pub struct WebGpuQueue(pub Instance, pub wgpu_core::id::QueueId); impl Resource for WebGpuQueue { @@ -30,7 +31,7 @@ pub fn op_webgpu_queue_submit( state: &mut OpState, #[smi] queue_rid: ResourceId, #[serde] command_buffers: Vec, -) -> Result { +) -> Result { let instance = state.borrow::(); let queue_resource = state.resource_table.get::(queue_rid)?; let queue = queue_resource.1; @@ -43,7 +44,7 @@ pub fn op_webgpu_queue_submit( let mut id = buffer_resource.1.borrow_mut(); Ok(id.take().unwrap()) }) - .collect::, AnyError>>()?; + .collect::, ResourceError>>()?; let maybe_err = gfx_select!(queue => instance.queue_submit(queue, &ids)).err(); @@ -84,7 +85,7 @@ pub fn op_webgpu_write_buffer( #[number] data_offset: usize, #[number] size: Option, #[buffer] buf: &[u8], -) -> Result { +) -> Result { let instance = state.borrow::(); let buffer_resource = state .resource_table @@ -117,7 +118,7 @@ pub fn op_webgpu_write_texture( #[serde] data_layout: GpuImageDataLayout, #[serde] size: wgpu_types::Extent3d, #[buffer] buf: &[u8], -) -> Result { +) -> Result { let instance = state.borrow::(); let texture_resource = state .resource_table diff --git a/ext/webgpu/render_pass.rs b/ext/webgpu/render_pass.rs index 9b9d87d9fc..43c4cae846 100644 --- a/ext/webgpu/render_pass.rs +++ b/ext/webgpu/render_pass.rs @@ -1,19 +1,27 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. +use std::borrow::Cow; +use std::cell::RefCell; + +use deno_core::error::ResourceError; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; use serde::Deserialize; -use std::borrow::Cow; -use std::cell::RefCell; use super::error::WebGpuResult; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum RenderPassError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource( + #[from] + #[inherit] + ResourceError, + ), + #[class(type)] #[error("size must be larger than 0")] InvalidSize, } @@ -44,7 +52,7 @@ pub struct RenderPassSetViewportArgs { pub fn op_webgpu_render_pass_set_viewport( state: &mut OpState, #[serde] args: RenderPassSetViewportArgs, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(args.render_pass_rid)?; @@ -71,7 +79,7 @@ pub fn op_webgpu_render_pass_set_scissor_rect( y: u32, width: u32, height: u32, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -93,7 +101,7 @@ pub fn op_webgpu_render_pass_set_blend_constant( state: &mut OpState, #[smi] render_pass_rid: ResourceId, #[serde] color: wgpu_types::Color, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -112,7 +120,7 @@ pub fn op_webgpu_render_pass_set_stencil_reference( state: &mut OpState, #[smi] render_pass_rid: ResourceId, reference: u32, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -131,7 +139,7 @@ pub fn op_webgpu_render_pass_begin_occlusion_query( state: &mut OpState, #[smi] render_pass_rid: ResourceId, query_index: u32, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -149,7 +157,7 @@ pub fn op_webgpu_render_pass_begin_occlusion_query( pub fn op_webgpu_render_pass_end_occlusion_query( state: &mut OpState, #[smi] render_pass_rid: ResourceId, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -167,7 +175,7 @@ pub fn op_webgpu_render_pass_execute_bundles( state: &mut OpState, #[smi] render_pass_rid: ResourceId, #[serde] bundles: Vec, -) -> Result { +) -> Result { let bundles = bundles .iter() .map(|rid| { @@ -177,7 +185,7 @@ pub fn op_webgpu_render_pass_execute_bundles( .get::(*rid)?; Ok(render_bundle_resource.1) }) - .collect::, deno_core::error::AnyError>>()?; + .collect::, ResourceError>>()?; let render_pass_resource = state .resource_table @@ -197,7 +205,7 @@ pub fn op_webgpu_render_pass_end( state: &mut OpState, #[smi] command_encoder_rid: ResourceId, #[smi] render_pass_rid: ResourceId, -) -> Result { +) -> Result { let command_encoder_resource = state .resource_table .get::( @@ -223,7 +231,7 @@ pub fn op_webgpu_render_pass_set_bind_group( #[buffer] dynamic_offsets_data: &[u32], #[number] dynamic_offsets_data_start: usize, #[number] dynamic_offsets_data_length: usize, -) -> Result { +) -> Result { let bind_group_resource = state .resource_table @@ -257,7 +265,7 @@ pub fn op_webgpu_render_pass_push_debug_group( state: &mut OpState, #[smi] render_pass_rid: ResourceId, #[string] group_label: &str, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -276,7 +284,7 @@ pub fn op_webgpu_render_pass_push_debug_group( pub fn op_webgpu_render_pass_pop_debug_group( state: &mut OpState, #[smi] render_pass_rid: ResourceId, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -294,7 +302,7 @@ pub fn op_webgpu_render_pass_insert_debug_marker( state: &mut OpState, #[smi] render_pass_rid: ResourceId, #[string] marker_label: &str, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -314,7 +322,7 @@ pub fn op_webgpu_render_pass_set_pipeline( state: &mut OpState, #[smi] render_pass_rid: ResourceId, pipeline: u32, -) -> Result { +) -> Result { let render_pipeline_resource = state .resource_table @@ -343,12 +351,10 @@ pub fn op_webgpu_render_pass_set_index_buffer( ) -> Result { let buffer_resource = state .resource_table - .get::(buffer) - .map_err(RenderPassError::Resource)?; + .get::(buffer)?; let render_pass_resource = state .resource_table - .get::(render_pass_rid) - .map_err(RenderPassError::Resource)?; + .get::(render_pass_rid)?; let size = if let Some(size) = size { Some(std::num::NonZeroU64::new(size).ok_or(RenderPassError::InvalidSize)?) @@ -378,12 +384,10 @@ pub fn op_webgpu_render_pass_set_vertex_buffer( ) -> Result { let buffer_resource = state .resource_table - .get::(buffer) - .map_err(RenderPassError::Resource)?; + .get::(buffer)?; let render_pass_resource = state .resource_table - .get::(render_pass_rid) - .map_err(RenderPassError::Resource)?; + .get::(render_pass_rid)?; let size = if let Some(size) = size { Some(std::num::NonZeroU64::new(size).ok_or(RenderPassError::InvalidSize)?) @@ -411,7 +415,7 @@ pub fn op_webgpu_render_pass_draw( instance_count: u32, first_vertex: u32, first_instance: u32, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -437,7 +441,7 @@ pub fn op_webgpu_render_pass_draw_indexed( first_index: u32, base_vertex: i32, first_instance: u32, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -461,7 +465,7 @@ pub fn op_webgpu_render_pass_draw_indirect( #[smi] render_pass_rid: ResourceId, indirect_buffer: u32, #[number] indirect_offset: u64, -) -> Result { +) -> Result { let buffer_resource = state .resource_table .get::(indirect_buffer)?; @@ -485,7 +489,7 @@ pub fn op_webgpu_render_pass_draw_indexed_indirect( #[smi] render_pass_rid: ResourceId, indirect_buffer: u32, #[number] indirect_offset: u64, -) -> Result { +) -> Result { let buffer_resource = state .resource_table .get::(indirect_buffer)?; diff --git a/ext/webgpu/sampler.rs b/ext/webgpu/sampler.rs index 9fc1269ea7..88c1947e63 100644 --- a/ext/webgpu/sampler.rs +++ b/ext/webgpu/sampler.rs @@ -1,12 +1,13 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::borrow::Cow; +use std::rc::Rc; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; use serde::Deserialize; -use std::borrow::Cow; -use std::rc::Rc; use super::error::WebGpuResult; @@ -46,7 +47,7 @@ pub struct CreateSamplerArgs { pub fn op_webgpu_create_sampler( state: &mut OpState, #[serde] args: CreateSamplerArgs, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table diff --git a/ext/webgpu/shader.rs b/ext/webgpu/shader.rs index 4653bd85bf..84615ea6f6 100644 --- a/ext/webgpu/shader.rs +++ b/ext/webgpu/shader.rs @@ -1,11 +1,12 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::borrow::Cow; +use std::rc::Rc; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; -use std::borrow::Cow; -use std::rc::Rc; use super::error::WebGpuResult; @@ -30,7 +31,7 @@ pub fn op_webgpu_create_shader_module( #[smi] device_rid: ResourceId, #[string] label: Cow, #[string] code: Cow, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table diff --git a/ext/webgpu/surface.rs b/ext/webgpu/surface.rs index 297eaeb008..23e617c7de 100644 --- a/ext/webgpu/surface.rs +++ b/ext/webgpu/surface.rs @@ -1,21 +1,31 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use super::WebGpuResult; +use std::borrow::Cow; +use std::rc::Rc; + +use deno_core::error::ResourceError; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; use serde::Deserialize; -use std::borrow::Cow; -use std::rc::Rc; use wgpu_types::SurfaceStatus; -#[derive(Debug, thiserror::Error)] +use crate::error::WebGpuResult; + +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum SurfaceError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource( + #[from] + #[inherit] + ResourceError, + ), + #[class(generic)] #[error("Invalid Surface Status")] InvalidStatus, + #[class(generic)] #[error(transparent)] Surface(wgpu_core::present::SurfaceError), } @@ -50,7 +60,7 @@ pub struct SurfaceConfigureArgs { pub fn op_webgpu_surface_configure( state: &mut OpState, #[serde] args: SurfaceConfigureArgs, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table @@ -88,13 +98,10 @@ pub fn op_webgpu_surface_get_current_texture( let instance = state.borrow::(); let device_resource = state .resource_table - .get::(device_rid) - .map_err(SurfaceError::Resource)?; + .get::(device_rid)?; let device = device_resource.1; - let surface_resource = state - .resource_table - .get::(surface_rid) - .map_err(SurfaceError::Resource)?; + let surface_resource = + state.resource_table.get::(surface_rid)?; let surface = surface_resource.1; let output = @@ -124,13 +131,10 @@ pub fn op_webgpu_surface_present( let instance = state.borrow::(); let device_resource = state .resource_table - .get::(device_rid) - .map_err(SurfaceError::Resource)?; + .get::(device_rid)?; let device = device_resource.1; - let surface_resource = state - .resource_table - .get::(surface_rid) - .map_err(SurfaceError::Resource)?; + let surface_resource = + state.resource_table.get::(surface_rid)?; let surface = surface_resource.1; let _ = gfx_select!(device => instance.surface_present(surface)) diff --git a/ext/webgpu/texture.rs b/ext/webgpu/texture.rs index f8a5e05a3e..10c5d902ee 100644 --- a/ext/webgpu/texture.rs +++ b/ext/webgpu/texture.rs @@ -1,12 +1,13 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::borrow::Cow; +use std::rc::Rc; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; use serde::Deserialize; -use std::borrow::Cow; -use std::rc::Rc; use super::error::WebGpuResult; pub(crate) struct WebGpuTexture { @@ -61,7 +62,7 @@ pub struct CreateTextureArgs { pub fn op_webgpu_create_texture( state: &mut OpState, #[serde] args: CreateTextureArgs, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table @@ -110,7 +111,7 @@ pub struct CreateTextureViewArgs { pub fn op_webgpu_create_texture_view( state: &mut OpState, #[serde] args: CreateTextureViewArgs, -) -> Result { +) -> Result { let instance = state.borrow::(); let texture_resource = state .resource_table diff --git a/ext/webidl/00_webidl.js b/ext/webidl/00_webidl.js index eb18cbcc3e..b3c3b299f0 100644 --- a/ext/webidl/00_webidl.js +++ b/ext/webidl/00_webidl.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Adapted from https://github.com/jsdom/webidl-conversions. // Copyright Domenic Denicola. Licensed under BSD-2-Clause License. diff --git a/ext/webidl/Cargo.toml b/ext/webidl/Cargo.toml index 60cb9f29f8..07ceb492b5 100644 --- a/ext/webidl/Cargo.toml +++ b/ext/webidl/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_webidl" -version = "0.184.0" +version = "0.186.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/webidl/benches/dict.js b/ext/webidl/benches/dict.js index 9e7367d62c..8aedc51235 100644 --- a/ext/webidl/benches/dict.js +++ b/ext/webidl/benches/dict.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file diff --git a/ext/webidl/benches/dict.rs b/ext/webidl/benches/dict.rs index cfb658fa84..aea491cf12 100644 --- a/ext/webidl/benches/dict.rs +++ b/ext/webidl/benches/dict.rs @@ -1,10 +1,9 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_bench_util::bench_js_sync; use deno_bench_util::bench_or_profile; use deno_bench_util::bencher::benchmark_group; use deno_bench_util::bencher::Bencher; - use deno_core::Extension; fn setup() -> Vec { diff --git a/ext/webidl/internal.d.ts b/ext/webidl/internal.d.ts index 375d548d32..a884d982aa 100644 --- a/ext/webidl/internal.d.ts +++ b/ext/webidl/internal.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-explicit-any /// diff --git a/ext/webidl/lib.rs b/ext/webidl/lib.rs index 51dbed33a5..7a3608def4 100644 --- a/ext/webidl/lib.rs +++ b/ext/webidl/lib.rs @@ -1,3 +1,3 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. deno_core::extension!(deno_webidl, esm = ["00_webidl.js"],); diff --git a/ext/websocket/01_websocket.js b/ext/websocket/01_websocket.js index 78572f5f00..e0db51f4be 100644 --- a/ext/websocket/01_websocket.js +++ b/ext/websocket/01_websocket.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// diff --git a/ext/websocket/02_websocketstream.js b/ext/websocket/02_websocketstream.js index 838ae3d4ce..a1b76fb6c0 100644 --- a/ext/websocket/02_websocketstream.js +++ b/ext/websocket/02_websocketstream.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// diff --git a/ext/websocket/Cargo.toml b/ext/websocket/Cargo.toml index 8b8359f074..39b400a7ac 100644 --- a/ext/websocket/Cargo.toml +++ b/ext/websocket/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_websocket" -version = "0.189.0" +version = "0.191.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -16,6 +16,7 @@ path = "lib.rs" [dependencies] bytes.workspace = true deno_core.workspace = true +deno_error.workspace = true deno_net.workspace = true deno_permissions.workspace = true deno_tls.workspace = true diff --git a/ext/websocket/autobahn/autobahn_server.js b/ext/websocket/autobahn/autobahn_server.js index 7400c8d547..1c0d4bbaf6 100644 --- a/ext/websocket/autobahn/autobahn_server.js +++ b/ext/websocket/autobahn/autobahn_server.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { parseArgs } from "@std/cli/parse-args"; const { port } = parseArgs(Deno.args, { diff --git a/ext/websocket/autobahn/fuzzingclient.js b/ext/websocket/autobahn/fuzzingclient.js index fed0fd6aa9..8602319650 100644 --- a/ext/websocket/autobahn/fuzzingclient.js +++ b/ext/websocket/autobahn/fuzzingclient.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file diff --git a/ext/websocket/lib.deno_websocket.d.ts b/ext/websocket/lib.deno_websocket.d.ts index fb7ea6070c..28cf8b8ab3 100644 --- a/ext/websocket/lib.deno_websocket.d.ts +++ b/ext/websocket/lib.deno_websocket.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-explicit-any no-var diff --git a/ext/websocket/lib.rs b/ext/websocket/lib.rs index 5aef1a7a55..deb424c9be 100644 --- a/ext/websocket/lib.rs +++ b/ext/websocket/lib.rs @@ -1,5 +1,13 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use crate::stream::WebSocketStream; +// Copyright 2018-2025 the Deno authors. MIT license. +use std::borrow::Cow; +use std::cell::Cell; +use std::cell::RefCell; +use std::future::Future; +use std::num::NonZeroUsize; +use std::path::PathBuf; +use std::rc::Rc; +use std::sync::Arc; + use bytes::Bytes; use deno_core::futures::TryFutureExt; use deno_core::op2; @@ -16,13 +24,22 @@ use deno_core::RcRef; use deno_core::Resource; use deno_core::ResourceId; use deno_core::ToJsBuffer; +use deno_error::JsErrorBox; use deno_net::raw::NetworkStream; +use deno_permissions::PermissionCheckError; use deno_tls::create_client_config; use deno_tls::rustls::ClientConfig; use deno_tls::rustls::ClientConnection; use deno_tls::RootCertStoreProvider; use deno_tls::SocketUse; use deno_tls::TlsKeys; +use fastwebsockets::CloseCode; +use fastwebsockets::FragmentCollectorRead; +use fastwebsockets::Frame; +use fastwebsockets::OpCode; +use fastwebsockets::Role; +use fastwebsockets::WebSocket; +use fastwebsockets::WebSocketWrite; use http::header::CONNECTION; use http::header::UPGRADE; use http::HeaderName; @@ -36,28 +53,13 @@ use rustls_tokio_stream::rustls::pki_types::ServerName; use rustls_tokio_stream::rustls::RootCertStore; use rustls_tokio_stream::TlsStream; use serde::Serialize; -use std::borrow::Cow; -use std::cell::Cell; -use std::cell::RefCell; -use std::future::Future; -use std::num::NonZeroUsize; -use std::path::PathBuf; -use std::rc::Rc; -use std::sync::Arc; use tokio::io::AsyncRead; use tokio::io::AsyncWrite; use tokio::io::ReadHalf; use tokio::io::WriteHalf; use tokio::net::TcpStream; -use deno_permissions::PermissionCheckError; -use fastwebsockets::CloseCode; -use fastwebsockets::FragmentCollectorRead; -use fastwebsockets::Frame; -use fastwebsockets::OpCode; -use fastwebsockets::Role; -use fastwebsockets::WebSocket; -use fastwebsockets::WebSocketWrite; +use crate::stream::WebSocketStream; mod stream; @@ -71,22 +73,30 @@ static USE_WRITEV: Lazy = Lazy::new(|| { false }); -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum WebsocketError { + #[class(inherit)] #[error(transparent)] Url(url::ParseError), + #[class(inherit)] #[error(transparent)] Permission(#[from] PermissionCheckError), + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] deno_core::error::ResourceError), + #[class(generic)] #[error(transparent)] Uri(#[from] http::uri::InvalidUri), + #[class(inherit)] #[error("{0}")] Io(#[from] std::io::Error), + #[class(type)] #[error(transparent)] WebSocket(#[from] fastwebsockets::WebSocketError), + #[class("DOMExceptionNetworkError")] #[error("failed to connect to WebSocket: {0}")] ConnectionFailed(#[from] HandshakeError), + #[class(inherit)] #[error(transparent)] Canceled(#[from] deno_core::Canceled), } @@ -95,9 +105,7 @@ pub enum WebsocketError { pub struct WsRootStoreProvider(Option>); impl WsRootStoreProvider { - pub fn get_or_try_init( - &self, - ) -> Result, deno_core::error::AnyError> { + pub fn get_or_try_init(&self) -> Result, JsErrorBox> { Ok(match &self.0 { Some(provider) => Some(provider.get_or_try_init()?.clone()), None => None, @@ -182,32 +190,45 @@ pub struct CreateResponse { extensions: String, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum HandshakeError { + #[class(type)] #[error("Missing path in url")] MissingPath, + #[class(generic)] #[error("Invalid status code {0}")] InvalidStatusCode(StatusCode), + #[class(generic)] #[error(transparent)] Http(#[from] http::Error), + #[class(type)] #[error(transparent)] WebSocket(#[from] fastwebsockets::WebSocketError), + #[class(generic)] #[error("Didn't receive h2 alpn, aborting connection")] NoH2Alpn, + #[class(generic)] #[error(transparent)] Rustls(#[from] deno_tls::rustls::Error), + #[class(inherit)] #[error(transparent)] Io(#[from] std::io::Error), + #[class(generic)] #[error(transparent)] H2(#[from] h2::Error), + #[class(type)] #[error("Invalid hostname: '{0}'")] InvalidHostname(String), + #[class(inherit)] #[error(transparent)] - RootStoreError(deno_core::error::AnyError), + RootStoreError(JsErrorBox), + #[class(inherit)] #[error(transparent)] Tls(deno_tls::TlsError), + #[class(type)] #[error(transparent)] HeaderName(#[from] http::header::InvalidHeaderName), + #[class(type)] #[error(transparent)] HeaderValue(#[from] http::header::InvalidHeaderValue), } @@ -472,8 +493,7 @@ where let r = state .borrow_mut() .resource_table - .get::(cancel_rid) - .map_err(WebsocketError::Resource)?; + .get::(cancel_rid)?; Some(r.0.clone()) } else { None @@ -677,8 +697,7 @@ pub async fn op_ws_send_binary_async( let resource = state .borrow_mut() .resource_table - .get::(rid) - .map_err(WebsocketError::Resource)?; + .get::(rid)?; let data = data.to_vec(); let lock = resource.reserve_lock(); resource @@ -696,8 +715,7 @@ pub async fn op_ws_send_text_async( let resource = state .borrow_mut() .resource_table - .get::(rid) - .map_err(WebsocketError::Resource)?; + .get::(rid)?; let lock = resource.reserve_lock(); resource .write_frame( @@ -731,8 +749,7 @@ pub async fn op_ws_send_ping( let resource = state .borrow_mut() .resource_table - .get::(rid) - .map_err(WebsocketError::Resource)?; + .get::(rid)?; let lock = resource.reserve_lock(); resource .write_frame( @@ -757,9 +774,14 @@ pub async fn op_ws_close( return Ok(()); }; + const EMPTY_PAYLOAD: &[u8] = &[]; + let frame = reason .map(|reason| Frame::close(code.unwrap_or(1005), reason.as_bytes())) - .unwrap_or_else(|| Frame::close_raw(vec![].into())); + .unwrap_or_else(|| match code { + Some(code) => Frame::close(code, EMPTY_PAYLOAD), + _ => Frame::close_raw(EMPTY_PAYLOAD.into()), + }); resource.closed.set(true); let lock = resource.reserve_lock(); diff --git a/ext/websocket/stream.rs b/ext/websocket/stream.rs index 2cd2622175..c2ac4ee5d8 100644 --- a/ext/websocket/stream.rs +++ b/ext/websocket/stream.rs @@ -1,4 +1,9 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. +use std::io::ErrorKind; +use std::pin::Pin; +use std::task::ready; +use std::task::Poll; + use bytes::Buf; use bytes::Bytes; use deno_net::raw::NetworkStream; @@ -6,10 +11,6 @@ use h2::RecvStream; use h2::SendStream; use hyper::upgrade::Upgraded; use hyper_util::rt::TokioIo; -use std::io::ErrorKind; -use std::pin::Pin; -use std::task::ready; -use std::task::Poll; use tokio::io::AsyncRead; use tokio::io::AsyncWrite; use tokio::io::ReadBuf; diff --git a/ext/webstorage/01_webstorage.js b/ext/webstorage/01_webstorage.js index 12abea8387..7adf190782 100644 --- a/ext/webstorage/01_webstorage.js +++ b/ext/webstorage/01_webstorage.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// diff --git a/ext/webstorage/Cargo.toml b/ext/webstorage/Cargo.toml index 4f9795d098..04e6381b00 100644 --- a/ext/webstorage/Cargo.toml +++ b/ext/webstorage/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_webstorage" -version = "0.179.0" +version = "0.181.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -15,6 +15,7 @@ path = "lib.rs" [dependencies] deno_core.workspace = true +deno_error.workspace = true deno_web.workspace = true rusqlite.workspace = true thiserror.workspace = true diff --git a/ext/webstorage/lib.deno_webstorage.d.ts b/ext/webstorage/lib.deno_webstorage.d.ts index fa6d403dea..5f5aafa1b8 100644 --- a/ext/webstorage/lib.deno_webstorage.d.ts +++ b/ext/webstorage/lib.deno_webstorage.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-explicit-any no-var diff --git a/ext/webstorage/lib.rs b/ext/webstorage/lib.rs index c3e4c46596..4653e1b948 100644 --- a/ext/webstorage/lib.rs +++ b/ext/webstorage/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // NOTE to all: use **cached** prepared statements when interfacing with SQLite. @@ -7,20 +7,23 @@ use std::path::PathBuf; use deno_core::op2; use deno_core::GarbageCollected; use deno_core::OpState; +pub use rusqlite; use rusqlite::params; use rusqlite::Connection; use rusqlite::OptionalExtension; -pub use rusqlite; - -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum WebStorageError { + #[class("DOMExceptionNotSupportedError")] #[error("LocalStorage is not supported in this context.")] ContextNotSupported, + #[class(generic)] #[error(transparent)] Sqlite(#[from] rusqlite::Error), + #[class(inherit)] #[error(transparent)] Io(std::io::Error), + #[class("DOMExceptionQuotaExceededError")] #[error("Exceeded maximum storage size")] StorageExceeded, } diff --git a/resolvers/deno/Cargo.toml b/resolvers/deno/Cargo.toml index 12c18d4452..bf4d68fa91 100644 --- a/resolvers/deno/Cargo.toml +++ b/resolvers/deno/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_resolver" -version = "0.15.0" +version = "0.17.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -14,21 +14,25 @@ description = "Deno resolution algorithm" path = "lib.rs" [features] -sync = ["dashmap"] +sync = ["dashmap", "deno_package_json/sync", "node_resolver/sync"] [dependencies] anyhow.workspace = true +async-trait.workspace = true base32.workspace = true boxed_error.workspace = true dashmap = { workspace = true, optional = true } +deno_cache_dir.workspace = true deno_config.workspace = true +deno_error.workspace = true deno_media_type.workspace = true +deno_npm.workspace = true deno_package_json.workspace = true -deno_package_json.features = ["sync"] deno_path_util.workspace = true deno_semver.workspace = true +log.workspace = true node_resolver.workspace = true -node_resolver.features = ["sync"] +parking_lot.workspace = true sys_traits.workspace = true thiserror.workspace = true url.workspace = true diff --git a/resolvers/deno/cjs.rs b/resolvers/deno/cjs.rs index 2ec253d41a..4358b0ced2 100644 --- a/resolvers/deno/cjs.rs +++ b/resolvers/deno/cjs.rs @@ -1,8 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_media_type::MediaType; use node_resolver::errors::ClosestPkgJsonError; -use node_resolver::InNpmPackageCheckerRc; +use node_resolver::InNpmPackageChecker; use node_resolver::PackageJsonResolverRc; use node_resolver::ResolutionMode; use sys_traits::FsRead; @@ -16,14 +16,16 @@ use crate::sync::MaybeDashMap; /// be CJS or ESM after they're loaded based on their contents. So these /// files will be "maybe CJS" until they're loaded. #[derive(Debug)] -pub struct CjsTracker { - is_cjs_resolver: IsCjsResolver, +pub struct CjsTracker { + is_cjs_resolver: IsCjsResolver, known: MaybeDashMap, } -impl CjsTracker { +impl + CjsTracker +{ pub fn new( - in_npm_pkg_checker: InNpmPackageCheckerRc, + in_npm_pkg_checker: TInNpmPackageChecker, pkg_json_resolver: PackageJsonResolverRc, mode: IsCjsResolutionMode, ) -> Self { @@ -125,15 +127,20 @@ pub enum IsCjsResolutionMode { /// Resolves whether a module is CJS or ESM. #[derive(Debug)] -pub struct IsCjsResolver { - in_npm_pkg_checker: InNpmPackageCheckerRc, +pub struct IsCjsResolver< + TInNpmPackageChecker: InNpmPackageChecker, + TSys: FsRead, +> { + in_npm_pkg_checker: TInNpmPackageChecker, pkg_json_resolver: PackageJsonResolverRc, mode: IsCjsResolutionMode, } -impl IsCjsResolver { +impl + IsCjsResolver +{ pub fn new( - in_npm_pkg_checker: InNpmPackageCheckerRc, + in_npm_pkg_checker: TInNpmPackageChecker, pkg_json_resolver: PackageJsonResolverRc, mode: IsCjsResolutionMode, ) -> Self { diff --git a/resolvers/deno/lib.rs b/resolvers/deno/lib.rs index c943aacdae..454c7f12e2 100644 --- a/resolvers/deno/lib.rs +++ b/resolvers/deno/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. #![deny(clippy::print_stderr)] #![deny(clippy::print_stdout)] @@ -6,21 +6,25 @@ use std::path::PathBuf; use boxed_error::Boxed; +use deno_cache_dir::npm::NpmCacheDir; use deno_config::workspace::MappedResolution; use deno_config::workspace::MappedResolutionDiagnostic; use deno_config::workspace::MappedResolutionError; use deno_config::workspace::WorkspaceResolvePkgJsonFolderError; use deno_config::workspace::WorkspaceResolver; +use deno_error::JsError; +use deno_npm::npm_rc::ResolvedNpmRc; use deno_package_json::PackageJsonDepValue; use deno_package_json::PackageJsonDepValueParseError; use deno_semver::npm::NpmPackageReqReference; use node_resolver::errors::NodeResolveError; use node_resolver::errors::PackageSubpathResolveError; -use node_resolver::InNpmPackageCheckerRc; +use node_resolver::InNpmPackageChecker; use node_resolver::IsBuiltInNodeModuleChecker; use node_resolver::NodeResolution; use node_resolver::NodeResolutionKind; use node_resolver::NodeResolverRc; +use node_resolver::NpmPackageFolderResolver; use node_resolver::ResolutionMode; use npm::MissingPackageNodeModulesFolderError; use npm::NodeModulesOutOfDateError; @@ -46,6 +50,12 @@ mod sync; #[allow(clippy::disallowed_types)] pub type WorkspaceResolverRc = crate::sync::MaybeArc; +#[allow(clippy::disallowed_types)] +pub(crate) type ResolvedNpmRcRc = crate::sync::MaybeArc; + +#[allow(clippy::disallowed_types)] +pub(crate) type NpmCacheDirRc = crate::sync::MaybeArc; + #[derive(Debug, Clone)] pub struct DenoResolution { pub url: Url, @@ -53,51 +63,81 @@ pub struct DenoResolution { pub found_package_json_dep: bool, } -#[derive(Debug, Boxed)] +#[derive(Debug, Boxed, JsError)] pub struct DenoResolveError(pub Box); -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] pub enum DenoResolveErrorKind { + #[class(type)] #[error("Importing from the vendor directory is not permitted. Use a remote specifier instead or disable vendoring.")] InvalidVendorFolderImport, + #[class(inherit)] #[error(transparent)] MappedResolution(#[from] MappedResolutionError), + #[class(inherit)] #[error(transparent)] MissingPackageNodeModulesFolder(#[from] MissingPackageNodeModulesFolderError), + #[class(inherit)] #[error(transparent)] Node(#[from] NodeResolveError), + #[class(inherit)] #[error(transparent)] NodeModulesOutOfDate(#[from] NodeModulesOutOfDateError), + #[class(inherit)] #[error(transparent)] PackageJsonDepValueParse(#[from] PackageJsonDepValueParseError), + #[class(inherit)] #[error(transparent)] PackageJsonDepValueUrlParse(url::ParseError), + #[class(inherit)] #[error(transparent)] PackageSubpathResolve(#[from] PackageSubpathResolveError), + #[class(inherit)] #[error(transparent)] ResolvePkgFolderFromDenoReq(#[from] ResolvePkgFolderFromDenoReqError), + #[class(inherit)] #[error(transparent)] WorkspaceResolvePkgJsonFolder(#[from] WorkspaceResolvePkgJsonFolderError), } #[derive(Debug)] pub struct NodeAndNpmReqResolver< + TInNpmPackageChecker: InNpmPackageChecker, TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir, > { - pub node_resolver: NodeResolverRc, - pub npm_req_resolver: NpmReqResolverRc, + pub node_resolver: NodeResolverRc< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >, + pub npm_req_resolver: NpmReqResolverRc< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >, } pub struct DenoResolverOptions< 'a, + TInNpmPackageChecker: InNpmPackageChecker, TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, TSloppyImportResolverFs: SloppyImportResolverFs, TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir, > { - pub in_npm_pkg_checker: InNpmPackageCheckerRc, - pub node_and_req_resolver: - Option>, + pub in_npm_pkg_checker: TInNpmPackageChecker, + pub node_and_req_resolver: Option< + NodeAndNpmReqResolver< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >, + >, pub sloppy_imports_resolver: Option>, pub workspace_resolver: WorkspaceResolverRc, @@ -112,13 +152,21 @@ pub struct DenoResolverOptions< /// import map, JSX settings. #[derive(Debug)] pub struct DenoResolver< + TInNpmPackageChecker: InNpmPackageChecker, TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, TSloppyImportResolverFs: SloppyImportResolverFs, TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir, > { - in_npm_pkg_checker: InNpmPackageCheckerRc, - node_and_npm_resolver: - Option>, + in_npm_pkg_checker: TInNpmPackageChecker, + node_and_npm_resolver: Option< + NodeAndNpmReqResolver< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >, + >, sloppy_imports_resolver: Option>, workspace_resolver: WorkspaceResolverRc, @@ -127,14 +175,25 @@ pub struct DenoResolver< } impl< + TInNpmPackageChecker: InNpmPackageChecker, TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, TSloppyImportResolverFs: SloppyImportResolverFs, TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir, - > DenoResolver + > + DenoResolver< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSloppyImportResolverFs, + TSys, + > { pub fn new( options: DenoResolverOptions< + TInNpmPackageChecker, TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, TSloppyImportResolverFs, TSys, >, diff --git a/resolvers/deno/npm/byonm.rs b/resolvers/deno/npm/byonm.rs index 3056a70f61..4f72692f8b 100644 --- a/resolvers/deno/npm/byonm.rs +++ b/resolvers/deno/npm/byonm.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::path::Path; @@ -27,17 +27,19 @@ use thiserror::Error; use url::Url; use super::local::normalize_pkg_name_for_node_modules_deno_folder; -use super::CliNpmReqResolver; -use super::ResolvePkgFolderFromDenoReqError; -#[derive(Debug, Error)] +#[derive(Debug, Error, deno_error::JsError)] pub enum ByonmResolvePkgFolderFromDenoReqError { + #[class(generic)] #[error("Could not find \"{}\" in a node_modules folder. Deno expects the node_modules/ directory to be up to date. Did you forget to run `deno install`?", .0)] MissingAlias(StackString), + #[class(inherit)] #[error(transparent)] PackageJson(#[from] PackageJsonLoadError), + #[class(generic)] #[error("Could not find a matching package for 'npm:{}' in the node_modules directory. Ensure you have all your JSR and npm dependencies listed in your deno.json or package.json, then run `deno install`. Alternatively, turn on auto-install by specifying `\"nodeModulesDir\": \"auto\"` in your deno.json file.", .0)] UnmatchedReq(PackageReq), + #[class(inherit)] #[error(transparent)] Io(#[from] std::io::Error), } @@ -85,7 +87,7 @@ impl } } - pub fn root_node_modules_dir(&self) -> Option<&Path> { + pub fn root_node_modules_path(&self) -> Option<&Path> { self.root_node_modules_dir.as_deref() } @@ -373,37 +375,8 @@ impl } } -impl< - Sys: FsCanonicalize - + FsMetadata - + FsRead - + FsReadDir - + Send - + Sync - + std::fmt::Debug, - > CliNpmReqResolver for ByonmNpmResolver -{ - fn resolve_pkg_folder_from_deno_module_req( - &self, - req: &PackageReq, - referrer: &Url, - ) -> Result { - ByonmNpmResolver::resolve_pkg_folder_from_deno_module_req( - self, req, referrer, - ) - .map_err(ResolvePkgFolderFromDenoReqError::Byonm) - } -} - -impl< - Sys: FsCanonicalize - + FsMetadata - + FsRead - + FsReadDir - + Send - + Sync - + std::fmt::Debug, - > NpmPackageFolderResolver for ByonmNpmResolver +impl + NpmPackageFolderResolver for ByonmNpmResolver { fn resolve_package_folder_from_package( &self, @@ -456,7 +429,7 @@ impl< } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ByonmInNpmPackageChecker; impl InNpmPackageChecker for ByonmInNpmPackageChecker { diff --git a/resolvers/deno/npm/local.rs b/resolvers/deno/npm/local.rs index aef476ad94..b05864b856 100644 --- a/resolvers/deno/npm/local.rs +++ b/resolvers/deno/npm/local.rs @@ -1,7 +1,59 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; +use deno_cache_dir::npm::mixed_case_package_name_decode; +use deno_npm::NpmPackageCacheFolderId; +use deno_semver::package::PackageNv; +use deno_semver::StackString; + +#[inline] +pub fn get_package_folder_id_folder_name( + folder_id: &NpmPackageCacheFolderId, +) -> String { + get_package_folder_id_folder_name_from_parts( + &folder_id.nv, + folder_id.copy_index, + ) +} + +pub fn get_package_folder_id_folder_name_from_parts( + nv: &PackageNv, + copy_index: u8, +) -> String { + let copy_str = if copy_index == 0 { + Cow::Borrowed("") + } else { + Cow::Owned(format!("_{}", copy_index)) + }; + let name = normalize_pkg_name_for_node_modules_deno_folder(&nv.name); + format!("{}@{}{}", name, nv.version, copy_str) +} + +pub fn get_package_folder_id_from_folder_name( + folder_name: &str, +) -> Option { + let folder_name = folder_name.replace('+', "/"); + let (name, ending) = folder_name.rsplit_once('@')?; + let name: StackString = if let Some(encoded_name) = name.strip_prefix('_') { + StackString::from_string(mixed_case_package_name_decode(encoded_name)?) + } else { + name.into() + }; + let (raw_version, copy_index) = match ending.split_once('_') { + Some((raw_version, copy_index)) => { + let copy_index = copy_index.parse::().ok()?; + (raw_version, copy_index) + } + None => (ending, 0), + }; + let version = deno_semver::Version::parse_from_npm(raw_version).ok()?; + Some(NpmPackageCacheFolderId { + nv: PackageNv { name, version }, + copy_index, + }) +} + /// Normalizes a package name for use at `node_modules/.deno/@[_]` pub fn normalize_pkg_name_for_node_modules_deno_folder(name: &str) -> Cow { let name = if name.to_lowercase() == name { @@ -25,3 +77,36 @@ fn mixed_case_package_name_encode(name: &str) -> String { ) .to_lowercase() } + +#[cfg(test)] +mod test { + use deno_npm::NpmPackageCacheFolderId; + use deno_semver::package::PackageNv; + + use super::*; + + #[test] + fn test_get_package_folder_id_folder_name() { + let cases = vec![ + ( + NpmPackageCacheFolderId { + nv: PackageNv::from_str("@types/foo@1.2.3").unwrap(), + copy_index: 1, + }, + "@types+foo@1.2.3_1".to_string(), + ), + ( + NpmPackageCacheFolderId { + nv: PackageNv::from_str("JSON@3.2.1").unwrap(), + copy_index: 0, + }, + "_jjju6tq@3.2.1".to_string(), + ), + ]; + for (input, output) in cases { + assert_eq!(get_package_folder_id_folder_name(&input), output); + let folder_id = get_package_folder_id_from_folder_name(&output).unwrap(); + assert_eq!(folder_id, input); + } + } +} diff --git a/resolvers/deno/npm/managed/common.rs b/resolvers/deno/npm/managed/common.rs new file mode 100644 index 0000000000..a92fe226dd --- /dev/null +++ b/resolvers/deno/npm/managed/common.rs @@ -0,0 +1,74 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::path::Path; +use std::path::PathBuf; + +use deno_npm::NpmPackageCacheFolderId; +use deno_npm::NpmPackageId; +use node_resolver::NpmPackageFolderResolver; +use sys_traits::FsCanonicalize; +use sys_traits::FsMetadata; +use url::Url; + +#[derive(Debug)] +pub enum NpmPackageFsResolver { + Local(super::local::LocalNpmPackageResolver), + Global(super::global::GlobalNpmPackageResolver), +} + +impl NpmPackageFsResolver { + /// The local node_modules folder (only for the local resolver). + pub fn node_modules_path(&self) -> Option<&Path> { + match self { + NpmPackageFsResolver::Local(resolver) => resolver.node_modules_path(), + NpmPackageFsResolver::Global(_) => None, + } + } + + pub fn maybe_package_folder( + &self, + package_id: &NpmPackageId, + ) -> Option { + match self { + NpmPackageFsResolver::Local(resolver) => { + resolver.maybe_package_folder(package_id) + } + NpmPackageFsResolver::Global(resolver) => { + resolver.maybe_package_folder(package_id) + } + } + } + + pub fn resolve_package_cache_folder_id_from_specifier( + &self, + specifier: &Url, + ) -> Result, std::io::Error> { + match self { + NpmPackageFsResolver::Local(resolver) => { + resolver.resolve_package_cache_folder_id_from_specifier(specifier) + } + NpmPackageFsResolver::Global(resolver) => { + resolver.resolve_package_cache_folder_id_from_specifier(specifier) + } + } + } +} + +impl NpmPackageFolderResolver + for NpmPackageFsResolver +{ + fn resolve_package_folder_from_package( + &self, + specifier: &str, + referrer: &Url, + ) -> Result { + match self { + NpmPackageFsResolver::Local(r) => { + r.resolve_package_folder_from_package(specifier, referrer) + } + NpmPackageFsResolver::Global(r) => { + r.resolve_package_folder_from_package(specifier, referrer) + } + } + } +} diff --git a/resolvers/deno/npm/managed/global.rs b/resolvers/deno/npm/managed/global.rs new file mode 100644 index 0000000000..271851c79c --- /dev/null +++ b/resolvers/deno/npm/managed/global.rs @@ -0,0 +1,141 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +//! Code for global npm cache resolution. + +use std::path::PathBuf; + +use deno_npm::NpmPackageCacheFolderId; +use deno_npm::NpmPackageId; +use deno_semver::package::PackageNv; +use deno_semver::StackString; +use deno_semver::Version; +use node_resolver::errors::PackageFolderResolveError; +use node_resolver::errors::PackageNotFoundError; +use node_resolver::errors::ReferrerNotFoundError; +use node_resolver::NpmPackageFolderResolver; +use url::Url; + +use super::resolution::NpmResolutionCellRc; +use super::NpmCacheDirRc; +use crate::ResolvedNpmRcRc; + +/// Resolves packages from the global npm cache. +#[derive(Debug)] +pub struct GlobalNpmPackageResolver { + cache: NpmCacheDirRc, + npm_rc: ResolvedNpmRcRc, + resolution: NpmResolutionCellRc, +} + +impl GlobalNpmPackageResolver { + pub fn new( + cache: NpmCacheDirRc, + npm_rc: ResolvedNpmRcRc, + resolution: NpmResolutionCellRc, + ) -> Self { + Self { + cache, + npm_rc, + resolution, + } + } + + pub fn maybe_package_folder(&self, id: &NpmPackageId) -> Option { + let folder_copy_index = self + .resolution + .resolve_pkg_cache_folder_copy_index_from_pkg_id(id)?; + let registry_url = self.npm_rc.get_registry_url(&id.nv.name); + Some(self.cache.package_folder_for_id( + &id.nv.name, + &id.nv.version.to_string(), + folder_copy_index, + registry_url, + )) + } + + pub fn resolve_package_cache_folder_id_from_specifier( + &self, + specifier: &Url, + ) -> Result, std::io::Error> { + Ok(self.resolve_package_cache_folder_id_from_specifier_inner(specifier)) + } + + fn resolve_package_cache_folder_id_from_specifier_inner( + &self, + specifier: &Url, + ) -> Option { + self + .cache + .resolve_package_folder_id_from_specifier(specifier) + .and_then(|cache_id| { + Some(NpmPackageCacheFolderId { + nv: PackageNv { + name: StackString::from_string(cache_id.name), + version: Version::parse_from_npm(&cache_id.version).ok()?, + }, + copy_index: cache_id.copy_index, + }) + }) + } +} + +impl NpmPackageFolderResolver for GlobalNpmPackageResolver { + fn resolve_package_folder_from_package( + &self, + name: &str, + referrer: &Url, + ) -> Result { + use deno_npm::resolution::PackageNotFoundFromReferrerError; + let Some(referrer_cache_folder_id) = + self.resolve_package_cache_folder_id_from_specifier_inner(referrer) + else { + return Err( + ReferrerNotFoundError { + referrer: referrer.clone(), + referrer_extra: None, + } + .into(), + ); + }; + let resolve_result = self + .resolution + .resolve_package_from_package(name, &referrer_cache_folder_id); + match resolve_result { + Ok(pkg) => match self.maybe_package_folder(&pkg.id) { + Some(folder) => Ok(folder), + None => Err( + PackageNotFoundError { + package_name: name.to_string(), + referrer: referrer.clone(), + referrer_extra: Some(format!( + "{} -> {}", + referrer_cache_folder_id, + pkg.id.as_serialized() + )), + } + .into(), + ), + }, + Err(err) => match *err { + PackageNotFoundFromReferrerError::Referrer(cache_folder_id) => Err( + ReferrerNotFoundError { + referrer: referrer.clone(), + referrer_extra: Some(cache_folder_id.to_string()), + } + .into(), + ), + PackageNotFoundFromReferrerError::Package { + name, + referrer: cache_folder_id_referrer, + } => Err( + PackageNotFoundError { + package_name: name, + referrer: referrer.clone(), + referrer_extra: Some(cache_folder_id_referrer.to_string()), + } + .into(), + ), + }, + } + } +} diff --git a/resolvers/deno/npm/managed/local.rs b/resolvers/deno/npm/managed/local.rs new file mode 100644 index 0000000000..e453101df4 --- /dev/null +++ b/resolvers/deno/npm/managed/local.rs @@ -0,0 +1,214 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +//! Code for local node_modules resolution. + +use std::borrow::Cow; +use std::path::Path; +use std::path::PathBuf; + +use deno_npm::NpmPackageCacheFolderId; +use deno_npm::NpmPackageId; +use deno_path_util::fs::canonicalize_path_maybe_not_exists; +use deno_path_util::url_from_directory_path; +use node_resolver::errors::PackageFolderResolveError; +use node_resolver::errors::PackageFolderResolveIoError; +use node_resolver::errors::PackageNotFoundError; +use node_resolver::errors::ReferrerNotFoundError; +use node_resolver::NpmPackageFolderResolver; +use sys_traits::FsCanonicalize; +use sys_traits::FsMetadata; +use url::Url; + +use super::resolution::NpmResolutionCellRc; +use crate::npm::local::get_package_folder_id_folder_name_from_parts; +use crate::npm::local::get_package_folder_id_from_folder_name; + +/// Resolver that creates a local node_modules directory +/// and resolves packages from it. +#[derive(Debug)] +pub struct LocalNpmPackageResolver { + resolution: NpmResolutionCellRc, + sys: TSys, + root_node_modules_path: PathBuf, + root_node_modules_url: Url, +} + +impl LocalNpmPackageResolver { + #[allow(clippy::too_many_arguments)] + pub fn new( + resolution: NpmResolutionCellRc, + sys: TSys, + node_modules_folder: PathBuf, + ) -> Self { + Self { + resolution, + sys, + root_node_modules_url: url_from_directory_path(&node_modules_folder) + .unwrap(), + root_node_modules_path: node_modules_folder, + } + } + + pub fn node_modules_path(&self) -> Option<&Path> { + Some(self.root_node_modules_path.as_ref()) + } + + pub fn maybe_package_folder(&self, id: &NpmPackageId) -> Option { + let folder_copy_index = self + .resolution + .resolve_pkg_cache_folder_copy_index_from_pkg_id(id)?; + // package is stored at: + // node_modules/.deno//node_modules/ + Some( + self + .root_node_modules_path + .join(".deno") + .join(get_package_folder_id_folder_name_from_parts( + &id.nv, + folder_copy_index, + )) + .join("node_modules") + .join(&id.nv.name), + ) + } + + pub fn resolve_package_cache_folder_id_from_specifier( + &self, + specifier: &Url, + ) -> Result, std::io::Error> { + let Some(folder_path) = + self.resolve_package_folder_from_specifier(specifier)? + else { + return Ok(None); + }; + // ex. project/node_modules/.deno/preact@10.24.3/node_modules/preact/ + let Some(node_modules_ancestor) = folder_path + .ancestors() + .find(|ancestor| ancestor.ends_with("node_modules")) + else { + return Ok(None); + }; + let Some(folder_name) = + node_modules_ancestor.parent().and_then(|p| p.file_name()) + else { + return Ok(None); + }; + Ok(get_package_folder_id_from_folder_name( + &folder_name.to_string_lossy(), + )) + } + + fn resolve_package_root(&self, path: &Path) -> PathBuf { + let mut last_found = path; + loop { + let parent = last_found.parent().unwrap(); + if parent.file_name().unwrap() == "node_modules" { + return last_found.to_path_buf(); + } else { + last_found = parent; + } + } + } + + fn resolve_folder_for_specifier( + &self, + specifier: &Url, + ) -> Result, std::io::Error> { + let Some(relative_url) = + self.root_node_modules_url.make_relative(specifier) + else { + return Ok(None); + }; + if relative_url.starts_with("../") { + return Ok(None); + } + // it's within the directory, so use it + let Some(path) = deno_path_util::url_to_file_path(specifier).ok() else { + return Ok(None); + }; + // Canonicalize the path so it's not pointing to the symlinked directory + // in `node_modules` directory of the referrer. + canonicalize_path_maybe_not_exists(&self.sys, &path).map(Some) + } + + fn resolve_package_folder_from_specifier( + &self, + specifier: &Url, + ) -> Result, std::io::Error> { + let Some(local_path) = self.resolve_folder_for_specifier(specifier)? else { + return Ok(None); + }; + let package_root_path = self.resolve_package_root(&local_path); + Ok(Some(package_root_path)) + } +} + +impl NpmPackageFolderResolver + for LocalNpmPackageResolver +{ + fn resolve_package_folder_from_package( + &self, + name: &str, + referrer: &Url, + ) -> Result { + let maybe_local_path = self + .resolve_folder_for_specifier(referrer) + .map_err(|err| PackageFolderResolveIoError { + package_name: name.to_string(), + referrer: referrer.clone(), + source: err, + })?; + let Some(local_path) = maybe_local_path else { + return Err( + ReferrerNotFoundError { + referrer: referrer.clone(), + referrer_extra: None, + } + .into(), + ); + }; + let package_root_path = self.resolve_package_root(&local_path); + let mut current_folder = package_root_path.as_path(); + while let Some(parent_folder) = current_folder.parent() { + current_folder = parent_folder; + let node_modules_folder = if current_folder.ends_with("node_modules") { + Cow::Borrowed(current_folder) + } else { + Cow::Owned(current_folder.join("node_modules")) + }; + + let sub_dir = join_package_name(&node_modules_folder, name); + if self.sys.fs_is_dir_no_err(&sub_dir) { + return Ok(self.sys.fs_canonicalize(&sub_dir).map_err(|err| { + PackageFolderResolveIoError { + package_name: name.to_string(), + referrer: referrer.clone(), + source: err, + } + })?); + } + + if current_folder == self.root_node_modules_path { + break; + } + } + + Err( + PackageNotFoundError { + package_name: name.to_string(), + referrer: referrer.clone(), + referrer_extra: None, + } + .into(), + ) + } +} + +fn join_package_name(path: &Path, package_name: &str) -> PathBuf { + let mut path = path.to_path_buf(); + // ensure backslashes are used on windows + for part in package_name.split('/') { + path = path.join(part); + } + path +} diff --git a/resolvers/deno/npm/managed/mod.rs b/resolvers/deno/npm/managed/mod.rs new file mode 100644 index 0000000000..291e299bc8 --- /dev/null +++ b/resolvers/deno/npm/managed/mod.rs @@ -0,0 +1,287 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +mod common; +mod global; +mod local; +mod resolution; + +use std::path::Path; +use std::path::PathBuf; + +use deno_npm::resolution::PackageCacheFolderIdNotFoundError; +use deno_npm::resolution::PackageNvNotFoundError; +use deno_npm::resolution::PackageReqNotFoundError; +use deno_npm::NpmPackageCacheFolderId; +use deno_npm::NpmPackageId; +use deno_npm::NpmSystemInfo; +use deno_path_util::fs::canonicalize_path_maybe_not_exists; +use deno_semver::package::PackageNv; +use deno_semver::package::PackageReq; +use node_resolver::InNpmPackageChecker; +use node_resolver::NpmPackageFolderResolver; +use sys_traits::FsCanonicalize; +use sys_traits::FsMetadata; +use url::Url; + +use self::common::NpmPackageFsResolver; +use self::global::GlobalNpmPackageResolver; +use self::local::LocalNpmPackageResolver; +pub use self::resolution::NpmResolutionCell; +pub use self::resolution::NpmResolutionCellRc; +use crate::NpmCacheDirRc; +use crate::ResolvedNpmRcRc; + +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum ResolvePkgFolderFromDenoModuleError { + #[class(inherit)] + #[error(transparent)] + PackageNvNotFound(#[from] PackageNvNotFoundError), + #[class(inherit)] + #[error(transparent)] + ResolvePkgFolderFromPkgId(#[from] ResolvePkgFolderFromPkgIdError), +} + +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[error(transparent)] +pub enum ResolvePkgFolderFromPkgIdError { + #[class(inherit)] + #[error(transparent)] + NotFound(#[from] NpmManagedPackageFolderNotFoundError), + #[class(inherit)] + #[error(transparent)] + FailedCanonicalizing(#[from] FailedCanonicalizingError), +} + +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(generic)] +#[error("Package folder not found for '{0}'")] +pub struct NpmManagedPackageFolderNotFoundError(deno_semver::StackString); + +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(generic)] +#[error("Failed canonicalizing '{}'", path.display())] +pub struct FailedCanonicalizingError { + path: PathBuf, + #[source] + source: std::io::Error, +} + +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum ManagedResolvePkgFolderFromDenoReqError { + #[class(inherit)] + #[error(transparent)] + PackageReqNotFound(#[from] PackageReqNotFoundError), + #[class(inherit)] + #[error(transparent)] + ResolvePkgFolderFromPkgId(#[from] ResolvePkgFolderFromPkgIdError), +} + +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum ResolvePkgIdFromSpecifierError { + #[class(inherit)] + #[error(transparent)] + Io(#[from] std::io::Error), + #[class(inherit)] + #[error(transparent)] + NotFound(#[from] PackageCacheFolderIdNotFoundError), +} + +pub struct ManagedNpmResolverCreateOptions< + TSys: FsCanonicalize + FsMetadata + Clone, +> { + pub npm_cache_dir: NpmCacheDirRc, + pub sys: TSys, + pub maybe_node_modules_path: Option, + pub npm_system_info: NpmSystemInfo, + pub npmrc: ResolvedNpmRcRc, + pub npm_resolution: NpmResolutionCellRc, +} + +#[allow(clippy::disallowed_types)] +pub type ManagedNpmResolverRc = + crate::sync::MaybeArc>; + +#[derive(Debug)] +pub struct ManagedNpmResolver { + fs_resolver: NpmPackageFsResolver, + npm_cache_dir: NpmCacheDirRc, + resolution: NpmResolutionCellRc, + sys: TSys, +} + +impl ManagedNpmResolver { + pub fn new( + options: ManagedNpmResolverCreateOptions, + ) -> ManagedNpmResolver { + let fs_resolver = match options.maybe_node_modules_path { + Some(node_modules_folder) => { + NpmPackageFsResolver::Local(LocalNpmPackageResolver::new( + options.npm_resolution.clone(), + options.sys.clone(), + node_modules_folder, + )) + } + None => NpmPackageFsResolver::Global(GlobalNpmPackageResolver::new( + options.npm_cache_dir.clone(), + options.npmrc.clone(), + options.npm_resolution.clone(), + )), + }; + + ManagedNpmResolver { + fs_resolver, + npm_cache_dir: options.npm_cache_dir, + sys: options.sys, + resolution: options.npm_resolution, + } + } + + #[inline] + pub fn root_node_modules_path(&self) -> Option<&Path> { + self.fs_resolver.node_modules_path() + } + + pub fn global_cache_root_path(&self) -> &Path { + self.npm_cache_dir.root_dir() + } + + pub fn global_cache_root_url(&self) -> &Url { + self.npm_cache_dir.root_dir_url() + } + + pub fn resolution(&self) -> &NpmResolutionCell { + self.resolution.as_ref() + } + + /// Checks if the provided package req's folder is cached. + pub fn is_pkg_req_folder_cached(&self, req: &PackageReq) -> bool { + self + .resolution + .resolve_pkg_id_from_pkg_req(req) + .ok() + .and_then(|id| self.resolve_pkg_folder_from_pkg_id(&id).ok()) + .map(|folder| self.sys.fs_exists_no_err(folder)) + .unwrap_or(false) + } + + pub fn resolve_pkg_folder_from_pkg_id( + &self, + package_id: &NpmPackageId, + ) -> Result { + let path = self + .fs_resolver + .maybe_package_folder(package_id) + .ok_or_else(|| { + NpmManagedPackageFolderNotFoundError(package_id.as_serialized()) + })?; + // todo(dsherret): investigate if this canonicalization is always + // necessary. For example, maybe it's not necessary for the global cache + let path = canonicalize_path_maybe_not_exists(&self.sys, &path).map_err( + |source| FailedCanonicalizingError { + path: path.to_path_buf(), + source, + }, + )?; + log::debug!( + "Resolved package folder of {} to {}", + package_id.as_serialized(), + path.display() + ); + Ok(path) + } + + pub fn resolve_pkg_folder_from_deno_module( + &self, + nv: &PackageNv, + ) -> Result { + let pkg_id = self.resolution.resolve_pkg_id_from_deno_module(nv)?; + Ok(self.resolve_pkg_folder_from_pkg_id(&pkg_id)?) + } + + pub fn resolve_pkg_folder_from_deno_module_req( + &self, + req: &PackageReq, + _referrer: &Url, + ) -> Result { + let pkg_id = self.resolution.resolve_pkg_id_from_pkg_req(req)?; + Ok(self.resolve_pkg_folder_from_pkg_id(&pkg_id)?) + } + + #[inline] + pub fn resolve_package_cache_folder_id_from_specifier( + &self, + specifier: &Url, + ) -> Result, std::io::Error> { + self + .fs_resolver + .resolve_package_cache_folder_id_from_specifier(specifier) + } + + /// Resolves the package id from the provided specifier. + pub fn resolve_pkg_id_from_specifier( + &self, + specifier: &Url, + ) -> Result, ResolvePkgIdFromSpecifierError> { + let Some(cache_folder_id) = self + .fs_resolver + .resolve_package_cache_folder_id_from_specifier(specifier)? + else { + return Ok(None); + }; + Ok(Some( + self + .resolution + .resolve_pkg_id_from_pkg_cache_folder_id(&cache_folder_id)?, + )) + } +} + +impl NpmPackageFolderResolver + for ManagedNpmResolver +{ + fn resolve_package_folder_from_package( + &self, + specifier: &str, + referrer: &Url, + ) -> Result { + let path = self + .fs_resolver + .resolve_package_folder_from_package(specifier, referrer)?; + log::debug!( + "Resolved {} from {} to {}", + specifier, + referrer, + path.display() + ); + Ok(path) + } +} + +#[derive(Debug, Clone)] +pub struct ManagedInNpmPackageChecker { + root_dir: Url, +} + +impl InNpmPackageChecker for ManagedInNpmPackageChecker { + fn in_npm_package(&self, specifier: &Url) -> bool { + specifier.as_ref().starts_with(self.root_dir.as_str()) + } +} + +pub struct ManagedInNpmPkgCheckerCreateOptions<'a> { + pub root_cache_dir_url: &'a Url, + pub maybe_node_modules_path: Option<&'a Path>, +} + +pub fn create_managed_in_npm_pkg_checker( + options: ManagedInNpmPkgCheckerCreateOptions, +) -> ManagedInNpmPackageChecker { + let root_dir = match options.maybe_node_modules_path { + Some(node_modules_folder) => { + deno_path_util::url_from_directory_path(node_modules_folder).unwrap() + } + None => options.root_cache_dir_url.clone(), + }; + debug_assert!(root_dir.as_str().ends_with('/')); + ManagedInNpmPackageChecker { root_dir } +} diff --git a/resolvers/deno/npm/managed/resolution.rs b/resolvers/deno/npm/managed/resolution.rs new file mode 100644 index 0000000000..faa0d43664 --- /dev/null +++ b/resolvers/deno/npm/managed/resolution.rs @@ -0,0 +1,188 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +use deno_npm::resolution::NpmPackagesPartitioned; +use deno_npm::resolution::NpmResolutionSnapshot; +use deno_npm::resolution::PackageCacheFolderIdNotFoundError; +use deno_npm::resolution::PackageNotFoundFromReferrerError; +use deno_npm::resolution::PackageNvNotFoundError; +use deno_npm::resolution::PackageReqNotFoundError; +use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot; +use deno_npm::NpmPackageCacheFolderId; +use deno_npm::NpmPackageId; +use deno_npm::NpmResolutionPackage; +use deno_npm::NpmSystemInfo; +use deno_semver::package::PackageNv; +use deno_semver::package::PackageReq; +use parking_lot::RwLock; + +#[allow(clippy::disallowed_types)] +pub type NpmResolutionCellRc = crate::sync::MaybeArc; + +/// Handles updating and storing npm resolution in memory. +/// +/// This does not interact with the file system. +#[derive(Default)] +pub struct NpmResolutionCell { + snapshot: RwLock, +} + +impl std::fmt::Debug for NpmResolutionCell { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let snapshot = self.snapshot.read(); + f.debug_struct("NpmResolution") + .field("snapshot", &snapshot.as_valid_serialized().as_serialized()) + .finish() + } +} + +impl NpmResolutionCell { + pub fn from_serialized( + initial_snapshot: Option, + ) -> Self { + let snapshot = + NpmResolutionSnapshot::new(initial_snapshot.unwrap_or_default()); + Self::new(snapshot) + } + + pub fn new(initial_snapshot: NpmResolutionSnapshot) -> Self { + Self { + snapshot: RwLock::new(initial_snapshot), + } + } + + pub fn resolve_pkg_cache_folder_copy_index_from_pkg_id( + &self, + id: &NpmPackageId, + ) -> Option { + self + .snapshot + .read() + .package_from_id(id) + .map(|p| p.copy_index) + } + + pub fn resolve_pkg_id_from_pkg_cache_folder_id( + &self, + id: &NpmPackageCacheFolderId, + ) -> Result { + self + .snapshot + .read() + .resolve_pkg_from_pkg_cache_folder_id(id) + .map(|pkg| pkg.id.clone()) + } + + pub fn resolve_package_from_package( + &self, + name: &str, + referrer: &NpmPackageCacheFolderId, + ) -> Result> { + self + .snapshot + .read() + .resolve_package_from_package(name, referrer) + .cloned() + } + + /// Resolve a node package from a deno module. + pub fn resolve_pkg_id_from_pkg_req( + &self, + req: &PackageReq, + ) -> Result { + self + .snapshot + .read() + .resolve_pkg_from_pkg_req(req) + .map(|pkg| pkg.id.clone()) + } + + pub fn resolve_pkg_reqs_from_pkg_id( + &self, + id: &NpmPackageId, + ) -> Vec { + let snapshot = self.snapshot.read(); + let mut pkg_reqs = snapshot + .package_reqs() + .iter() + .filter(|(_, nv)| *nv == &id.nv) + .map(|(req, _)| req.clone()) + .collect::>(); + pkg_reqs.sort(); // be deterministic + pkg_reqs + } + + pub fn resolve_pkg_id_from_deno_module( + &self, + id: &PackageNv, + ) -> Result { + self + .snapshot + .read() + .resolve_package_from_deno_module(id) + .map(|pkg| pkg.id.clone()) + } + + pub fn package_reqs(&self) -> Vec<(PackageReq, PackageNv)> { + self + .snapshot + .read() + .package_reqs() + .iter() + .map(|(k, v)| (k.clone(), v.clone())) + .collect() + } + + pub fn top_level_packages(&self) -> Vec { + self + .snapshot + .read() + .top_level_packages() + .cloned() + .collect::>() + } + + pub fn all_system_packages( + &self, + system_info: &NpmSystemInfo, + ) -> Vec { + self.snapshot.read().all_system_packages(system_info) + } + + pub fn all_system_packages_partitioned( + &self, + system_info: &NpmSystemInfo, + ) -> NpmPackagesPartitioned { + self + .snapshot + .read() + .all_system_packages_partitioned(system_info) + } + + pub fn snapshot(&self) -> NpmResolutionSnapshot { + self.snapshot.read().clone() + } + + pub fn serialized_valid_snapshot( + &self, + ) -> ValidSerializedNpmResolutionSnapshot { + self.snapshot.read().as_valid_serialized() + } + + pub fn serialized_valid_snapshot_for_system( + &self, + system_info: &NpmSystemInfo, + ) -> ValidSerializedNpmResolutionSnapshot { + self + .snapshot + .read() + .as_valid_serialized_for_system(system_info) + } + + pub fn subset(&self, package_reqs: &[PackageReq]) -> NpmResolutionSnapshot { + self.snapshot.read().subset(package_reqs) + } + + pub fn set_snapshot(&self, snapshot: NpmResolutionSnapshot) { + *self.snapshot.write() = snapshot; + } +} diff --git a/resolvers/deno/npm/mod.rs b/resolvers/deno/npm/mod.rs index 082940eb34..fed3d388bf 100644 --- a/resolvers/deno/npm/mod.rs +++ b/resolvers/deno/npm/mod.rs @@ -1,9 +1,11 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::fmt::Debug; +use std::path::Path; use std::path::PathBuf; use boxed_error::Boxed; +use deno_error::JsError; use deno_semver::npm::NpmPackageReqReference; use deno_semver::package::PackageReq; use node_resolver::errors::NodeResolveError; @@ -13,11 +15,12 @@ use node_resolver::errors::PackageFolderResolveIoError; use node_resolver::errors::PackageNotFoundError; use node_resolver::errors::PackageResolveErrorKind; use node_resolver::errors::PackageSubpathResolveError; -use node_resolver::InNpmPackageCheckerRc; +use node_resolver::InNpmPackageChecker; use node_resolver::IsBuiltInNodeModuleChecker; use node_resolver::NodeResolution; use node_resolver::NodeResolutionKind; use node_resolver::NodeResolverRc; +use node_resolver::NpmPackageFolderResolver; use node_resolver::ResolutionMode; use sys_traits::FsCanonicalize; use sys_traits::FsMetadata; @@ -26,120 +29,298 @@ use sys_traits::FsReadDir; use thiserror::Error; use url::Url; -pub use byonm::ByonmInNpmPackageChecker; -pub use byonm::ByonmNpmResolver; -pub use byonm::ByonmNpmResolverCreateOptions; -pub use byonm::ByonmNpmResolverRc; -pub use byonm::ByonmResolvePkgFolderFromDenoReqError; -pub use local::normalize_pkg_name_for_node_modules_deno_folder; +pub use self::byonm::ByonmInNpmPackageChecker; +pub use self::byonm::ByonmNpmResolver; +pub use self::byonm::ByonmNpmResolverCreateOptions; +pub use self::byonm::ByonmNpmResolverRc; +pub use self::byonm::ByonmResolvePkgFolderFromDenoReqError; +pub use self::local::get_package_folder_id_folder_name; +pub use self::local::normalize_pkg_name_for_node_modules_deno_folder; +use self::managed::create_managed_in_npm_pkg_checker; +use self::managed::ManagedInNpmPackageChecker; +use self::managed::ManagedInNpmPkgCheckerCreateOptions; +pub use self::managed::ManagedNpmResolver; +use self::managed::ManagedNpmResolverCreateOptions; +pub use self::managed::ManagedNpmResolverRc; +use crate::sync::new_rc; +use crate::sync::MaybeSend; +use crate::sync::MaybeSync; mod byonm; mod local; +pub mod managed; -#[derive(Debug, Error)] +pub enum CreateInNpmPkgCheckerOptions<'a> { + Managed(ManagedInNpmPkgCheckerCreateOptions<'a>), + Byonm, +} + +#[derive(Debug, Clone)] +pub enum DenoInNpmPackageChecker { + Managed(ManagedInNpmPackageChecker), + Byonm(ByonmInNpmPackageChecker), +} + +impl DenoInNpmPackageChecker { + pub fn new(options: CreateInNpmPkgCheckerOptions) -> Self { + match options { + CreateInNpmPkgCheckerOptions::Managed(options) => { + DenoInNpmPackageChecker::Managed(create_managed_in_npm_pkg_checker( + options, + )) + } + CreateInNpmPkgCheckerOptions::Byonm => { + DenoInNpmPackageChecker::Byonm(ByonmInNpmPackageChecker) + } + } + } +} + +impl InNpmPackageChecker for DenoInNpmPackageChecker { + fn in_npm_package(&self, specifier: &Url) -> bool { + match self { + DenoInNpmPackageChecker::Managed(c) => c.in_npm_package(specifier), + DenoInNpmPackageChecker::Byonm(c) => c.in_npm_package(specifier), + } + } +} + +#[derive(Debug, Error, JsError)] +#[class(generic)] #[error("Could not resolve \"{}\", but found it in a package.json. Deno expects the node_modules/ directory to be up to date. Did you forget to run `deno install`?", specifier)] pub struct NodeModulesOutOfDateError { pub specifier: String, } -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] +#[class(generic)] #[error("Could not find '{}'. Deno expects the node_modules/ directory to be up to date. Did you forget to run `deno install`?", package_json_path.display())] pub struct MissingPackageNodeModulesFolderError { pub package_json_path: PathBuf, } -#[derive(Debug, Boxed)] +#[derive(Debug, Boxed, JsError)] pub struct ResolveIfForNpmPackageError( pub Box, ); -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] pub enum ResolveIfForNpmPackageErrorKind { + #[class(inherit)] #[error(transparent)] NodeResolve(#[from] NodeResolveError), + #[class(inherit)] #[error(transparent)] NodeModulesOutOfDate(#[from] NodeModulesOutOfDateError), } -#[derive(Debug, Boxed)] +#[derive(Debug, Boxed, JsError)] pub struct ResolveReqWithSubPathError(pub Box); -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] pub enum ResolveReqWithSubPathErrorKind { + #[class(inherit)] #[error(transparent)] MissingPackageNodeModulesFolder(#[from] MissingPackageNodeModulesFolderError), + #[class(inherit)] #[error(transparent)] ResolvePkgFolderFromDenoReq(#[from] ResolvePkgFolderFromDenoReqError), + #[class(inherit)] #[error(transparent)] PackageSubpathResolve(#[from] PackageSubpathResolveError), } -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] pub enum ResolvePkgFolderFromDenoReqError { - // todo(dsherret): don't use anyhow here + #[class(inherit)] #[error(transparent)] - Managed(anyhow::Error), + Managed(managed::ManagedResolvePkgFolderFromDenoReqError), + #[class(inherit)] #[error(transparent)] - Byonm(#[from] ByonmResolvePkgFolderFromDenoReqError), + Byonm(byonm::ByonmResolvePkgFolderFromDenoReqError), } -#[allow(clippy::disallowed_types)] -pub type CliNpmReqResolverRc = crate::sync::MaybeArc; - -// todo(dsherret): a temporary trait until we extract -// out the CLI npm resolver into here -pub trait CliNpmReqResolver: Debug + Send + Sync { - fn resolve_pkg_folder_from_deno_module_req( - &self, - req: &PackageReq, - referrer: &Url, - ) -> Result; -} - -pub struct NpmReqResolverOptions< - TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, - TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir, +pub enum NpmResolverCreateOptions< + TSys: FsRead + + FsCanonicalize + + FsMetadata + + std::fmt::Debug + + MaybeSend + + MaybeSync + + Clone + + 'static, > { + Managed(ManagedNpmResolverCreateOptions), + Byonm(ByonmNpmResolverCreateOptions), +} + +#[derive(Debug, Clone)] +pub enum NpmResolver { /// The resolver when "bring your own node_modules" is enabled where Deno /// does not setup the node_modules directories automatically, but instead /// uses what already exists on the file system. - pub byonm_resolver: Option>, - pub in_npm_pkg_checker: InNpmPackageCheckerRc, - pub node_resolver: NodeResolverRc, - pub npm_req_resolver: CliNpmReqResolverRc, + Byonm(ByonmNpmResolverRc), + Managed(ManagedNpmResolverRc), +} + +impl NpmResolver { + pub fn new< + TCreateSys: FsCanonicalize + + FsMetadata + + FsRead + + FsReadDir + + std::fmt::Debug + + MaybeSend + + MaybeSync + + Clone + + 'static, + >( + options: NpmResolverCreateOptions, + ) -> NpmResolver { + match options { + NpmResolverCreateOptions::Managed(options) => { + NpmResolver::Managed(new_rc(ManagedNpmResolver::::new::< + TCreateSys, + >(options))) + } + NpmResolverCreateOptions::Byonm(options) => { + NpmResolver::Byonm(new_rc(ByonmNpmResolver::new(options))) + } + } + } + + pub fn is_byonm(&self) -> bool { + matches!(self, NpmResolver::Byonm(_)) + } + + pub fn is_managed(&self) -> bool { + matches!(self, NpmResolver::Managed(_)) + } + + pub fn as_managed(&self) -> Option<&ManagedNpmResolver> { + match self { + NpmResolver::Managed(resolver) => Some(resolver), + NpmResolver::Byonm(_) => None, + } + } + + pub fn root_node_modules_path(&self) -> Option<&Path> { + match self { + NpmResolver::Byonm(resolver) => resolver.root_node_modules_path(), + NpmResolver::Managed(resolver) => resolver.root_node_modules_path(), + } + } + + pub fn resolve_pkg_folder_from_deno_module_req( + &self, + req: &PackageReq, + referrer: &Url, + ) -> Result { + match self { + NpmResolver::Byonm(byonm_resolver) => byonm_resolver + .resolve_pkg_folder_from_deno_module_req(req, referrer) + .map_err(ResolvePkgFolderFromDenoReqError::Byonm), + NpmResolver::Managed(managed_resolver) => managed_resolver + .resolve_pkg_folder_from_deno_module_req(req, referrer) + .map_err(ResolvePkgFolderFromDenoReqError::Managed), + } + } +} + +impl + NpmPackageFolderResolver for NpmResolver +{ + fn resolve_package_folder_from_package( + &self, + specifier: &str, + referrer: &Url, + ) -> Result { + match self { + NpmResolver::Byonm(byonm_resolver) => { + byonm_resolver.resolve_package_folder_from_package(specifier, referrer) + } + NpmResolver::Managed(managed_resolver) => managed_resolver + .resolve_package_folder_from_package(specifier, referrer), + } + } +} + +pub struct NpmReqResolverOptions< + TInNpmPackageChecker: InNpmPackageChecker, + TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, + TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir, +> { + pub in_npm_pkg_checker: TInNpmPackageChecker, + pub node_resolver: NodeResolverRc< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >, + pub npm_resolver: NpmResolver, pub sys: TSys, } #[allow(clippy::disallowed_types)] -pub type NpmReqResolverRc = - crate::sync::MaybeArc>; +pub type NpmReqResolverRc< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, +> = crate::sync::MaybeArc< + NpmReqResolver< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >, +>; #[derive(Debug)] pub struct NpmReqResolver< + TInNpmPackageChecker: InNpmPackageChecker, TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir, > { - byonm_resolver: Option>, sys: TSys, - in_npm_pkg_checker: InNpmPackageCheckerRc, - node_resolver: NodeResolverRc, - npm_resolver: CliNpmReqResolverRc, + in_npm_pkg_checker: TInNpmPackageChecker, + node_resolver: NodeResolverRc< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >, + npm_resolver: NpmResolver, } impl< + TInNpmPackageChecker: InNpmPackageChecker, TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir, - > NpmReqResolver + > + NpmReqResolver< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + > { pub fn new( - options: NpmReqResolverOptions, + options: NpmReqResolverOptions< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >, ) -> Self { Self { - byonm_resolver: options.byonm_resolver, sys: options.sys, in_npm_pkg_checker: options.in_npm_pkg_checker, node_resolver: options.node_resolver, - npm_resolver: options.npm_req_resolver, + npm_resolver: options.npm_resolver, } } @@ -181,7 +362,7 @@ impl< match resolution_result { Ok(url) => Ok(url), Err(err) => { - if self.byonm_resolver.is_some() { + if matches!(self.npm_resolver, NpmResolver::Byonm(_)) { let package_json_path = package_folder.join("package.json"); if !self.sys.fs_exists_no_err(&package_json_path) { return Err( @@ -249,7 +430,9 @@ impl< .into_box(), ); } - if let Some(byonm_npm_resolver) = &self.byonm_resolver { + if let NpmResolver::Byonm(byonm_npm_resolver) = + &self.npm_resolver + { if byonm_npm_resolver .find_ancestor_package_json_with_dep( package_name, diff --git a/resolvers/deno/sloppy_imports.rs b/resolvers/deno/sloppy_imports.rs index 6644222a8b..486d2dab1e 100644 --- a/resolvers/deno/sloppy_imports.rs +++ b/resolvers/deno/sloppy_imports.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::path::Path; @@ -7,8 +7,12 @@ use std::path::PathBuf; use deno_media_type::MediaType; use deno_path_util::url_from_file_path; use deno_path_util::url_to_file_path; +use sys_traits::FsMetadata; +use sys_traits::FsMetadataValue; use url::Url; +use crate::sync::MaybeDashMap; + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum SloppyImportsFsEntry { File, @@ -368,6 +372,50 @@ impl SloppyImportsResolver { } } +#[derive(Debug)] +pub struct SloppyImportsCachedFs { + sys: TSys, + cache: Option>>, +} + +impl SloppyImportsCachedFs { + pub fn new(sys: TSys) -> Self { + Self { + sys, + cache: Some(Default::default()), + } + } + + pub fn new_without_stat_cache(sys: TSys) -> Self { + Self { sys, cache: None } + } +} + +impl SloppyImportResolverFs for SloppyImportsCachedFs { + fn stat_sync(&self, path: &Path) -> Option { + if let Some(cache) = &self.cache { + if let Some(entry) = cache.get(path) { + return *entry; + } + } + + let entry = self.sys.fs_metadata(path).ok().and_then(|stat| { + if stat.file_type().is_file() { + Some(SloppyImportsFsEntry::File) + } else if stat.file_type().is_dir() { + Some(SloppyImportsFsEntry::Dir) + } else { + None + } + }); + + if let Some(cache) = &self.cache { + cache.insert(path.to_owned(), entry); + } + entry + } +} + #[cfg(test)] mod test { use test_util::TestContext; diff --git a/resolvers/deno/sync.rs b/resolvers/deno/sync.rs index ebcf8509d5..af3e290bb2 100644 --- a/resolvers/deno/sync.rs +++ b/resolvers/deno/sync.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. pub use inner::*; @@ -6,6 +6,8 @@ pub use inner::*; mod inner { #![allow(clippy::disallowed_types)] + pub use core::marker::Send as MaybeSend; + pub use core::marker::Sync as MaybeSync; pub use std::sync::Arc as MaybeArc; pub use dashmap::DashMap as MaybeDashMap; @@ -21,6 +23,11 @@ mod inner { use std::hash::RandomState; pub use std::rc::Rc as MaybeArc; + pub trait MaybeSync {} + impl MaybeSync for T where T: ?Sized {} + pub trait MaybeSend {} + impl MaybeSend for T where T: ?Sized {} + // Wrapper struct that exposes a subset of `DashMap` API. #[derive(Debug)] pub struct MaybeDashMap(RefCell>); @@ -36,7 +43,13 @@ mod inner { } impl MaybeDashMap { - pub fn get<'a>(&'a self, key: &K) -> Option> { + pub fn get<'a, Q: Eq + Hash + ?Sized>( + &'a self, + key: &Q, + ) -> Option> + where + K: std::borrow::Borrow, + { Ref::filter_map(self.0.borrow(), |map| map.get(key)).ok() } @@ -46,3 +59,9 @@ mod inner { } } } + +#[allow(clippy::disallowed_types)] +#[inline] +pub fn new_rc(value: T) -> MaybeArc { + MaybeArc::new(value) +} diff --git a/resolvers/node/Cargo.toml b/resolvers/node/Cargo.toml index 1e35c0a355..ee3a783860 100644 --- a/resolvers/node/Cargo.toml +++ b/resolvers/node/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "node_resolver" -version = "0.22.0" +version = "0.24.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -20,6 +20,7 @@ sync = ["deno_package_json/sync"] anyhow.workspace = true async-trait.workspace = true boxed_error.workspace = true +deno_error.workspace = true deno_media_type.workspace = true deno_package_json.workspace = true deno_path_util.workspace = true diff --git a/resolvers/node/analyze.rs b/resolvers/node/analyze.rs index 2024e6a1e8..e144e2b8fb 100644 --- a/resolvers/node/analyze.rs +++ b/resolvers/node/analyze.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::collections::BTreeSet; @@ -6,6 +6,8 @@ use std::collections::HashSet; use std::path::Path; use std::path::PathBuf; +use anyhow::Context; +use anyhow::Error as AnyError; use deno_path_util::url_from_file_path; use deno_path_util::url_to_file_path; use futures::future::LocalBoxFuture; @@ -13,19 +15,16 @@ use futures::stream::FuturesUnordered; use futures::FutureExt; use futures::StreamExt; use once_cell::sync::Lazy; - -use anyhow::Context; -use anyhow::Error as AnyError; use sys_traits::FsCanonicalize; use sys_traits::FsMetadata; use sys_traits::FsRead; use url::Url; -use crate::npm::InNpmPackageCheckerRc; use crate::resolution::NodeResolverRc; +use crate::InNpmPackageChecker; use crate::IsBuiltInNodeModuleChecker; use crate::NodeResolutionKind; -use crate::NpmPackageFolderResolverRc; +use crate::NpmPackageFolderResolver; use crate::PackageJsonResolverRc; use crate::PathClean; use crate::ResolutionMode; @@ -63,28 +62,49 @@ pub trait CjsCodeAnalyzer { pub struct NodeCodeTranslator< TCjsCodeAnalyzer: CjsCodeAnalyzer, + TInNpmPackageChecker: InNpmPackageChecker, TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, TSys: FsCanonicalize + FsMetadata + FsRead, > { cjs_code_analyzer: TCjsCodeAnalyzer, - in_npm_pkg_checker: InNpmPackageCheckerRc, - node_resolver: NodeResolverRc, - npm_resolver: NpmPackageFolderResolverRc, + in_npm_pkg_checker: TInNpmPackageChecker, + node_resolver: NodeResolverRc< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >, + npm_resolver: TNpmPackageFolderResolver, pkg_json_resolver: PackageJsonResolverRc, sys: TSys, } impl< TCjsCodeAnalyzer: CjsCodeAnalyzer, + TInNpmPackageChecker: InNpmPackageChecker, TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, TSys: FsCanonicalize + FsMetadata + FsRead, - > NodeCodeTranslator + > + NodeCodeTranslator< + TCjsCodeAnalyzer, + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + > { pub fn new( cjs_code_analyzer: TCjsCodeAnalyzer, - in_npm_pkg_checker: InNpmPackageCheckerRc, - node_resolver: NodeResolverRc, - npm_resolver: NpmPackageFolderResolverRc, + in_npm_pkg_checker: TInNpmPackageChecker, + node_resolver: NodeResolverRc< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >, + npm_resolver: TNpmPackageFolderResolver, pkg_json_resolver: PackageJsonResolverRc, sys: TSys, ) -> Self { diff --git a/resolvers/node/errors.rs b/resolvers/node/errors.rs index 26b1a1d84a..1b4ce460d1 100644 --- a/resolvers/node/errors.rs +++ b/resolvers/node/errors.rs @@ -1,10 +1,11 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::fmt::Write; use std::path::PathBuf; use boxed_error::Boxed; +use deno_error::JsError; use thiserror::Error; use url::Url; @@ -55,8 +56,7 @@ pub trait NodeJsErrorCoded { fn code(&self) -> NodeJsErrorCode; } -// todo(https://github.com/denoland/deno_core/issues/810): make this a TypeError -#[derive(Debug, Clone, Error)] +#[derive(Debug, Clone, Error, JsError)] #[error( "[{}] Invalid module '{}' {}{}", self.code(), @@ -64,6 +64,7 @@ pub trait NodeJsErrorCoded { reason, maybe_referrer.as_ref().map(|referrer| format!(" imported from '{}'", referrer)).unwrap_or_default() )] +#[class(type)] pub struct InvalidModuleSpecifierError { pub request: String, pub reason: Cow<'static, str>, @@ -76,13 +77,15 @@ impl NodeJsErrorCoded for InvalidModuleSpecifierError { } } -#[derive(Debug, Boxed)] +#[derive(Debug, Boxed, JsError)] pub struct LegacyResolveError(pub Box); -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] pub enum LegacyResolveErrorKind { + #[class(inherit)] #[error(transparent)] TypesNotFound(#[from] TypesNotFoundError), + #[class(inherit)] #[error(transparent)] ModuleNotFound(#[from] ModuleNotFoundError), } @@ -96,13 +99,14 @@ impl NodeJsErrorCoded for LegacyResolveError { } } -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] #[error( "Could not find package '{}' from referrer '{}'{}.", package_name, referrer, referrer_extra.as_ref().map(|r| format!(" ({})", r)).unwrap_or_default() )] +#[class(generic)] pub struct PackageNotFoundError { pub package_name: String, pub referrer: Url, @@ -116,12 +120,13 @@ impl NodeJsErrorCoded for PackageNotFoundError { } } -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] #[error( "Could not find referrer npm package '{}'{}.", referrer, referrer_extra.as_ref().map(|r| format!(" ({})", r)).unwrap_or_default() )] +#[class(generic)] pub struct ReferrerNotFoundError { pub referrer: Url, /// Extra information about the referrer. @@ -134,12 +139,14 @@ impl NodeJsErrorCoded for ReferrerNotFoundError { } } -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] +#[class(inherit)] #[error("Failed resolving '{package_name}' from referrer '{referrer}'.")] pub struct PackageFolderResolveIoError { pub package_name: String, pub referrer: Url, #[source] + #[inherit] pub source: std::io::Error, } @@ -159,15 +166,18 @@ impl NodeJsErrorCoded for PackageFolderResolveError { } } -#[derive(Debug, Boxed)] +#[derive(Debug, Boxed, JsError)] pub struct PackageFolderResolveError(pub Box); -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] pub enum PackageFolderResolveErrorKind { + #[class(inherit)] #[error(transparent)] PackageNotFound(#[from] PackageNotFoundError), + #[class(inherit)] #[error(transparent)] ReferrerNotFound(#[from] ReferrerNotFoundError), + #[class(inherit)] #[error(transparent)] Io(#[from] PackageFolderResolveIoError), } @@ -182,20 +192,24 @@ impl NodeJsErrorCoded for PackageSubpathResolveError { } } -#[derive(Debug, Boxed)] +#[derive(Debug, Boxed, JsError)] pub struct PackageSubpathResolveError(pub Box); -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] pub enum PackageSubpathResolveErrorKind { + #[class(inherit)] #[error(transparent)] PkgJsonLoad(#[from] PackageJsonLoadError), + #[class(inherit)] #[error(transparent)] Exports(PackageExportsResolveError), + #[class(inherit)] #[error(transparent)] LegacyResolve(LegacyResolveError), } -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] +#[class(generic)] #[error( "Target '{}' not found from '{}'{}{}.", target, @@ -241,19 +255,24 @@ impl NodeJsErrorCoded for PackageTargetResolveError { } } -#[derive(Debug, Boxed)] +#[derive(Debug, Boxed, JsError)] pub struct PackageTargetResolveError(pub Box); -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] pub enum PackageTargetResolveErrorKind { + #[class(inherit)] #[error(transparent)] NotFound(#[from] PackageTargetNotFoundError), + #[class(inherit)] #[error(transparent)] InvalidPackageTarget(#[from] InvalidPackageTargetError), + #[class(inherit)] #[error(transparent)] InvalidModuleSpecifier(#[from] InvalidModuleSpecifierError), + #[class(inherit)] #[error(transparent)] PackageResolve(#[from] PackageResolveError), + #[class(inherit)] #[error(transparent)] TypesNotFound(#[from] TypesNotFoundError), } @@ -267,24 +286,27 @@ impl NodeJsErrorCoded for PackageExportsResolveError { } } -#[derive(Debug, Boxed)] +#[derive(Debug, Boxed, JsError)] pub struct PackageExportsResolveError(pub Box); -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] pub enum PackageExportsResolveErrorKind { + #[class(inherit)] #[error(transparent)] PackagePathNotExported(#[from] PackagePathNotExportedError), + #[class(inherit)] #[error(transparent)] PackageTargetResolve(#[from] PackageTargetResolveError), } -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] #[error( "[{}] Could not find types for '{}'{}", self.code(), self.0.code_specifier, self.0.maybe_referrer.as_ref().map(|r| format!(" imported from '{}'", r)).unwrap_or_default(), )] +#[class(generic)] pub struct TypesNotFoundError(pub Box); #[derive(Debug)] @@ -299,7 +321,7 @@ impl NodeJsErrorCoded for TypesNotFoundError { } } -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] #[error( "[{}] Invalid package config. {}", self.code(), @@ -325,17 +347,18 @@ impl NodeJsErrorCoded for ClosestPkgJsonError { } } -#[derive(Debug, Boxed)] +#[derive(Debug, Boxed, JsError)] pub struct ClosestPkgJsonError(pub Box); -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] pub enum ClosestPkgJsonErrorKind { + #[class(inherit)] #[error(transparent)] Load(#[from] PackageJsonLoadError), } -// todo(https://github.com/denoland/deno_core/issues/810): make this a TypeError -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] +#[class(type)] #[error( "[{}] Package import specifier \"{}\" is not defined{}{}", self.code(), @@ -355,17 +378,21 @@ impl NodeJsErrorCoded for PackageImportNotDefinedError { } } -#[derive(Debug, Boxed)] +#[derive(Debug, Boxed, JsError)] pub struct PackageImportsResolveError(pub Box); -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] pub enum PackageImportsResolveErrorKind { + #[class(inherit)] #[error(transparent)] ClosestPkgJson(ClosestPkgJsonError), + #[class(inherit)] #[error(transparent)] InvalidModuleSpecifier(#[from] InvalidModuleSpecifierError), + #[class(inherit)] #[error(transparent)] NotDefined(#[from] PackageImportNotDefinedError), + #[class(inherit)] #[error(transparent)] Target(#[from] PackageTargetResolveError), } @@ -393,24 +420,30 @@ impl NodeJsErrorCoded for PackageResolveError { } } -#[derive(Debug, Boxed)] +#[derive(Debug, Boxed, JsError)] pub struct PackageResolveError(pub Box); -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] pub enum PackageResolveErrorKind { + #[class(inherit)] #[error(transparent)] ClosestPkgJson(#[from] ClosestPkgJsonError), + #[class(inherit)] #[error(transparent)] InvalidModuleSpecifier(#[from] InvalidModuleSpecifierError), + #[class(inherit)] #[error(transparent)] PackageFolderResolve(#[from] PackageFolderResolveError), + #[class(inherit)] #[error(transparent)] ExportsResolve(#[from] PackageExportsResolveError), + #[class(inherit)] #[error(transparent)] SubpathResolve(#[from] PackageSubpathResolveError), } -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] +#[class(generic)] #[error("Failed joining '{path}' from '{base}'.")] pub struct NodeResolveRelativeJoinError { pub path: String, @@ -419,43 +452,54 @@ pub struct NodeResolveRelativeJoinError { pub source: url::ParseError, } -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] +#[class(generic)] #[error("Failed resolving specifier from data url referrer.")] pub struct DataUrlReferrerError { #[source] pub source: url::ParseError, } -#[derive(Debug, Boxed)] +#[derive(Debug, Boxed, JsError)] pub struct NodeResolveError(pub Box); -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] pub enum NodeResolveErrorKind { + #[class(inherit)] #[error(transparent)] RelativeJoin(#[from] NodeResolveRelativeJoinError), + #[class(inherit)] #[error(transparent)] PackageImportsResolve(#[from] PackageImportsResolveError), + #[class(inherit)] #[error(transparent)] UnsupportedEsmUrlScheme(#[from] UnsupportedEsmUrlSchemeError), + #[class(inherit)] #[error(transparent)] DataUrlReferrer(#[from] DataUrlReferrerError), + #[class(inherit)] #[error(transparent)] PackageResolve(#[from] PackageResolveError), + #[class(inherit)] #[error(transparent)] TypesNotFound(#[from] TypesNotFoundError), + #[class(inherit)] #[error(transparent)] FinalizeResolution(#[from] FinalizeResolutionError), } -#[derive(Debug, Boxed)] +#[derive(Debug, Boxed, JsError)] pub struct FinalizeResolutionError(pub Box); -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] pub enum FinalizeResolutionErrorKind { + #[class(inherit)] #[error(transparent)] InvalidModuleSpecifierError(#[from] InvalidModuleSpecifierError), + #[class(inherit)] #[error(transparent)] ModuleNotFound(#[from] ModuleNotFoundError), + #[class(inherit)] #[error(transparent)] UnsupportedDirImport(#[from] UnsupportedDirImportError), } @@ -470,7 +514,8 @@ impl NodeJsErrorCoded for FinalizeResolutionError { } } -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] +#[class(generic)] #[error( "[{}] Cannot find {} '{}'{}", self.code(), @@ -490,7 +535,8 @@ impl NodeJsErrorCoded for ModuleNotFoundError { } } -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] +#[class(generic)] #[error( "[{}] Directory import '{}' is not supported resolving ES modules{}", self.code(), @@ -508,7 +554,8 @@ impl NodeJsErrorCoded for UnsupportedDirImportError { } } -#[derive(Debug)] +#[derive(Debug, JsError)] +#[class(generic)] pub struct InvalidPackageTargetError { pub pkg_json_path: PathBuf, pub sub_path: String, @@ -564,7 +611,8 @@ impl NodeJsErrorCoded for InvalidPackageTargetError { } } -#[derive(Debug)] +#[derive(Debug, JsError)] +#[class(generic)] pub struct PackagePathNotExportedError { pub pkg_json_path: PathBuf, pub subpath: String, @@ -614,7 +662,8 @@ impl std::fmt::Display for PackagePathNotExportedError { } } -#[derive(Debug, Clone, Error)] +#[derive(Debug, Clone, Error, JsError)] +#[class(type)] #[error( "[{}] Only file and data URLs are supported by the default ESM loader.{} Received protocol '{}'", self.code(), @@ -631,20 +680,25 @@ impl NodeJsErrorCoded for UnsupportedEsmUrlSchemeError { } } -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] pub enum ResolvePkgJsonBinExportError { + #[class(inherit)] #[error(transparent)] PkgJsonLoad(#[from] PackageJsonLoadError), + #[class(generic)] #[error("Failed resolving binary export. '{}' did not exist", pkg_json_path.display())] MissingPkgJson { pkg_json_path: PathBuf }, + #[class(generic)] #[error("Failed resolving binary export. {message}")] InvalidBinProperty { message: String }, } -#[derive(Debug, Error)] +#[derive(Debug, Error, JsError)] pub enum ResolveBinaryCommandsError { + #[class(inherit)] #[error(transparent)] PkgJsonLoad(#[from] PackageJsonLoadError), + #[class(generic)] #[error("'{}' did not have a name", pkg_json_path.display())] MissingPkgJsonName { pkg_json_path: PathBuf }, } @@ -659,7 +713,7 @@ mod test { assert_eq!( PackagePathNotExportedError { pkg_json_path: PathBuf::from("test_path").join("package.json"), - subpath: "./jsx-runtime".to_string(), + subpath: "./jsx-runtime".to_string(), maybe_referrer: None, resolution_kind: NodeResolutionKind::Types }.to_string(), @@ -668,7 +722,7 @@ mod test { assert_eq!( PackagePathNotExportedError { pkg_json_path: PathBuf::from("test_path").join("package.json"), - subpath: ".".to_string(), + subpath: ".".to_string(), maybe_referrer: None, resolution_kind: NodeResolutionKind::Types }.to_string(), diff --git a/resolvers/node/lib.rs b/resolvers/node/lib.rs index 075f819ebb..c0e6383237 100644 --- a/resolvers/node/lib.rs +++ b/resolvers/node/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. #![deny(clippy::print_stderr)] #![deny(clippy::print_stdout)] @@ -9,19 +9,19 @@ mod npm; mod package_json; mod path; mod resolution; + mod sync; pub use deno_package_json::PackageJson; pub use npm::InNpmPackageChecker; -pub use npm::InNpmPackageCheckerRc; pub use npm::NpmPackageFolderResolver; -pub use npm::NpmPackageFolderResolverRc; pub use package_json::PackageJsonResolver; pub use package_json::PackageJsonResolverRc; pub use package_json::PackageJsonThreadLocalCache; pub use path::PathClean; pub use resolution::parse_npm_pkg_name; pub use resolution::resolve_specifier_into_node_modules; +pub use resolution::ConditionsFromResolutionMode; pub use resolution::IsBuiltInNodeModuleChecker; pub use resolution::NodeResolution; pub use resolution::NodeResolutionKind; diff --git a/resolvers/node/npm.rs b/resolvers/node/npm.rs index ab3a179426..bb3de2a7f5 100644 --- a/resolvers/node/npm.rs +++ b/resolvers/node/npm.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::path::Path; use std::path::PathBuf; @@ -9,16 +9,8 @@ use url::Url; use crate::errors; use crate::path::PathClean; -use crate::sync::MaybeSend; -use crate::sync::MaybeSync; -#[allow(clippy::disallowed_types)] -pub type NpmPackageFolderResolverRc = - crate::sync::MaybeArc; - -pub trait NpmPackageFolderResolver: - std::fmt::Debug + MaybeSend + MaybeSync -{ +pub trait NpmPackageFolderResolver { /// Resolves an npm package folder path from the specified referrer. fn resolve_package_folder_from_package( &self, @@ -27,11 +19,8 @@ pub trait NpmPackageFolderResolver: ) -> Result; } -#[allow(clippy::disallowed_types)] -pub type InNpmPackageCheckerRc = crate::sync::MaybeArc; - /// Checks if a provided specifier is in an npm package. -pub trait InNpmPackageChecker: std::fmt::Debug + MaybeSend + MaybeSync { +pub trait InNpmPackageChecker { fn in_npm_package(&self, specifier: &Url) -> bool; fn in_npm_package_at_dir_path(&self, path: &Path) -> bool { diff --git a/resolvers/node/package_json.rs b/resolvers/node/package_json.rs index ebbe099014..2e1d5110bd 100644 --- a/resolvers/node/package_json.rs +++ b/resolvers/node/package_json.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::cell::RefCell; use std::collections::HashMap; diff --git a/resolvers/node/path.rs b/resolvers/node/path.rs index 8c2d35fadf..525aeb36ef 100644 --- a/resolvers/node/path.rs +++ b/resolvers/node/path.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::path::Component; use std::path::Path; diff --git a/resolvers/node/resolution.rs b/resolvers/node/resolution.rs index 95631daf39..9ea5e17e41 100644 --- a/resolvers/node/resolution.rs +++ b/resolvers/node/resolution.rs @@ -1,11 +1,13 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; +use std::fmt::Debug; use std::path::Path; use std::path::PathBuf; use anyhow::bail; use anyhow::Error as AnyError; +use deno_package_json::PackageJson; use deno_path_util::url_from_file_path; use serde_json::Map; use serde_json::Value; @@ -44,22 +46,41 @@ use crate::errors::TypesNotFoundError; use crate::errors::TypesNotFoundErrorData; use crate::errors::UnsupportedDirImportError; use crate::errors::UnsupportedEsmUrlSchemeError; -use crate::npm::InNpmPackageCheckerRc; -use crate::NpmPackageFolderResolverRc; +use crate::InNpmPackageChecker; +use crate::NpmPackageFolderResolver; use crate::PackageJsonResolverRc; use crate::PathClean; -use deno_package_json::PackageJson; pub static DEFAULT_CONDITIONS: &[&str] = &["deno", "node", "import"]; pub static REQUIRE_CONDITIONS: &[&str] = &["require", "node"]; static TYPES_ONLY_CONDITIONS: &[&str] = &["types"]; -fn conditions_from_resolution_mode( - resolution_mode: ResolutionMode, -) -> &'static [&'static str] { - match resolution_mode { - ResolutionMode::Import => DEFAULT_CONDITIONS, - ResolutionMode::Require => REQUIRE_CONDITIONS, +type ConditionsFromResolutionModeFn = Box< + dyn Fn(ResolutionMode) -> &'static [&'static str] + Send + Sync + 'static, +>; + +#[derive(Default)] +pub struct ConditionsFromResolutionMode(Option); + +impl Debug for ConditionsFromResolutionMode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ConditionsFromResolutionMode").finish() + } +} + +impl ConditionsFromResolutionMode { + pub fn new(func: ConditionsFromResolutionModeFn) -> Self { + Self(Some(func)) + } + + fn resolve( + &self, + resolution_mode: ResolutionMode, + ) -> &'static [&'static str] { + match &self.0 { + Some(func) => func(ResolutionMode::Import), + None => resolution_mode.default_conditions(), + } } } @@ -69,6 +90,15 @@ pub enum ResolutionMode { Require, } +impl ResolutionMode { + pub fn default_conditions(&self) -> &'static [&'static str] { + match self { + ResolutionMode::Import => DEFAULT_CONDITIONS, + ResolutionMode::Require => REQUIRE_CONDITIONS, + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum NodeResolutionKind { Execution, @@ -107,32 +137,55 @@ pub trait IsBuiltInNodeModuleChecker: std::fmt::Debug { } #[allow(clippy::disallowed_types)] -pub type NodeResolverRc = - crate::sync::MaybeArc>; +pub type NodeResolverRc< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, +> = crate::sync::MaybeArc< + NodeResolver< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >, +>; #[derive(Debug)] pub struct NodeResolver< + TInNpmPackageChecker: InNpmPackageChecker, TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, TSys: FsCanonicalize + FsMetadata + FsRead, > { - in_npm_pkg_checker: InNpmPackageCheckerRc, + in_npm_pkg_checker: TInNpmPackageChecker, is_built_in_node_module_checker: TIsBuiltInNodeModuleChecker, - npm_pkg_folder_resolver: NpmPackageFolderResolverRc, + npm_pkg_folder_resolver: TNpmPackageFolderResolver, pkg_json_resolver: PackageJsonResolverRc, sys: TSys, + conditions_from_resolution_mode: ConditionsFromResolutionMode, } impl< + TInNpmPackageChecker: InNpmPackageChecker, TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, TSys: FsCanonicalize + FsMetadata + FsRead, - > NodeResolver + > + NodeResolver< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + > { pub fn new( - in_npm_pkg_checker: InNpmPackageCheckerRc, + in_npm_pkg_checker: TInNpmPackageChecker, is_built_in_node_module_checker: TIsBuiltInNodeModuleChecker, - npm_pkg_folder_resolver: NpmPackageFolderResolverRc, + npm_pkg_folder_resolver: TNpmPackageFolderResolver, pkg_json_resolver: PackageJsonResolverRc, sys: TSys, + conditions_from_resolution_mode: ConditionsFromResolutionMode, ) -> Self { Self { in_npm_pkg_checker, @@ -140,6 +193,7 @@ impl< npm_pkg_folder_resolver, pkg_json_resolver, sys, + conditions_from_resolution_mode, } } @@ -197,11 +251,14 @@ impl< } } + let conditions = self + .conditions_from_resolution_mode + .resolve(resolution_mode); let url = self.module_resolve( specifier, referrer, resolution_mode, - conditions_from_resolution_mode(resolution_mode), + conditions, resolution_kind, )?; @@ -211,6 +268,7 @@ impl< &file_path, Some(referrer), resolution_mode, + conditions, )? } else { url @@ -343,7 +401,9 @@ impl< &package_subpath, maybe_referrer, resolution_mode, - conditions_from_resolution_mode(resolution_mode), + self + .conditions_from_resolution_mode + .resolve(resolution_mode), resolution_kind, )?; // TODO(bartlomieju): skipped checking errors for commonJS resolution and @@ -405,12 +465,24 @@ impl< Ok(url) } + /// Resolves an npm package folder path from the specified referrer. + pub fn resolve_package_folder_from_package( + &self, + specifier: &str, + referrer: &Url, + ) -> Result { + self + .npm_pkg_folder_resolver + .resolve_package_folder_from_package(specifier, referrer) + } + /// Checks if the resolved file has a corresponding declaration file. fn path_to_declaration_url( &self, path: &Path, maybe_referrer: Option<&Url>, resolution_mode: ResolutionMode, + conditions: &[&str], ) -> Result { fn probe_extensions( sys: &TSys, @@ -474,7 +546,7 @@ impl< /* sub path */ ".", maybe_referrer, resolution_mode, - conditions_from_resolution_mode(resolution_mode), + conditions, NodeResolutionKind::Types, ); if let Ok(resolution) = resolution_result { @@ -855,6 +927,7 @@ impl< &path, maybe_referrer, resolution_mode, + conditions, )?)); } else { return Ok(Some(url)); @@ -1212,6 +1285,7 @@ impl< package_subpath, maybe_referrer, resolution_mode, + conditions, resolution_kind, ) .map_err(|err| { @@ -1249,6 +1323,7 @@ impl< package_json, referrer, resolution_mode, + conditions, resolution_kind, ) .map_err(|err| { @@ -1268,6 +1343,7 @@ impl< package_json, referrer, resolution_mode, + conditions, resolution_kind, ) .map_err(|err| { @@ -1281,6 +1357,7 @@ impl< package_subpath, referrer, resolution_mode, + conditions, resolution_kind, ) .map_err(|err| { @@ -1294,12 +1371,18 @@ impl< package_subpath: &str, referrer: Option<&Url>, resolution_mode: ResolutionMode, + conditions: &[&str], resolution_kind: NodeResolutionKind, ) -> Result { assert_ne!(package_subpath, "."); let file_path = directory.join(package_subpath); if resolution_kind.is_types() { - Ok(self.path_to_declaration_url(&file_path, referrer, resolution_mode)?) + Ok(self.path_to_declaration_url( + &file_path, + referrer, + resolution_mode, + conditions, + )?) } else { Ok(url_from_file_path(&file_path).unwrap()) } @@ -1311,6 +1394,7 @@ impl< package_subpath: &str, maybe_referrer: Option<&Url>, resolution_mode: ResolutionMode, + conditions: &[&str], resolution_kind: NodeResolutionKind, ) -> Result { if package_subpath == "." { @@ -1327,6 +1411,7 @@ impl< package_subpath, maybe_referrer, resolution_mode, + conditions, resolution_kind, ) .map_err(|err| err.into()) @@ -1338,6 +1423,7 @@ impl< package_json: &PackageJson, maybe_referrer: Option<&Url>, resolution_mode: ResolutionMode, + conditions: &[&str], resolution_kind: NodeResolutionKind, ) -> Result { let pkg_json_kind = match resolution_mode { @@ -1356,6 +1442,7 @@ impl< &main, maybe_referrer, resolution_mode, + conditions, ); // don't surface errors, fallback to checking the index now if let Ok(url) = decl_url_result { diff --git a/resolvers/node/sync.rs b/resolvers/node/sync.rs index 3c4729aa2c..218253b453 100644 --- a/resolvers/node/sync.rs +++ b/resolvers/node/sync.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. pub use inner::*; @@ -7,17 +7,9 @@ mod inner { #![allow(clippy::disallowed_types)] pub use std::sync::Arc as MaybeArc; - - pub use core::marker::Send as MaybeSend; - pub use core::marker::Sync as MaybeSync; } #[cfg(not(feature = "sync"))] mod inner { pub use std::rc::Rc as MaybeArc; - - pub trait MaybeSync {} - impl MaybeSync for T where T: ?Sized {} - pub trait MaybeSend {} - impl MaybeSend for T where T: ?Sized {} } diff --git a/resolvers/npm_cache/Cargo.toml b/resolvers/npm_cache/Cargo.toml index 48d0a32437..4c6cca2416 100644 --- a/resolvers/npm_cache/Cargo.toml +++ b/resolvers/npm_cache/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_npm_cache" -version = "0.3.0" +version = "0.5.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -14,16 +14,11 @@ description = "Helpers for downloading and caching npm dependencies for Deno" path = "lib.rs" [dependencies] -# todo(dsherret): remove this dependency -anyhow.workspace = true -# todo(dsherret): remove this dependency -deno_core.workspace = true - async-trait.workspace = true base64.workspace = true boxed_error.workspace = true deno_cache_dir.workspace = true -deno_error.workspace = true +deno_error = { workspace = true, features = ["serde", "serde_json", "tokio"] } deno_npm.workspace = true deno_path_util.workspace = true deno_semver.workspace = true diff --git a/resolvers/npm_cache/fs_util.rs b/resolvers/npm_cache/fs_util.rs index ed123f085c..77269ebe0b 100644 --- a/resolvers/npm_cache/fs_util.rs +++ b/resolvers/npm_cache/fs_util.rs @@ -1,10 +1,10 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use anyhow::Context; -use anyhow::Error as AnyError; use std::io::ErrorKind; use std::path::Path; +use std::path::PathBuf; use std::time::Duration; + use sys_traits::FsCreateDirAll; use sys_traits::FsDirEntry; use sys_traits::FsHardLink; @@ -12,6 +12,56 @@ use sys_traits::FsReadDir; use sys_traits::FsRemoveFile; use sys_traits::ThreadSleep; +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum HardLinkDirRecursiveError { + #[class(inherit)] + #[error(transparent)] + Io(#[from] std::io::Error), + #[class(inherit)] + #[error("Creating {path}")] + Creating { + path: PathBuf, + #[source] + #[inherit] + source: std::io::Error, + }, + #[class(inherit)] + #[error("Creating {path}")] + Reading { + path: PathBuf, + #[source] + #[inherit] + source: std::io::Error, + }, + #[class(inherit)] + #[error("Dir {from} to {to}")] + Dir { + from: PathBuf, + to: PathBuf, + #[source] + #[inherit] + source: Box, + }, + #[class(inherit)] + #[error("Removing file to hard link {from} to {to}")] + RemoveFileToHardLink { + from: PathBuf, + to: PathBuf, + #[source] + #[inherit] + source: std::io::Error, + }, + #[class(inherit)] + #[error("Hard linking {from} to {to}")] + HardLinking { + from: PathBuf, + to: PathBuf, + #[source] + #[inherit] + source: std::io::Error, + }, +} + /// Hardlinks the files in one directory to another directory. /// /// Note: Does not handle symlinks. @@ -21,13 +71,19 @@ pub fn hard_link_dir_recursive< sys: &TSys, from: &Path, to: &Path, -) -> Result<(), AnyError> { - sys - .fs_create_dir_all(to) - .with_context(|| format!("Creating {}", to.display()))?; - let read_dir = sys - .fs_read_dir(from) - .with_context(|| format!("Reading {}", from.display()))?; +) -> Result<(), HardLinkDirRecursiveError> { + sys.fs_create_dir_all(to).map_err(|source| { + HardLinkDirRecursiveError::Creating { + path: to.to_path_buf(), + source, + } + })?; + let read_dir = sys.fs_read_dir(from).map_err(|source| { + HardLinkDirRecursiveError::Reading { + path: from.to_path_buf(), + source, + } + })?; for entry in read_dir { let entry = entry?; @@ -36,8 +92,12 @@ pub fn hard_link_dir_recursive< let new_to = to.join(entry.file_name()); if file_type.is_dir() { - hard_link_dir_recursive(sys, &new_from, &new_to).with_context(|| { - format!("Dir {} to {}", new_from.display(), new_to.display()) + hard_link_dir_recursive(sys, &new_from, &new_to).map_err(|source| { + HardLinkDirRecursiveError::Dir { + from: new_from.to_path_buf(), + to: new_to.to_path_buf(), + source: Box::new(source), + } })?; } else if file_type.is_file() { // note: chance for race conditions here between attempting to create, @@ -54,12 +114,10 @@ pub fn hard_link_dir_recursive< // faster to reduce contention. sys.thread_sleep(Duration::from_millis(10)); } else { - return Err(err).with_context(|| { - format!( - "Removing file to hard link {} to {}", - new_from.display(), - new_to.display() - ) + return Err(HardLinkDirRecursiveError::RemoveFileToHardLink { + from: new_from.to_path_buf(), + to: new_to.to_path_buf(), + source: err, }); } } @@ -73,22 +131,18 @@ pub fn hard_link_dir_recursive< if err.kind() == ErrorKind::AlreadyExists { sys.thread_sleep(Duration::from_millis(10)); } else { - return Err(err).with_context(|| { - format!( - "Hard linking {} to {}", - new_from.display(), - new_to.display() - ) + return Err(HardLinkDirRecursiveError::HardLinking { + from: new_from.to_path_buf(), + to: new_to.to_path_buf(), + source: err, }); } } } else { - return Err(err).with_context(|| { - format!( - "Hard linking {} to {}", - new_from.display(), - new_to.display() - ) + return Err(HardLinkDirRecursiveError::HardLinking { + from: new_from.to_path_buf(), + to: new_to.to_path_buf(), + source: err, }); } } diff --git a/resolvers/npm_cache/lib.rs b/resolvers/npm_cache/lib.rs index e681fa71ac..f0de201b75 100644 --- a/resolvers/npm_cache/lib.rs +++ b/resolvers/npm_cache/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashSet; use std::io::ErrorKind; @@ -6,11 +6,9 @@ use std::path::Path; use std::path::PathBuf; use std::sync::Arc; -use anyhow::bail; -use anyhow::Context; -use anyhow::Error as AnyError; use deno_cache_dir::file_fetcher::CacheSetting; use deno_cache_dir::npm::NpmCacheDir; +use deno_error::JsErrorBox; use deno_npm::npm_rc::ResolvedNpmRc; use deno_npm::registry::NpmPackageInfo; use deno_npm::NpmPackageCacheFolderId; @@ -40,18 +38,19 @@ mod tarball; mod tarball_extract; pub use fs_util::hard_link_dir_recursive; -pub use registry_info::RegistryInfoProvider; -pub use tarball::TarballCache; - // todo(#27198): make both of these private and get the rest of the code // using RegistryInfoProvider. pub use registry_info::get_package_url; +pub use registry_info::RegistryInfoProvider; pub use remote::maybe_auth_header_for_npm_registry; +pub use tarball::EnsurePackageError; +pub use tarball::TarballCache; -#[derive(Debug)] +#[derive(Debug, deno_error::JsError)] +#[class(generic)] pub struct DownloadError { pub status_code: Option, - pub error: AnyError, + pub error: JsErrorBox, } impl std::error::Error for DownloadError { @@ -204,7 +203,7 @@ impl< pub fn ensure_copy_package( &self, folder_id: &NpmPackageCacheFolderId, - ) -> Result<(), AnyError> { + ) -> Result<(), WithFolderSyncLockError> { let registry_url = self.npmrc.get_registry_url(&folder_id.nv.name); assert_ne!(folder_id.copy_index, 0); let package_folder = self.cache_dir.package_folder_for_id( @@ -238,6 +237,7 @@ impl< &original_package_folder, &package_folder, ) + .map_err(JsErrorBox::from_err) })?; Ok(()) } @@ -296,30 +296,32 @@ impl< pub fn load_package_info( &self, name: &str, - ) -> Result, AnyError> { + ) -> Result, serde_json::Error> { let file_cache_path = self.get_registry_package_info_file_cache_path(name); let file_text = match std::fs::read_to_string(file_cache_path) { Ok(file_text) => file_text, Err(err) if err.kind() == ErrorKind::NotFound => return Ok(None), - Err(err) => return Err(err.into()), + Err(err) => return Err(serde_json::Error::io(err)), }; - Ok(serde_json::from_str(&file_text)?) + serde_json::from_str(&file_text) } pub fn save_package_info( &self, name: &str, package_info: &NpmPackageInfo, - ) -> Result<(), AnyError> { + ) -> Result<(), JsErrorBox> { let file_cache_path = self.get_registry_package_info_file_cache_path(name); - let file_text = serde_json::to_string(&package_info)?; + let file_text = + serde_json::to_string(&package_info).map_err(JsErrorBox::from_err)?; atomic_write_file_with_retries( &self.sys, &file_cache_path, file_text.as_bytes(), 0o644, - )?; + ) + .map_err(JsErrorBox::from_err)?; Ok(()) } @@ -331,18 +333,52 @@ impl< const NPM_PACKAGE_SYNC_LOCK_FILENAME: &str = ".deno_sync_lock"; +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum WithFolderSyncLockError { + #[class(inherit)] + #[error("Error creating '{path}'")] + CreateDir { + path: PathBuf, + #[source] + #[inherit] + source: std::io::Error, + }, + #[class(inherit)] + #[error("Error creating package sync lock file at '{path}'. Maybe try manually deleting this folder.")] + CreateLockFile { + path: PathBuf, + #[source] + #[inherit] + source: std::io::Error, + }, + #[class(inherit)] + #[error(transparent)] + Action(#[from] JsErrorBox), + #[class(generic)] + #[error("Failed setting up package cache directory for {package}, then failed cleaning it up.\n\nOriginal error:\n\n{error}\n\nRemove error:\n\n{remove_error}\n\nPlease manually delete this folder or you will run into issues using this package in the future:\n\n{output_folder}")] + SetUpPackageCacheDir { + package: Box, + error: Box, + remove_error: std::io::Error, + output_folder: PathBuf, + }, +} + // todo(dsherret): use `sys` here instead of `std::fs`. fn with_folder_sync_lock( package: &PackageNv, output_folder: &Path, - action: impl FnOnce() -> Result<(), AnyError>, -) -> Result<(), AnyError> { + action: impl FnOnce() -> Result<(), JsErrorBox>, +) -> Result<(), WithFolderSyncLockError> { fn inner( output_folder: &Path, - action: impl FnOnce() -> Result<(), AnyError>, - ) -> Result<(), AnyError> { - std::fs::create_dir_all(output_folder).with_context(|| { - format!("Error creating '{}'.", output_folder.display()) + action: impl FnOnce() -> Result<(), JsErrorBox>, + ) -> Result<(), WithFolderSyncLockError> { + std::fs::create_dir_all(output_folder).map_err(|source| { + WithFolderSyncLockError::CreateDir { + path: output_folder.to_path_buf(), + source, + } })?; // This sync lock file is a way to ensure that partially created @@ -366,16 +402,10 @@ fn with_folder_sync_lock( let _ignore = std::fs::remove_file(&sync_lock_path); Ok(()) } - Err(err) => { - bail!( - concat!( - "Error creating package sync lock file at '{}'. ", - "Maybe try manually deleting this folder.\n\n{:#}", - ), - output_folder.display(), - err - ); - } + Err(err) => Err(WithFolderSyncLockError::CreateLockFile { + path: output_folder.to_path_buf(), + source: err, + }), } } @@ -384,19 +414,12 @@ fn with_folder_sync_lock( Err(err) => { if let Err(remove_err) = std::fs::remove_dir_all(output_folder) { if remove_err.kind() != std::io::ErrorKind::NotFound { - bail!( - concat!( - "Failed setting up package cache directory for {}, then ", - "failed cleaning it up.\n\nOriginal error:\n\n{}\n\n", - "Remove error:\n\n{}\n\nPlease manually ", - "delete this folder or you will run into issues using this ", - "package in the future:\n\n{}" - ), - package, - err, - remove_err, - output_folder.display(), - ); + return Err(WithFolderSyncLockError::SetUpPackageCacheDir { + package: Box::new(package.clone()), + error: Box::new(err), + remove_error: remove_err, + output_folder: output_folder.to_path_buf(), + }); } } Err(err) diff --git a/resolvers/npm_cache/registry_info.rs b/resolvers/npm_cache/registry_info.rs index 57e188200d..673f2ff445 100644 --- a/resolvers/npm_cache/registry_info.rs +++ b/resolvers/npm_cache/registry_info.rs @@ -1,14 +1,11 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashMap; use std::collections::HashSet; use std::sync::Arc; -use anyhow::anyhow; -use anyhow::bail; -use anyhow::Context; -use anyhow::Error as AnyError; use async_trait::async_trait; +use deno_error::JsErrorBox; use deno_npm::npm_rc::ResolvedNpmRc; use deno_npm::registry::NpmPackageInfo; use deno_npm::registry::NpmRegistryApi; @@ -27,7 +24,6 @@ use sys_traits::FsRemoveFile; use sys_traits::FsRename; use sys_traits::SystemRandom; use sys_traits::ThreadSleep; -use thiserror::Error; use url::Url; use crate::remote::maybe_auth_header_for_npm_registry; @@ -35,34 +31,9 @@ use crate::NpmCache; use crate::NpmCacheHttpClient; use crate::NpmCacheSetting; -type LoadResult = Result>; +type LoadResult = Result>; type LoadFuture = LocalBoxFuture<'static, LoadResult>; -#[derive(Debug, Error)] -#[error(transparent)] -pub struct AnyhowJsError(pub AnyError); - -impl deno_error::JsErrorClass for AnyhowJsError { - fn get_class(&self) -> &'static str { - "generic" - } - - fn get_message(&self) -> std::borrow::Cow<'static, str> { - self.0.to_string().into() - } - - fn get_additional_properties( - &self, - ) -> Option< - Vec<( - std::borrow::Cow<'static, str>, - std::borrow::Cow<'static, str>, - )>, - > { - None - } -} - #[derive(Debug, Clone)] enum FutureResult { PackageNotExists, @@ -80,7 +51,7 @@ enum MemoryCacheItem { FsCached, /// An item is memory cached when it fails saving to the file system cache /// or the package does not exist. - MemoryCached(Result>, Arc>), + MemoryCached(Result>, Arc>), } #[derive(Debug, Default)] @@ -125,6 +96,39 @@ impl MemoryCache { } } +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(generic)] +pub enum LoadFileCachedPackageInfoError { + #[error("Previously saved '{name}' from the npm cache, but now it fails to load: {err}")] + LoadPackageInfo { + err: serde_json::Error, + name: String, + }, + #[error("The package '{0}' previously saved its registry information to the file system cache, but that file no longer exists.")] + FileMissing(String), +} + +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(inherit)] +#[error("Failed loading {url} for package \"{name}\"")] +pub struct LoadPackageInfoError { + url: Url, + name: String, + #[inherit] + #[source] + inner: LoadPackageInfoInnerError, +} + +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum LoadPackageInfoInnerError { + #[class(inherit)] + #[error("{0}")] + LoadFileCachedPackageInfo(LoadFileCachedPackageInfoError), + #[class(inherit)] + #[error("{0}")] + Other(Arc), +} + // todo(#27198): refactor to store this only in the http cache /// Downloads packuments from the npm registry. @@ -224,7 +228,7 @@ impl< package_name: name.to_string(), }), Err(err) => Err(NpmRegistryPackageInfoLoadError::LoadError(Arc::new( - AnyhowJsError(err), + JsErrorBox::from_err(err), ))), } } @@ -232,20 +236,20 @@ impl< pub async fn maybe_package_info( self: &Arc, name: &str, - ) -> Result>, AnyError> { - self.load_package_info_inner(name).await.with_context(|| { - format!( - "Failed loading {} for package \"{}\"", - get_package_url(&self.npmrc, name), - name - ) + ) -> Result>, LoadPackageInfoError> { + self.load_package_info_inner(name).await.map_err(|err| { + LoadPackageInfoError { + url: get_package_url(&self.npmrc, name), + name: name.to_string(), + inner: err, + } }) } async fn load_package_info_inner( self: &Arc, name: &str, - ) -> Result>, AnyError> { + ) -> Result>, LoadPackageInfoInnerError> { let (cache_item, clear_id) = { let mut mem_cache = self.memory_cache.lock(); let cache_item = if let Some(cache_item) = mem_cache.get(name) { @@ -270,9 +274,10 @@ impl< .load_file_cached_package_info(name) .await .map(|info| Some(Arc::new(info))) + .map_err(LoadPackageInfoInnerError::LoadFileCachedPackageInfo) } MemoryCacheItem::MemoryCached(maybe_info) => { - maybe_info.clone().map_err(|e| anyhow!("{}", e)) + maybe_info.clone().map_err(LoadPackageInfoInnerError::Other) } MemoryCacheItem::Pending(value_creator) => { match value_creator.get().await { @@ -304,13 +309,13 @@ impl< Ok(None) } Err(err) => { - let return_err = anyhow!("{:#}", err); + let return_err = err.clone(); self.memory_cache.lock().try_insert( clear_id, name, MemoryCacheItem::MemoryCached(Err(err)), ); - Err(return_err) + Err(LoadPackageInfoInnerError::Other(return_err)) } } } @@ -320,7 +325,7 @@ impl< async fn load_file_cached_package_info( &self, name: &str, - ) -> Result { + ) -> Result { // this scenario failing should be exceptionally rare so let's // deal with improving it only when anyone runs into an issue let maybe_package_info = deno_unsync::spawn_blocking({ @@ -330,17 +335,15 @@ impl< }) .await .unwrap() - .with_context(|| { - format!( - "Previously saved '{}' from the npm cache, but now it fails to load.", - name - ) + .map_err(|err| LoadFileCachedPackageInfoError::LoadPackageInfo { + err, + name: name.to_string(), })?; match maybe_package_info { Some(package_info) => Ok(package_info), - None => { - bail!("The package '{}' previously saved its registry information to the file system cache, but that file no longer exists.", name) - } + None => Err(LoadFileCachedPackageInfoError::FileMissing( + name.to_string(), + )), } } @@ -352,7 +355,8 @@ impl< match maybe_auth_header_for_npm_registry(registry_config) { Ok(maybe_auth_header) => maybe_auth_header, Err(err) => { - return std::future::ready(Err(Arc::new(err))).boxed_local() + return std::future::ready(Err(Arc::new(JsErrorBox::from_err(err)))) + .boxed_local() } }; let name = name.to_string(); @@ -363,14 +367,14 @@ impl< || downloader.previously_loaded_packages.lock().contains(&name) { // attempt to load from the file cache - if let Some(info) = downloader.cache.load_package_info(&name)? { + if let Some(info) = downloader.cache.load_package_info(&name).map_err(JsErrorBox::from_err)? { let result = Arc::new(info); return Ok(FutureResult::SavedFsCache(result)); } } if *downloader.cache.cache_setting() == NpmCacheSetting::Only { - return Err(deno_core::error::custom_error( + return Err(JsErrorBox::new( "NotCached", format!( "npm package not found in cache: \"{name}\", --cached-only is specified." @@ -386,12 +390,12 @@ impl< package_url, maybe_auth_header, ) - .await?; + .await.map_err(JsErrorBox::from_err)?; match maybe_bytes { Some(bytes) => { let future_result = deno_unsync::spawn_blocking( - move || -> Result { - let package_info = serde_json::from_slice(&bytes)?; + move || -> Result { + let package_info = serde_json::from_slice(&bytes).map_err(JsErrorBox::from_err)?; match downloader.cache.save_package_info(&name, &package_info) { Ok(()) => { Ok(FutureResult::SavedFsCache(Arc::new(package_info))) @@ -407,7 +411,8 @@ impl< } }, ) - .await??; + .await + .map_err(JsErrorBox::from_err)??; Ok(future_result) } None => Ok(FutureResult::PackageNotExists), diff --git a/resolvers/npm_cache/remote.rs b/resolvers/npm_cache/remote.rs index 538554612f..0e04d05502 100644 --- a/resolvers/npm_cache/remote.rs +++ b/resolvers/npm_cache/remote.rs @@ -1,17 +1,27 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use anyhow::bail; -use anyhow::Context; -use anyhow::Error as AnyError; use base64::prelude::BASE64_STANDARD; use base64::Engine; use deno_npm::npm_rc::RegistryConfig; use http::header; +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum AuthHeaderForNpmRegistryError { + #[class(type)] + #[error("Both the username and password must be provided for basic auth")] + Both, + #[class(type)] + #[error("The password in npmrc is an invalid base64 string: {0}")] + Base64(base64::DecodeError), +} + // TODO(bartlomieju): support more auth methods besides token and basic auth pub fn maybe_auth_header_for_npm_registry( registry_config: &RegistryConfig, -) -> Result, AnyError> { +) -> Result< + Option<(header::HeaderName, header::HeaderValue)>, + AuthHeaderForNpmRegistryError, +> { if let Some(token) = registry_config.auth_token.as_ref() { return Ok(Some(( header::AUTHORIZATION, @@ -33,7 +43,7 @@ pub fn maybe_auth_header_for_npm_registry( if (username.is_some() && password.is_none()) || (username.is_none() && password.is_some()) { - bail!("Both the username and password must be provided for basic auth") + return Err(AuthHeaderForNpmRegistryError::Both); } if username.is_some() && password.is_some() { @@ -42,7 +52,7 @@ pub fn maybe_auth_header_for_npm_registry( // https://github.com/npm/cli/blob/780afc50e3a345feb1871a28e33fa48235bc3bd5/workspaces/config/lib/index.js#L846-L851 let pw_base64 = BASE64_STANDARD .decode(password.unwrap()) - .with_context(|| "The password in npmrc is an invalid base64 string")?; + .map_err(AuthHeaderForNpmRegistryError::Base64)?; let bearer = BASE64_STANDARD.encode(format!( "{}:{}", username.unwrap(), diff --git a/resolvers/npm_cache/tarball.rs b/resolvers/npm_cache/tarball.rs index 3a7e9df8a9..7a9453e655 100644 --- a/resolvers/npm_cache/tarball.rs +++ b/resolvers/npm_cache/tarball.rs @@ -1,12 +1,9 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashMap; use std::sync::Arc; -use anyhow::anyhow; -use anyhow::bail; -use anyhow::Context; -use anyhow::Error as AnyError; +use deno_error::JsErrorBox; use deno_npm::npm_rc::ResolvedNpmRc; use deno_npm::registry::NpmPackageVersionDistInfo; use deno_semver::package::PackageNv; @@ -33,7 +30,7 @@ use crate::NpmCache; use crate::NpmCacheHttpClient; use crate::NpmCacheSetting; -type LoadResult = Result<(), Arc>; +type LoadResult = Result<(), Arc>; type LoadFuture = LocalBoxFuture<'static, LoadResult>; #[derive(Debug, Clone)] @@ -41,7 +38,7 @@ enum MemoryCacheItem { /// The cache item hasn't finished yet. Pending(Arc>), /// The result errored. - Errored(Arc), + Errored(Arc), /// This package has already been cached. Cached, } @@ -73,6 +70,14 @@ pub struct TarballCache< memory_cache: Mutex>, } +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(generic)] +#[error("Failed caching npm package '{package_nv}'")] +pub struct EnsurePackageError { + package_nv: Box, + #[source] + source: Arc, +} impl< THttpClient: NpmCacheHttpClient, TSys: FsCreateDirAll @@ -108,18 +113,21 @@ impl< self: &Arc, package_nv: &PackageNv, dist: &NpmPackageVersionDistInfo, - ) -> Result<(), AnyError> { + ) -> Result<(), EnsurePackageError> { self .ensure_package_inner(package_nv, dist) .await - .with_context(|| format!("Failed caching npm package '{}'.", package_nv)) + .map_err(|source| EnsurePackageError { + package_nv: Box::new(package_nv.clone()), + source, + }) } async fn ensure_package_inner( self: &Arc, package_nv: &PackageNv, dist: &NpmPackageVersionDistInfo, - ) -> Result<(), AnyError> { + ) -> Result<(), Arc> { let cache_item = { let mut mem_cache = self.memory_cache.lock(); if let Some(cache_item) = mem_cache.get(package_nv) { @@ -141,7 +149,7 @@ impl< match cache_item { MemoryCacheItem::Cached => Ok(()), - MemoryCacheItem::Errored(err) => Err(anyhow!("{:#}", err)), + MemoryCacheItem::Errored(err) => Err(err), MemoryCacheItem::Pending(creator) => { let result = creator.get().await; match result { @@ -151,10 +159,9 @@ impl< Ok(()) } Err(err) => { - let result_err = anyhow!("{:#}", err); *self.memory_cache.lock().get_mut(package_nv).unwrap() = - MemoryCacheItem::Errored(err); - Err(result_err) + MemoryCacheItem::Errored(err.clone()); + Err(err) } } } @@ -176,7 +183,7 @@ impl< if should_use_cache && package_folder_exists { return Ok(()); } else if tarball_cache.cache.cache_setting() == &NpmCacheSetting::Only { - return Err(deno_core::error::custom_error( + return Err(JsErrorBox::new( "NotCached", format!( "npm package not found in cache: \"{}\", --cached-only is specified.", @@ -187,12 +194,12 @@ impl< } if dist.tarball.is_empty() { - bail!("Tarball URL was empty."); + return Err(JsErrorBox::generic("Tarball URL was empty.")); } // IMPORTANT: npm registries may specify tarball URLs at different URLS than the // registry, so we MUST get the auth for the tarball URL and not the registry URL. - let tarball_uri = Url::parse(&dist.tarball)?; + let tarball_uri = Url::parse(&dist.tarball).map_err(JsErrorBox::from_err)?; let maybe_registry_config = tarball_cache.npmrc.tarball_config(&tarball_uri); let maybe_auth_header = maybe_registry_config.and_then(|c| maybe_auth_header_for_npm_registry(c).ok()?); @@ -207,7 +214,7 @@ impl< && maybe_registry_config.is_none() && tarball_cache.npmrc.get_registry_config(&package_nv.name).auth_token.is_some() { - bail!( + return Err(JsErrorBox::generic(format!( concat!( "No auth for tarball URI, but present for scoped registry.\n\n", "Tarball URI: {}\n", @@ -216,9 +223,9 @@ impl< ), dist.tarball, registry_url, - ) + ))); } - return Err(err.into()) + return Err(JsErrorBox::from_err(err)) }, }; match maybe_bytes { @@ -247,10 +254,10 @@ impl< extraction_mode, ) }) - .await? + .await.map_err(JsErrorBox::from_err)?.map_err(JsErrorBox::from_err) } None => { - bail!("Could not find npm package tarball at: {}", dist.tarball); + Err(JsErrorBox::generic(format!("Could not find npm package tarball at: {}", dist.tarball))) } } } diff --git a/resolvers/npm_cache/tarball_extract.rs b/resolvers/npm_cache/tarball_extract.rs index affe93eaa4..e53e4544d2 100644 --- a/resolvers/npm_cache/tarball_extract.rs +++ b/resolvers/npm_cache/tarball_extract.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::collections::HashSet; @@ -7,9 +7,6 @@ use std::io::ErrorKind; use std::path::Path; use std::path::PathBuf; -use anyhow::bail; -use anyhow::Context; -use anyhow::Error as AnyError; use base64::prelude::BASE64_STANDARD; use base64::Engine; use deno_npm::registry::NpmPackageVersionDistInfo; @@ -31,23 +28,37 @@ pub enum TarballExtractionMode { SiblingTempDir, } +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum VerifyAndExtractTarballError { + #[class(inherit)] + #[error(transparent)] + TarballIntegrity(#[from] TarballIntegrityError), + #[class(inherit)] + #[error(transparent)] + ExtractTarball(#[from] ExtractTarballError), + #[class(inherit)] + #[error("Failed moving extracted tarball to final destination")] + MoveFailed(std::io::Error), +} + pub fn verify_and_extract_tarball( package_nv: &PackageNv, data: &[u8], dist_info: &NpmPackageVersionDistInfo, output_folder: &Path, extraction_mode: TarballExtractionMode, -) -> Result<(), AnyError> { +) -> Result<(), VerifyAndExtractTarballError> { verify_tarball_integrity(package_nv, data, &dist_info.integrity())?; match extraction_mode { - TarballExtractionMode::Overwrite => extract_tarball(data, output_folder), + TarballExtractionMode::Overwrite => { + extract_tarball(data, output_folder).map_err(Into::into) + } TarballExtractionMode::SiblingTempDir => { let temp_dir = get_atomic_dir_path(output_folder); extract_tarball(data, &temp_dir)?; rename_with_retries(&temp_dir, output_folder) - .map_err(AnyError::from) - .context("Failed moving extracted tarball to final destination.") + .map_err(VerifyAndExtractTarballError::MoveFailed) } } } @@ -89,11 +100,32 @@ fn rename_with_retries( } } +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(generic)] +pub enum TarballIntegrityError { + #[error("Not implemented hash function for {package}: {hash_kind}")] + NotImplementedHashFunction { + package: Box, + hash_kind: String, + }, + #[error("Not implemented integrity kind for {package}: {integrity}")] + NotImplementedIntegrityKind { + package: Box, + integrity: String, + }, + #[error("Tarball checksum did not match what was provided by npm registry for {package}.\n\nExpected: {expected}\nActual: {actual}")] + MismatchedChecksum { + package: Box, + expected: String, + actual: String, + }, +} + fn verify_tarball_integrity( package: &PackageNv, data: &[u8], npm_integrity: &NpmPackageVersionDistInfoIntegrity, -) -> Result<(), AnyError> { +) -> Result<(), TarballIntegrityError> { use ring::digest::Context; let (tarball_checksum, expected_checksum) = match npm_integrity { NpmPackageVersionDistInfoIntegrity::Integrity { @@ -103,11 +135,12 @@ fn verify_tarball_integrity( let algo = match *algorithm { "sha512" => &ring::digest::SHA512, "sha1" => &ring::digest::SHA1_FOR_LEGACY_USE_ONLY, - hash_kind => bail!( - "Not implemented hash function for {}: {}", - package, - hash_kind - ), + hash_kind => { + return Err(TarballIntegrityError::NotImplementedHashFunction { + package: Box::new(package.clone()), + hash_kind: hash_kind.to_string(), + }); + } }; let mut hash_ctx = Context::new(algo); hash_ctx.update(data); @@ -123,26 +156,39 @@ fn verify_tarball_integrity( (tarball_checksum, hex) } NpmPackageVersionDistInfoIntegrity::UnknownIntegrity(integrity) => { - bail!( - "Not implemented integrity kind for {}: {}", - package, - integrity - ) + return Err(TarballIntegrityError::NotImplementedIntegrityKind { + package: Box::new(package.clone()), + integrity: integrity.to_string(), + }); } }; if tarball_checksum != *expected_checksum { - bail!( - "Tarball checksum did not match what was provided by npm registry for {}.\n\nExpected: {}\nActual: {}", - package, - expected_checksum, - tarball_checksum, - ) + return Err(TarballIntegrityError::MismatchedChecksum { + package: Box::new(package.clone()), + expected: expected_checksum.to_string(), + actual: tarball_checksum, + }); } Ok(()) } -fn extract_tarball(data: &[u8], output_folder: &Path) -> Result<(), AnyError> { +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum ExtractTarballError { + #[class(inherit)] + #[error(transparent)] + Io(#[from] std::io::Error), + #[class(generic)] + #[error( + "Extracted directory '{0}' of npm tarball was not in output directory." + )] + NotInOutputDirectory(PathBuf), +} + +fn extract_tarball( + data: &[u8], + output_folder: &Path, +) -> Result<(), ExtractTarballError> { fs::create_dir_all(output_folder)?; let output_folder = fs::canonicalize(output_folder)?; let tar = GzDecoder::new(data); @@ -174,10 +220,9 @@ fn extract_tarball(data: &[u8], output_folder: &Path) -> Result<(), AnyError> { fs::create_dir_all(dir_path)?; let canonicalized_dir = fs::canonicalize(dir_path)?; if !canonicalized_dir.starts_with(&output_folder) { - bail!( - "Extracted directory '{}' of npm tarball was not in output directory.", - canonicalized_dir.display() - ) + return Err(ExtractTarballError::NotInOutputDirectory( + canonicalized_dir.to_path_buf(), + )); } } diff --git a/resolvers/npm_cache/todo.md b/resolvers/npm_cache/todo.md index e10b1cfd89..e460fcae86 100644 --- a/resolvers/npm_cache/todo.md +++ b/resolvers/npm_cache/todo.md @@ -1,7 +1,5 @@ This crate is a work in progress: -1. Remove `deno_core` dependency. -1. Remove `anyhow` dependency. 1. Add a clippy.toml file that bans accessing the file system directory and instead does it through a trait. 1. Make this crate work in Wasm. diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index ca21547efc..b87d4cfbdf 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_runtime" -version = "0.192.0" +version = "0.194.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -49,6 +49,7 @@ deno_core.workspace = true deno_cron.workspace = true deno_crypto.workspace = true deno_fetch.workspace = true +deno_os.workspace = true deno_ffi.workspace = true deno_fs = { workspace = true, features = ["sync_fs"] } deno_http.workspace = true @@ -59,6 +60,7 @@ deno_kv.workspace = true deno_tls.workspace = true deno_url.workspace = true deno_web.workspace = true +deno_process.workspace = true deno_webgpu.workspace = true deno_webidl.workspace = true deno_websocket.workspace = true @@ -79,6 +81,7 @@ deno_console.workspace = true deno_core.workspace = true deno_cron.workspace = true deno_crypto.workspace = true +deno_error.workspace = true deno_fetch.workspace = true deno_ffi.workspace = true deno_fs = { workspace = true, features = ["sync_fs"] } @@ -88,8 +91,11 @@ deno_kv.workspace = true deno_napi.workspace = true deno_net.workspace = true deno_node.workspace = true +deno_os.workspace = true deno_path_util.workspace = true deno_permissions.workspace = true +deno_process.workspace = true +deno_resolver.workspace = true deno_telemetry.workspace = true deno_terminal.workspace = true deno_tls.workspace = true @@ -112,7 +118,6 @@ hyper-util.workspace = true hyper_v014 = { workspace = true, features = ["server", "stream", "http1", "http2", "runtime"] } libc.workspace = true log.workspace = true -netif = "0.1.6" notify.workspace = true once_cell.workspace = true percent-encoding.workspace = true @@ -120,8 +125,6 @@ regex.workspace = true rustyline = { workspace = true, features = ["custom-bindings"] } same-file = "1.0.6" serde.workspace = true -signal-hook = "0.3.17" -signal-hook-registry = "1.4.0" sys_traits.workspace = true tempfile.workspace = true thiserror.workspace = true diff --git a/runtime/code_cache.rs b/runtime/code_cache.rs index b4a7ce188f..b7ee8a9ed6 100644 --- a/runtime/code_cache.rs +++ b/runtime/code_cache.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::ModuleSpecifier; diff --git a/runtime/errors.rs b/runtime/errors.rs deleted file mode 100644 index 01588c593b..0000000000 --- a/runtime/errors.rs +++ /dev/null @@ -1,1957 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. - -//! There are many types of errors in Deno: -//! - AnyError: a generic wrapper that can encapsulate any type of error. -//! - JsError: a container for the error message and stack trace for exceptions -//! thrown in JavaScript code. We use this to pretty-print stack traces. -//! - Diagnostic: these are errors that originate in TypeScript's compiler. -//! They're similar to JsError, in that they have line numbers. But -//! Diagnostics are compile-time type errors, whereas JsErrors are runtime -//! exceptions. - -use crate::ops::fs_events::FsEventsError; -use crate::ops::http::HttpStartError; -use crate::ops::os::OsError; -use crate::ops::permissions::PermissionError; -use crate::ops::process::CheckRunPermissionError; -use crate::ops::process::ProcessError; -use crate::ops::signal::SignalError; -use crate::ops::tty::TtyError; -use crate::ops::web_worker::SyncFetchError; -use crate::ops::worker_host::CreateWorkerError; -use deno_broadcast_channel::BroadcastChannelError; -use deno_cache::CacheError; -use deno_canvas::CanvasError; -use deno_core::error::AnyError; -use deno_core::serde_json; -use deno_core::url; -use deno_core::ModuleResolutionError; -use deno_cron::CronError; -use deno_crypto::DecryptError; -use deno_crypto::EncryptError; -use deno_crypto::ExportKeyError; -use deno_crypto::GenerateKeyError; -use deno_crypto::ImportKeyError; -use deno_fetch::FetchError; -use deno_fetch::HttpClientCreateError; -use deno_ffi::CallError; -use deno_ffi::CallbackError; -use deno_ffi::DlfcnError; -use deno_ffi::IRError; -use deno_ffi::ReprError; -use deno_ffi::StaticError; -use deno_fs::FsOpsError; -use deno_fs::FsOpsErrorKind; -use deno_http::HttpError; -use deno_http::HttpNextError; -use deno_http::WebSocketUpgradeError; -use deno_io::fs::FsError; -use deno_kv::KvCheckError; -use deno_kv::KvError; -use deno_kv::KvErrorKind; -use deno_kv::KvMutationError; -use deno_napi::NApiError; -use deno_net::ops::NetError; -use deno_permissions::ChildPermissionError; -use deno_permissions::NetDescriptorFromUrlParseError; -use deno_permissions::PathResolveError; -use deno_permissions::PermissionCheckError; -use deno_permissions::RunDescriptorParseError; -use deno_permissions::SysDescriptorParseError; -use deno_tls::TlsError; -use deno_web::BlobError; -use deno_web::CompressionError; -use deno_web::MessagePortError; -use deno_web::StreamResourceError; -use deno_web::WebError; -use deno_websocket::HandshakeError; -use deno_websocket::WebsocketError; -use deno_webstorage::WebStorageError; -use rustyline::error::ReadlineError; -use std::env; -use std::error::Error; -use std::io; -use std::sync::Arc; - -fn get_run_descriptor_parse_error(e: &RunDescriptorParseError) -> &'static str { - match e { - RunDescriptorParseError::Which(_) => "Error", - RunDescriptorParseError::PathResolve(e) => get_path_resolve_error(e), - RunDescriptorParseError::EmptyRunQuery => "Error", - } -} - -fn get_sys_descriptor_parse_error(e: &SysDescriptorParseError) -> &'static str { - match e { - SysDescriptorParseError::InvalidKind(_) => "TypeError", - SysDescriptorParseError::Empty => "Error", - } -} - -fn get_path_resolve_error(e: &PathResolveError) -> &'static str { - match e { - PathResolveError::CwdResolve(e) => get_io_error_class(e), - PathResolveError::EmptyPath => "Error", - } -} - -fn get_permission_error_class(e: &PermissionError) -> &'static str { - match e { - PermissionError::InvalidPermissionName(_) => "ReferenceError", - PermissionError::PathResolve(e) => get_path_resolve_error(e), - PermissionError::NetDescriptorParse(_) => "URIError", - PermissionError::SysDescriptorParse(e) => get_sys_descriptor_parse_error(e), - PermissionError::RunDescriptorParse(e) => get_run_descriptor_parse_error(e), - } -} - -fn get_permission_check_error_class(e: &PermissionCheckError) -> &'static str { - match e { - PermissionCheckError::PermissionDenied(_) => "NotCapable", - PermissionCheckError::InvalidFilePath(_) => "URIError", - PermissionCheckError::NetDescriptorForUrlParse(e) => match e { - NetDescriptorFromUrlParseError::MissingHost(_) => "TypeError", - NetDescriptorFromUrlParseError::Host(_) => "URIError", - }, - PermissionCheckError::SysDescriptorParse(e) => { - get_sys_descriptor_parse_error(e) - } - PermissionCheckError::PathResolve(e) => get_path_resolve_error(e), - PermissionCheckError::HostParse(_) => "URIError", - } -} - -fn get_dlopen_error_class(error: &dlopen2::Error) -> &'static str { - use dlopen2::Error::*; - match error { - NullCharacter(_) => "InvalidData", - OpeningLibraryError(ref e) => get_io_error_class(e), - SymbolGettingError(ref e) => get_io_error_class(e), - AddrNotMatchingDll(ref e) => get_io_error_class(e), - NullSymbol => "NotFound", - } -} - -fn get_env_var_error_class(error: &env::VarError) -> &'static str { - use env::VarError::*; - match error { - NotPresent => "NotFound", - NotUnicode(..) => "InvalidData", - } -} - -fn get_io_error_class(error: &io::Error) -> &'static str { - use io::ErrorKind::*; - match error.kind() { - NotFound => "NotFound", - PermissionDenied => "PermissionDenied", - ConnectionRefused => "ConnectionRefused", - ConnectionReset => "ConnectionReset", - ConnectionAborted => "ConnectionAborted", - NotConnected => "NotConnected", - AddrInUse => "AddrInUse", - AddrNotAvailable => "AddrNotAvailable", - BrokenPipe => "BrokenPipe", - AlreadyExists => "AlreadyExists", - InvalidInput => "TypeError", - InvalidData => "InvalidData", - TimedOut => "TimedOut", - Interrupted => "Interrupted", - WriteZero => "WriteZero", - UnexpectedEof => "UnexpectedEof", - Other => "Error", - WouldBlock => "WouldBlock", - // Non-exhaustive enum - might add new variants - // in the future - kind => { - let kind_str = kind.to_string(); - match kind_str.as_str() { - "FilesystemLoop" => "FilesystemLoop", - "IsADirectory" => "IsADirectory", - "NetworkUnreachable" => "NetworkUnreachable", - "NotADirectory" => "NotADirectory", - _ => "Error", - } - } - } -} - -fn get_module_resolution_error_class( - _: &ModuleResolutionError, -) -> &'static str { - "URIError" -} - -fn get_notify_error_class(error: ¬ify::Error) -> &'static str { - use notify::ErrorKind::*; - match error.kind { - Generic(_) => "Error", - Io(ref e) => get_io_error_class(e), - PathNotFound => "NotFound", - WatchNotFound => "NotFound", - InvalidConfig(_) => "InvalidData", - MaxFilesWatch => "Error", - } -} - -fn get_regex_error_class(error: ®ex::Error) -> &'static str { - use regex::Error::*; - match error { - Syntax(_) => "SyntaxError", - CompiledTooBig(_) => "RangeError", - _ => "Error", - } -} - -fn get_serde_json_error_class( - error: &serde_json::error::Error, -) -> &'static str { - use deno_core::serde_json::error::*; - match error.classify() { - Category::Io => error - .source() - .and_then(|e| e.downcast_ref::()) - .map(get_io_error_class) - .unwrap(), - Category::Syntax => "SyntaxError", - Category::Data => "InvalidData", - Category::Eof => "UnexpectedEof", - } -} - -fn get_url_parse_error_class(_error: &url::ParseError) -> &'static str { - "URIError" -} - -fn get_hyper_error_class(_error: &hyper::Error) -> &'static str { - "Http" -} - -fn get_hyper_util_error_class( - _error: &hyper_util::client::legacy::Error, -) -> &'static str { - "Http" -} - -fn get_hyper_v014_error_class(_error: &hyper_v014::Error) -> &'static str { - "Http" -} - -#[cfg(unix)] -pub fn get_nix_error_class(error: &nix::Error) -> &'static str { - match error { - nix::Error::ECHILD => "NotFound", - nix::Error::EINVAL => "TypeError", - nix::Error::ENOENT => "NotFound", - nix::Error::ENOTTY => "BadResource", - nix::Error::EPERM => "PermissionDenied", - nix::Error::ESRCH => "NotFound", - nix::Error::ELOOP => "FilesystemLoop", - nix::Error::ENOTDIR => "NotADirectory", - nix::Error::ENETUNREACH => "NetworkUnreachable", - nix::Error::EISDIR => "IsADirectory", - nix::Error::UnknownErrno => "Error", - &nix::Error::ENOTSUP => unreachable!(), - _ => "Error", - } -} - -fn get_webgpu_error_class(e: &deno_webgpu::InitError) -> &'static str { - match e { - deno_webgpu::InitError::Resource(e) => { - get_error_class_name(e).unwrap_or("Error") - } - deno_webgpu::InitError::InvalidAdapter(_) => "Error", - deno_webgpu::InitError::RequestDevice(_) => "DOMExceptionOperationError", - deno_webgpu::InitError::InvalidDevice(_) => "Error", - } -} - -fn get_webgpu_buffer_error_class( - e: &deno_webgpu::buffer::BufferError, -) -> &'static str { - match e { - deno_webgpu::buffer::BufferError::Resource(e) => { - get_error_class_name(e).unwrap_or("Error") - } - deno_webgpu::buffer::BufferError::InvalidUsage => "TypeError", - deno_webgpu::buffer::BufferError::Access(_) => "DOMExceptionOperationError", - } -} - -fn get_webgpu_bundle_error_class( - e: &deno_webgpu::bundle::BundleError, -) -> &'static str { - match e { - deno_webgpu::bundle::BundleError::Resource(e) => { - get_error_class_name(e).unwrap_or("Error") - } - deno_webgpu::bundle::BundleError::InvalidSize => "TypeError", - } -} - -fn get_webgpu_byow_error_class( - e: &deno_webgpu::byow::ByowError, -) -> &'static str { - match e { - deno_webgpu::byow::ByowError::WebGPUNotInitiated => "TypeError", - deno_webgpu::byow::ByowError::InvalidParameters => "TypeError", - deno_webgpu::byow::ByowError::CreateSurface(_) => "Error", - deno_webgpu::byow::ByowError::InvalidSystem => "TypeError", - #[cfg(any( - target_os = "windows", - target_os = "linux", - target_os = "freebsd", - target_os = "openbsd" - ))] - deno_webgpu::byow::ByowError::NullWindow => "TypeError", - #[cfg(any( - target_os = "linux", - target_os = "freebsd", - target_os = "openbsd" - ))] - deno_webgpu::byow::ByowError::NullDisplay => "TypeError", - #[cfg(target_os = "macos")] - deno_webgpu::byow::ByowError::NSViewDisplay => "TypeError", - } -} - -fn get_webgpu_render_pass_error_class( - e: &deno_webgpu::render_pass::RenderPassError, -) -> &'static str { - match e { - deno_webgpu::render_pass::RenderPassError::Resource(e) => { - get_error_class_name(e).unwrap_or("Error") - } - deno_webgpu::render_pass::RenderPassError::InvalidSize => "TypeError", - } -} - -fn get_webgpu_surface_error_class( - e: &deno_webgpu::surface::SurfaceError, -) -> &'static str { - match e { - deno_webgpu::surface::SurfaceError::Resource(e) => { - get_error_class_name(e).unwrap_or("Error") - } - deno_webgpu::surface::SurfaceError::Surface(_) => "Error", - deno_webgpu::surface::SurfaceError::InvalidStatus => "Error", - } -} - -fn get_crypto_decrypt_error_class(e: &DecryptError) -> &'static str { - match e { - DecryptError::General(e) => get_crypto_shared_error_class(e), - DecryptError::Pkcs1(_) => "Error", - DecryptError::Failed => "DOMExceptionOperationError", - DecryptError::InvalidLength => "TypeError", - DecryptError::InvalidCounterLength => "TypeError", - DecryptError::InvalidTagLength => "TypeError", - DecryptError::InvalidKeyOrIv => "DOMExceptionOperationError", - DecryptError::TooMuchData => "DOMExceptionOperationError", - DecryptError::InvalidIvLength => "TypeError", - DecryptError::Rsa(_) => "DOMExceptionOperationError", - } -} - -fn get_crypto_encrypt_error_class(e: &EncryptError) -> &'static str { - match e { - EncryptError::General(e) => get_crypto_shared_error_class(e), - EncryptError::InvalidKeyOrIv => "DOMExceptionOperationError", - EncryptError::Failed => "DOMExceptionOperationError", - EncryptError::InvalidLength => "TypeError", - EncryptError::InvalidIvLength => "TypeError", - EncryptError::InvalidCounterLength => "TypeError", - EncryptError::TooMuchData => "DOMExceptionOperationError", - } -} - -fn get_crypto_shared_error_class(e: &deno_crypto::SharedError) -> &'static str { - match e { - deno_crypto::SharedError::ExpectedValidPrivateKey => "TypeError", - deno_crypto::SharedError::ExpectedValidPublicKey => "TypeError", - deno_crypto::SharedError::ExpectedValidPrivateECKey => "TypeError", - deno_crypto::SharedError::ExpectedValidPublicECKey => "TypeError", - deno_crypto::SharedError::ExpectedPrivateKey => "TypeError", - deno_crypto::SharedError::ExpectedPublicKey => "TypeError", - deno_crypto::SharedError::ExpectedSecretKey => "TypeError", - deno_crypto::SharedError::FailedDecodePrivateKey => { - "DOMExceptionOperationError" - } - deno_crypto::SharedError::FailedDecodePublicKey => { - "DOMExceptionOperationError" - } - deno_crypto::SharedError::UnsupportedFormat => { - "DOMExceptionNotSupportedError" - } - } -} - -fn get_crypto_ed25519_error_class( - e: &deno_crypto::Ed25519Error, -) -> &'static str { - match e { - deno_crypto::Ed25519Error::FailedExport => "DOMExceptionOperationError", - deno_crypto::Ed25519Error::Der(_) => "Error", - deno_crypto::Ed25519Error::KeyRejected(_) => "Error", - } -} - -fn get_crypto_export_key_error_class(e: &ExportKeyError) -> &'static str { - match e { - ExportKeyError::General(e) => get_crypto_shared_error_class(e), - ExportKeyError::Der(_) => "Error", - ExportKeyError::UnsupportedNamedCurve => "DOMExceptionNotSupportedError", - } -} - -fn get_crypto_generate_key_error_class(e: &GenerateKeyError) -> &'static str { - match e { - GenerateKeyError::General(e) => get_crypto_shared_error_class(e), - GenerateKeyError::BadPublicExponent => "DOMExceptionOperationError", - GenerateKeyError::InvalidHMACKeyLength => "DOMExceptionOperationError", - GenerateKeyError::FailedRSAKeySerialization => "DOMExceptionOperationError", - GenerateKeyError::InvalidAESKeyLength => "DOMExceptionOperationError", - GenerateKeyError::FailedRSAKeyGeneration => "DOMExceptionOperationError", - GenerateKeyError::FailedECKeyGeneration => "DOMExceptionOperationError", - GenerateKeyError::FailedKeyGeneration => "DOMExceptionOperationError", - } -} - -fn get_crypto_import_key_error_class(e: &ImportKeyError) -> &'static str { - match e { - ImportKeyError::General(e) => get_crypto_shared_error_class(e), - ImportKeyError::InvalidModulus => "DOMExceptionDataError", - ImportKeyError::InvalidPublicExponent => "DOMExceptionDataError", - ImportKeyError::InvalidPrivateExponent => "DOMExceptionDataError", - ImportKeyError::InvalidFirstPrimeFactor => "DOMExceptionDataError", - ImportKeyError::InvalidSecondPrimeFactor => "DOMExceptionDataError", - ImportKeyError::InvalidFirstCRTExponent => "DOMExceptionDataError", - ImportKeyError::InvalidSecondCRTExponent => "DOMExceptionDataError", - ImportKeyError::InvalidCRTCoefficient => "DOMExceptionDataError", - ImportKeyError::InvalidB64Coordinate => "DOMExceptionDataError", - ImportKeyError::InvalidRSAPublicKey => "DOMExceptionDataError", - ImportKeyError::InvalidRSAPrivateKey => "DOMExceptionDataError", - ImportKeyError::UnsupportedAlgorithm => "DOMExceptionDataError", - ImportKeyError::PublicKeyTooLong => "DOMExceptionDataError", - ImportKeyError::PrivateKeyTooLong => "DOMExceptionDataError", - ImportKeyError::InvalidP256ECPoint => "DOMExceptionDataError", - ImportKeyError::InvalidP384ECPoint => "DOMExceptionDataError", - ImportKeyError::InvalidP521ECPoint => "DOMExceptionDataError", - ImportKeyError::UnsupportedNamedCurve => "DOMExceptionDataError", - ImportKeyError::CurveMismatch => "DOMExceptionDataError", - ImportKeyError::InvalidKeyData => "DOMExceptionDataError", - ImportKeyError::InvalidJWKPrivateKey => "DOMExceptionDataError", - ImportKeyError::EllipticCurve(_) => "DOMExceptionDataError", - ImportKeyError::ExpectedValidPkcs8Data => "DOMExceptionDataError", - ImportKeyError::MalformedParameters => "DOMExceptionDataError", - ImportKeyError::Spki(_) => "DOMExceptionDataError", - ImportKeyError::InvalidP256ECSPKIData => "DOMExceptionDataError", - ImportKeyError::InvalidP384ECSPKIData => "DOMExceptionDataError", - ImportKeyError::InvalidP521ECSPKIData => "DOMExceptionDataError", - ImportKeyError::Der(_) => "DOMExceptionDataError", - } -} - -fn get_crypto_x448_error_class(e: &deno_crypto::X448Error) -> &'static str { - match e { - deno_crypto::X448Error::FailedExport => "DOMExceptionOperationError", - deno_crypto::X448Error::Der(_) => "Error", - } -} - -fn get_crypto_x25519_error_class(e: &deno_crypto::X25519Error) -> &'static str { - match e { - deno_crypto::X25519Error::FailedExport => "DOMExceptionOperationError", - deno_crypto::X25519Error::Der(_) => "Error", - } -} - -fn get_crypto_error_class(e: &deno_crypto::Error) -> &'static str { - match e { - deno_crypto::Error::Der(_) => "Error", - deno_crypto::Error::JoinError(_) => "Error", - deno_crypto::Error::MissingArgumentHash => "TypeError", - deno_crypto::Error::MissingArgumentSaltLength => "TypeError", - deno_crypto::Error::Other(e) => get_error_class_name(e).unwrap_or("Error"), - deno_crypto::Error::UnsupportedAlgorithm => "TypeError", - deno_crypto::Error::KeyRejected(_) => "Error", - deno_crypto::Error::RSA(_) => "Error", - deno_crypto::Error::Pkcs1(_) => "Error", - deno_crypto::Error::Unspecified(_) => "Error", - deno_crypto::Error::InvalidKeyFormat => "TypeError", - deno_crypto::Error::MissingArgumentPublicKey => "TypeError", - deno_crypto::Error::P256Ecdsa(_) => "Error", - deno_crypto::Error::DecodePrivateKey => "TypeError", - deno_crypto::Error::MissingArgumentNamedCurve => "TypeError", - deno_crypto::Error::MissingArgumentInfo => "TypeError", - deno_crypto::Error::HKDFLengthTooLarge => "DOMExceptionOperationError", - deno_crypto::Error::General(e) => get_crypto_shared_error_class(e), - deno_crypto::Error::Base64Decode(_) => "Error", - deno_crypto::Error::DataInvalidSize => "TypeError", - deno_crypto::Error::InvalidKeyLength => "TypeError", - deno_crypto::Error::EncryptionError => "DOMExceptionOperationError", - deno_crypto::Error::DecryptionError => "DOMExceptionOperationError", - deno_crypto::Error::ArrayBufferViewLengthExceeded(_) => { - "DOMExceptionQuotaExceededError" - } - } -} - -fn get_napi_error_class(e: &NApiError) -> &'static str { - match e { - NApiError::InvalidPath - | NApiError::LibLoading(_) - | NApiError::ModuleNotFound(_) => "TypeError", - NApiError::Permission(e) => get_permission_check_error_class(e), - } -} - -fn get_web_error_class(e: &WebError) -> &'static str { - match e { - WebError::Base64Decode => "DOMExceptionInvalidCharacterError", - WebError::InvalidEncodingLabel(_) => "RangeError", - WebError::BufferTooLong => "TypeError", - WebError::ValueTooLarge => "RangeError", - WebError::BufferTooSmall => "RangeError", - WebError::DataInvalid => "TypeError", - WebError::DataError(_) => "Error", - } -} - -fn get_web_compression_error_class(e: &CompressionError) -> &'static str { - match e { - CompressionError::UnsupportedFormat => "TypeError", - CompressionError::ResourceClosed => "TypeError", - CompressionError::IoTypeError(_) => "TypeError", - CompressionError::Io(e) => get_io_error_class(e), - } -} - -fn get_web_message_port_error_class(e: &MessagePortError) -> &'static str { - match e { - MessagePortError::InvalidTransfer => "TypeError", - MessagePortError::NotReady => "TypeError", - MessagePortError::TransferSelf => "TypeError", - MessagePortError::Canceled(e) => { - let io_err: io::Error = e.to_owned().into(); - get_io_error_class(&io_err) - } - MessagePortError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - } -} - -fn get_web_stream_resource_error_class( - e: &StreamResourceError, -) -> &'static str { - match e { - StreamResourceError::Canceled(e) => { - let io_err: io::Error = e.to_owned().into(); - get_io_error_class(&io_err) - } - StreamResourceError::Js(_) => "TypeError", - } -} - -fn get_web_blob_error_class(e: &BlobError) -> &'static str { - match e { - BlobError::BlobPartNotFound => "TypeError", - BlobError::SizeLargerThanBlobPart => "TypeError", - BlobError::BlobURLsNotSupported => "TypeError", - BlobError::Url(_) => "Error", - } -} - -fn get_ffi_repr_error_class(e: &ReprError) -> &'static str { - match e { - ReprError::InvalidOffset => "TypeError", - ReprError::InvalidArrayBuffer => "TypeError", - ReprError::DestinationLengthTooShort => "RangeError", - ReprError::InvalidCString => "TypeError", - ReprError::CStringTooLong => "TypeError", - ReprError::InvalidBool => "TypeError", - ReprError::InvalidU8 => "TypeError", - ReprError::InvalidI8 => "TypeError", - ReprError::InvalidU16 => "TypeError", - ReprError::InvalidI16 => "TypeError", - ReprError::InvalidU32 => "TypeError", - ReprError::InvalidI32 => "TypeError", - ReprError::InvalidU64 => "TypeError", - ReprError::InvalidI64 => "TypeError", - ReprError::InvalidF32 => "TypeError", - ReprError::InvalidF64 => "TypeError", - ReprError::InvalidPointer => "TypeError", - ReprError::Permission(e) => get_permission_check_error_class(e), - } -} - -fn get_ffi_dlfcn_error_class(e: &DlfcnError) -> &'static str { - match e { - DlfcnError::RegisterSymbol { .. } => "Error", - DlfcnError::Dlopen(_) => "Error", - DlfcnError::Permission(e) => get_permission_check_error_class(e), - DlfcnError::Other(e) => get_error_class_name(e).unwrap_or("Error"), - } -} - -fn get_ffi_static_error_class(e: &StaticError) -> &'static str { - match e { - StaticError::Dlfcn(e) => get_ffi_dlfcn_error_class(e), - StaticError::InvalidTypeVoid => "TypeError", - StaticError::InvalidTypeStruct => "TypeError", - StaticError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - } -} - -fn get_ffi_callback_error_class(e: &CallbackError) -> &'static str { - match e { - CallbackError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - CallbackError::Other(e) => get_error_class_name(e).unwrap_or("Error"), - CallbackError::Permission(e) => get_permission_check_error_class(e), - } -} - -fn get_ffi_call_error_class(e: &CallError) -> &'static str { - match e { - CallError::IR(_) => "TypeError", - CallError::NonblockingCallFailure(_) => "Error", - CallError::InvalidSymbol(_) => "TypeError", - CallError::Permission(e) => get_permission_check_error_class(e), - CallError::Callback(e) => get_ffi_callback_error_class(e), - CallError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - } -} - -fn get_webstorage_class_name(e: &WebStorageError) -> &'static str { - match e { - WebStorageError::ContextNotSupported => "DOMExceptionNotSupportedError", - WebStorageError::Sqlite(_) => "Error", - WebStorageError::Io(e) => get_io_error_class(e), - WebStorageError::StorageExceeded => "DOMExceptionQuotaExceededError", - } -} - -fn get_tls_error_class(e: &TlsError) -> &'static str { - match e { - TlsError::Rustls(_) => "Error", - TlsError::UnableAddPemFileToCert(e) => get_io_error_class(e), - TlsError::CertInvalid - | TlsError::CertsNotFound - | TlsError::KeysNotFound - | TlsError::KeyDecode => "InvalidData", - } -} - -pub fn get_cron_error_class(e: &CronError) -> &'static str { - match e { - CronError::Resource(e) => { - deno_core::error::get_custom_error_class(e).unwrap_or("Error") - } - CronError::NameExceeded(_) => "TypeError", - CronError::NameInvalid => "TypeError", - CronError::AlreadyExists => "TypeError", - CronError::TooManyCrons => "TypeError", - CronError::InvalidCron => "TypeError", - CronError::InvalidBackoff => "TypeError", - CronError::AcquireError(_) => "Error", - CronError::Other(e) => get_error_class_name(e).unwrap_or("Error"), - } -} - -fn get_canvas_error(e: &CanvasError) -> &'static str { - match e { - CanvasError::UnsupportedColorType(_) => "TypeError", - CanvasError::Image(_) => "Error", - } -} - -pub fn get_cache_error(error: &CacheError) -> &'static str { - match error { - CacheError::Sqlite(_) => "Error", - CacheError::JoinError(_) => "Error", - CacheError::Resource(err) => { - deno_core::error::get_custom_error_class(err).unwrap_or("Error") - } - CacheError::Other(e) => get_error_class_name(e).unwrap_or("Error"), - CacheError::Io(err) => get_io_error_class(err), - } -} - -fn get_broadcast_channel_error(error: &BroadcastChannelError) -> &'static str { - match error { - BroadcastChannelError::Resource(err) => { - deno_core::error::get_custom_error_class(err).unwrap() - } - BroadcastChannelError::MPSCSendError(_) => "Error", - BroadcastChannelError::BroadcastSendError(_) => "Error", - BroadcastChannelError::Other(err) => { - get_error_class_name(err).unwrap_or("Error") - } - } -} - -fn get_fetch_error(error: &FetchError) -> &'static str { - match error { - FetchError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - FetchError::Permission(e) => get_permission_check_error_class(e), - FetchError::NetworkError => "TypeError", - FetchError::FsNotGet(_) => "TypeError", - FetchError::PathToUrl(_) => "TypeError", - FetchError::InvalidUrl(_) => "TypeError", - FetchError::InvalidHeaderName(_) => "TypeError", - FetchError::InvalidHeaderValue(_) => "TypeError", - FetchError::DataUrl(_) => "TypeError", - FetchError::Base64(_) => "TypeError", - FetchError::BlobNotFound => "TypeError", - FetchError::SchemeNotSupported(_) => "TypeError", - FetchError::RequestCanceled => "TypeError", - FetchError::Http(_) => "Error", - FetchError::ClientCreate(e) => get_http_client_create_error(e), - FetchError::Url(e) => get_url_parse_error_class(e), - FetchError::Method(_) => "TypeError", - FetchError::ClientSend(_) => "TypeError", - FetchError::RequestBuilderHook(_) => "TypeError", - FetchError::Io(e) => get_io_error_class(e), - } -} - -fn get_http_client_create_error(error: &HttpClientCreateError) -> &'static str { - match error { - HttpClientCreateError::Tls(_) => "TypeError", - HttpClientCreateError::InvalidUserAgent(_) => "TypeError", - HttpClientCreateError::InvalidProxyUrl => "TypeError", - HttpClientCreateError::HttpVersionSelectionInvalid => "TypeError", - HttpClientCreateError::RootCertStore(_) => "TypeError", - } -} - -fn get_websocket_error(error: &WebsocketError) -> &'static str { - match error { - WebsocketError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - WebsocketError::Permission(e) => get_permission_check_error_class(e), - WebsocketError::Url(e) => get_url_parse_error_class(e), - WebsocketError::Io(e) => get_io_error_class(e), - WebsocketError::WebSocket(_) => "TypeError", - WebsocketError::ConnectionFailed(_) => "DOMExceptionNetworkError", - WebsocketError::Uri(_) => "Error", - WebsocketError::Canceled(e) => { - let io_err: io::Error = e.to_owned().into(); - get_io_error_class(&io_err) - } - } -} - -fn get_websocket_handshake_error(error: &HandshakeError) -> &'static str { - match error { - HandshakeError::RootStoreError(e) => { - get_error_class_name(e).unwrap_or("Error") - } - HandshakeError::Tls(e) => get_tls_error_class(e), - HandshakeError::MissingPath => "TypeError", - HandshakeError::Http(_) => "Error", - HandshakeError::InvalidHostname(_) => "TypeError", - HandshakeError::Io(e) => get_io_error_class(e), - HandshakeError::Rustls(_) => "Error", - HandshakeError::H2(_) => "Error", - HandshakeError::NoH2Alpn => "Error", - HandshakeError::InvalidStatusCode(_) => "Error", - HandshakeError::WebSocket(_) => "TypeError", - HandshakeError::HeaderName(_) => "TypeError", - HandshakeError::HeaderValue(_) => "TypeError", - } -} - -fn get_fs_ops_error(error: &FsOpsError) -> &'static str { - use FsOpsErrorKind::*; - match error.as_kind() { - Io(e) => get_io_error_class(e), - OperationError(e) => get_fs_error(&e.err), - Permission(e) => get_permission_check_error_class(e), - Resource(e) | Other(e) => get_error_class_name(e).unwrap_or("Error"), - InvalidUtf8(_) => "InvalidData", - StripPrefix(_) => "Error", - Canceled(e) => { - let io_err: io::Error = e.to_owned().into(); - get_io_error_class(&io_err) - } - InvalidSeekMode(_) => "TypeError", - InvalidControlCharacter(_) => "Error", - InvalidCharacter(_) => "Error", - #[cfg(windows)] - InvalidTrailingCharacter => "Error", - NotCapableAccess { .. } => "NotCapable", - NotCapable(_) => "NotCapable", - } -} - -fn get_kv_error(error: &KvError) -> &'static str { - use KvErrorKind::*; - match error.as_kind() { - DatabaseHandler(e) | Resource(e) | Kv(e) => { - get_error_class_name(e).unwrap_or("Error") - } - TooManyRanges(_) => "TypeError", - TooManyEntries(_) => "TypeError", - TooManyChecks(_) => "TypeError", - TooManyMutations(_) => "TypeError", - TooManyKeys(_) => "TypeError", - InvalidLimit => "TypeError", - InvalidBoundaryKey => "TypeError", - KeyTooLargeToRead(_) => "TypeError", - KeyTooLargeToWrite(_) => "TypeError", - TotalMutationTooLarge(_) => "TypeError", - TotalKeyTooLarge(_) => "TypeError", - Io(e) => get_io_error_class(e), - QueueMessageNotFound => "TypeError", - StartKeyNotInKeyspace => "TypeError", - EndKeyNotInKeyspace => "TypeError", - StartKeyGreaterThanEndKey => "TypeError", - InvalidCheck(e) => match e { - KvCheckError::InvalidVersionstamp => "TypeError", - KvCheckError::Io(e) => get_io_error_class(e), - }, - InvalidMutation(e) => match e { - KvMutationError::BigInt(_) => "Error", - KvMutationError::Io(e) => get_io_error_class(e), - KvMutationError::InvalidMutationWithValue(_) => "TypeError", - KvMutationError::InvalidMutationWithoutValue(_) => "TypeError", - }, - InvalidEnqueue(e) => get_io_error_class(e), - EmptyKey => "TypeError", - ValueTooLarge(_) => "TypeError", - EnqueuePayloadTooLarge(_) => "TypeError", - InvalidCursor => "TypeError", - CursorOutOfBounds => "TypeError", - InvalidRange => "TypeError", - } -} - -fn get_net_error(error: &NetError) -> &'static str { - match error { - NetError::ListenerClosed => "BadResource", - NetError::ListenerBusy => "Busy", - NetError::SocketClosed => "BadResource", - NetError::SocketClosedNotConnected => "NotConnected", - NetError::SocketBusy => "Busy", - NetError::Io(e) => get_io_error_class(e), - NetError::AcceptTaskOngoing => "Busy", - NetError::RootCertStore(e) | NetError::Resource(e) => { - get_error_class_name(e).unwrap_or("Error") - } - NetError::Permission(e) => get_permission_check_error_class(e), - NetError::NoResolvedAddress => "Error", - NetError::AddrParse(_) => "Error", - NetError::Map(e) => get_net_map_error(e), - NetError::Canceled(e) => { - let io_err: io::Error = e.to_owned().into(); - get_io_error_class(&io_err) - } - NetError::DnsNotFound(_) => "NotFound", - NetError::DnsNotConnected(_) => "NotConnected", - NetError::DnsTimedOut(_) => "TimedOut", - NetError::Dns(_) => "Error", - NetError::UnsupportedRecordType => "NotSupported", - NetError::InvalidUtf8(_) => "InvalidData", - NetError::UnexpectedKeyType => "Error", - NetError::InvalidHostname(_) => "TypeError", - NetError::TcpStreamBusy => "Busy", - NetError::Rustls(_) => "Error", - NetError::Tls(e) => get_tls_error_class(e), - NetError::ListenTlsRequiresKey => "InvalidData", - NetError::Reunite(_) => "Error", - } -} - -fn get_net_map_error(error: &deno_net::io::MapError) -> &'static str { - match error { - deno_net::io::MapError::Io(e) => get_io_error_class(e), - deno_net::io::MapError::NoResources => "Error", - } -} - -fn get_child_permission_error(e: &ChildPermissionError) -> &'static str { - match e { - ChildPermissionError::Escalation => "NotCapable", - ChildPermissionError::PathResolve(e) => get_path_resolve_error(e), - ChildPermissionError::NetDescriptorParse(_) => "URIError", - ChildPermissionError::EnvDescriptorParse(_) => "Error", - ChildPermissionError::SysDescriptorParse(e) => { - get_sys_descriptor_parse_error(e) - } - ChildPermissionError::RunDescriptorParse(e) => { - get_run_descriptor_parse_error(e) - } - } -} - -fn get_create_worker_error(error: &CreateWorkerError) -> &'static str { - match error { - CreateWorkerError::ClassicWorkers => "DOMExceptionNotSupportedError", - CreateWorkerError::Permission(e) => get_child_permission_error(e), - CreateWorkerError::ModuleResolution(e) => { - get_module_resolution_error_class(e) - } - CreateWorkerError::Io(e) => get_io_error_class(e), - CreateWorkerError::MessagePort(e) => get_web_message_port_error_class(e), - } -} - -fn get_tty_error(error: &TtyError) -> &'static str { - match error { - TtyError::Resource(e) | TtyError::Other(e) => { - get_error_class_name(e).unwrap_or("Error") - } - TtyError::Io(e) => get_io_error_class(e), - #[cfg(unix)] - TtyError::Nix(e) => get_nix_error_class(e), - } -} - -fn get_readline_error(error: &ReadlineError) -> &'static str { - match error { - ReadlineError::Io(e) => get_io_error_class(e), - ReadlineError::Eof => "Error", - ReadlineError::Interrupted => "Error", - #[cfg(unix)] - ReadlineError::Errno(e) => get_nix_error_class(e), - ReadlineError::WindowResized => "Error", - #[cfg(windows)] - ReadlineError::Decode(_) => "Error", - #[cfg(windows)] - ReadlineError::SystemError(_) => "Error", - _ => "Error", - } -} - -fn get_signal_error(error: &SignalError) -> &'static str { - match error { - SignalError::InvalidSignalStr(_) => "TypeError", - SignalError::InvalidSignalInt(_) => "TypeError", - SignalError::SignalNotAllowed(_) => "TypeError", - SignalError::Io(e) => get_io_error_class(e), - } -} - -fn get_fs_events_error(error: &FsEventsError) -> &'static str { - match error { - FsEventsError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - FsEventsError::Permission(e) => get_permission_check_error_class(e), - FsEventsError::Notify(e) => get_notify_error_class(e), - FsEventsError::Canceled(e) => { - let io_err: io::Error = e.to_owned().into(); - get_io_error_class(&io_err) - } - } -} - -fn get_http_start_error(error: &HttpStartError) -> &'static str { - match error { - HttpStartError::TcpStreamInUse => "Busy", - HttpStartError::TlsStreamInUse => "Busy", - HttpStartError::UnixSocketInUse => "Busy", - HttpStartError::ReuniteTcp(_) => "Error", - #[cfg(unix)] - HttpStartError::ReuniteUnix(_) => "Error", - HttpStartError::Io(e) => get_io_error_class(e), - HttpStartError::Other(e) => get_error_class_name(e).unwrap_or("Error"), - } -} - -fn get_process_error(error: &ProcessError) -> &'static str { - match error { - ProcessError::SpawnFailed { error, .. } => get_process_error(error), - ProcessError::FailedResolvingCwd(e) | ProcessError::Io(e) => { - get_io_error_class(e) - } - ProcessError::Permission(e) => get_permission_check_error_class(e), - ProcessError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - ProcessError::BorrowMut(_) => "Error", - ProcessError::Which(_) => "Error", - ProcessError::ChildProcessAlreadyTerminated => "TypeError", - ProcessError::Signal(e) => get_signal_error(e), - ProcessError::MissingCmd => "Error", - ProcessError::InvalidPid => "TypeError", - #[cfg(unix)] - ProcessError::Nix(e) => get_nix_error_class(e), - ProcessError::RunPermission(e) => match e { - CheckRunPermissionError::Permission(e) => { - get_permission_check_error_class(e) - } - CheckRunPermissionError::Other(e) => { - get_error_class_name(e).unwrap_or("Error") - } - }, - } -} - -fn get_http_error(error: &HttpError) -> &'static str { - match error { - HttpError::Canceled(e) => { - let io_err: io::Error = e.to_owned().into(); - get_io_error_class(&io_err) - } - HttpError::HyperV014(e) => get_hyper_v014_error_class(e), - HttpError::InvalidHeaderName(_) => "Error", - HttpError::InvalidHeaderValue(_) => "Error", - HttpError::Http(_) => "Error", - HttpError::ResponseHeadersAlreadySent => "Http", - HttpError::ConnectionClosedWhileSendingResponse => "Http", - HttpError::AlreadyInUse => "Http", - HttpError::Io(e) => get_io_error_class(e), - HttpError::NoResponseHeaders => "Http", - HttpError::ResponseAlreadyCompleted => "Http", - HttpError::UpgradeBodyUsed => "Http", - HttpError::Resource(e) | HttpError::Other(e) => { - get_error_class_name(e).unwrap_or("Error") - } - } -} - -fn get_http_next_error(error: &HttpNextError) -> &'static str { - match error { - HttpNextError::Io(e) => get_io_error_class(e), - HttpNextError::WebSocketUpgrade(e) => get_websocket_upgrade_error(e), - HttpNextError::Hyper(e) => get_hyper_error_class(e), - HttpNextError::JoinError(_) => "Error", - HttpNextError::Canceled(e) => { - let io_err: io::Error = e.to_owned().into(); - get_io_error_class(&io_err) - } - HttpNextError::UpgradeUnavailable(_) => "Error", - HttpNextError::HttpPropertyExtractor(e) | HttpNextError::Resource(e) => { - get_error_class_name(e).unwrap_or("Error") - } - } -} - -fn get_websocket_upgrade_error(error: &WebSocketUpgradeError) -> &'static str { - match error { - WebSocketUpgradeError::InvalidHeaders => "Http", - WebSocketUpgradeError::HttpParse(_) => "Error", - WebSocketUpgradeError::Http(_) => "Error", - WebSocketUpgradeError::Utf8(_) => "Error", - WebSocketUpgradeError::InvalidHeaderName(_) => "Error", - WebSocketUpgradeError::InvalidHeaderValue(_) => "Error", - WebSocketUpgradeError::InvalidHttpStatusLine => "Http", - WebSocketUpgradeError::UpgradeBufferAlreadyCompleted => "Http", - } -} - -fn get_fs_error(e: &FsError) -> &'static str { - match &e { - FsError::Io(e) => get_io_error_class(e), - FsError::FileBusy => "Busy", - FsError::NotSupported => "NotSupported", - FsError::NotCapable(_) => "NotCapable", - } -} - -mod node { - use super::get_error_class_name; - use super::get_io_error_class; - use super::get_permission_check_error_class; - use super::get_serde_json_error_class; - use super::get_url_parse_error_class; - pub use deno_node::ops::blocklist::BlocklistError; - pub use deno_node::ops::crypto::cipher::CipherContextError; - pub use deno_node::ops::crypto::cipher::CipherError; - pub use deno_node::ops::crypto::cipher::DecipherContextError; - pub use deno_node::ops::crypto::cipher::DecipherError; - pub use deno_node::ops::crypto::digest::HashError; - pub use deno_node::ops::crypto::keys::AsymmetricPrivateKeyDerError; - pub use deno_node::ops::crypto::keys::AsymmetricPrivateKeyError; - pub use deno_node::ops::crypto::keys::AsymmetricPublicKeyDerError; - pub use deno_node::ops::crypto::keys::AsymmetricPublicKeyError; - pub use deno_node::ops::crypto::keys::AsymmetricPublicKeyJwkError; - pub use deno_node::ops::crypto::keys::EcJwkError; - pub use deno_node::ops::crypto::keys::EdRawError; - pub use deno_node::ops::crypto::keys::ExportPrivateKeyPemError; - pub use deno_node::ops::crypto::keys::ExportPublicKeyPemError; - pub use deno_node::ops::crypto::keys::GenerateRsaPssError; - pub use deno_node::ops::crypto::keys::RsaJwkError; - pub use deno_node::ops::crypto::keys::RsaPssParamsParseError; - pub use deno_node::ops::crypto::keys::X509PublicKeyError; - pub use deno_node::ops::crypto::sign::KeyObjectHandlePrehashedSignAndVerifyError; - pub use deno_node::ops::crypto::x509::X509Error; - pub use deno_node::ops::crypto::DiffieHellmanError; - pub use deno_node::ops::crypto::EcdhEncodePubKey; - pub use deno_node::ops::crypto::HkdfError; - pub use deno_node::ops::crypto::Pbkdf2Error; - pub use deno_node::ops::crypto::PrivateEncryptDecryptError; - pub use deno_node::ops::crypto::ScryptAsyncError; - pub use deno_node::ops::crypto::SignEd25519Error; - pub use deno_node::ops::crypto::VerifyEd25519Error; - pub use deno_node::ops::fs::FsError; - pub use deno_node::ops::http::ConnError; - pub use deno_node::ops::http2::Http2Error; - pub use deno_node::ops::idna::IdnaError; - pub use deno_node::ops::ipc::IpcError; - pub use deno_node::ops::ipc::IpcJsonStreamError; - use deno_node::ops::os::priority::PriorityError; - pub use deno_node::ops::os::OsError; - pub use deno_node::ops::require::RequireError; - use deno_node::ops::require::RequireErrorKind; - pub use deno_node::ops::worker_threads::WorkerThreadsFilenameError; - pub use deno_node::ops::zlib::brotli::BrotliError; - pub use deno_node::ops::zlib::mode::ModeError; - pub use deno_node::ops::zlib::ZlibError; - - pub fn get_blocklist_error(error: &BlocklistError) -> &'static str { - match error { - BlocklistError::AddrParse(_) => "Error", - BlocklistError::IpNetwork(_) => "Error", - BlocklistError::InvalidAddress => "Error", - BlocklistError::IpVersionMismatch => "Error", - } - } - - pub fn get_fs_error(error: &FsError) -> &'static str { - match error { - FsError::Permission(e) => get_permission_check_error_class(e), - FsError::Io(e) => get_io_error_class(e), - #[cfg(windows)] - FsError::PathHasNoRoot => "Error", - #[cfg(not(any(unix, windows)))] - FsError::UnsupportedPlatform => "Error", - FsError::Fs(e) => super::get_fs_error(e), - } - } - - pub fn get_idna_error(error: &IdnaError) -> &'static str { - match error { - IdnaError::InvalidInput => "RangeError", - IdnaError::InputTooLong => "Error", - IdnaError::IllegalInput => "RangeError", - } - } - - pub fn get_ipc_json_stream_error(error: &IpcJsonStreamError) -> &'static str { - match error { - IpcJsonStreamError::Io(e) => get_io_error_class(e), - IpcJsonStreamError::SimdJson(_) => "Error", - } - } - - pub fn get_ipc_error(error: &IpcError) -> &'static str { - match error { - IpcError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - IpcError::IpcJsonStream(e) => get_ipc_json_stream_error(e), - IpcError::Canceled(e) => { - let io_err: std::io::Error = e.to_owned().into(); - get_io_error_class(&io_err) - } - IpcError::SerdeJson(e) => get_serde_json_error_class(e), - } - } - - pub fn get_worker_threads_filename_error( - error: &WorkerThreadsFilenameError, - ) -> &'static str { - match error { - WorkerThreadsFilenameError::Permission(e) => { - get_error_class_name(e).unwrap_or("Error") - } - WorkerThreadsFilenameError::UrlParse(e) => get_url_parse_error_class(e), - WorkerThreadsFilenameError::InvalidRelativeUrl => "Error", - WorkerThreadsFilenameError::UrlFromPathString => "Error", - WorkerThreadsFilenameError::UrlToPathString => "Error", - WorkerThreadsFilenameError::UrlToPath => "Error", - WorkerThreadsFilenameError::FileNotFound(_) => "Error", - WorkerThreadsFilenameError::Fs(e) => super::get_io_error_class(e), - } - } - - pub fn get_require_error(error: &RequireError) -> &'static str { - use RequireErrorKind::*; - match error.as_kind() { - UrlParse(e) => get_url_parse_error_class(e), - Permission(e) => get_error_class_name(e).unwrap_or("Error"), - PackageExportsResolve(_) - | PackageJsonLoad(_) - | ClosestPkgJson(_) - | FilePathConversion(_) - | UrlConversion(_) - | ReadModule(_) - | PackageImportsResolve(_) => "Error", - Fs(e) | UnableToGetCwd(e) => super::get_io_error_class(e), - } - } - - pub fn get_http2_error(error: &Http2Error) -> &'static str { - match error { - Http2Error::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - Http2Error::UrlParse(e) => get_url_parse_error_class(e), - Http2Error::H2(_) => "Error", - } - } - - pub fn get_os_error(error: &OsError) -> &'static str { - match error { - OsError::Priority(e) => match e { - PriorityError::Io(e) => get_io_error_class(e), - #[cfg(windows)] - PriorityError::InvalidPriority => "TypeError", - }, - OsError::Permission(e) => get_permission_check_error_class(e), - OsError::FailedToGetCpuInfo => "TypeError", - OsError::FailedToGetUserInfo(e) => get_io_error_class(e), - } - } - - pub fn get_brotli_error(error: &BrotliError) -> &'static str { - match error { - BrotliError::InvalidEncoderMode => "TypeError", - BrotliError::CompressFailed => "TypeError", - BrotliError::DecompressFailed => "TypeError", - BrotliError::Join(_) => "Error", - BrotliError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - BrotliError::Io(e) => get_io_error_class(e), - } - } - - pub fn get_mode_error(_: &ModeError) -> &'static str { - "Error" - } - - pub fn get_zlib_error(e: &ZlibError) -> &'static str { - match e { - ZlibError::NotInitialized => "TypeError", - ZlibError::Mode(e) => get_mode_error(e), - ZlibError::Other(e) => get_error_class_name(e).unwrap_or("Error"), - } - } - - pub fn get_crypto_cipher_context_error( - e: &CipherContextError, - ) -> &'static str { - match e { - CipherContextError::ContextInUse => "TypeError", - CipherContextError::Cipher(e) => get_crypto_cipher_error(e), - CipherContextError::Resource(e) => { - get_error_class_name(e).unwrap_or("Error") - } - } - } - - pub fn get_crypto_cipher_error(e: &CipherError) -> &'static str { - match e { - CipherError::InvalidIvLength => "TypeError", - CipherError::InvalidKeyLength => "RangeError", - CipherError::InvalidInitializationVector => "TypeError", - CipherError::CannotPadInputData => "TypeError", - CipherError::UnknownCipher(_) => "TypeError", - } - } - - pub fn get_crypto_decipher_context_error( - e: &DecipherContextError, - ) -> &'static str { - match e { - DecipherContextError::ContextInUse => "TypeError", - DecipherContextError::Decipher(e) => get_crypto_decipher_error(e), - DecipherContextError::Resource(e) => { - get_error_class_name(e).unwrap_or("Error") - } - } - } - - pub fn get_crypto_decipher_error(e: &DecipherError) -> &'static str { - match e { - DecipherError::InvalidIvLength => "TypeError", - DecipherError::InvalidKeyLength => "RangeError", - DecipherError::InvalidInitializationVector => "TypeError", - DecipherError::CannotUnpadInputData => "TypeError", - DecipherError::DataAuthenticationFailed => "TypeError", - DecipherError::SetAutoPaddingFalseAes128GcmUnsupported => "TypeError", - DecipherError::SetAutoPaddingFalseAes256GcmUnsupported => "TypeError", - DecipherError::UnknownCipher(_) => "TypeError", - } - } - - pub fn get_x509_error(_: &X509Error) -> &'static str { - "Error" - } - - pub fn get_crypto_key_object_handle_prehashed_sign_and_verify_error( - e: &KeyObjectHandlePrehashedSignAndVerifyError, - ) -> &'static str { - match e { - KeyObjectHandlePrehashedSignAndVerifyError::InvalidDsaSignatureEncoding => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::KeyIsNotPrivate => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::DigestNotAllowedForRsaSignature(_) => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigestWithRsa => "Error", - KeyObjectHandlePrehashedSignAndVerifyError::DigestNotAllowedForRsaPssSignature(_) => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigestWithRsaPss => "Error", - KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigestWithDsa => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::RsaPssHashAlgorithmUnsupported => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::PrivateKeyDisallowsUsage { .. } => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigest => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::X25519KeyCannotBeUsedForSigning => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::Ed25519KeyCannotBeUsedForPrehashedSigning => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::DhKeyCannotBeUsedForSigning => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::KeyIsNotPublicOrPrivate => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::InvalidDsaSignature => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::X25519KeyCannotBeUsedForVerification => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::Ed25519KeyCannotBeUsedForPrehashedVerification => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::DhKeyCannotBeUsedForVerification => "TypeError", - } - } - - pub fn get_crypto_hash_error(_: &HashError) -> &'static str { - "Error" - } - - pub fn get_asymmetric_public_key_jwk_error( - e: &AsymmetricPublicKeyJwkError, - ) -> &'static str { - match e { - AsymmetricPublicKeyJwkError::UnsupportedJwkEcCurveP224 => "TypeError", - AsymmetricPublicKeyJwkError::JwkExportNotImplementedForKeyType => { - "TypeError" - } - AsymmetricPublicKeyJwkError::KeyIsNotAsymmetricPublicKey => "TypeError", - } - } - - pub fn get_generate_rsa_pss_error(_: &GenerateRsaPssError) -> &'static str { - "TypeError" - } - - pub fn get_asymmetric_private_key_der_error( - e: &AsymmetricPrivateKeyDerError, - ) -> &'static str { - match e { - AsymmetricPrivateKeyDerError::KeyIsNotAsymmetricPrivateKey => "TypeError", - AsymmetricPrivateKeyDerError::InvalidRsaPrivateKey => "TypeError", - AsymmetricPrivateKeyDerError::ExportingNonRsaPrivateKeyAsPkcs1Unsupported => "TypeError", - AsymmetricPrivateKeyDerError::InvalidEcPrivateKey => "TypeError", - AsymmetricPrivateKeyDerError::ExportingNonEcPrivateKeyAsSec1Unsupported => "TypeError", - AsymmetricPrivateKeyDerError::ExportingNonRsaPssPrivateKeyAsPkcs8Unsupported => "Error", - AsymmetricPrivateKeyDerError::InvalidDsaPrivateKey => "TypeError", - AsymmetricPrivateKeyDerError::InvalidX25519PrivateKey => "TypeError", - AsymmetricPrivateKeyDerError::InvalidEd25519PrivateKey => "TypeError", - AsymmetricPrivateKeyDerError::InvalidDhPrivateKey => "TypeError", - AsymmetricPrivateKeyDerError::UnsupportedKeyType(_) => "TypeError", - } - } - - pub fn get_asymmetric_public_key_der_error( - _: &AsymmetricPublicKeyDerError, - ) -> &'static str { - "TypeError" - } - - pub fn get_export_public_key_pem_error( - e: &ExportPublicKeyPemError, - ) -> &'static str { - match e { - ExportPublicKeyPemError::AsymmetricPublicKeyDer(e) => { - get_asymmetric_public_key_der_error(e) - } - ExportPublicKeyPemError::VeryLargeData => "TypeError", - ExportPublicKeyPemError::Der(_) => "Error", - } - } - - pub fn get_export_private_key_pem_error( - e: &ExportPrivateKeyPemError, - ) -> &'static str { - match e { - ExportPrivateKeyPemError::AsymmetricPublicKeyDer(e) => { - get_asymmetric_private_key_der_error(e) - } - ExportPrivateKeyPemError::VeryLargeData => "TypeError", - ExportPrivateKeyPemError::Der(_) => "Error", - } - } - - pub fn get_x509_public_key_error(e: &X509PublicKeyError) -> &'static str { - match e { - X509PublicKeyError::X509(_) => "Error", - X509PublicKeyError::Rsa(_) => "Error", - X509PublicKeyError::Asn1(_) => "Error", - X509PublicKeyError::Ec(_) => "Error", - X509PublicKeyError::UnsupportedEcNamedCurve => "TypeError", - X509PublicKeyError::MissingEcParameters => "TypeError", - X509PublicKeyError::MalformedDssPublicKey => "TypeError", - X509PublicKeyError::UnsupportedX509KeyType => "TypeError", - } - } - - pub fn get_rsa_jwk_error(e: &RsaJwkError) -> &'static str { - match e { - RsaJwkError::Base64(_) => "Error", - RsaJwkError::Rsa(_) => "Error", - RsaJwkError::MissingRsaPrivateComponent => "TypeError", - } - } - - pub fn get_ec_jwk_error(e: &EcJwkError) -> &'static str { - match e { - EcJwkError::Ec(_) => "Error", - EcJwkError::UnsupportedCurve(_) => "TypeError", - } - } - - pub fn get_ed_raw_error(e: &EdRawError) -> &'static str { - match e { - EdRawError::Ed25519Signature(_) => "Error", - EdRawError::InvalidEd25519Key => "TypeError", - EdRawError::UnsupportedCurve => "TypeError", - } - } - - pub fn get_pbkdf2_error(e: &Pbkdf2Error) -> &'static str { - match e { - Pbkdf2Error::UnsupportedDigest(_) => "TypeError", - Pbkdf2Error::Join(_) => "Error", - } - } - - pub fn get_scrypt_async_error(e: &ScryptAsyncError) -> &'static str { - match e { - ScryptAsyncError::Join(_) => "Error", - ScryptAsyncError::Other(e) => get_error_class_name(e).unwrap_or("Error"), - } - } - - pub fn get_hkdf_error_error(e: &HkdfError) -> &'static str { - match e { - HkdfError::ExpectedSecretKey => "TypeError", - HkdfError::HkdfExpandFailed => "TypeError", - HkdfError::UnsupportedDigest(_) => "TypeError", - HkdfError::Join(_) => "Error", - } - } - - pub fn get_rsa_pss_params_parse_error( - _: &RsaPssParamsParseError, - ) -> &'static str { - "TypeError" - } - - pub fn get_asymmetric_private_key_error( - e: &AsymmetricPrivateKeyError, - ) -> &'static str { - match e { - AsymmetricPrivateKeyError::InvalidPemPrivateKeyInvalidUtf8(_) => "TypeError", - AsymmetricPrivateKeyError::InvalidEncryptedPemPrivateKey => "TypeError", - AsymmetricPrivateKeyError::InvalidPemPrivateKey => "TypeError", - AsymmetricPrivateKeyError::EncryptedPrivateKeyRequiresPassphraseToDecrypt => "TypeError", - AsymmetricPrivateKeyError::InvalidPkcs1PrivateKey => "TypeError", - AsymmetricPrivateKeyError::InvalidSec1PrivateKey => "TypeError", - AsymmetricPrivateKeyError::UnsupportedPemLabel(_) => "TypeError", - AsymmetricPrivateKeyError::RsaPssParamsParse(e) => get_rsa_pss_params_parse_error(e), - AsymmetricPrivateKeyError::InvalidEncryptedPkcs8PrivateKey => "TypeError", - AsymmetricPrivateKeyError::InvalidPkcs8PrivateKey => "TypeError", - AsymmetricPrivateKeyError::Pkcs1PrivateKeyDoesNotSupportEncryptionWithPassphrase => "TypeError", - AsymmetricPrivateKeyError::Sec1PrivateKeyDoesNotSupportEncryptionWithPassphrase => "TypeError", - AsymmetricPrivateKeyError::UnsupportedEcNamedCurve => "TypeError", - AsymmetricPrivateKeyError::InvalidPrivateKey => "TypeError", - AsymmetricPrivateKeyError::InvalidDsaPrivateKey => "TypeError", - AsymmetricPrivateKeyError::MalformedOrMissingNamedCurveInEcParameters => "TypeError", - AsymmetricPrivateKeyError::UnsupportedKeyType(_) => "TypeError", - AsymmetricPrivateKeyError::UnsupportedKeyFormat(_) => "TypeError", - AsymmetricPrivateKeyError::InvalidX25519PrivateKey => "TypeError", - AsymmetricPrivateKeyError::X25519PrivateKeyIsWrongLength => "TypeError", - AsymmetricPrivateKeyError::InvalidEd25519PrivateKey => "TypeError", - AsymmetricPrivateKeyError::MissingDhParameters => "TypeError", - AsymmetricPrivateKeyError::UnsupportedPrivateKeyOid => "TypeError", - } - } - - pub fn get_asymmetric_public_key_error( - e: &AsymmetricPublicKeyError, - ) -> &'static str { - match e { - AsymmetricPublicKeyError::InvalidPemPrivateKeyInvalidUtf8(_) => { - "TypeError" - } - AsymmetricPublicKeyError::InvalidPemPublicKey => "TypeError", - AsymmetricPublicKeyError::InvalidPkcs1PublicKey => "TypeError", - AsymmetricPublicKeyError::AsymmetricPrivateKey(e) => { - get_asymmetric_private_key_error(e) - } - AsymmetricPublicKeyError::InvalidX509Certificate => "TypeError", - AsymmetricPublicKeyError::X509(_) => "Error", - AsymmetricPublicKeyError::X509PublicKey(e) => { - get_x509_public_key_error(e) - } - AsymmetricPublicKeyError::UnsupportedPemLabel(_) => "TypeError", - AsymmetricPublicKeyError::InvalidSpkiPublicKey => "TypeError", - AsymmetricPublicKeyError::UnsupportedKeyType(_) => "TypeError", - AsymmetricPublicKeyError::UnsupportedKeyFormat(_) => "TypeError", - AsymmetricPublicKeyError::Spki(_) => "Error", - AsymmetricPublicKeyError::Pkcs1(_) => "Error", - AsymmetricPublicKeyError::RsaPssParamsParse(_) => "TypeError", - AsymmetricPublicKeyError::MalformedDssPublicKey => "TypeError", - AsymmetricPublicKeyError::MalformedOrMissingNamedCurveInEcParameters => { - "TypeError" - } - AsymmetricPublicKeyError::MalformedOrMissingPublicKeyInEcSpki => { - "TypeError" - } - AsymmetricPublicKeyError::Ec(_) => "Error", - AsymmetricPublicKeyError::UnsupportedEcNamedCurve => "TypeError", - AsymmetricPublicKeyError::MalformedOrMissingPublicKeyInX25519Spki => { - "TypeError" - } - AsymmetricPublicKeyError::X25519PublicKeyIsTooShort => "TypeError", - AsymmetricPublicKeyError::InvalidEd25519PublicKey => "TypeError", - AsymmetricPublicKeyError::MissingDhParameters => "TypeError", - AsymmetricPublicKeyError::MalformedDhParameters => "TypeError", - AsymmetricPublicKeyError::MalformedOrMissingPublicKeyInDhSpki => { - "TypeError" - } - AsymmetricPublicKeyError::UnsupportedPrivateKeyOid => "TypeError", - } - } - - pub fn get_private_encrypt_decrypt_error( - e: &PrivateEncryptDecryptError, - ) -> &'static str { - match e { - PrivateEncryptDecryptError::Pkcs8(_) => "Error", - PrivateEncryptDecryptError::Spki(_) => "Error", - PrivateEncryptDecryptError::Utf8(_) => "Error", - PrivateEncryptDecryptError::Rsa(_) => "Error", - PrivateEncryptDecryptError::UnknownPadding => "TypeError", - } - } - - pub fn get_ecdh_encode_pub_key_error(e: &EcdhEncodePubKey) -> &'static str { - match e { - EcdhEncodePubKey::InvalidPublicKey => "TypeError", - EcdhEncodePubKey::UnsupportedCurve => "TypeError", - EcdhEncodePubKey::Sec1(_) => "Error", - } - } - - pub fn get_diffie_hellman_error(_: &DiffieHellmanError) -> &'static str { - "TypeError" - } - - pub fn get_sign_ed25519_error(_: &SignEd25519Error) -> &'static str { - "TypeError" - } - - pub fn get_verify_ed25519_error(_: &VerifyEd25519Error) -> &'static str { - "TypeError" - } - - pub fn get_conn_error(e: &ConnError) -> &'static str { - match e { - ConnError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - ConnError::Permission(e) => get_permission_check_error_class(e), - ConnError::InvalidUrl(_) => "TypeError", - ConnError::InvalidHeaderName(_) => "TypeError", - ConnError::InvalidHeaderValue(_) => "TypeError", - ConnError::Url(e) => get_url_parse_error_class(e), - ConnError::Method(_) => "TypeError", - ConnError::Io(e) => get_io_error_class(e), - ConnError::Hyper(e) => super::get_hyper_error_class(e), - ConnError::TlsStreamBusy => "Busy", - ConnError::TcpStreamBusy => "Busy", - ConnError::ReuniteTcp(_) => "Error", - ConnError::Canceled(_) => "Error", - } - } -} - -fn get_os_error(error: &OsError) -> &'static str { - match error { - OsError::Permission(e) => get_permission_check_error_class(e), - OsError::InvalidUtf8(_) => "InvalidData", - OsError::EnvEmptyKey => "TypeError", - OsError::EnvInvalidKey(_) => "TypeError", - OsError::EnvInvalidValue(_) => "TypeError", - OsError::Io(e) => get_io_error_class(e), - OsError::Var(e) => get_env_var_error_class(e), - } -} - -fn get_sync_fetch_error(error: &SyncFetchError) -> &'static str { - match error { - SyncFetchError::BlobUrlsNotSupportedInContext => "TypeError", - SyncFetchError::Io(e) => get_io_error_class(e), - SyncFetchError::InvalidScriptUrl => "TypeError", - SyncFetchError::InvalidStatusCode(_) => "TypeError", - SyncFetchError::ClassicScriptSchemeUnsupportedInWorkers(_) => "TypeError", - SyncFetchError::InvalidUri(_) => "Error", - SyncFetchError::InvalidMimeType(_) => "DOMExceptionNetworkError", - SyncFetchError::MissingMimeType => "DOMExceptionNetworkError", - SyncFetchError::Fetch(e) => get_fetch_error(e), - SyncFetchError::Join(_) => "Error", - SyncFetchError::Other(e) => get_error_class_name(e).unwrap_or("Error"), - } -} - -pub fn get_error_class_name(e: &AnyError) -> Option<&'static str> { - deno_core::error::get_custom_error_class(e) - .or_else(|| { - e.downcast_ref::() - .map(get_child_permission_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_permission_check_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_permission_error_class) - }) - .or_else(|| e.downcast_ref::().map(get_fs_error)) - .or_else(|| { - e.downcast_ref::() - .map(node::get_blocklist_error) - }) - .or_else(|| e.downcast_ref::().map(node::get_fs_error)) - .or_else(|| { - e.downcast_ref::() - .map(node::get_idna_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_ipc_json_stream_error) - }) - .or_else(|| e.downcast_ref::().map(node::get_ipc_error)) - .or_else(|| { - e.downcast_ref::() - .map(node::get_worker_threads_filename_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_require_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_http2_error) - }) - .or_else(|| e.downcast_ref::().map(node::get_os_error)) - .or_else(|| { - e.downcast_ref::() - .map(node::get_brotli_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_mode_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_zlib_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_crypto_cipher_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_crypto_cipher_context_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_crypto_decipher_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_crypto_decipher_context_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_x509_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_crypto_key_object_handle_prehashed_sign_and_verify_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_crypto_hash_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_asymmetric_public_key_jwk_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_generate_rsa_pss_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_asymmetric_private_key_der_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_asymmetric_public_key_der_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_export_public_key_pem_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_export_private_key_pem_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_rsa_jwk_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_ec_jwk_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_ed_raw_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_pbkdf2_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_scrypt_async_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_hkdf_error_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_rsa_pss_params_parse_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_asymmetric_private_key_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_asymmetric_public_key_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_private_encrypt_decrypt_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_ecdh_encode_pub_key_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_diffie_hellman_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_sign_ed25519_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_verify_ed25519_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_conn_error) - }) - .or_else(|| e.downcast_ref::().map(get_napi_error_class)) - .or_else(|| e.downcast_ref::().map(get_web_error_class)) - .or_else(|| { - e.downcast_ref::() - .map(get_create_worker_error) - }) - .or_else(|| e.downcast_ref::().map(get_tty_error)) - .or_else(|| e.downcast_ref::().map(get_readline_error)) - .or_else(|| e.downcast_ref::().map(get_signal_error)) - .or_else(|| e.downcast_ref::().map(get_fs_events_error)) - .or_else(|| e.downcast_ref::().map(get_http_start_error)) - .or_else(|| e.downcast_ref::().map(get_process_error)) - .or_else(|| e.downcast_ref::().map(get_os_error)) - .or_else(|| e.downcast_ref::().map(get_sync_fetch_error)) - .or_else(|| { - e.downcast_ref::() - .map(get_web_compression_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_web_message_port_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_web_stream_resource_error_class) - }) - .or_else(|| e.downcast_ref::().map(get_web_blob_error_class)) - .or_else(|| e.downcast_ref::().map(|_| "TypeError")) - .or_else(|| e.downcast_ref::().map(get_ffi_repr_error_class)) - .or_else(|| e.downcast_ref::().map(get_http_error)) - .or_else(|| e.downcast_ref::().map(get_http_next_error)) - .or_else(|| { - e.downcast_ref::() - .map(get_websocket_upgrade_error) - }) - .or_else(|| e.downcast_ref::().map(get_fs_ops_error)) - .or_else(|| { - e.downcast_ref::() - .map(get_ffi_dlfcn_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_ffi_static_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_ffi_callback_error_class) - }) - .or_else(|| e.downcast_ref::().map(get_ffi_call_error_class)) - .or_else(|| e.downcast_ref::().map(get_tls_error_class)) - .or_else(|| e.downcast_ref::().map(get_cron_error_class)) - .or_else(|| e.downcast_ref::().map(get_canvas_error)) - .or_else(|| e.downcast_ref::().map(get_cache_error)) - .or_else(|| e.downcast_ref::().map(get_websocket_error)) - .or_else(|| { - e.downcast_ref::() - .map(get_websocket_handshake_error) - }) - .or_else(|| e.downcast_ref::().map(get_kv_error)) - .or_else(|| e.downcast_ref::().map(get_fetch_error)) - .or_else(|| { - e.downcast_ref::() - .map(get_http_client_create_error) - }) - .or_else(|| e.downcast_ref::().map(get_net_error)) - .or_else(|| { - e.downcast_ref::() - .map(get_net_map_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_broadcast_channel_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_webgpu_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_webgpu_buffer_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_webgpu_bundle_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_webgpu_byow_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_webgpu_render_pass_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_webgpu_surface_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_crypto_decrypt_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_crypto_encrypt_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_crypto_shared_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_crypto_ed25519_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_crypto_export_key_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_crypto_generate_key_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_crypto_import_key_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_crypto_x448_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_crypto_x25519_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_crypto_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_webstorage_class_name) - }) - .or_else(|| { - e.downcast_ref::() - .map(|_| "TypeError") - }) - .or_else(|| { - e.downcast_ref::() - .map(get_dlopen_error_class) - }) - .or_else(|| e.downcast_ref::().map(get_hyper_error_class)) - .or_else(|| { - e.downcast_ref::() - .map(get_hyper_util_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_hyper_v014_error_class) - }) - .or_else(|| { - e.downcast_ref::>() - .map(|e| get_hyper_v014_error_class(e)) - }) - .or_else(|| { - e.downcast_ref::().map(|e| { - let io_err: io::Error = e.to_owned().into(); - get_io_error_class(&io_err) - }) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_env_var_error_class) - }) - .or_else(|| e.downcast_ref::().map(get_io_error_class)) - .or_else(|| { - e.downcast_ref::() - .map(get_module_resolution_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_notify_error_class) - }) - .or_else(|| e.downcast_ref::().map(get_regex_error_class)) - .or_else(|| { - e.downcast_ref::() - .map(get_serde_json_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_url_parse_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(|_| "TypeError") - }) - .or_else(|| { - #[cfg(unix)] - let maybe_get_nix_error_class = - || e.downcast_ref::().map(get_nix_error_class); - #[cfg(not(unix))] - let maybe_get_nix_error_class = || Option::<&'static str>::None; - (maybe_get_nix_error_class)() - }) -} diff --git a/runtime/examples/extension/bootstrap.js b/runtime/examples/extension/bootstrap.js index 9461acb84a..78e0cb999f 100644 --- a/runtime/examples/extension/bootstrap.js +++ b/runtime/examples/extension/bootstrap.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { op_hello } from "ext:core/ops"; function hello() { op_hello("world"); diff --git a/runtime/examples/extension/main.js b/runtime/examples/extension/main.js index 4d6e4e3b7d..4a66aecf58 100644 --- a/runtime/examples/extension/main.js +++ b/runtime/examples/extension/main.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. console.log("Hello world from JS!"); console.log(Deno.build); Extension.hello(); diff --git a/runtime/examples/extension/main.rs b/runtime/examples/extension/main.rs index a4ac85bf5e..a1c24f30e4 100644 --- a/runtime/examples/extension/main.rs +++ b/runtime/examples/extension/main.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. #![allow(clippy::print_stdout)] #![allow(clippy::print_stderr)] @@ -12,6 +12,8 @@ use deno_core::op2; use deno_core::FsModuleLoader; use deno_core::ModuleSpecifier; use deno_fs::RealFs; +use deno_resolver::npm::DenoInNpmPackageChecker; +use deno_resolver::npm::NpmResolver; use deno_runtime::deno_permissions::PermissionsContainer; use deno_runtime::permissions::RuntimePermissionDescriptorParser; use deno_runtime::worker::MainWorker; @@ -41,8 +43,12 @@ async fn main() -> Result<(), AnyError> { RuntimePermissionDescriptorParser::new(sys_traits::impls::RealSys), ); let mut worker = MainWorker::bootstrap_from_options( - main_module.clone(), - WorkerServiceOptions:: { + &main_module, + WorkerServiceOptions::< + DenoInNpmPackageChecker, + NpmResolver, + sys_traits::impls::RealSys, + > { module_loader: Rc::new(FsModuleLoader), permissions: PermissionsContainer::allow_all(permission_desc_parser), blob_store: Default::default(), diff --git a/runtime/fmt_errors.rs b/runtime/fmt_errors.rs index 3c60c3a3d7..6aa4765829 100644 --- a/runtime/fmt_errors.rs +++ b/runtime/fmt_errors.rs @@ -1,11 +1,12 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. //! This mod provides DenoError to unify errors across Deno. +use std::fmt::Write as _; + use color_print::cformat; use color_print::cstr; use deno_core::error::format_frame; use deno_core::error::JsError; use deno_terminal::colors; -use std::fmt::Write as _; #[derive(Debug, Clone)] struct ErrorReference<'a> { @@ -422,7 +423,7 @@ fn get_suggestions_for_terminal_errors(e: &JsError) -> Vec { "Run again with `--unstable-webgpu` flag to enable this API.", ), ]; - } else if msg.contains("listenQuic is not a function") { + } else if msg.contains("QuicEndpoint is not a constructor") { return vec![ FixSuggestion::info("listenQuic is an unstable API."), FixSuggestion::hint( @@ -490,9 +491,10 @@ pub fn format_js_error(js_error: &JsError) -> String { #[cfg(test)] mod tests { - use super::*; use test_util::strip_ansi_codes; + use super::*; + #[test] fn test_format_none_source_line() { let actual = format_maybe_source_line(None, None, false, 0); diff --git a/runtime/fs_util.rs b/runtime/fs_util.rs index a858e9770d..7788a97170 100644 --- a/runtime/fs_util.rs +++ b/runtime/fs_util.rs @@ -1,10 +1,11 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::path::Path; +use std::path::PathBuf; use deno_core::anyhow::Context; use deno_core::error::AnyError; use deno_path_util::normalize_path; -use std::path::Path; -use std::path::PathBuf; #[inline] pub fn resolve_from_cwd(path: &Path) -> Result { diff --git a/runtime/inspector_server.rs b/runtime/inspector_server.rs index a789dd3dca..75e9668db4 100644 --- a/runtime/inspector_server.rs +++ b/runtime/inspector_server.rs @@ -1,7 +1,15 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Alias for the future `!` type. use core::convert::Infallible as Never; +use std::cell::RefCell; +use std::collections::HashMap; +use std::net::SocketAddr; +use std::pin::pin; +use std::process; +use std::rc::Rc; +use std::thread; + use deno_core::anyhow::Context; use deno_core::error::AnyError; use deno_core::futures::channel::mpsc; @@ -28,13 +36,6 @@ use fastwebsockets::OpCode; use fastwebsockets::WebSocket; use hyper::body::Bytes; use hyper_util::rt::TokioIo; -use std::cell::RefCell; -use std::collections::HashMap; -use std::net::SocketAddr; -use std::pin::pin; -use std::process; -use std::rc::Rc; -use std::thread; use tokio::net::TcpListener; use tokio::sync::broadcast; use uuid::Uuid; diff --git a/runtime/js.rs b/runtime/js.rs index a8384ceacf..55ab75b66b 100644 --- a/runtime/js.rs +++ b/runtime/js.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. #[cfg(not(feature = "include_js_files_for_snapshotting"))] pub static SOURCE_CODE_FOR_99_MAIN_JS: &str = include_str!("js/99_main.js"); diff --git a/runtime/js/01_errors.js b/runtime/js/01_errors.js index ea567a5d08..09fd82e867 100644 --- a/runtime/js/01_errors.js +++ b/runtime/js/01_errors.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, primordials } from "ext:core/mod.js"; const { BadResource, Interrupted, NotCapable } = core; diff --git a/runtime/js/01_version.ts b/runtime/js/01_version.ts index 33a8f50cdd..779a886897 100644 --- a/runtime/js/01_version.ts +++ b/runtime/js/01_version.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { primordials } from "ext:core/mod.js"; const { diff --git a/runtime/js/06_util.js b/runtime/js/06_util.js index bf71c371b9..658cfa69aa 100644 --- a/runtime/js/06_util.js +++ b/runtime/js/06_util.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { primordials } from "ext:core/mod.js"; import { op_bootstrap_log_level } from "ext:core/ops"; diff --git a/runtime/js/10_permissions.js b/runtime/js/10_permissions.js index 831b6bf2ae..c835cc1c5a 100644 --- a/runtime/js/10_permissions.js +++ b/runtime/js/10_permissions.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { primordials } from "ext:core/mod.js"; import { diff --git a/runtime/js/11_workers.js b/runtime/js/11_workers.js index 3853761920..fd36866936 100644 --- a/runtime/js/11_workers.js +++ b/runtime/js/11_workers.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, primordials } from "ext:core/mod.js"; import { diff --git a/runtime/js/40_fs_events.js b/runtime/js/40_fs_events.js index 322ee6b3ca..25f397b840 100644 --- a/runtime/js/40_fs_events.js +++ b/runtime/js/40_fs_events.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, primordials } from "ext:core/mod.js"; import { op_fs_events_open, op_fs_events_poll } from "ext:core/ops"; diff --git a/runtime/js/40_tty.js b/runtime/js/40_tty.js index 72e7b68846..56f8721eaf 100644 --- a/runtime/js/40_tty.js +++ b/runtime/js/40_tty.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, primordials } from "ext:core/mod.js"; import { op_console_size } from "ext:core/ops"; const { diff --git a/runtime/js/41_prompt.js b/runtime/js/41_prompt.js index 8460862d2e..e300f69a3c 100644 --- a/runtime/js/41_prompt.js +++ b/runtime/js/41_prompt.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, primordials } from "ext:core/mod.js"; import { op_read_line_prompt } from "ext:core/ops"; const { diff --git a/runtime/js/90_deno_ns.js b/runtime/js/90_deno_ns.js index 5511649279..5aaf0614dc 100644 --- a/runtime/js/90_deno_ns.js +++ b/runtime/js/90_deno_ns.js @@ -1,6 +1,6 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -import { core } from "ext:core/mod.js"; +import { core, primordials } from "ext:core/mod.js"; import { op_net_listen_udp, op_net_listen_unixpacket, @@ -13,7 +13,6 @@ import * as console from "ext:deno_console/01_console.js"; import * as ffi from "ext:deno_ffi/00_ffi.js"; import * as net from "ext:deno_net/01_net.js"; import * as tls from "ext:deno_net/02_tls.js"; -import * as quic from "ext:deno_net/03_quic.js"; import * as serve from "ext:deno_http/00_serve.ts"; import * as http from "ext:deno_http/01_http.js"; import * as websocket from "ext:deno_http/02_websocket.ts"; @@ -22,16 +21,20 @@ import * as version from "ext:runtime/01_version.ts"; import * as permissions from "ext:runtime/10_permissions.js"; import * as io from "ext:deno_io/12_io.js"; import * as fs from "ext:deno_fs/30_fs.js"; -import * as os from "ext:runtime/30_os.js"; +import * as os from "ext:deno_os/30_os.js"; import * as fsEvents from "ext:runtime/40_fs_events.js"; -import * as process from "ext:runtime/40_process.js"; -import * as signals from "ext:runtime/40_signals.js"; +import * as process from "ext:deno_process/40_process.js"; +import * as signals from "ext:deno_os/40_signals.js"; import * as tty from "ext:runtime/40_tty.js"; import * as kv from "ext:deno_kv/01_db.ts"; import * as cron from "ext:deno_cron/01_cron.ts"; import * as webgpuSurface from "ext:deno_webgpu/02_surface.js"; import * as telemetry from "ext:deno_telemetry/telemetry.ts"; +const { ObjectDefineProperties } = primordials; + +const loadQuic = core.createLazyLoader("ext:deno_net/03_quic.js"); + const denoNs = { Process: process.Process, run: process.run, @@ -175,17 +178,28 @@ denoNsUnstableById[unstableIds.net] = { op_net_listen_udp, op_net_listen_unixpacket, ), - - connectQuic: quic.connectQuic, - listenQuic: quic.listenQuic, - QuicBidirectionalStream: quic.QuicBidirectionalStream, - QuicConn: quic.QuicConn, - QuicListener: quic.QuicListener, - QuicReceiveStream: quic.QuicReceiveStream, - QuicSendStream: quic.QuicSendStream, - QuicIncoming: quic.QuicIncoming, }; +ObjectDefineProperties(denoNsUnstableById[unstableIds.net], { + connectQuic: core.propWritableLazyLoaded((q) => q.connectQuic, loadQuic), + QuicEndpoint: core.propWritableLazyLoaded((q) => q.QuicEndpoint, loadQuic), + QuicBidirectionalStream: core.propWritableLazyLoaded( + (q) => q.QuicBidirectionalStream, + loadQuic, + ), + QuicConn: core.propWritableLazyLoaded((q) => q.QuicConn, loadQuic), + QuicListener: core.propWritableLazyLoaded((q) => q.QuicListener, loadQuic), + QuicReceiveStream: core.propWritableLazyLoaded( + (q) => q.QuicReceiveStream, + loadQuic, + ), + QuicSendStream: core.propWritableLazyLoaded( + (q) => q.QuicSendStream, + loadQuic, + ), + QuicIncoming: core.propWritableLazyLoaded((q) => q.QuicIncoming, loadQuic), +}); + // denoNsUnstableById[unstableIds.unsafeProto] = { __proto__: null } denoNsUnstableById[unstableIds.webgpu] = { diff --git a/runtime/js/98_global_scope_shared.js b/runtime/js/98_global_scope_shared.js index c01bde6fad..99bace7647 100644 --- a/runtime/js/98_global_scope_shared.js +++ b/runtime/js/98_global_scope_shared.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core } from "ext:core/mod.js"; diff --git a/runtime/js/98_global_scope_window.js b/runtime/js/98_global_scope_window.js index 098422f56f..c42a940a82 100644 --- a/runtime/js/98_global_scope_window.js +++ b/runtime/js/98_global_scope_window.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, primordials } from "ext:core/mod.js"; import { diff --git a/runtime/js/98_global_scope_worker.js b/runtime/js/98_global_scope_worker.js index 4dc6157867..f10bb2830d 100644 --- a/runtime/js/98_global_scope_worker.js +++ b/runtime/js/98_global_scope_worker.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { core, primordials } from "ext:core/mod.js"; import { diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js index a11444bc36..2971fd2c00 100644 --- a/runtime/js/99_main.js +++ b/runtime/js/99_main.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Remove Intl.v8BreakIterator because it is a non-standard API. delete Intl.v8BreakIterator; @@ -55,7 +55,7 @@ import { registerDeclarativeServer } from "ext:deno_http/00_serve.ts"; import * as event from "ext:deno_web/02_event.js"; import * as location from "ext:deno_web/12_location.js"; import * as version from "ext:runtime/01_version.ts"; -import * as os from "ext:runtime/30_os.js"; +import * as os from "ext:deno_os/30_os.js"; import * as timers from "ext:deno_web/02_timers.js"; import { getDefaultInspectOptions, diff --git a/runtime/lib.rs b/runtime/lib.rs index 1f449dc69a..c83fe5d60b 100644 --- a/runtime/lib.rs +++ b/runtime/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. pub use deno_broadcast_channel; pub use deno_cache; @@ -16,7 +16,10 @@ pub use deno_kv; pub use deno_napi; pub use deno_net; pub use deno_node; +pub use deno_os; pub use deno_permissions; +pub use deno_process; +pub use deno_telemetry; pub use deno_terminal::colors; pub use deno_tls; pub use deno_url; @@ -27,16 +30,13 @@ pub use deno_websocket; pub use deno_webstorage; pub mod code_cache; -pub mod errors; pub mod fmt_errors; pub mod fs_util; pub mod inspector_server; pub mod js; pub mod ops; pub mod permissions; -pub mod signal; pub mod snapshot; -pub mod sys_info; pub mod tokio_util; pub mod web_worker; pub mod worker; @@ -47,6 +47,7 @@ pub use worker_bootstrap::WorkerExecutionMode; pub use worker_bootstrap::WorkerLogLevel; pub mod shared; +pub use deno_os::exit; pub use shared::runtime; pub struct UnstableGranularFlag { @@ -115,7 +116,7 @@ pub static UNSTABLE_GRANULAR_FLAGS: &[UnstableGranularFlag] = &[ }, // TODO(bartlomieju): consider removing it UnstableGranularFlag { - name: ops::process::UNSTABLE_FEATURE_NAME, + name: deno_process::UNSTABLE_FEATURE_NAME, help_text: "Enable unstable process APIs", show_in_help: false, id: 10, @@ -148,12 +149,6 @@ pub static UNSTABLE_GRANULAR_FLAGS: &[UnstableGranularFlag] = &[ }, ]; -pub fn exit(code: i32) -> ! { - deno_telemetry::flush(); - #[allow(clippy::disallowed_methods)] - std::process::exit(code); -} - #[cfg(test)] mod test { use super::*; diff --git a/runtime/ops/bootstrap.rs b/runtime/ops/bootstrap.rs index bbbddc61ba..b362217d2c 100644 --- a/runtime/ops/bootstrap.rs +++ b/runtime/ops/bootstrap.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::op2; use deno_core::OpState; diff --git a/runtime/ops/fs_events.rs b/runtime/ops/fs_events.rs index f6e5ceff5c..5336c232c9 100644 --- a/runtime/ops/fs_events.rs +++ b/runtime/ops/fs_events.rs @@ -1,5 +1,14 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. +use std::borrow::Cow; +use std::cell::RefCell; +use std::convert::From; +use std::path::Path; +use std::path::PathBuf; +use std::rc::Rc; +use std::sync::Arc; + +use deno_core::op2; use deno_core::parking_lot::Mutex; use deno_core::AsyncRefCell; use deno_core::CancelFuture; @@ -8,9 +17,8 @@ use deno_core::OpState; use deno_core::RcRef; use deno_core::Resource; use deno_core::ResourceId; - -use deno_core::op2; - +use deno_error::builtin_classes::GENERIC_ERROR; +use deno_error::JsErrorClass; use deno_permissions::PermissionsContainer; use notify::event::Event as NotifyEvent; use notify::event::ModifyKind; @@ -20,13 +28,6 @@ use notify::RecommendedWatcher; use notify::RecursiveMode; use notify::Watcher; use serde::Serialize; -use std::borrow::Cow; -use std::cell::RefCell; -use std::convert::From; -use std::path::Path; -use std::path::PathBuf; -use std::rc::Rc; -use std::sync::Arc; use tokio::sync::mpsc; deno_core::extension!( @@ -117,14 +118,29 @@ fn is_file_removed(event_path: &PathBuf) -> bool { } } -#[derive(Debug, thiserror::Error)] +deno_error::js_error_wrapper!(NotifyError, JsNotifyError, |err| { + match &err.kind { + notify::ErrorKind::Generic(_) => GENERIC_ERROR.into(), + notify::ErrorKind::Io(e) => e.get_class(), + notify::ErrorKind::PathNotFound => "NotFound".into(), + notify::ErrorKind::WatchNotFound => "NotFound".into(), + notify::ErrorKind::InvalidConfig(_) => "InvalidData".into(), + notify::ErrorKind::MaxFilesWatch => GENERIC_ERROR.into(), + } +}); + +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum FsEventsError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] deno_core::error::ResourceError), + #[class(inherit)] #[error(transparent)] Permission(#[from] deno_permissions::PermissionCheckError), + #[class(inherit)] #[error(transparent)] - Notify(#[from] NotifyError), + Notify(JsNotifyError), + #[class(inherit)] #[error(transparent)] Canceled(#[from] deno_core::Canceled), } @@ -144,7 +160,9 @@ fn start_watcher( let sender_clone = senders.clone(); let watcher: RecommendedWatcher = Watcher::new( move |res: Result| { - let res2 = res.map(FsEvent::from).map_err(FsEventsError::Notify); + let res2 = res + .map(FsEvent::from) + .map_err(|e| FsEventsError::Notify(JsNotifyError(e))); for (paths, sender) in sender_clone.lock().iter() { // Ignore result, if send failed it means that watcher was already closed, // but not all messages have been flushed. @@ -170,7 +188,8 @@ fn start_watcher( } }, Default::default(), - )?; + ) + .map_err(|e| FsEventsError::Notify(JsNotifyError(e)))?; state.put::(WatcherState { watcher, senders }); @@ -199,7 +218,10 @@ fn op_fs_events_open( .check_read(path, "Deno.watchFs()")?; let watcher = state.borrow_mut::(); - watcher.watcher.watch(&path, recursive_mode)?; + watcher + .watcher + .watch(&path, recursive_mode) + .map_err(|e| FsEventsError::Notify(JsNotifyError(e)))?; } let resource = FsEventsResource { receiver: AsyncRefCell::new(receiver), @@ -215,17 +237,13 @@ async fn op_fs_events_poll( state: Rc>, #[smi] rid: ResourceId, ) -> Result, FsEventsError> { - let resource = state - .borrow() - .resource_table - .get::(rid) - .map_err(FsEventsError::Resource)?; + let resource = state.borrow().resource_table.get::(rid)?; let mut receiver = RcRef::map(&resource, |r| &r.receiver).borrow_mut().await; let cancel = RcRef::map(resource, |r| &r.cancel); let maybe_result = receiver.recv().or_cancel(cancel).await?; match maybe_result { Some(Ok(value)) => Ok(Some(value)), - Some(Err(err)) => Err(FsEventsError::Notify(err)), + Some(Err(err)) => Err(FsEventsError::Notify(JsNotifyError(err))), None => Ok(None), } } diff --git a/runtime/ops/http.rs b/runtime/ops/http.rs index 6e31576686..931b407779 100644 --- a/runtime/ops/http.rs +++ b/runtime/ops/http.rs @@ -1,7 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::rc::Rc; +use deno_core::error::ResourceError; use deno_core::op2; use deno_core::OpState; use deno_core::ResourceId; @@ -13,23 +14,34 @@ pub const UNSTABLE_FEATURE_NAME: &str = "http"; deno_core::extension!(deno_http_runtime, ops = [op_http_start],); -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum HttpStartError { + #[class("Busy")] #[error("TCP stream is currently in use")] TcpStreamInUse, + #[class("Busy")] #[error("TLS stream is currently in use")] TlsStreamInUse, + #[class("Busy")] #[error("Unix socket is currently in use")] UnixSocketInUse, + #[class(generic)] #[error(transparent)] ReuniteTcp(#[from] tokio::net::tcp::ReuniteError), #[cfg(unix)] + #[class(generic)] #[error(transparent)] ReuniteUnix(#[from] tokio::net::unix::ReuniteError), + #[class(inherit)] #[error("{0}")] - Io(#[from] std::io::Error), + Io( + #[from] + #[inherit] + std::io::Error, + ), + #[class(inherit)] #[error(transparent)] - Other(deno_core::error::AnyError), + Resource(#[inherit] ResourceError), } #[op2(fast)] @@ -89,5 +101,5 @@ fn op_http_start( )); } - Err(HttpStartError::Other(deno_core::error::bad_resource_id())) + Err(HttpStartError::Resource(ResourceError::BadResourceId)) } diff --git a/runtime/ops/mod.rs b/runtime/ops/mod.rs index 67065b901b..04065ff2f8 100644 --- a/runtime/ops/mod.rs +++ b/runtime/ops/mod.rs @@ -1,13 +1,10 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. pub mod bootstrap; pub mod fs_events; pub mod http; -pub mod os; pub mod permissions; -pub mod process; pub mod runtime; -pub mod signal; pub mod tty; pub mod web_worker; pub mod worker_host; diff --git a/runtime/ops/permissions.rs b/runtime/ops/permissions.rs index b5f9e284df..0ad14d433b 100644 --- a/runtime/ops/permissions.rs +++ b/runtime/ops/permissions.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use ::deno_permissions::PermissionState; use ::deno_permissions::PermissionsContainer; @@ -45,16 +45,21 @@ impl From for PermissionStatus { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum PermissionError { + #[class(reference)] #[error("No such permission name: {0}")] InvalidPermissionName(String), + #[class(inherit)] #[error("{0}")] PathResolve(#[from] ::deno_permissions::PathResolveError), + #[class(uri)] #[error("{0}")] NetDescriptorParse(#[from] ::deno_permissions::NetDescriptorParseError), + #[class(inherit)] #[error("{0}")] SysDescriptorParse(#[from] ::deno_permissions::SysDescriptorParseError), + #[class(inherit)] #[error("{0}")] RunDescriptorParse(#[from] ::deno_permissions::RunDescriptorParseError), } diff --git a/runtime/ops/runtime.rs b/runtime/ops/runtime.rs index 8d54783fc9..e95193167d 100644 --- a/runtime/ops/runtime.rs +++ b/runtime/ops/runtime.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::op2; use deno_core::ModuleSpecifier; @@ -34,6 +34,7 @@ pub fn op_ppid() -> i64 { // - Apache License, Version 2.0 // - MIT license use std::mem; + use winapi::shared::minwindef::DWORD; use winapi::um::handleapi::CloseHandle; use winapi::um::handleapi::INVALID_HANDLE_VALUE; diff --git a/runtime/ops/tty.rs b/runtime/ops/tty.rs index 7849185faa..a929b7d18a 100644 --- a/runtime/ops/tty.rs +++ b/runtime/ops/tty.rs @@ -1,9 +1,26 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. +#[cfg(unix)] +use std::cell::RefCell; +#[cfg(unix)] +use std::collections::HashMap; use std::io::Error; +#[cfg(windows)] +use std::sync::Arc; use deno_core::op2; +#[cfg(windows)] +use deno_core::parking_lot::Mutex; use deno_core::OpState; +#[cfg(unix)] +use deno_core::ResourceId; +use deno_error::builtin_classes::GENERIC_ERROR; +use deno_error::JsErrorBox; +use deno_error::JsErrorClass; +#[cfg(windows)] +use deno_io::WinTtyState; +#[cfg(unix)] +use nix::sys::termios; use rustyline::config::Configurer; use rustyline::error::ReadlineError; use rustyline::Cmd; @@ -12,22 +29,6 @@ use rustyline::KeyCode; use rustyline::KeyEvent; use rustyline::Modifiers; -#[cfg(windows)] -use deno_core::parking_lot::Mutex; -#[cfg(windows)] -use deno_io::WinTtyState; -#[cfg(windows)] -use std::sync::Arc; - -#[cfg(unix)] -use deno_core::ResourceId; -#[cfg(unix)] -use nix::sys::termios; -#[cfg(unix)] -use std::cell::RefCell; -#[cfg(unix)] -use std::collections::HashMap; - #[cfg(unix)] #[derive(Default, Clone)] struct TtyModeStore( @@ -49,6 +50,8 @@ impl TtyModeStore { } } +#[cfg(unix)] +use deno_process::JsNixError; #[cfg(windows)] use winapi::shared::minwindef::DWORD; #[cfg(windows)] @@ -63,17 +66,29 @@ deno_core::extension!( }, ); -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum TtyError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource( + #[from] + #[inherit] + deno_core::error::ResourceError, + ), + #[class(inherit)] #[error("{0}")] - Io(#[from] std::io::Error), + Io( + #[from] + #[inherit] + Error, + ), #[cfg(unix)] + #[class(inherit)] #[error(transparent)] - Nix(nix::Error), + Nix(#[inherit] JsNixError), + #[class(inherit)] #[error(transparent)] - Other(deno_core::error::AnyError), + Other(#[inherit] JsErrorBox), } // ref: @@ -103,10 +118,7 @@ fn op_set_raw( is_raw: bool, cbreak: bool, ) -> Result<(), TtyError> { - let handle_or_fd = state - .resource_table - .get_fd(rid) - .map_err(TtyError::Resource)?; + let handle_or_fd = state.resource_table.get_fd(rid)?; // From https://github.com/kkawakam/rustyline/blob/master/src/tty/windows.rs // and https://github.com/kkawakam/rustyline/blob/master/src/tty/unix.rs @@ -115,14 +127,14 @@ fn op_set_raw( // Copyright (c) 2019 Timon. MIT license. #[cfg(windows)] { + use deno_error::JsErrorBox; use winapi::shared::minwindef::FALSE; - use winapi::um::consoleapi; let handle = handle_or_fd; if cbreak { - return Err(TtyError::Other(deno_core::error::not_supported())); + return Err(TtyError::Other(JsErrorBox::not_supported())); } let mut original_mode: DWORD = 0; @@ -267,8 +279,8 @@ fn op_set_raw( Some(mode) => mode, None => { // Save original mode. - let original_mode = - termios::tcgetattr(raw_fd).map_err(TtyError::Nix)?; + let original_mode = termios::tcgetattr(raw_fd) + .map_err(|e| TtyError::Nix(JsNixError(e)))?; tty_mode_store.set(rid, original_mode.clone()); original_mode } @@ -291,12 +303,12 @@ fn op_set_raw( raw.control_chars[termios::SpecialCharacterIndices::VMIN as usize] = 1; raw.control_chars[termios::SpecialCharacterIndices::VTIME as usize] = 0; termios::tcsetattr(raw_fd, termios::SetArg::TCSADRAIN, &raw) - .map_err(TtyError::Nix)?; + .map_err(|e| TtyError::Nix(JsNixError(e)))?; } else { // Try restore saved mode. if let Some(mode) = tty_mode_store.take(rid) { termios::tcsetattr(raw_fd, termios::SetArg::TCSADRAIN, &mode) - .map_err(TtyError::Nix)?; + .map_err(|e| TtyError::Nix(JsNixError(e)))?; } } @@ -314,10 +326,7 @@ fn op_console_size( result: &mut [u32], rid: u32, ) -> Result<(), TtyError> { - let fd = state - .resource_table - .get_fd(rid) - .map_err(TtyError::Resource)?; + let fd = state.resource_table.get_fd(rid)?; let size = console_size_from_fd(fd)?; result[0] = size.cols; result[1] = size.rows; @@ -435,12 +444,28 @@ mod tests { } } +deno_error::js_error_wrapper!(ReadlineError, JsReadlineError, |err| { + match err { + ReadlineError::Io(e) => e.get_class(), + ReadlineError::Eof => GENERIC_ERROR.into(), + ReadlineError::Interrupted => GENERIC_ERROR.into(), + #[cfg(unix)] + ReadlineError::Errno(e) => JsNixError(*e).get_class(), + ReadlineError::WindowResized => GENERIC_ERROR.into(), + #[cfg(windows)] + ReadlineError::Decode(_) => GENERIC_ERROR.into(), + #[cfg(windows)] + ReadlineError::SystemError(_) => GENERIC_ERROR.into(), + _ => GENERIC_ERROR.into(), + } +}); + #[op2] #[string] pub fn op_read_line_prompt( #[string] prompt_text: &str, #[string] default_value: &str, -) -> Result, ReadlineError> { +) -> Result, JsReadlineError> { let mut editor = Editor::<(), rustyline::history::DefaultHistory>::new() .expect("Failed to create editor."); @@ -460,6 +485,6 @@ pub fn op_read_line_prompt( Ok(None) } Err(ReadlineError::Eof) => Ok(None), - Err(err) => Err(err), + Err(err) => Err(JsReadlineError(err)), } } diff --git a/runtime/ops/web_worker.rs b/runtime/ops/web_worker.rs index d0c3eea668..5cde7d5373 100644 --- a/runtime/ops/web_worker.rs +++ b/runtime/ops/web_worker.rs @@ -1,19 +1,20 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. mod sync_fetch; -use crate::web_worker::WebWorkerInternalHandle; -use crate::web_worker::WebWorkerType; +use std::cell::RefCell; +use std::rc::Rc; + use deno_core::op2; use deno_core::CancelFuture; use deno_core::OpState; use deno_web::JsMessageData; use deno_web::MessagePortError; -use std::cell::RefCell; -use std::rc::Rc; +pub use sync_fetch::SyncFetchError; use self::sync_fetch::op_worker_sync_fetch; -pub use sync_fetch::SyncFetchError; +use crate::web_worker::WebWorkerInternalHandle; +use crate::web_worker::WebWorkerType; deno_core::extension!( deno_web_worker, diff --git a/runtime/ops/web_worker/sync_fetch.rs b/runtime/ops/web_worker/sync_fetch.rs index 508bcb7bb0..4c5da428b2 100644 --- a/runtime/ops/web_worker/sync_fetch.rs +++ b/runtime/ops/web_worker/sync_fetch.rs @@ -1,9 +1,7 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::sync::Arc; -use crate::web_worker::WebWorkerInternalHandle; -use crate::web_worker::WebWorkerType; use deno_core::futures::StreamExt; use deno_core::op2; use deno_core::url::Url; @@ -16,6 +14,9 @@ use hyper::body::Bytes; use serde::Deserialize; use serde::Serialize; +use crate::web_worker::WebWorkerInternalHandle; +use crate::web_worker::WebWorkerType; + // TODO(andreubotella) Properly parse the MIME type fn mime_type_essence(mime_type: &str) -> String { let essence = match mime_type.split_once(';') { @@ -25,30 +26,53 @@ fn mime_type_essence(mime_type: &str) -> String { essence.trim().to_ascii_lowercase() } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum SyncFetchError { + #[class(type)] #[error("Blob URLs are not supported in this context.")] BlobUrlsNotSupportedInContext, + #[class(inherit)] #[error("{0}")] - Io(#[from] std::io::Error), + Io( + #[from] + #[inherit] + std::io::Error, + ), + #[class(type)] #[error("Invalid script URL")] InvalidScriptUrl, + #[class(type)] #[error("http status error: {0}")] InvalidStatusCode(http::StatusCode), + #[class(type)] #[error("Classic scripts with scheme {0}: are not supported in workers")] ClassicScriptSchemeUnsupportedInWorkers(String), + #[class(generic)] #[error("{0}")] InvalidUri(#[from] http::uri::InvalidUri), + #[class("DOMExceptionNetworkError")] #[error("Invalid MIME type {0:?}.")] InvalidMimeType(String), + #[class("DOMExceptionNetworkError")] #[error("Missing MIME type.")] MissingMimeType, + #[class(inherit)] #[error(transparent)] - Fetch(#[from] FetchError), + Fetch( + #[from] + #[inherit] + FetchError, + ), + #[class(inherit)] #[error(transparent)] - Join(#[from] tokio::task::JoinError), + Join( + #[from] + #[inherit] + tokio::task::JoinError, + ), + #[class(inherit)] #[error(transparent)] - Other(deno_core::error::AnyError), + Other(#[inherit] deno_error::JsErrorBox), } #[derive(Serialize, Deserialize)] diff --git a/runtime/ops/worker_host.rs b/runtime/ops/worker_host.rs index 131bad1962..c77b3af694 100644 --- a/runtime/ops/worker_host.rs +++ b/runtime/ops/worker_host.rs @@ -1,15 +1,10 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::cell::RefCell; +use std::collections::HashMap; +use std::rc::Rc; +use std::sync::Arc; -use crate::ops::TestingFeaturesEnabled; -use crate::web_worker::run_web_worker; -use crate::web_worker::SendableWebWorkerHandle; -use crate::web_worker::WebWorker; -use crate::web_worker::WebWorkerHandle; -use crate::web_worker::WebWorkerType; -use crate::web_worker::WorkerControlEvent; -use crate::web_worker::WorkerId; -use crate::web_worker::WorkerMetadata; -use crate::worker::FormatJsErrorFn; use deno_core::op2; use deno_core::serde::Deserialize; use deno_core::CancelFuture; @@ -22,10 +17,17 @@ use deno_web::deserialize_js_transferables; use deno_web::JsMessageData; use deno_web::MessagePortError; use log::debug; -use std::cell::RefCell; -use std::collections::HashMap; -use std::rc::Rc; -use std::sync::Arc; + +use crate::ops::TestingFeaturesEnabled; +use crate::web_worker::run_web_worker; +use crate::web_worker::SendableWebWorkerHandle; +use crate::web_worker::WebWorker; +use crate::web_worker::WebWorkerHandle; +use crate::web_worker::WebWorkerType; +use crate::web_worker::WorkerControlEvent; +use crate::web_worker::WorkerId; +use crate::web_worker::WorkerMetadata; +use crate::worker::FormatJsErrorFn; pub const UNSTABLE_FEATURE_NAME: &str = "worker-options"; @@ -118,16 +120,21 @@ pub struct CreateWorkerArgs { close_on_idle: bool, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum CreateWorkerError { + #[class("DOMExceptionNotSupportedError")] #[error("Classic workers are not supported.")] ClassicWorkers, + #[class(inherit)] #[error(transparent)] Permission(deno_permissions::ChildPermissionError), + #[class(inherit)] #[error(transparent)] ModuleResolution(#[from] deno_core::ModuleResolutionError), + #[class(inherit)] #[error(transparent)] MessagePort(#[from] MessagePortError), + #[class(inherit)] #[error("{0}")] Io(#[from] std::io::Error), } diff --git a/runtime/permissions.rs b/runtime/permissions.rs index 968c41560c..8b65c6b1b0 100644 --- a/runtime/permissions.rs +++ b/runtime/permissions.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::path::Path; use std::path::PathBuf; diff --git a/runtime/permissions/Cargo.toml b/runtime/permissions/Cargo.toml index a7bd342a9c..bdca6b379c 100644 --- a/runtime/permissions/Cargo.toml +++ b/runtime/permissions/Cargo.toml @@ -1,8 +1,8 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "deno_permissions" -version = "0.43.0" +version = "0.45.0" authors.workspace = true edition.workspace = true license.workspace = true @@ -16,6 +16,7 @@ path = "lib.rs" [dependencies] capacity_builder.workspace = true deno_core.workspace = true +deno_error.workspace = true deno_path_util.workspace = true deno_terminal.workspace = true fqdn = "0.3.4" diff --git a/runtime/permissions/lib.rs b/runtime/permissions/lib.rs index 1c5fb36f93..3a357d2d44 100644 --- a/runtime/permissions/lib.rs +++ b/runtime/permissions/lib.rs @@ -1,4 +1,17 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::borrow::Cow; +use std::collections::HashSet; +use std::ffi::OsStr; +use std::fmt; +use std::fmt::Debug; +use std::hash::Hash; +use std::net::IpAddr; +use std::net::Ipv6Addr; +use std::path::Path; +use std::path::PathBuf; +use std::string::ToString; +use std::sync::Arc; use capacity_builder::StringBuilder; use deno_core::parking_lot::Mutex; @@ -15,28 +28,15 @@ use deno_path_util::url_to_file_path; use deno_terminal::colors; use fqdn::FQDN; use once_cell::sync::Lazy; -use std::borrow::Cow; -use std::collections::HashSet; -use std::ffi::OsStr; -use std::fmt; -use std::fmt::Debug; -use std::hash::Hash; -use std::net::IpAddr; -use std::net::Ipv6Addr; -use std::path::Path; -use std::path::PathBuf; -use std::string::ToString; -use std::sync::Arc; pub mod prompter; use prompter::permission_prompt; -use prompter::PERMISSION_EMOJI; - pub use prompter::set_prompt_callbacks; pub use prompter::set_prompter; pub use prompter::PermissionPrompter; pub use prompter::PromptCallback; pub use prompter::PromptResponse; +use prompter::PERMISSION_EMOJI; #[derive(Debug, thiserror::Error)] pub enum PermissionDeniedError { @@ -819,7 +819,8 @@ pub enum Host { Ip(IpAddr), } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] +#[class(uri)] pub enum HostParseError { #[error("invalid IPv6 address: '{0}'")] InvalidIpv6(String), @@ -954,10 +955,12 @@ pub enum NetDescriptorParseError { Host(#[from] HostParseError), } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum NetDescriptorFromUrlParseError { + #[class(type)] #[error("Missing host in url: '{0}'")] MissingHost(Url), + #[class(inherit)] #[error("{0}")] Host(#[from] HostParseError), } @@ -1324,10 +1327,12 @@ pub enum RunQueryDescriptor { Name(String), } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum PathResolveError { + #[class(inherit)] #[error("failed resolving cwd: {0}")] CwdResolve(#[source] std::io::Error), + #[class(generic)] #[error("Empty path is not allowed")] EmptyPath, } @@ -1484,12 +1489,15 @@ pub enum AllowRunDescriptorParseResult { Descriptor(AllowRunDescriptor), } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum RunDescriptorParseError { + #[class(generic)] #[error("{0}")] Which(#[from] which::Error), + #[class(inherit)] #[error("{0}")] PathResolve(#[from] PathResolveError), + #[class(generic)] #[error("Empty run query is not allowed")] EmptyRunQuery, } @@ -1510,11 +1518,10 @@ impl AllowRunDescriptor { match which::which_in(text, std::env::var_os("PATH"), cwd) { Ok(path) => path, Err(err) => match err { - which::Error::BadAbsolutePath | which::Error::BadRelativePath => { + which::Error::CannotGetCurrentDirAndPathListEmpty => { return Err(err); } which::Error::CannotFindBinaryPath - | which::Error::CannotGetCurrentDir | which::Error::CannotCanonicalize => { return Ok(AllowRunDescriptorParseResult::Unresolved(Box::new(err))) } @@ -1574,10 +1581,12 @@ fn denies_run_name(name: &str, cmd_path: &Path) -> bool { suffix.is_empty() || suffix.starts_with('.') } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum SysDescriptorParseError { + #[class(type)] #[error("unknown system info kind \"{0}\"")] - InvalidKind(String), // TypeError + InvalidKind(String), + #[class(generic)] #[error("Empty sys not allowed")] Empty, // Error } @@ -2302,34 +2311,46 @@ pub enum CheckSpecifierKind { Dynamic, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum ChildPermissionError { + #[class("NotCapable")] #[error("Can't escalate parent thread permissions")] Escalation, + #[class(inherit)] #[error("{0}")] PathResolve(#[from] PathResolveError), + #[class(uri)] #[error("{0}")] NetDescriptorParse(#[from] NetDescriptorParseError), + #[class(generic)] #[error("{0}")] EnvDescriptorParse(#[from] EnvDescriptorParseError), + #[class(inherit)] #[error("{0}")] SysDescriptorParse(#[from] SysDescriptorParseError), + #[class(inherit)] #[error("{0}")] RunDescriptorParse(#[from] RunDescriptorParseError), } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum PermissionCheckError { + #[class("NotCapable")] #[error(transparent)] PermissionDenied(#[from] PermissionDeniedError), + #[class(uri)] #[error("Invalid file path.\n Specifier: {0}")] InvalidFilePath(Url), + #[class(inherit)] #[error(transparent)] NetDescriptorForUrlParse(#[from] NetDescriptorFromUrlParseError), + #[class(inherit)] #[error(transparent)] SysDescriptorParse(#[from] SysDescriptorParseError), + #[class(inherit)] #[error(transparent)] PathResolve(#[from] PathResolveError), + #[class(uri)] #[error(transparent)] HostParse(#[from] HostParseError), } @@ -3691,11 +3712,13 @@ pub fn is_standalone() -> bool { #[cfg(test)] mod tests { - use super::*; + use std::net::Ipv4Addr; + use deno_core::serde_json::json; use fqdn::fqdn; use prompter::tests::*; - use std::net::Ipv4Addr; + + use super::*; // Creates vector of strings, Vec macro_rules! svec { diff --git a/runtime/permissions/prompter.rs b/runtime/permissions/prompter.rs index 0272744cc2..94384427d1 100644 --- a/runtime/permissions/prompter.rs +++ b/runtime/permissions/prompter.rs @@ -1,10 +1,5 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::is_standalone; -use deno_core::error::JsStackFrame; -use deno_core::parking_lot::Mutex; -use deno_terminal::colors; -use once_cell::sync::Lazy; use std::fmt::Write; use std::io::BufRead; use std::io::IsTerminal; @@ -12,6 +7,13 @@ use std::io::StderrLock; use std::io::StdinLock; use std::io::Write as IoWrite; +use deno_core::error::JsStackFrame; +use deno_core::parking_lot::Mutex; +use deno_terminal::colors; +use once_cell::sync::Lazy; + +use crate::is_standalone; + /// Helper function to make control characters visible so users can see the underlying filename. fn escape_control_characters(s: &str) -> std::borrow::Cow { if !s.contains(|c: char| c.is_ascii_control() || c.is_control()) { @@ -489,10 +491,11 @@ impl PermissionPrompter for TtyPrompter { #[cfg(test)] pub mod tests { - use super::*; use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering; + use super::*; + pub struct TestPrompter; impl PermissionPrompter for TestPrompter { diff --git a/runtime/shared.rs b/runtime/shared.rs index f7d76f67a7..ecf2088fe1 100644 --- a/runtime/shared.rs +++ b/runtime/shared.rs @@ -1,16 +1,17 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Utilities shared between `build.rs` and the rest of the crate. +use std::path::Path; + use deno_ast::MediaType; use deno_ast::ParseParams; use deno_ast::SourceMapOption; -use deno_core::error::AnyError; use deno_core::extension; use deno_core::Extension; use deno_core::ModuleCodeString; use deno_core::ModuleName; use deno_core::SourceMapData; -use std::path::Path; +use deno_error::JsErrorBox; extension!(runtime, deps = [ @@ -41,10 +42,7 @@ extension!(runtime, "06_util.js", "10_permissions.js", "11_workers.js", - "30_os.js", "40_fs_events.js", - "40_process.js", - "40_signals.js", "40_tty.js", "41_prompt.js", "90_deno_ns.js", @@ -63,10 +61,21 @@ extension!(runtime, } ); +deno_error::js_error_wrapper!( + deno_ast::ParseDiagnostic, + JsParseDiagnostic, + "Error" +); +deno_error::js_error_wrapper!( + deno_ast::TranspileError, + JsTranspileError, + "Error" +); + pub fn maybe_transpile_source( name: ModuleName, source: ModuleCodeString, -) -> Result<(ModuleCodeString, Option), AnyError> { +) -> Result<(ModuleCodeString, Option), JsErrorBox> { // Always transpile `node:` built-in modules, since they might be TypeScript. let media_type = if name.starts_with("node:") { MediaType::TypeScript @@ -91,7 +100,8 @@ pub fn maybe_transpile_source( capture_tokens: false, scope_analysis: false, maybe_syntax: None, - })?; + }) + .map_err(|e| JsErrorBox::from_err(JsParseDiagnostic(e)))?; let transpiled_source = parsed .transpile( &deno_ast::TranspileOptions { @@ -107,7 +117,8 @@ pub fn maybe_transpile_source( }, ..Default::default() }, - )? + ) + .map_err(|e| JsErrorBox::from_err(JsTranspileError(e)))? .into_source(); let maybe_source_map: Option = transpiled_source diff --git a/runtime/snapshot.rs b/runtime/snapshot.rs index ad73f485ad..eec8579e59 100644 --- a/runtime/snapshot.rs +++ b/runtime/snapshot.rs @@ -1,9 +1,12 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::borrow::Cow; +use std::io::Write; +use std::path::Path; +use std::path::PathBuf; +use std::rc::Rc; +use std::sync::Arc; -use crate::ops; -use crate::ops::bootstrap::SnapshotOptions; -use crate::shared::maybe_transpile_source; -use crate::shared::runtime; use deno_cache::SqliteBackedCache; use deno_core::snapshot::*; use deno_core::v8; @@ -11,12 +14,13 @@ use deno_core::Extension; use deno_http::DefaultHttpPropertyExtractor; use deno_io::fs::FsError; use deno_permissions::PermissionCheckError; -use std::borrow::Cow; -use std::io::Write; -use std::path::Path; -use std::path::PathBuf; -use std::rc::Rc; -use std::sync::Arc; +use deno_resolver::npm::DenoInNpmPackageChecker; +use deno_resolver::npm::NpmResolver; + +use crate::ops; +use crate::ops::bootstrap::SnapshotOptions; +use crate::shared::maybe_transpile_source; +use crate::shared::runtime; #[derive(Clone)] struct Permissions; @@ -306,8 +310,12 @@ pub fn create_runtime_snapshot( ), deno_io::deno_io::init_ops_and_esm(Default::default()), deno_fs::deno_fs::init_ops_and_esm::(fs.clone()), + deno_os::deno_os::init_ops_and_esm(Default::default()), + deno_process::deno_process::init_ops_and_esm(Default::default()), deno_node::deno_node::init_ops_and_esm::< Permissions, + DenoInNpmPackageChecker, + NpmResolver, sys_traits::impls::RealSys, >(None, fs.clone()), runtime::init_ops_and_esm(), @@ -317,10 +325,7 @@ pub fn create_runtime_snapshot( None, ), ops::fs_events::deno_fs_events::init_ops(), - ops::os::deno_os::init_ops(Default::default()), ops::permissions::deno_permissions::init_ops(), - ops::process::deno_process::init_ops(None), - ops::signal::deno_signal::init_ops(), ops::tty::deno_tty::init_ops(), ops::http::deno_http_runtime::init_ops(), ops::bootstrap::deno_bootstrap::init_ops(Some(snapshot_options)), diff --git a/runtime/tokio_util.rs b/runtime/tokio_util.rs index aa0282ece8..370b8a6d92 100644 --- a/runtime/tokio_util.rs +++ b/runtime/tokio_util.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::fmt::Debug; use std::str::FromStr; diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs index 2b46d9a2ff..bb769c46a9 100644 --- a/runtime/web_worker.rs +++ b/runtime/web_worker.rs @@ -1,10 +1,19 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::cell::RefCell; +use std::fmt; +use std::rc::Rc; +use std::sync::atomic::AtomicBool; +use std::sync::atomic::AtomicU32; +use std::sync::atomic::Ordering; +use std::sync::Arc; +use std::task::Context; +use std::task::Poll; use deno_broadcast_channel::InMemoryBroadcastChannel; use deno_cache::CreateCache; use deno_cache::SqliteBackedCache; -use deno_core::error::AnyError; -use deno_core::error::JsError; +use deno_core::error::CoreError; use deno_core::futures::channel::mpsc; use deno_core::futures::future::poll_fn; use deno_core::futures::stream::StreamExt; @@ -19,7 +28,6 @@ use deno_core::CompiledWasmModuleStore; use deno_core::DetachedBuffer; use deno_core::Extension; use deno_core::FeatureChecker; -use deno_core::GetErrorClassFn; use deno_core::JsRuntime; use deno_core::ModuleCodeString; use deno_core::ModuleId; @@ -36,6 +44,7 @@ use deno_kv::dynamic::MultiBackendDbHandler; use deno_node::ExtNodeSys; use deno_node::NodeExtInitServices; use deno_permissions::PermissionsContainer; +use deno_process::NpmProcessStateProviderRc; use deno_terminal::colors; use deno_tls::RootCertStoreProvider; use deno_tls::TlsKeys; @@ -46,19 +55,11 @@ use deno_web::JsMessageData; use deno_web::MessagePort; use deno_web::Transferable; use log::debug; -use std::cell::RefCell; -use std::fmt; -use std::rc::Rc; -use std::sync::atomic::AtomicBool; -use std::sync::atomic::AtomicU32; -use std::sync::atomic::Ordering; -use std::sync::Arc; -use std::task::Context; -use std::task::Poll; +use node_resolver::InNpmPackageChecker; +use node_resolver::NpmPackageFolderResolver; use crate::inspector_server::InspectorServer; use crate::ops; -use crate::ops::process::NpmProcessStateProviderRc; use crate::shared::maybe_transpile_source; use crate::shared::runtime; use crate::tokio_util::create_and_run_current_thread; @@ -104,8 +105,7 @@ pub enum WebWorkerType { /// Events that are sent to host from child /// worker. pub enum WorkerControlEvent { - Error(AnyError), - TerminalError(AnyError), + TerminalError(CoreError), Close, } @@ -118,15 +118,13 @@ impl Serialize for WorkerControlEvent { { let type_id = match &self { WorkerControlEvent::TerminalError(_) => 1_i32, - WorkerControlEvent::Error(_) => 2_i32, WorkerControlEvent::Close => 3_i32, }; match self { - WorkerControlEvent::TerminalError(error) - | WorkerControlEvent::Error(error) => { - let value = match error.downcast_ref::() { - Some(js_error) => { + WorkerControlEvent::TerminalError(error) => { + let value = match error { + CoreError::Js(js_error) => { let frame = js_error.frames.iter().find(|f| match &f.file_name { Some(s) => !s.trim_start_matches('[').starts_with("ext:"), None => false, @@ -138,7 +136,7 @@ impl Serialize for WorkerControlEvent { "columnNumber": frame.map(|f| f.column_number.as_ref()), }) } - None => json!({ + _ => json!({ "message": error.to_string(), }), }; @@ -338,7 +336,11 @@ fn create_handles( (internal_handle, external_handle) } -pub struct WebWorkerServiceOptions { +pub struct WebWorkerServiceOptions< + TInNpmPackageChecker: InNpmPackageChecker + 'static, + TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static, + TExtNodeSys: ExtNodeSys + 'static, +> { pub blob_store: Arc, pub broadcast_channel: InMemoryBroadcastChannel, pub compiled_wasm_module_store: Option, @@ -346,7 +348,13 @@ pub struct WebWorkerServiceOptions { pub fs: Arc, pub maybe_inspector_server: Option>, pub module_loader: Rc, - pub node_services: Option>, + pub node_services: Option< + NodeExtInitServices< + TInNpmPackageChecker, + TNpmPackageFolderResolver, + TExtNodeSys, + >, + >, pub npm_process_state_provider: Option, pub permissions: PermissionsContainer, pub root_cert_store_provider: Option>, @@ -367,7 +375,6 @@ pub struct WebWorkerOptions { pub create_web_worker_cb: Arc, pub format_js_error_fn: Option>, pub worker_type: WebWorkerType, - pub get_error_class_fn: Option, pub cache_storage_dir: Option, pub stdio: Stdio, pub strace_ops: Option>, @@ -403,8 +410,16 @@ impl Drop for WebWorker { } impl WebWorker { - pub fn bootstrap_from_options( - services: WebWorkerServiceOptions, + pub fn bootstrap_from_options< + TInNpmPackageChecker: InNpmPackageChecker + 'static, + TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static, + TExtNodeSys: ExtNodeSys + 'static, + >( + services: WebWorkerServiceOptions< + TInNpmPackageChecker, + TNpmPackageFolderResolver, + TExtNodeSys, + >, options: WebWorkerOptions, ) -> (Self, SendableWebWorkerHandle) { let (mut worker, handle, bootstrap_options) = @@ -413,8 +428,16 @@ impl WebWorker { (worker, handle) } - fn from_options( - services: WebWorkerServiceOptions, + fn from_options< + TInNpmPackageChecker: InNpmPackageChecker + 'static, + TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static, + TExtNodeSys: ExtNodeSys + 'static, + >( + services: WebWorkerServiceOptions< + TInNpmPackageChecker, + TNpmPackageFolderResolver, + TExtNodeSys, + >, mut options: WebWorkerOptions, ) -> (Self, SendableWebWorkerHandle, BootstrapOptions) { deno_core::extension!(deno_permissions_web_worker, @@ -505,10 +528,16 @@ impl WebWorker { deno_fs::deno_fs::init_ops_and_esm::( services.fs.clone(), ), - deno_node::deno_node::init_ops_and_esm::( - services.node_services, - services.fs, + deno_os::deno_os_worker::init_ops_and_esm(), + deno_process::deno_process::init_ops_and_esm( + services.npm_process_state_provider, ), + deno_node::deno_node::init_ops_and_esm::< + PermissionsContainer, + TInNpmPackageChecker, + TNpmPackageFolderResolver, + TExtNodeSys, + >(services.node_services, services.fs), // Runtime ops that are always initialized for WebWorkers ops::runtime::deno_runtime::init_ops_and_esm(options.main_module.clone()), ops::worker_host::deno_worker_host::init_ops_and_esm( @@ -516,12 +545,7 @@ impl WebWorker { options.format_js_error_fn, ), ops::fs_events::deno_fs_events::init_ops_and_esm(), - ops::os::deno_os_worker::init_ops_and_esm(), ops::permissions::deno_permissions::init_ops_and_esm(), - ops::process::deno_process::init_ops_and_esm( - services.npm_process_state_provider, - ), - ops::signal::deno_signal::init_ops_and_esm(), ops::tty::deno_tty::init_ops_and_esm(), ops::http::deno_http_runtime::init_ops_and_esm(), ops::bootstrap::deno_bootstrap::init_ops_and_esm( @@ -568,7 +592,6 @@ impl WebWorker { module_loader: Some(services.module_loader), startup_snapshot: options.startup_snapshot, create_params: options.create_params, - get_error_class_fn: options.get_error_class_fn, shared_array_buffer_store: services.shared_array_buffer_store, compiled_wasm_module_store: services.compiled_wasm_module_store, extensions, @@ -736,7 +759,7 @@ impl WebWorker { &mut self, name: &'static str, source_code: ModuleCodeString, - ) -> Result<(), AnyError> { + ) -> Result<(), CoreError> { self.js_runtime.execute_script(name, source_code)?; Ok(()) } @@ -745,7 +768,7 @@ impl WebWorker { pub async fn preload_main_module( &mut self, module_specifier: &ModuleSpecifier, - ) -> Result { + ) -> Result { self.js_runtime.load_main_es_module(module_specifier).await } @@ -753,7 +776,7 @@ impl WebWorker { pub async fn preload_side_module( &mut self, module_specifier: &ModuleSpecifier, - ) -> Result { + ) -> Result { self.js_runtime.load_side_es_module(module_specifier).await } @@ -764,7 +787,7 @@ impl WebWorker { pub async fn execute_side_module( &mut self, module_specifier: &ModuleSpecifier, - ) -> Result<(), AnyError> { + ) -> Result<(), CoreError> { let id = self.preload_side_module(module_specifier).await?; let mut receiver = self.js_runtime.mod_evaluate(id); tokio::select! { @@ -788,7 +811,7 @@ impl WebWorker { pub async fn execute_main_module( &mut self, id: ModuleId, - ) -> Result<(), AnyError> { + ) -> Result<(), CoreError> { let mut receiver = self.js_runtime.mod_evaluate(id); let poll_options = PollEventLoopOptions::default(); @@ -814,7 +837,7 @@ impl WebWorker { &mut self, cx: &mut Context, poll_options: PollEventLoopOptions, - ) -> Poll> { + ) -> Poll> { // If awakened because we are terminating, just return Ok if self.internal_handle.terminate_if_needed() { return Poll::Ready(Ok(())); @@ -858,7 +881,7 @@ impl WebWorker { pub async fn run_event_loop( &mut self, poll_options: PollEventLoopOptions, - ) -> Result<(), AnyError> { + ) -> Result<(), CoreError> { poll_fn(|cx| self.poll_event_loop(cx, poll_options)).await } @@ -892,14 +915,14 @@ impl WebWorker { } fn print_worker_error( - error: &AnyError, + error: &CoreError, name: &str, format_js_error_fn: Option<&FormatJsErrorFn>, ) { let error_str = match format_js_error_fn { - Some(format_js_error_fn) => match error.downcast_ref::() { - Some(js_error) => format_js_error_fn(js_error), - None => error.to_string(), + Some(format_js_error_fn) => match error { + CoreError::Js(js_error) => format_js_error_fn(js_error), + _ => error.to_string(), }, None => error.to_string(), }; @@ -918,7 +941,7 @@ pub fn run_web_worker( specifier: ModuleSpecifier, mut maybe_source_code: Option, format_js_error_fn: Option>, -) -> Result<(), AnyError> { +) -> Result<(), CoreError> { let name = worker.name.to_string(); // TODO(bartlomieju): run following block using "select!" diff --git a/runtime/worker.rs b/runtime/worker.rs index a9a4440410..72eb54ec47 100644 --- a/runtime/worker.rs +++ b/runtime/worker.rs @@ -1,10 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::collections::HashMap; use std::rc::Rc; use std::sync::atomic::AtomicBool; -use std::sync::atomic::AtomicI32; -use std::sync::atomic::Ordering::Relaxed; use std::sync::Arc; use std::time::Duration; use std::time::Instant; @@ -12,14 +10,13 @@ use std::time::Instant; use deno_broadcast_channel::InMemoryBroadcastChannel; use deno_cache::CreateCache; use deno_cache::SqliteBackedCache; -use deno_core::error::AnyError; +use deno_core::error::CoreError; use deno_core::error::JsError; use deno_core::merge_op_metrics; use deno_core::v8; use deno_core::CompiledWasmModuleStore; use deno_core::Extension; use deno_core::FeatureChecker; -use deno_core::GetErrorClassFn; use deno_core::InspectorSessionKind; use deno_core::InspectorSessionOptions; use deno_core::JsRuntime; @@ -41,17 +38,20 @@ use deno_io::Stdio; use deno_kv::dynamic::MultiBackendDbHandler; use deno_node::ExtNodeSys; use deno_node::NodeExtInitServices; +use deno_os::ExitCode; use deno_permissions::PermissionsContainer; +use deno_process::NpmProcessStateProviderRc; use deno_tls::RootCertStoreProvider; use deno_tls::TlsKeys; use deno_web::BlobStore; use log::debug; +use node_resolver::InNpmPackageChecker; +use node_resolver::NpmPackageFolderResolver; use crate::code_cache::CodeCache; use crate::code_cache::CodeCacheType; use crate::inspector_server::InspectorServer; use crate::ops; -use crate::ops::process::NpmProcessStateProviderRc; use crate::shared::maybe_transpile_source; use crate::shared::runtime; use crate::BootstrapOptions; @@ -59,10 +59,10 @@ use crate::BootstrapOptions; pub type FormatJsErrorFn = dyn Fn(&JsError) -> String + Sync + Send; pub fn import_meta_resolve_callback( - loader: &dyn deno_core::ModuleLoader, + loader: &dyn ModuleLoader, specifier: String, referrer: String, -) -> Result { +) -> Result { loader.resolve( &specifier, &referrer, @@ -96,19 +96,6 @@ pub fn validate_import_attributes_callback( } } -#[derive(Clone, Default)] -pub struct ExitCode(Arc); - -impl ExitCode { - pub fn get(&self) -> i32 { - self.0.load(Relaxed) - } - - pub fn set(&mut self, code: i32) { - self.0.store(code, Relaxed); - } -} - /// This worker is created and used by almost all /// subcommands in Deno executable. /// @@ -129,7 +116,11 @@ pub struct MainWorker { dispatch_process_exit_event_fn_global: v8::Global, } -pub struct WorkerServiceOptions { +pub struct WorkerServiceOptions< + TInNpmPackageChecker: InNpmPackageChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, + TExtNodeSys: ExtNodeSys, +> { pub blob_store: Arc, pub broadcast_channel: InMemoryBroadcastChannel, pub feature_checker: Arc, @@ -140,7 +131,13 @@ pub struct WorkerServiceOptions { /// If not provided runtime will error if code being /// executed tries to load modules. pub module_loader: Rc, - pub node_services: Option>, + pub node_services: Option< + NodeExtInitServices< + TInNpmPackageChecker, + TNpmPackageFolderResolver, + TExtNodeSys, + >, + >, pub npm_process_state_provider: Option, pub permissions: PermissionsContainer, pub root_cert_store_provider: Option>, @@ -202,9 +199,6 @@ pub struct WorkerOptions { /// If Some, print a low-level trace output for ops matching the given patterns. pub strace_ops: Option>, - /// Allows to map error type to a string "class" used to represent - /// error in JavaScript. - pub get_error_class_fn: Option, pub cache_storage_dir: Option, pub origin_storage_dir: Option, pub stdio: Stdio, @@ -225,7 +219,6 @@ impl Default for WorkerOptions { strace_ops: Default::default(), maybe_inspector_server: Default::default(), format_js_error_fn: Default::default(), - get_error_class_fn: Default::default(), origin_storage_dir: Default::default(), cache_storage_dir: Default::default(), extensions: Default::default(), @@ -305,9 +298,17 @@ pub fn create_op_metrics( } impl MainWorker { - pub fn bootstrap_from_options( - main_module: ModuleSpecifier, - services: WorkerServiceOptions, + pub fn bootstrap_from_options< + TInNpmPackageChecker: InNpmPackageChecker + 'static, + TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static, + TExtNodeSys: ExtNodeSys + 'static, + >( + main_module: &ModuleSpecifier, + services: WorkerServiceOptions< + TInNpmPackageChecker, + TNpmPackageFolderResolver, + TExtNodeSys, + >, options: WorkerOptions, ) -> Self { let (mut worker, bootstrap_options) = @@ -316,9 +317,17 @@ impl MainWorker { worker } - fn from_options( - main_module: ModuleSpecifier, - services: WorkerServiceOptions, + fn from_options< + TInNpmPackageChecker: InNpmPackageChecker + 'static, + TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static, + TExtNodeSys: ExtNodeSys + 'static, + >( + main_module: &ModuleSpecifier, + services: WorkerServiceOptions< + TInNpmPackageChecker, + TNpmPackageFolderResolver, + TExtNodeSys, + >, mut options: WorkerOptions, ) -> (Self, BootstrapOptions) { deno_core::extension!(deno_permissions_worker, @@ -340,7 +349,7 @@ impl MainWorker { // Permissions: many ops depend on this let enable_testing_features = options.bootstrap.enable_testing_features; - let exit_code = ExitCode(Arc::new(AtomicI32::new(0))); + let exit_code = ExitCode::default(); let create_cache = options.cache_storage_dir.map(|storage_dir| { let create_cache_fn = move || SqliteBackedCache::new(storage_dir.clone()); CreateCache(Arc::new(create_cache_fn)) @@ -418,10 +427,16 @@ impl MainWorker { deno_fs::deno_fs::init_ops_and_esm::( services.fs.clone(), ), - deno_node::deno_node::init_ops_and_esm::( - services.node_services, - services.fs, + deno_os::deno_os::init_ops_and_esm(exit_code.clone()), + deno_process::deno_process::init_ops_and_esm( + services.npm_process_state_provider, ), + deno_node::deno_node::init_ops_and_esm::< + PermissionsContainer, + TInNpmPackageChecker, + TNpmPackageFolderResolver, + TExtNodeSys, + >(services.node_services, services.fs), // Ops from this crate ops::runtime::deno_runtime::init_ops_and_esm(main_module.clone()), ops::worker_host::deno_worker_host::init_ops_and_esm( @@ -429,12 +444,7 @@ impl MainWorker { options.format_js_error_fn.clone(), ), ops::fs_events::deno_fs_events::init_ops_and_esm(), - ops::os::deno_os::init_ops_and_esm(exit_code.clone()), ops::permissions::deno_permissions::init_ops_and_esm(), - ops::process::deno_process::init_ops_and_esm( - services.npm_process_state_provider, - ), - ops::signal::deno_signal::init_ops_and_esm(), ops::tty::deno_tty::init_ops_and_esm(), ops::http::deno_http_runtime::init_ops_and_esm(), ops::bootstrap::deno_bootstrap::init_ops_and_esm( @@ -489,7 +499,6 @@ impl MainWorker { startup_snapshot: options.startup_snapshot, create_params: options.create_params, skip_op_registration: options.skip_op_registration, - get_error_class_fn: options.get_error_class_fn, shared_array_buffer_store: services.shared_array_buffer_store.clone(), compiled_wasm_module_store: services.compiled_wasm_module_store.clone(), extensions, @@ -708,7 +717,7 @@ impl MainWorker { &mut self, script_name: &'static str, source_code: ModuleCodeString, - ) -> Result, AnyError> { + ) -> Result, CoreError> { self.js_runtime.execute_script(script_name, source_code) } @@ -716,7 +725,7 @@ impl MainWorker { pub async fn preload_main_module( &mut self, module_specifier: &ModuleSpecifier, - ) -> Result { + ) -> Result { self.js_runtime.load_main_es_module(module_specifier).await } @@ -724,7 +733,7 @@ impl MainWorker { pub async fn preload_side_module( &mut self, module_specifier: &ModuleSpecifier, - ) -> Result { + ) -> Result { self.js_runtime.load_side_es_module(module_specifier).await } @@ -732,7 +741,7 @@ impl MainWorker { pub async fn evaluate_module( &mut self, id: ModuleId, - ) -> Result<(), AnyError> { + ) -> Result<(), CoreError> { self.wait_for_inspector_session(); let mut receiver = self.js_runtime.mod_evaluate(id); tokio::select! { @@ -757,7 +766,7 @@ impl MainWorker { pub async fn run_up_to_duration( &mut self, duration: Duration, - ) -> Result<(), AnyError> { + ) -> Result<(), CoreError> { match tokio::time::timeout( duration, self @@ -776,7 +785,7 @@ impl MainWorker { pub async fn execute_side_module( &mut self, module_specifier: &ModuleSpecifier, - ) -> Result<(), AnyError> { + ) -> Result<(), CoreError> { let id = self.preload_side_module(module_specifier).await?; self.evaluate_module(id).await } @@ -787,7 +796,7 @@ impl MainWorker { pub async fn execute_main_module( &mut self, module_specifier: &ModuleSpecifier, - ) -> Result<(), AnyError> { + ) -> Result<(), CoreError> { let id = self.preload_main_module(module_specifier).await?; self.evaluate_module(id).await } @@ -818,10 +827,10 @@ impl MainWorker { pub async fn run_event_loop( &mut self, wait_for_inspector: bool, - ) -> Result<(), AnyError> { + ) -> Result<(), CoreError> { self .js_runtime - .run_event_loop(deno_core::PollEventLoopOptions { + .run_event_loop(PollEventLoopOptions { wait_for_inspector, ..Default::default() }) @@ -837,7 +846,7 @@ impl MainWorker { /// Dispatches "load" event to the JavaScript runtime. /// /// Does not poll event loop, and thus not await any of the "load" event handlers. - pub fn dispatch_load_event(&mut self) -> Result<(), AnyError> { + pub fn dispatch_load_event(&mut self) -> Result<(), JsError> { let scope = &mut self.js_runtime.handle_scope(); let tc_scope = &mut v8::TryCatch::new(scope); let dispatch_load_event_fn = @@ -846,7 +855,7 @@ impl MainWorker { dispatch_load_event_fn.call(tc_scope, undefined.into(), &[]); if let Some(exception) = tc_scope.exception() { let error = JsError::from_v8_exception(tc_scope, exception); - return Err(error.into()); + return Err(error); } Ok(()) } @@ -854,7 +863,7 @@ impl MainWorker { /// Dispatches "unload" event to the JavaScript runtime. /// /// Does not poll event loop, and thus not await any of the "unload" event handlers. - pub fn dispatch_unload_event(&mut self) -> Result<(), AnyError> { + pub fn dispatch_unload_event(&mut self) -> Result<(), JsError> { let scope = &mut self.js_runtime.handle_scope(); let tc_scope = &mut v8::TryCatch::new(scope); let dispatch_unload_event_fn = @@ -863,13 +872,13 @@ impl MainWorker { dispatch_unload_event_fn.call(tc_scope, undefined.into(), &[]); if let Some(exception) = tc_scope.exception() { let error = JsError::from_v8_exception(tc_scope, exception); - return Err(error.into()); + return Err(error); } Ok(()) } /// Dispatches process.emit("exit") event for node compat. - pub fn dispatch_process_exit_event(&mut self) -> Result<(), AnyError> { + pub fn dispatch_process_exit_event(&mut self) -> Result<(), JsError> { let scope = &mut self.js_runtime.handle_scope(); let tc_scope = &mut v8::TryCatch::new(scope); let dispatch_process_exit_event_fn = @@ -878,7 +887,7 @@ impl MainWorker { dispatch_process_exit_event_fn.call(tc_scope, undefined.into(), &[]); if let Some(exception) = tc_scope.exception() { let error = JsError::from_v8_exception(tc_scope, exception); - return Err(error.into()); + return Err(error); } Ok(()) } @@ -886,7 +895,7 @@ impl MainWorker { /// Dispatches "beforeunload" event to the JavaScript runtime. Returns a boolean /// indicating if the event was prevented and thus event loop should continue /// running. - pub fn dispatch_beforeunload_event(&mut self) -> Result { + pub fn dispatch_beforeunload_event(&mut self) -> Result { let scope = &mut self.js_runtime.handle_scope(); let tc_scope = &mut v8::TryCatch::new(scope); let dispatch_beforeunload_event_fn = @@ -896,16 +905,14 @@ impl MainWorker { dispatch_beforeunload_event_fn.call(tc_scope, undefined.into(), &[]); if let Some(exception) = tc_scope.exception() { let error = JsError::from_v8_exception(tc_scope, exception); - return Err(error.into()); + return Err(error); } let ret_val = ret_val.unwrap(); Ok(ret_val.is_false()) } /// Dispatches process.emit("beforeExit") event for node compat. - pub fn dispatch_process_beforeexit_event( - &mut self, - ) -> Result { + pub fn dispatch_process_beforeexit_event(&mut self) -> Result { let scope = &mut self.js_runtime.handle_scope(); let tc_scope = &mut v8::TryCatch::new(scope); let dispatch_process_beforeexit_event_fn = v8::Local::new( @@ -920,7 +927,7 @@ impl MainWorker { ); if let Some(exception) = tc_scope.exception() { let error = JsError::from_v8_exception(tc_scope, exception); - return Err(error.into()); + return Err(error); } let ret_val = ret_val.unwrap(); Ok(ret_val.is_true()) diff --git a/runtime/worker_bootstrap.rs b/runtime/worker_bootstrap.rs index 8364fe0d2b..ff90804f3b 100644 --- a/runtime/worker_bootstrap.rs +++ b/runtime/worker_bootstrap.rs @@ -1,13 +1,13 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::cell::RefCell; +use std::thread; use deno_core::v8; use deno_core::ModuleSpecifier; use deno_telemetry::OtelConfig; -use serde::Serialize; -use std::cell::RefCell; -use std::thread; - use deno_terminal::colors; +use serde::Serialize; /// The execution mode for this worker. Some modes may have implicit behaviour. #[derive(Copy, Clone)] diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 1300066c64..cff778b2de 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -1,4 +1,4 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "cli_tests" diff --git a/tests/ffi/Cargo.toml b/tests/ffi/Cargo.toml index a5d2883ef2..bae9aa6bb5 100644 --- a/tests/ffi/Cargo.toml +++ b/tests/ffi/Cargo.toml @@ -1,4 +1,4 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "test_ffi" diff --git a/tests/ffi/src/lib.rs b/tests/ffi/src/lib.rs index 09c2afb3de..ca416fb980 100644 --- a/tests/ffi/src/lib.rs +++ b/tests/ffi/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. #![allow(clippy::print_stdout)] #![allow(clippy::print_stderr)] diff --git a/tests/ffi/tests/bench.js b/tests/ffi/tests/bench.js index 2b4fbd55ba..c4b935398a 100644 --- a/tests/ffi/tests/bench.js +++ b/tests/ffi/tests/bench.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file const targetDir = Deno.execPath().replace(/[^\/\\]+$/, ""); diff --git a/tests/ffi/tests/event_loop_integration.ts b/tests/ffi/tests/event_loop_integration.ts index e3914d9662..17c2d17f0b 100644 --- a/tests/ffi/tests/event_loop_integration.ts +++ b/tests/ffi/tests/event_loop_integration.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console diff --git a/tests/ffi/tests/ffi_callback_errors.ts b/tests/ffi/tests/ffi_callback_errors.ts index 797ff236c1..3f165158b4 100644 --- a/tests/ffi/tests/ffi_callback_errors.ts +++ b/tests/ffi/tests/ffi_callback_errors.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console diff --git a/tests/ffi/tests/ffi_types.ts b/tests/ffi/tests/ffi_types.ts index a996195c69..0ae51c61fb 100644 --- a/tests/ffi/tests/ffi_types.ts +++ b/tests/ffi/tests/ffi_types.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file // Only for testing types. Invoke with `deno install --entrypoint` diff --git a/tests/ffi/tests/integration_tests.rs b/tests/ffi/tests/integration_tests.rs index dbc0036bc2..7e92641ae5 100644 --- a/tests/ffi/tests/integration_tests.rs +++ b/tests/ffi/tests/integration_tests.rs @@ -1,10 +1,11 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. #![allow(clippy::print_stdout)] #![allow(clippy::print_stderr)] -use pretty_assertions::assert_eq; use std::process::Command; + +use pretty_assertions::assert_eq; use test_util::deno_cmd; use test_util::deno_config_path; use test_util::ffi_tests_path; diff --git a/tests/ffi/tests/test.js b/tests/ffi/tests/test.js index 074db81882..a93b648a2e 100644 --- a/tests/ffi/tests/test.js +++ b/tests/ffi/tests/test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file // Run using cargo test or `--v8-flags=--allow-natives-syntax` diff --git a/tests/ffi/tests/thread_safe_test.js b/tests/ffi/tests/thread_safe_test.js index fffa61a04f..519b0bd4fd 100644 --- a/tests/ffi/tests/thread_safe_test.js +++ b/tests/ffi/tests/thread_safe_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file const targetDir = Deno.execPath().replace(/[^\/\\]+$/, ""); diff --git a/tests/ffi/tests/thread_safe_test_worker.js b/tests/ffi/tests/thread_safe_test_worker.js index fc4854436e..390b4d8a3f 100644 --- a/tests/ffi/tests/thread_safe_test_worker.js +++ b/tests/ffi/tests/thread_safe_test_worker.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file const targetDir = Deno.execPath().replace(/[^\/\\]+$/, ""); diff --git a/tests/integration/bench_tests.rs b/tests/integration/bench_tests.rs index 4ee029d648..b8d38a7f91 100644 --- a/tests/integration/bench_tests.rs +++ b/tests/integration/bench_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::serde_json::json; use deno_core::url::Url; diff --git a/tests/integration/cache_tests.rs b/tests/integration/cache_tests.rs index 4cddae1af1..3fbed3cbd4 100644 --- a/tests/integration/cache_tests.rs +++ b/tests/integration/cache_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use test_util::TestContext; use test_util::TestContextBuilder; diff --git a/tests/integration/check_tests.rs b/tests/integration/check_tests.rs index a1fdf83403..15a2d96d04 100644 --- a/tests/integration/check_tests.rs +++ b/tests/integration/check_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_lockfile::NewLockfileOptions; use deno_semver::jsr::JsrDepPackageReq; diff --git a/tests/integration/compile_tests.rs b/tests/integration/compile_tests.rs index a715233933..e61a1ed9eb 100644 --- a/tests/integration/compile_tests.rs +++ b/tests/integration/compile_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::serde_json; use test_util as util; diff --git a/tests/integration/coverage_tests.rs b/tests/integration/coverage_tests.rs index ab18ef76d3..ab09d54267 100644 --- a/tests/integration/coverage_tests.rs +++ b/tests/integration/coverage_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::serde_json; use test_util as util; diff --git a/tests/integration/eval_tests.rs b/tests/integration/eval_tests.rs index 198be3a4e8..836cab900e 100644 --- a/tests/integration/eval_tests.rs +++ b/tests/integration/eval_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use test_util as util; diff --git a/tests/integration/flags_tests.rs b/tests/integration/flags_tests.rs index e233ca5baf..e819ea6c99 100644 --- a/tests/integration/flags_tests.rs +++ b/tests/integration/flags_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use test_util as util; use util::assert_contains; diff --git a/tests/integration/fmt_tests.rs b/tests/integration/fmt_tests.rs index ccf54a4d0f..468c9cfbc8 100644 --- a/tests/integration/fmt_tests.rs +++ b/tests/integration/fmt_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::serde_json::json; use test_util as util; diff --git a/tests/integration/init_tests.rs b/tests/integration/init_tests.rs index a447e7bcef..5bbec687b0 100644 --- a/tests/integration/init_tests.rs +++ b/tests/integration/init_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use test_util as util; use util::assert_contains; diff --git a/tests/integration/inspector_tests.rs b/tests/integration/inspector_tests.rs index fa1b3a9d83..7c1be193a1 100644 --- a/tests/integration/inspector_tests.rs +++ b/tests/integration/inspector_tests.rs @@ -1,4 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::io::BufRead; +use std::process::ChildStderr; +use std::time::Duration; use bytes::Bytes; use deno_core::anyhow::anyhow; @@ -6,7 +10,6 @@ use deno_core::error::AnyError; use deno_core::serde_json; use deno_core::serde_json::json; use deno_core::url; - use fastwebsockets::FragmentCollector; use fastwebsockets::Frame; use fastwebsockets::WebSocket; @@ -15,9 +18,6 @@ use hyper::upgrade::Upgraded; use hyper::Request; use hyper::Response; use hyper_util::rt::TokioIo; -use std::io::BufRead; -use std::process::ChildStderr; -use std::time::Duration; use test_util as util; use tokio::net::TcpStream; use tokio::time::timeout; diff --git a/tests/integration/install_tests.rs b/tests/integration/install_tests.rs index b0c1e44778..29a65a70b8 100644 --- a/tests/integration/install_tests.rs +++ b/tests/integration/install_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use test_util as util; use test_util::assert_contains; diff --git a/tests/integration/js_unit_tests.rs b/tests/integration/js_unit_tests.rs index afb97a3458..9ecec8b426 100644 --- a/tests/integration/js_unit_tests.rs +++ b/tests/integration/js_unit_tests.rs @@ -1,9 +1,10 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::io::BufRead; use std::io::BufReader; use std::time::Duration; use std::time::Instant; + use test_util as util; util::unit_test_factory!( diff --git a/tests/integration/jsr_tests.rs b/tests/integration/jsr_tests.rs index d3fa5cd98f..0902b7d0a2 100644 --- a/tests/integration/jsr_tests.rs +++ b/tests/integration/jsr_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_cache_dir::HttpCache; use deno_core::serde_json; @@ -66,12 +66,11 @@ fn fast_check_cache() { // ensure cache works let output = check_debug_cmd.run(); assert_contains!(output.combined_output(), "Already type checked."); - let building_fast_check_msg = "Building fast check graph"; - assert_not_contains!(output.combined_output(), building_fast_check_msg); // now validated type_check_cache_path.remove_file(); let output = check_debug_cmd.run(); + let building_fast_check_msg = "Building fast check graph"; assert_contains!(output.combined_output(), building_fast_check_msg); assert_contains!( output.combined_output(), diff --git a/tests/integration/jupyter_tests.rs b/tests/integration/jupyter_tests.rs index e99780a276..4ef993c157 100644 --- a/tests/integration/jupyter_tests.rs +++ b/tests/integration/jupyter_tests.rs @@ -1,15 +1,10 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::process::Output; use std::sync::Arc; use std::time::Duration; use bytes::Bytes; -use test_util::assertions::assert_json_subset; -use test_util::DenoChild; -use test_util::TestContext; -use test_util::TestContextBuilder; - use chrono::DateTime; use chrono::Utc; use deno_core::anyhow::Result; @@ -18,6 +13,10 @@ use deno_core::serde_json::json; use deno_core::serde_json::Value; use serde::Deserialize; use serde::Serialize; +use test_util::assertions::assert_json_subset; +use test_util::DenoChild; +use test_util::TestContext; +use test_util::TestContextBuilder; use tokio::sync::Mutex; use tokio::time::timeout; use uuid::Uuid; diff --git a/tests/integration/lsp_tests.rs b/tests/integration/lsp_tests.rs index 4a8999f821..ece27c2253 100644 --- a/tests/integration/lsp_tests.rs +++ b/tests/integration/lsp_tests.rs @@ -1,4 +1,7 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::fs; +use std::str::FromStr; use deno_ast::ModuleSpecifier; use deno_core::serde::Deserialize; @@ -7,8 +10,6 @@ use deno_core::serde_json::json; use deno_core::serde_json::Value; use deno_core::url::Url; use pretty_assertions::assert_eq; -use std::fs; -use std::str::FromStr; use test_util::assert_starts_with; use test_util::assertions::assert_json_subset; use test_util::deno_cmd_with_deno_dir; @@ -9937,6 +9938,74 @@ fn lsp_auto_imports_npm_auto() { client.shutdown(); } +// Regression test for https://github.com/denoland/deno/issues/23869. +#[test] +fn lsp_auto_imports_remote_dts() { + let context = TestContextBuilder::new() + .use_http_server() + .use_temp_cwd() + .build(); + let temp_dir = context.temp_dir(); + let mut client = context.new_lsp_command().build(); + client.initialize_default(); + client.did_open(json!({ + "textDocument": { + "uri": temp_dir.url().join("file.ts").unwrap(), + "languageId": "typescript", + "version": 1, + "text": r#" + import "http://localhost:4545/subdir/imports_declaration/imports_interface.ts"; + const a: SomeInterface + "#, + }, + })); + client.write_request( + "workspace/executeCommand", + json!({ + "command": "deno.cache", + "arguments": [[], temp_dir.url().join("file.ts").unwrap()], + }), + ); + let list = client.get_completion_list( + temp_dir.url().join("file.ts").unwrap(), + (2, 21), + json!({ "triggerKind": 2 }), + ); + assert!(!list.is_incomplete); + let item = list + .items + .iter() + .find(|item| item.label == "SomeInterface") + .unwrap(); + let res = client.write_request("completionItem/resolve", json!(item)); + assert_eq!( + res, + json!({ + "label": "SomeInterface", + "labelDetails": { + "description": "http://localhost:4545/subdir/imports_declaration/interface.d.ts", + }, + "kind": 8, + "detail": "interface SomeInterface", + "documentation": { + "kind": "markdown", + "value": "", + }, + "sortText": "￿16_1", + "additionalTextEdits": [ + { + "range": { + "start": { "line": 2, "character": 0 }, + "end": { "line": 2, "character": 0 }, + }, + "newText": " import { SomeInterface } from \"http://localhost:4545/subdir/imports_declaration/interface.d.ts\";\n", + }, + ], + }), + ); + client.shutdown(); +} + #[test] fn lsp_npm_specifier_unopened_file() { let context = TestContextBuilder::new() @@ -11622,6 +11691,46 @@ fn lsp_format_exclude_default_config() { client.shutdown(); } +#[test] +fn lsp_format_untitled() { + let context = TestContextBuilder::new().use_temp_cwd().build(); + let mut client = context.new_lsp_command().build(); + client.initialize_default(); + client.did_open(json!({ + "textDocument": { + "uri": "untitled:Untitled-1", + "languageId": "typescript", + "version": 1, + "text": " console.log();\n", + }, + })); + let res = client.write_request( + "textDocument/formatting", + json!({ + "textDocument": { + "uri": "untitled:Untitled-1", + }, + "options": { + "tabSize": 2, + "insertSpaces": true, + }, + }), + ); + assert_eq!( + res, + json!([ + { + "range": { + "start": { "line": 0, "character": 0 }, + "end": { "line": 0, "character": 2 }, + }, + "newText": "", + }, + ]) + ); + client.shutdown(); +} + #[test] fn lsp_format_json() { let context = TestContextBuilder::new().use_temp_cwd().build(); @@ -11889,13 +11998,22 @@ fn lsp_format_html() { fn lsp_format_css() { let context = TestContextBuilder::new().use_temp_cwd().build(); let temp_dir = context.temp_dir(); - let file = source_file(temp_dir.path().join("file.css"), " foo {}"); + let css_file = source_file(temp_dir.path().join("file.css"), " foo {}\n"); + let scss_file = source_file(temp_dir.path().join("file.scss"), " $font-stack: Helvetica, sans-serif;\n\nbody {\n font: 100% $font-stack;\n}\n"); + let sass_file = source_file( + temp_dir.path().join("file.sass"), + " $font-stack: Helvetica, sans-serif\n\nbody\n font: 100% $font-stack\n", + ); + let less_file = source_file( + temp_dir.path().join("file.less"), + " @width: 10px;\n\n#header {\n width: @width;\n}\n", + ); let mut client = context.new_lsp_command().build(); client.initialize_default(); let res = client.write_request( "textDocument/formatting", json!({ - "textDocument": { "uri": file.url() }, + "textDocument": { "uri": css_file.url() }, "options": { "tabSize": 2, "insertSpaces": true, @@ -11912,12 +12030,71 @@ fn lsp_format_css() { }, "newText": "", }, + ]), + ); + let res = client.write_request( + "textDocument/formatting", + json!({ + "textDocument": { "uri": scss_file.url() }, + "options": { + "tabSize": 2, + "insertSpaces": true, + }, + }), + ); + assert_eq!( + res, + json!([ { "range": { - "start": { "line": 0, "character": 8 }, - "end": { "line": 0, "character": 8 }, + "start": { "line": 0, "character": 0 }, + "end": { "line": 0, "character": 2 }, }, - "newText": "\n", + "newText": "", + }, + ]), + ); + let res = client.write_request( + "textDocument/formatting", + json!({ + "textDocument": { "uri": sass_file.url() }, + "options": { + "tabSize": 2, + "insertSpaces": true, + }, + }), + ); + assert_eq!( + res, + json!([ + { + "range": { + "start": { "line": 0, "character": 0 }, + "end": { "line": 0, "character": 2 }, + }, + "newText": "", + }, + ]), + ); + let res = client.write_request( + "textDocument/formatting", + json!({ + "textDocument": { "uri": less_file.url() }, + "options": { + "tabSize": 2, + "insertSpaces": true, + }, + }), + ); + assert_eq!( + res, + json!([ + { + "range": { + "start": { "line": 0, "character": 0 }, + "end": { "line": 0, "character": 2 }, + }, + "newText": "", }, ]), ); @@ -17085,3 +17262,154 @@ fn lsp_wasm_module() { ); client.shutdown(); } + +#[test] +fn wildcard_augment() { + let context = TestContextBuilder::new().use_temp_cwd().build(); + let mut client = context.new_lsp_command().build(); + let temp_dir = context.temp_dir().path(); + let source = source_file( + temp_dir.join("index.ts"), + r#" + import styles from "./hello_world.scss"; + + function bar(v: string): string { + return v; + } + + bar(styles); + "#, + ); + temp_dir.join("index.d.ts").write( + r#" + declare module '*.scss' { + const content: string; + export default content; + } + "#, + ); + temp_dir + .join("hello_world.scss") + .write("body { color: red; }"); + + client.initialize_default(); + + let diagnostics = client.did_open_file(&source); + assert_eq!(diagnostics.all().len(), 0); +} + +#[test] +fn compiler_options_types() { + let context = TestContextBuilder::for_npm().use_temp_cwd().build(); + let mut client = context.new_lsp_command().build(); + let temp = context.temp_dir(); + let temp_dir = temp.path(); + let source = source_file( + temp_dir.join("index.ts"), + r#" + const foo = [1]; + foo.augmented(); + "#, + ); + + let deno_json = json!({ + "imports": { + "@denotest/augments-global": "npm:@denotest/augments-global@1" + }, + "compilerOptions": { "types": ["@denotest/augments-global"] }, + }); + + temp.write("deno.json", deno_json.to_string()); + + client.initialize_default(); + + for node_modules_dir in ["none", "auto", "manual"] { + let mut deno_json = deno_json.clone(); + deno_json["nodeModulesDir"] = json!(node_modules_dir); + temp.write("deno.json", deno_json.to_string()); + context.run_deno("install"); + client.did_change_watched_files(json!({ + "changes": [{ + "uri": temp.url().join("deno.json").unwrap(), + "type": 2, + }], + })); + + let diagnostics = client.did_open_file(&source); + eprintln!("{:#?}", diagnostics.all()); + assert_eq!(diagnostics.all().len(), 0); + client.did_close_file(&source); + } +} + +#[test] +fn type_reference_import_meta() { + let context = TestContextBuilder::for_npm().use_temp_cwd().build(); + let mut client = context.new_lsp_command().build(); + let temp = context.temp_dir(); + let temp_dir = temp.path(); + let source = source_file( + temp_dir.join("index.ts"), + r#" + const test = import.meta.env.TEST; + const bar = import.meta.bar; + console.log(test, bar); + "#, + ); + /* + tests type reference w/ bare specifier, type reference in an npm package, + and augmentation of `ImportMeta` (this combination modeled after the vanilla vite template, + which uses `vite/client`) + + @denotest/augments-global/import-meta: + ```dts + /// + + export type Foo = number; + ``` + + real-import-meta.d.ts: + ```dts + interface ImportMetaEnv { + TEST: string; + } + + interface ImportMeta { + env: ImportMetaEnv; + bar: number; + } + ``` + */ + temp.write( + "types.d.ts", + r#" + /// + "#, + ); + + let deno_json = json!({ + "imports": { + "@denotest/augments-global": "npm:@denotest/augments-global@1" + } + }); + temp.write("deno.json", deno_json.to_string()); + + client.initialize_default(); + + for node_modules_dir in ["none", "auto", "manual"] { + let mut deno_json = deno_json.clone(); + deno_json["nodeModulesDir"] = json!(node_modules_dir); + temp.write("deno.json", deno_json.to_string()); + context.run_deno("install"); + client.did_change_watched_files(json!({ + "changes": [{ + "uri": temp.url().join("deno.json").unwrap(), + "type": 2, + }], + })); + + let diagnostics = client.did_open_file(&source); + assert_eq!(diagnostics.all().len(), 0); + client.did_close_file(&source); + } +} diff --git a/tests/integration/mod.rs b/tests/integration/mod.rs index 37c7502284..a69bc65042 100644 --- a/tests/integration/mod.rs +++ b/tests/integration/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. #![allow(clippy::print_stdout)] #![allow(clippy::print_stderr)] diff --git a/tests/integration/node_unit_tests.rs b/tests/integration/node_unit_tests.rs index 7da1ae20a8..ed314e886e 100644 --- a/tests/integration/node_unit_tests.rs +++ b/tests/integration/node_unit_tests.rs @@ -1,9 +1,10 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::io::BufRead; use std::io::BufReader; use std::time::Duration; use std::time::Instant; + use test_util as util; use test_util::itest; use util::deno_config_path; diff --git a/tests/integration/npm_tests.rs b/tests/integration/npm_tests.rs index ffd3b817d4..033d948b2e 100644 --- a/tests/integration/npm_tests.rs +++ b/tests/integration/npm_tests.rs @@ -1,9 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::serde_json; use deno_core::serde_json::json; use deno_core::serde_json::Value; - use pretty_assertions::assert_eq; use test_util as util; use test_util::itest; diff --git a/tests/integration/pm_tests.rs b/tests/integration/pm_tests.rs index e3db9006fa..e8985ebfb1 100644 --- a/tests/integration/pm_tests.rs +++ b/tests/integration/pm_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use deno_core::serde_json::json; use test_util::assert_contains; diff --git a/tests/integration/publish_tests.rs b/tests/integration/publish_tests.rs index b97479e78e..332b7c6fa6 100644 --- a/tests/integration/publish_tests.rs +++ b/tests/integration/publish_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::process::Command; diff --git a/tests/integration/repl_tests.rs b/tests/integration/repl_tests.rs index 9eceb2f05d..4faf629af5 100644 --- a/tests/integration/repl_tests.rs +++ b/tests/integration/repl_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use test_util as util; use test_util::assert_contains; diff --git a/tests/integration/run_tests.rs b/tests/integration/run_tests.rs index 77c0a46c5f..abf1c200d9 100644 --- a/tests/integration/run_tests.rs +++ b/tests/integration/run_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::io::BufReader; use std::io::Cursor; @@ -11,7 +11,6 @@ use std::sync::Arc; use bytes::Bytes; use deno_core::serde_json::json; use deno_core::url; - use deno_tls::rustls; use deno_tls::rustls::ClientConnection; use deno_tls::rustls_pemfile; @@ -446,7 +445,7 @@ fn permissions_trace() { 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", + "┃ ├─ Object.hostname (ext:deno_os/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", @@ -2215,15 +2214,16 @@ fn basic_auth_tokens() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_resolve_dns() { + use std::net::SocketAddr; + use std::str::FromStr; + use std::sync::Arc; + use std::time::Duration; + use hickory_server::authority::Catalog; use hickory_server::authority::ZoneType; use hickory_server::proto::rr::Name; use hickory_server::store::in_memory::InMemoryAuthority; use hickory_server::ServerFuture; - use std::net::SocketAddr; - use std::str::FromStr; - use std::sync::Arc; - use std::time::Duration; use tokio::net::TcpListener; use tokio::net::UdpSocket; use tokio::sync::oneshot; @@ -2663,7 +2663,6 @@ async fn websocket_server_multi_field_connection_header() { let message = socket.read_frame().await.unwrap(); assert_eq!(message.opcode, fastwebsockets::OpCode::Close); - assert!(message.payload.is_empty()); socket .write_frame(fastwebsockets::Frame::close_raw(vec![].into())) .await diff --git a/tests/integration/serve_tests.rs b/tests/integration/serve_tests.rs index f3c8a31d93..8771930847 100644 --- a/tests/integration/serve_tests.rs +++ b/tests/integration/serve_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::cell::RefCell; use std::collections::HashMap; diff --git a/tests/integration/shared_library_tests.rs b/tests/integration/shared_library_tests.rs index 4d33e6584e..d7cdf5b426 100644 --- a/tests/integration/shared_library_tests.rs +++ b/tests/integration/shared_library_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. #[cfg(all(target_os = "linux", target_arch = "x86_64"))] #[test] diff --git a/tests/integration/task_tests.rs b/tests/integration/task_tests.rs index f2e901228a..1db5376cdd 100644 --- a/tests/integration/task_tests.rs +++ b/tests/integration/task_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Most of the tests for this are in deno_task_shell. // These tests are intended to only test integration. diff --git a/tests/integration/test_tests.rs b/tests/integration/test_tests.rs index ca83682833..cfa9d9f2d6 100644 --- a/tests/integration/test_tests.rs +++ b/tests/integration/test_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use test_util as util; use util::assert_contains; diff --git a/tests/integration/upgrade_tests.rs b/tests/integration/upgrade_tests.rs index 5132b4ca5b..7748f0ca1a 100644 --- a/tests/integration/upgrade_tests.rs +++ b/tests/integration/upgrade_tests.rs @@ -1,8 +1,9 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::process::Command; use std::process::Stdio; use std::time::Instant; + use test_util as util; use test_util::assert_starts_with; use test_util::TestContext; diff --git a/tests/integration/watcher_tests.rs b/tests/integration/watcher_tests.rs index 055e46af9c..a180be2fb3 100644 --- a/tests/integration/watcher_tests.rs +++ b/tests/integration/watcher_tests.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use flaky_test::flaky_test; use test_util as util; @@ -6,9 +6,8 @@ use test_util::assert_contains; use test_util::env_vars_for_npm_tests; use test_util::TempDir; use tokio::io::AsyncBufReadExt; -use util::DenoChild; - use util::assert_not_contains; +use util::DenoChild; /// Logs to stderr every time next_line() is called struct LoggingLines diff --git a/tests/lib.rs b/tests/lib.rs index 0a39b9f87d..d841ab9f3f 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1 +1 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. diff --git a/tests/napi/Cargo.toml b/tests/napi/Cargo.toml index e3de253683..e8a39a0cda 100644 --- a/tests/napi/Cargo.toml +++ b/tests/napi/Cargo.toml @@ -1,4 +1,4 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "test_napi" diff --git a/tests/napi/array_test.js b/tests/napi/array_test.js index 572d3a8994..c72e5d3849 100644 --- a/tests/napi/array_test.js +++ b/tests/napi/array_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, loadTestLibrary } from "./common.js"; diff --git a/tests/napi/arraybuffer_test.js b/tests/napi/arraybuffer_test.js index f55b9a78c5..a11f761130 100644 --- a/tests/napi/arraybuffer_test.js +++ b/tests/napi/arraybuffer_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, loadTestLibrary } from "./common.js"; diff --git a/tests/napi/async_test.js b/tests/napi/async_test.js index 4d9ad99c26..f3d258a543 100644 --- a/tests/napi/async_test.js +++ b/tests/napi/async_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, loadTestLibrary } from "./common.js"; diff --git a/tests/napi/bigint_test.js b/tests/napi/bigint_test.js index 4a9ada2057..19c5317d75 100644 --- a/tests/napi/bigint_test.js +++ b/tests/napi/bigint_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertThrows, loadTestLibrary } from "./common.js"; diff --git a/tests/napi/build.rs b/tests/napi/build.rs index c2fe86a531..73fce9172a 100644 --- a/tests/napi/build.rs +++ b/tests/napi/build.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. extern crate napi_build; diff --git a/tests/napi/callback_test.js b/tests/napi/callback_test.js index c132fefa18..3c56b11a28 100644 --- a/tests/napi/callback_test.js +++ b/tests/napi/callback_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertThrows, loadTestLibrary } from "./common.js"; diff --git a/tests/napi/cleanup_hook_test.js b/tests/napi/cleanup_hook_test.js index 2c1f73e12b..8e4430eef7 100644 --- a/tests/napi/cleanup_hook_test.js +++ b/tests/napi/cleanup_hook_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console diff --git a/tests/napi/coerce_test.js b/tests/napi/coerce_test.js index 64f0148016..91e8950980 100644 --- a/tests/napi/coerce_test.js +++ b/tests/napi/coerce_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, loadTestLibrary } from "./common.js"; diff --git a/tests/napi/common.js b/tests/napi/common.js index 6dfdc873a8..7df63c4f90 100644 --- a/tests/napi/common.js +++ b/tests/napi/common.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. export { assert, assertEquals, assertRejects, assertThrows } from "@std/assert"; export { fromFileUrl } from "@std/path"; diff --git a/tests/napi/date_test.js b/tests/napi/date_test.js index 49eec5cca1..2625010494 100644 --- a/tests/napi/date_test.js +++ b/tests/napi/date_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, loadTestLibrary } from "./common.js"; diff --git a/tests/napi/env_test.js b/tests/napi/env_test.js index 72b868a668..0b9fad314b 100644 --- a/tests/napi/env_test.js +++ b/tests/napi/env_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, loadTestLibrary } from "./common.js"; diff --git a/tests/napi/error_test.js b/tests/napi/error_test.js index 57acde5c16..cab36b0a30 100644 --- a/tests/napi/error_test.js +++ b/tests/napi/error_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, diff --git a/tests/napi/init_test.js b/tests/napi/init_test.js index 9486824780..8cd5298dde 100644 --- a/tests/napi/init_test.js +++ b/tests/napi/init_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { Buffer } from "node:buffer"; import { assert, libSuffix } from "./common.js"; diff --git a/tests/napi/make_callback_test.js b/tests/napi/make_callback_test.js index b1f7912aea..60aa5ae4c7 100644 --- a/tests/napi/make_callback_test.js +++ b/tests/napi/make_callback_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, loadTestLibrary } from "./common.js"; diff --git a/tests/napi/mem_test.js b/tests/napi/mem_test.js index bee8c194ea..2c8b0be75a 100644 --- a/tests/napi/mem_test.js +++ b/tests/napi/mem_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, loadTestLibrary } from "./common.js"; diff --git a/tests/napi/module.c b/tests/napi/module.c index 1ae2ace5d3..9eb90887a8 100644 --- a/tests/napi/module.c +++ b/tests/napi/module.c @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. typedef struct napi_module { int nm_version; diff --git a/tests/napi/numbers_test.js b/tests/napi/numbers_test.js index 8a99c831d0..4914a24751 100644 --- a/tests/napi/numbers_test.js +++ b/tests/napi/numbers_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, loadTestLibrary } from "./common.js"; diff --git a/tests/napi/object_test.js b/tests/napi/object_test.js index 6226b0138c..5ab81359c4 100644 --- a/tests/napi/object_test.js +++ b/tests/napi/object_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, diff --git a/tests/napi/object_wrap_test.js b/tests/napi/object_wrap_test.js index ee6d4af86b..7c7eecbbd4 100644 --- a/tests/napi/object_wrap_test.js +++ b/tests/napi/object_wrap_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { Buffer } from "node:buffer"; import { assert, assertEquals, loadTestLibrary } from "./common.js"; diff --git a/tests/napi/promise_test.js b/tests/napi/promise_test.js index e4bbfee6b8..3b9ba15b67 100644 --- a/tests/napi/promise_test.js +++ b/tests/napi/promise_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertRejects, loadTestLibrary } from "./common.js"; diff --git a/tests/napi/properties_test.js b/tests/napi/properties_test.js index 21a3555e8e..ee86eaa19b 100644 --- a/tests/napi/properties_test.js +++ b/tests/napi/properties_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, loadTestLibrary } from "./common.js"; diff --git a/tests/napi/src/array.rs b/tests/napi/src/array.rs index 6df420eb57..b2aba94fff 100644 --- a/tests/napi/src/array.rs +++ b/tests/napi/src/array.rs @@ -1,12 +1,14 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::ptr; + +use napi_sys::ValueType::napi_number; +use napi_sys::ValueType::napi_object; +use napi_sys::*; use crate::assert_napi_ok; use crate::napi_get_callback_info; use crate::napi_new_property; -use napi_sys::ValueType::napi_number; -use napi_sys::ValueType::napi_object; -use napi_sys::*; -use std::ptr; extern "C" fn test_array_new( env: napi_env, diff --git a/tests/napi/src/arraybuffer.rs b/tests/napi/src/arraybuffer.rs index 8402f5d861..0fe39b53cc 100644 --- a/tests/napi/src/arraybuffer.rs +++ b/tests/napi/src/arraybuffer.rs @@ -1,9 +1,10 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use napi_sys::*; use crate::assert_napi_ok; use crate::napi_get_callback_info; use crate::napi_new_property; -use napi_sys::*; extern "C" fn test_detached( env: napi_env, diff --git a/tests/napi/src/async.rs b/tests/napi/src/async.rs index 367d2e9ef0..a91f7037b2 100644 --- a/tests/napi/src/async.rs +++ b/tests/napi/src/async.rs @@ -1,14 +1,16 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::os::raw::c_char; +use std::os::raw::c_void; +use std::ptr; + +use napi_sys::Status::napi_ok; +use napi_sys::ValueType::napi_function; +use napi_sys::*; use crate::assert_napi_ok; use crate::napi_get_callback_info; use crate::napi_new_property; -use napi_sys::Status::napi_ok; -use napi_sys::ValueType::napi_function; -use napi_sys::*; -use std::os::raw::c_char; -use std::os::raw::c_void; -use std::ptr; pub struct Baton { called: bool, diff --git a/tests/napi/src/bigint.rs b/tests/napi/src/bigint.rs index d867823313..6e1d728b32 100644 --- a/tests/napi/src/bigint.rs +++ b/tests/napi/src/bigint.rs @@ -1,13 +1,15 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::ptr; + +use napi_sys::Status::napi_pending_exception; +use napi_sys::ValueType::napi_bigint; +use napi_sys::*; use crate::assert_napi_ok; use crate::cstr; use crate::napi_get_callback_info; use crate::napi_new_property; -use napi_sys::Status::napi_pending_exception; -use napi_sys::ValueType::napi_bigint; -use napi_sys::*; -use std::ptr; extern "C" fn is_lossless( env: napi_env, diff --git a/tests/napi/src/callback.rs b/tests/napi/src/callback.rs index 2512f6a38f..1ce1d688c2 100644 --- a/tests/napi/src/callback.rs +++ b/tests/napi/src/callback.rs @@ -1,15 +1,17 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::ptr; -use crate::assert_napi_ok; -use crate::napi_get_callback_info; -use crate::napi_new_property; use napi_sys::ValueType::napi_function; use napi_sys::ValueType::napi_object; use napi_sys::ValueType::napi_undefined; use napi_sys::*; -use std::ptr; use Status::napi_pending_exception; +use crate::assert_napi_ok; +use crate::napi_get_callback_info; +use crate::napi_new_property; + /// `test_callback_run((a, b) => a + b, [1, 2])` => 3 extern "C" fn test_callback_run( env: napi_env, diff --git a/tests/napi/src/coerce.rs b/tests/napi/src/coerce.rs index a405783843..e0fa50c89e 100644 --- a/tests/napi/src/coerce.rs +++ b/tests/napi/src/coerce.rs @@ -1,10 +1,12 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::ptr; + +use napi_sys::*; use crate::assert_napi_ok; use crate::napi_get_callback_info; use crate::napi_new_property; -use napi_sys::*; -use std::ptr; extern "C" fn test_coerce_bool( env: napi_env, diff --git a/tests/napi/src/date.rs b/tests/napi/src/date.rs index 4d3c155c32..1db5bd088b 100644 --- a/tests/napi/src/date.rs +++ b/tests/napi/src/date.rs @@ -1,11 +1,13 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::ptr; + +use napi_sys::ValueType::napi_number; +use napi_sys::*; use crate::assert_napi_ok; use crate::napi_get_callback_info; use crate::napi_new_property; -use napi_sys::ValueType::napi_number; -use napi_sys::*; -use std::ptr; extern "C" fn create_date( env: napi_env, diff --git a/tests/napi/src/env.rs b/tests/napi/src/env.rs index ebc6532a3c..b1b56191ec 100644 --- a/tests/napi/src/env.rs +++ b/tests/napi/src/env.rs @@ -1,9 +1,10 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use napi_sys::*; use crate::assert_napi_ok; use crate::napi_get_callback_info; use crate::napi_new_property; -use napi_sys::*; extern "C" fn get_node_global( env: napi_env, diff --git a/tests/napi/src/error.rs b/tests/napi/src/error.rs index e0d79c836a..6de0d529b2 100644 --- a/tests/napi/src/error.rs +++ b/tests/napi/src/error.rs @@ -1,11 +1,13 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::ptr; + +use napi_sys::*; use crate::assert_napi_ok; use crate::cstr; use crate::napi_get_callback_info; use crate::napi_new_property; -use napi_sys::*; -use std::ptr; extern "C" fn check_error( env: napi_env, diff --git a/tests/napi/src/finalizer.rs b/tests/napi/src/finalizer.rs index 9769e775e2..56e0a326a7 100644 --- a/tests/napi/src/finalizer.rs +++ b/tests/napi/src/finalizer.rs @@ -1,11 +1,13 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::ptr; + +use napi_sys::ValueType::napi_object; +use napi_sys::*; use crate::assert_napi_ok; use crate::napi_get_callback_info; use crate::napi_new_property; -use napi_sys::ValueType::napi_object; -use napi_sys::*; -use std::ptr; unsafe extern "C" fn finalize_cb( _env: napi_env, diff --git a/tests/napi/src/lib.rs b/tests/napi/src/lib.rs index 8c6190ad3e..6162feded6 100644 --- a/tests/napi/src/lib.rs +++ b/tests/napi/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. #![allow(clippy::all)] #![allow(clippy::print_stdout)] diff --git a/tests/napi/src/make_callback.rs b/tests/napi/src/make_callback.rs index 945df34523..c19d34e50c 100644 --- a/tests/napi/src/make_callback.rs +++ b/tests/napi/src/make_callback.rs @@ -1,10 +1,12 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::ptr; + +use napi_sys::ValueType::napi_function; +use napi_sys::*; use crate::assert_napi_ok; use crate::cstr; -use napi_sys::ValueType::napi_function; -use napi_sys::*; -use std::ptr; extern "C" fn make_callback( env: napi_env, diff --git a/tests/napi/src/mem.rs b/tests/napi/src/mem.rs index ebb6a5c7ac..a05cd3abf4 100644 --- a/tests/napi/src/mem.rs +++ b/tests/napi/src/mem.rs @@ -1,9 +1,11 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::ptr; + +use napi_sys::*; use crate::assert_napi_ok; use crate::napi_new_property; -use napi_sys::*; -use std::ptr; extern "C" fn adjust_external_memory( env: napi_env, diff --git a/tests/napi/src/numbers.rs b/tests/napi/src/numbers.rs index 777ccbfac7..9c4174f727 100644 --- a/tests/napi/src/numbers.rs +++ b/tests/napi/src/numbers.rs @@ -1,11 +1,13 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::ptr; + +use napi_sys::ValueType::napi_number; +use napi_sys::*; use crate::assert_napi_ok; use crate::napi_get_callback_info; use crate::napi_new_property; -use napi_sys::ValueType::napi_number; -use napi_sys::*; -use std::ptr; extern "C" fn test_int32( env: napi_env, diff --git a/tests/napi/src/object.rs b/tests/napi/src/object.rs index 9876f4dae0..9014134803 100644 --- a/tests/napi/src/object.rs +++ b/tests/napi/src/object.rs @@ -1,10 +1,12 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::ptr; + +use napi_sys::*; use crate::assert_napi_ok; use crate::napi_get_callback_info; use crate::napi_new_property; -use napi_sys::*; -use std::ptr; extern "C" fn test_object_new( env: napi_env, diff --git a/tests/napi/src/object_wrap.rs b/tests/napi/src/object_wrap.rs index 63e9e2e232..11844917b5 100644 --- a/tests/napi/src/object_wrap.rs +++ b/tests/napi/src/object_wrap.rs @@ -1,16 +1,18 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::assert_napi_ok; -use crate::napi_get_callback_info; -use crate::napi_new_property; -use napi_sys::ValueType::napi_number; -use napi_sys::*; use std::cell::RefCell; use std::collections::HashMap; use std::os::raw::c_char; use std::os::raw::c_void; use std::ptr; +use napi_sys::ValueType::napi_number; +use napi_sys::*; + +use crate::assert_napi_ok; +use crate::napi_get_callback_info; +use crate::napi_new_property; + pub struct NapiObject { counter: i32, } diff --git a/tests/napi/src/primitives.rs b/tests/napi/src/primitives.rs index 28fb8ec3db..7717a0aaac 100644 --- a/tests/napi/src/primitives.rs +++ b/tests/napi/src/primitives.rs @@ -1,9 +1,11 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::ptr; + +use napi_sys::*; use crate::assert_napi_ok; use crate::napi_new_property; -use napi_sys::*; -use std::ptr; extern "C" fn test_get_undefined( env: napi_env, diff --git a/tests/napi/src/promise.rs b/tests/napi/src/promise.rs index 1f1c31f1eb..eab379d617 100644 --- a/tests/napi/src/promise.rs +++ b/tests/napi/src/promise.rs @@ -1,11 +1,13 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::ptr; +use std::ptr::addr_of_mut; + +use napi_sys::*; use crate::assert_napi_ok; use crate::napi_get_callback_info; use crate::napi_new_property; -use napi_sys::*; -use std::ptr; -use std::ptr::addr_of_mut; static mut CURRENT_DEFERRED: napi_deferred = ptr::null_mut(); diff --git a/tests/napi/src/properties.rs b/tests/napi/src/properties.rs index 43bef1949a..4244c7ba06 100644 --- a/tests/napi/src/properties.rs +++ b/tests/napi/src/properties.rs @@ -1,10 +1,12 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::ptr; + +use napi_sys::PropertyAttributes::*; +use napi_sys::*; use crate::assert_napi_ok; use crate::cstr; -use napi_sys::PropertyAttributes::*; -use napi_sys::*; -use std::ptr; static NICE: i64 = 69; diff --git a/tests/napi/src/strings.rs b/tests/napi/src/strings.rs index 301ab23df2..027ae68176 100644 --- a/tests/napi/src/strings.rs +++ b/tests/napi/src/strings.rs @@ -1,10 +1,11 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use napi_sys::ValueType::napi_string; +use napi_sys::*; use crate::assert_napi_ok; use crate::napi_get_callback_info; use crate::napi_new_property; -use napi_sys::ValueType::napi_string; -use napi_sys::*; extern "C" fn test_utf8(env: napi_env, info: napi_callback_info) -> napi_value { let (args, argc, _) = napi_get_callback_info!(env, info, 1); diff --git a/tests/napi/src/symbol.rs b/tests/napi/src/symbol.rs index 6387d449f1..30c7cbde64 100644 --- a/tests/napi/src/symbol.rs +++ b/tests/napi/src/symbol.rs @@ -1,10 +1,11 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use napi_sys::ValueType::napi_string; +use napi_sys::*; use crate::assert_napi_ok; use crate::napi_get_callback_info; use crate::napi_new_property; -use napi_sys::ValueType::napi_string; -use napi_sys::*; extern "C" fn symbol_new( env: napi_env, diff --git a/tests/napi/src/tsfn.rs b/tests/napi/src/tsfn.rs index a3a231cec1..830145501d 100644 --- a/tests/napi/src/tsfn.rs +++ b/tests/napi/src/tsfn.rs @@ -1,13 +1,14 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // This test performs initialization similar to napi-rs. // https://github.com/napi-rs/napi-rs/commit/a5a04a4e545f268769cc78e2bd6c45af4336aac3 -use napi_sys as sys; use std::ffi::c_char; use std::ffi::c_void; use std::ptr; +use napi_sys as sys; + macro_rules! check_status_or_panic { ($code:expr, $msg:expr) => {{ let c = $code; diff --git a/tests/napi/src/typedarray.rs b/tests/napi/src/typedarray.rs index b512bd32fe..95adf957e4 100644 --- a/tests/napi/src/typedarray.rs +++ b/tests/napi/src/typedarray.rs @@ -1,16 +1,18 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::assert_napi_ok; -use crate::napi_get_callback_info; -use crate::napi_new_property; use core::ffi::c_void; +use std::os::raw::c_char; +use std::ptr; + use napi_sys::Status::napi_ok; use napi_sys::TypedarrayType; use napi_sys::ValueType::napi_number; use napi_sys::ValueType::napi_object; use napi_sys::*; -use std::os::raw::c_char; -use std::ptr; + +use crate::assert_napi_ok; +use crate::napi_get_callback_info; +use crate::napi_new_property; extern "C" fn test_multiply( env: napi_env, diff --git a/tests/napi/src/uv.rs b/tests/napi/src/uv.rs index 555470c008..45ca114adc 100644 --- a/tests/napi/src/uv.rs +++ b/tests/napi/src/uv.rs @@ -1,8 +1,11 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::mem::MaybeUninit; +use std::ptr; +use std::ptr::addr_of_mut; +use std::ptr::null_mut; +use std::time::Duration; -use crate::assert_napi_ok; -use crate::napi_get_callback_info; -use crate::napi_new_property; use libuv_sys_lite::uv_async_init; use libuv_sys_lite::uv_async_t; use libuv_sys_lite::uv_close; @@ -12,11 +15,10 @@ use libuv_sys_lite::uv_mutex_lock; use libuv_sys_lite::uv_mutex_t; use libuv_sys_lite::uv_mutex_unlock; use napi_sys::*; -use std::mem::MaybeUninit; -use std::ptr; -use std::ptr::addr_of_mut; -use std::ptr::null_mut; -use std::time::Duration; + +use crate::assert_napi_ok; +use crate::napi_get_callback_info; +use crate::napi_new_property; struct KeepAlive { tsfn: napi_threadsafe_function, diff --git a/tests/napi/strings_test.js b/tests/napi/strings_test.js index 45cb133b28..01fc873a74 100644 --- a/tests/napi/strings_test.js +++ b/tests/napi/strings_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, loadTestLibrary } from "./common.js"; diff --git a/tests/napi/symbol_test.js b/tests/napi/symbol_test.js index d8edec0232..3f0f277647 100644 --- a/tests/napi/symbol_test.js +++ b/tests/napi/symbol_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, loadTestLibrary } from "./common.js"; diff --git a/tests/napi/tests/napi_tests.rs b/tests/napi/tests/napi_tests.rs index 53d4258f93..f97fdce289 100644 --- a/tests/napi/tests/napi_tests.rs +++ b/tests/napi/tests/napi_tests.rs @@ -1,9 +1,10 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. #![allow(clippy::print_stdout)] #![allow(clippy::print_stderr)] use std::process::Command; + use test_util::deno_cmd; use test_util::deno_config_path; use test_util::env_vars_for_npm_tests; diff --git a/tests/napi/typedarray_test.js b/tests/napi/typedarray_test.js index 25729754a5..f7887e4b1c 100644 --- a/tests/napi/typedarray_test.js +++ b/tests/napi/typedarray_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, loadTestLibrary } from "./common.js"; diff --git a/tests/napi/uv_test.js b/tests/napi/uv_test.js index af20b26493..f0ff613f31 100644 --- a/tests/napi/uv_test.js +++ b/tests/napi/uv_test.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, loadTestLibrary } from "./common.js"; diff --git a/tests/node_compat/common.ts b/tests/node_compat/common.ts index 2982095a29..a86373d69f 100644 --- a/tests/node_compat/common.ts +++ b/tests/node_compat/common.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { partition } from "@std/collections/partition"; import { join } from "@std/path"; import * as JSONC from "@std/jsonc"; diff --git a/tests/node_compat/config.jsonc b/tests/node_compat/config.jsonc index cda2923789..c2edc32ef6 100644 --- a/tests/node_compat/config.jsonc +++ b/tests/node_compat/config.jsonc @@ -368,9 +368,11 @@ "test-dgram-send-callback-multi-buffer.js", "test-dgram-send-callback-recursive.js", "test-dgram-send-default-host.js", - "test-dgram-send-empty-array.js", - "test-dgram-send-empty-buffer.js", - "test-dgram-send-empty-packet.js", + // TODO(kt3k): These tests are flaky on macOS CI. + // https://github.com/denoland/deno/issues/27316 + // "test-dgram-send-empty-array.js", + // "test-dgram-send-empty-buffer.js", + // "test-dgram-send-empty-packet.js", "test-dgram-send-error.js", "test-dgram-send-invalid-msg-type.js", "test-dgram-send-multi-buffer-copy.js", diff --git a/tests/node_compat/polyfill_globals.js b/tests/node_compat/polyfill_globals.js index f22143d9bd..8bbd5cc7df 100644 --- a/tests/node_compat/polyfill_globals.js +++ b/tests/node_compat/polyfill_globals.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { Buffer } from "node:buffer"; import { clearImmediate, diff --git a/tests/node_compat/runner.ts b/tests/node_compat/runner.ts index 56803fad44..6bc750447a 100644 --- a/tests/node_compat/runner.ts +++ b/tests/node_compat/runner.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import "./polyfill_globals.js"; import { createRequire } from "node:module"; import { toFileUrl } from "@std/path/to-file-url"; diff --git a/tests/node_compat/runner/TODO.md b/tests/node_compat/runner/TODO.md index 8ad00c9bfd..c885622d6f 100644 --- a/tests/node_compat/runner/TODO.md +++ b/tests/node_compat/runner/TODO.md @@ -1,7 +1,7 @@ # Remaining Node Tests -1155 tests out of 3681 have been ported from Node 20.11.1 (31.38% ported, 69.14% remaining). +1152 tests out of 3681 have been ported from Node 20.11.1 (31.30% ported, 69.22% remaining). NOTE: This file should not be manually edited. Please edit `tests/node_compat/config.json` and run `deno task setup` in `tests/node_compat/runner` dir instead. @@ -499,6 +499,9 @@ NOTE: This file should not be manually edited. Please edit `tests/node_compat/co - [parallel/test-dgram-multicast-set-interface.js](https://github.com/nodejs/node/tree/v20.11.1/test/parallel/test-dgram-multicast-set-interface.js) - [parallel/test-dgram-multicast-setTTL.js](https://github.com/nodejs/node/tree/v20.11.1/test/parallel/test-dgram-multicast-setTTL.js) - [parallel/test-dgram-send-address-types.js](https://github.com/nodejs/node/tree/v20.11.1/test/parallel/test-dgram-send-address-types.js) +- [parallel/test-dgram-send-empty-array.js](https://github.com/nodejs/node/tree/v20.11.1/test/parallel/test-dgram-send-empty-array.js) +- [parallel/test-dgram-send-empty-buffer.js](https://github.com/nodejs/node/tree/v20.11.1/test/parallel/test-dgram-send-empty-buffer.js) +- [parallel/test-dgram-send-empty-packet.js](https://github.com/nodejs/node/tree/v20.11.1/test/parallel/test-dgram-send-empty-packet.js) - [parallel/test-dgram-send-queue-info.js](https://github.com/nodejs/node/tree/v20.11.1/test/parallel/test-dgram-send-queue-info.js) - [parallel/test-dgram-sendto.js](https://github.com/nodejs/node/tree/v20.11.1/test/parallel/test-dgram-sendto.js) - [parallel/test-dgram-setBroadcast.js](https://github.com/nodejs/node/tree/v20.11.1/test/parallel/test-dgram-setBroadcast.js) diff --git a/tests/node_compat/runner/challenge_new_test.ts b/tests/node_compat/runner/challenge_new_test.ts index 313bf60490..c95391d3e0 100644 --- a/tests/node_compat/runner/challenge_new_test.ts +++ b/tests/node_compat/runner/challenge_new_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console import { deadline } from "@std/async/deadline"; diff --git a/tests/node_compat/runner/setup.ts b/tests/node_compat/runner/setup.ts index b655633ead..d256842e14 100755 --- a/tests/node_compat/runner/setup.ts +++ b/tests/node_compat/runner/setup.ts @@ -1,5 +1,5 @@ #!/usr/bin/env -S deno run --allow-read=. --allow-write=. --allow-run=git --config=tests/config/deno.json -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console diff --git a/tests/node_compat/test.ts b/tests/node_compat/test.ts index 52d2b17169..fe6b2e879b 100644 --- a/tests/node_compat/test.ts +++ b/tests/node_compat/test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console diff --git a/tests/node_compat/test/parallel/test-dgram-send-empty-array.js b/tests/node_compat/test/parallel/test-dgram-send-empty-array.js deleted file mode 100644 index cf2508d9ca..0000000000 --- a/tests/node_compat/test/parallel/test-dgram-send-empty-array.js +++ /dev/null @@ -1,32 +0,0 @@ -// deno-fmt-ignore-file -// deno-lint-ignore-file - -// Copyright Joyent and Node contributors. All rights reserved. MIT license. -// Taken from Node 20.11.1 -// This file is automatically generated by `tests/node_compat/runner/setup.ts`. Do not modify this file manually. - -'use strict'; - -const common = require('../common'); - -const assert = require('assert'); -const dgram = require('dgram'); - -const client = dgram.createSocket('udp4'); - -let interval; - -client.on('message', common.mustCall(function onMessage(buf, info) { - const expected = Buffer.alloc(0); - assert.ok(buf.equals(expected), `Expected empty message but got ${buf}`); - clearInterval(interval); - client.close(); -})); - -client.on('listening', common.mustCall(function() { - interval = setInterval(function() { - client.send([], client.address().port, common.localhostIPv4); - }, 10); -})); - -client.bind(0); diff --git a/tests/node_compat/test/parallel/test-dgram-send-empty-buffer.js b/tests/node_compat/test/parallel/test-dgram-send-empty-buffer.js deleted file mode 100644 index de5101cbd2..0000000000 --- a/tests/node_compat/test/parallel/test-dgram-send-empty-buffer.js +++ /dev/null @@ -1,50 +0,0 @@ -// deno-fmt-ignore-file -// deno-lint-ignore-file - -// Copyright Joyent and Node contributors. All rights reserved. MIT license. -// Taken from Node 20.11.1 -// This file is automatically generated by `tests/node_compat/runner/setup.ts`. Do not modify this file manually. - -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -'use strict'; -const common = require('../common'); - -const assert = require('assert'); -const dgram = require('dgram'); - -const client = dgram.createSocket('udp4'); - -client.bind(0, common.mustCall(function() { - const port = this.address().port; - - client.on('message', common.mustCall(function onMessage(buffer) { - assert.strictEqual(buffer.length, 0); - clearInterval(interval); - client.close(); - })); - - const buf = Buffer.alloc(0); - const interval = setInterval(function() { - client.send(buf, 0, 0, port, '127.0.0.1', common.mustCall()); - }, 10); -})); diff --git a/tests/node_compat/test/parallel/test-dgram-send-empty-packet.js b/tests/node_compat/test/parallel/test-dgram-send-empty-packet.js deleted file mode 100644 index 01f7a459ce..0000000000 --- a/tests/node_compat/test/parallel/test-dgram-send-empty-packet.js +++ /dev/null @@ -1,36 +0,0 @@ -// deno-fmt-ignore-file -// deno-lint-ignore-file - -// Copyright Joyent and Node contributors. All rights reserved. MIT license. -// Taken from Node 20.11.1 -// This file is automatically generated by `tests/node_compat/runner/setup.ts`. Do not modify this file manually. - -'use strict'; -const common = require('../common'); - -const assert = require('assert'); -const dgram = require('dgram'); - -const client = dgram.createSocket('udp4'); - -client.bind(0, common.mustCall(function() { - - client.on('message', common.mustCall(callback)); - - const port = this.address().port; - const buf = Buffer.alloc(1); - - const interval = setInterval(function() { - client.send(buf, 0, 0, port, '127.0.0.1', common.mustCall(callback)); - }, 10); - - function callback(firstArg) { - // If client.send() callback, firstArg should be null. - // If client.on('message') listener, firstArg should be a 0-length buffer. - if (firstArg instanceof Buffer) { - assert.strictEqual(firstArg.length, 0); - clearInterval(interval); - client.close(); - } - } -})); diff --git a/tests/node_compat/test_runner.rs b/tests/node_compat/test_runner.rs index 15749ca7fd..150b632b90 100644 --- a/tests/node_compat/test_runner.rs +++ b/tests/node_compat/test_runner.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use test_util as util; use util::deno_config_path; diff --git a/tests/registry/jsr/@deno/otel/0.0.2/deno.json b/tests/registry/jsr/@deno/otel/0.0.2/deno.json deleted file mode 100644 index cfa44a7d07..0000000000 --- a/tests/registry/jsr/@deno/otel/0.0.2/deno.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "@deno/otel", - "version": "0.0.2", - "exports": { - ".": "./src/index.ts", - "./register": "./src/register.ts" - }, - "tasks": { - "check:license": "deno run -A tools/check_license.ts", - "check:docs": "deno doc --lint src/index.ts", - "check": "deno task check:license --check", - "ok": "deno fmt --check && deno lint && deno task check" - } -} diff --git a/tests/registry/jsr/@deno/otel/0.0.2/src/index.ts b/tests/registry/jsr/@deno/otel/0.0.2/src/index.ts deleted file mode 100644 index 9c44457832..0000000000 --- a/tests/registry/jsr/@deno/otel/0.0.2/src/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2024-2024 the Deno authors. All rights reserved. MIT license. - -import { context } from "npm:@opentelemetry/api@1"; -import { - BasicTracerProvider, - SimpleSpanProcessor, -} from "npm:@opentelemetry/sdk-trace-base@1"; - -// @ts-ignore Deno.telemetry is not typed yet -const telemetry = Deno.telemetry ?? Deno.tracing; - -let COUNTER = 1; - -/** - * Register `Deno.telemetry` with the OpenTelemetry library. - */ -export function register() { - context.setGlobalContextManager( - new telemetry.ContextManager() ?? telemetry.ContextManager(), - ); - - const provider = new BasicTracerProvider({ - idGenerator: Deno.env.get("DENO_UNSTABLE_OTEL_DETERMINISTIC") === "1" ? { - generateSpanId() { - return "1" + String(COUNTER++).padStart(15, "0"); - }, - generateTraceId() { - return "1" + String(COUNTER++).padStart(31, "0"); - } - } : undefined - }); - - // @ts-ignore Deno.tracing is not typed yet - const exporter = new telemetry.SpanExporter(); - provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); - - provider.register(); -} diff --git a/tests/registry/jsr/@deno/otel/0.0.2/src/register.ts b/tests/registry/jsr/@deno/otel/0.0.2/src/register.ts deleted file mode 100644 index 5443707076..0000000000 --- a/tests/registry/jsr/@deno/otel/0.0.2/src/register.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2024-2024 the Deno authors. All rights reserved. MIT license. - -import { register } from "./index.ts"; - -register(); diff --git a/tests/registry/jsr/@deno/otel/0.0.2_meta.json b/tests/registry/jsr/@deno/otel/0.0.2_meta.json deleted file mode 100644 index 79c28d61d1..0000000000 --- a/tests/registry/jsr/@deno/otel/0.0.2_meta.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "exports": { - ".": "./src/index.ts", - "./register": "./src/register.ts" - } -} \ No newline at end of file diff --git a/tests/registry/jsr/@deno/otel/meta.json b/tests/registry/jsr/@deno/otel/meta.json deleted file mode 100644 index 1cb49741a1..0000000000 --- a/tests/registry/jsr/@deno/otel/meta.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "scope": "deno", - "name": "otel", - "latest": "0.0.2", - "versions": { - "0.0.2": {} - } -} \ No newline at end of file diff --git a/tests/registry/jsr/@std/assert/0.220.1/mod.ts b/tests/registry/jsr/@std/assert/0.220.1/mod.ts index fdcb56c8cf..44aa962030 100644 --- a/tests/registry/jsr/@std/assert/0.220.1/mod.ts +++ b/tests/registry/jsr/@std/assert/0.220.1/mod.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /** A library of assertion functions. * If the assertion is false an `AssertionError` will be thrown which will diff --git a/tests/registry/jsr/@std/assert/1.0.0/mod.ts b/tests/registry/jsr/@std/assert/1.0.0/mod.ts index fdcb56c8cf..44aa962030 100644 --- a/tests/registry/jsr/@std/assert/1.0.0/mod.ts +++ b/tests/registry/jsr/@std/assert/1.0.0/mod.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /** A library of assertion functions. * If the assertion is false an `AssertionError` will be thrown which will diff --git a/tests/registry/jsr/@std/http/1.0.0/mod.ts b/tests/registry/jsr/@std/http/1.0.0/mod.ts index 0a0e82847f..991765213a 100644 --- a/tests/registry/jsr/@std/http/1.0.0/mod.ts +++ b/tests/registry/jsr/@std/http/1.0.0/mod.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /** * Request handler for {@linkcode Route}. diff --git a/tests/registry/jsr/@std/path/0.220.1/_common/assert_path.ts b/tests/registry/jsr/@std/path/0.220.1/_common/assert_path.ts index 7033edcd1a..2d7f7f1b92 100644 --- a/tests/registry/jsr/@std/path/0.220.1/_common/assert_path.ts +++ b/tests/registry/jsr/@std/path/0.220.1/_common/assert_path.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright the Browserify authors. MIT License. export function assertPath(path?: string) { diff --git a/tests/registry/jsr/@std/path/0.220.1/_common/constants.ts b/tests/registry/jsr/@std/path/0.220.1/_common/constants.ts index 9bfd411b66..2dae0df89f 100644 --- a/tests/registry/jsr/@std/path/0.220.1/_common/constants.ts +++ b/tests/registry/jsr/@std/path/0.220.1/_common/constants.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright the Browserify authors. MIT License. // Ported from https://github.com/browserify/path-browserify/ // This module is browser compatible. diff --git a/tests/registry/jsr/@std/path/0.220.1/_common/normalize.ts b/tests/registry/jsr/@std/path/0.220.1/_common/normalize.ts index 3a1a162845..a3d0a0caee 100644 --- a/tests/registry/jsr/@std/path/0.220.1/_common/normalize.ts +++ b/tests/registry/jsr/@std/path/0.220.1/_common/normalize.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // This module is browser compatible. import { assertPath } from "./assert_path.ts"; diff --git a/tests/registry/jsr/@std/path/0.220.1/_common/normalize_string.ts b/tests/registry/jsr/@std/path/0.220.1/_common/normalize_string.ts index d8f0e090a6..dbcf59029b 100644 --- a/tests/registry/jsr/@std/path/0.220.1/_common/normalize_string.ts +++ b/tests/registry/jsr/@std/path/0.220.1/_common/normalize_string.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright the Browserify authors. MIT License. // Ported from https://github.com/browserify/path-browserify/ // This module is browser compatible. diff --git a/tests/registry/jsr/@std/path/0.220.1/posix/_util.ts b/tests/registry/jsr/@std/path/0.220.1/posix/_util.ts index b446155df5..ff4f87c2aa 100644 --- a/tests/registry/jsr/@std/path/0.220.1/posix/_util.ts +++ b/tests/registry/jsr/@std/path/0.220.1/posix/_util.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright the Browserify authors. MIT License. // Ported from https://github.com/browserify/path-browserify/ // This module is browser compatible. diff --git a/tests/registry/jsr/@std/path/0.220.1/posix/join.ts b/tests/registry/jsr/@std/path/0.220.1/posix/join.ts index 625762ab97..85bfb63794 100644 --- a/tests/registry/jsr/@std/path/0.220.1/posix/join.ts +++ b/tests/registry/jsr/@std/path/0.220.1/posix/join.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // This module is browser compatible. import { assertPath } from "../_common/assert_path.ts"; diff --git a/tests/registry/jsr/@std/path/0.220.1/posix/normalize.ts b/tests/registry/jsr/@std/path/0.220.1/posix/normalize.ts index 8e88ad254b..40ccc59412 100644 --- a/tests/registry/jsr/@std/path/0.220.1/posix/normalize.ts +++ b/tests/registry/jsr/@std/path/0.220.1/posix/normalize.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // This module is browser compatible. import { assertArg } from "../_common/normalize.ts"; diff --git a/tests/registry/jsr/@std/url/0.220.1/join.ts b/tests/registry/jsr/@std/url/0.220.1/join.ts index b9c8f19d31..b1f42a0a97 100644 --- a/tests/registry/jsr/@std/url/0.220.1/join.ts +++ b/tests/registry/jsr/@std/url/0.220.1/join.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // This module is browser compatible. import { join as posixJoin } from "jsr:@std/path@^0.220.1/posix/join"; diff --git a/tests/registry/jsr/@std/url/0.220.1/normalize.ts b/tests/registry/jsr/@std/url/0.220.1/normalize.ts index e8d728435b..f9d89dd8f9 100644 --- a/tests/registry/jsr/@std/url/0.220.1/normalize.ts +++ b/tests/registry/jsr/@std/url/0.220.1/normalize.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // This module is browser compatible. import { normalize as posixNormalize } from "jsr:@std/path@^0.220.1/posix/normalize"; diff --git a/tests/registry/npm/@denotest/augments-global/1.0.0/import-meta.d.ts b/tests/registry/npm/@denotest/augments-global/1.0.0/import-meta.d.ts new file mode 100644 index 0000000000..9dbe976c2f --- /dev/null +++ b/tests/registry/npm/@denotest/augments-global/1.0.0/import-meta.d.ts @@ -0,0 +1,3 @@ +/// + +export type Foo = number; \ No newline at end of file diff --git a/tests/registry/npm/@denotest/augments-global/1.0.0/index.d.ts b/tests/registry/npm/@denotest/augments-global/1.0.0/index.d.ts new file mode 100644 index 0000000000..f4e31e06dd --- /dev/null +++ b/tests/registry/npm/@denotest/augments-global/1.0.0/index.d.ts @@ -0,0 +1 @@ +import "./other.d.ts"; \ No newline at end of file diff --git a/tests/registry/npm/@denotest/augments-global/1.0.0/other.d.ts b/tests/registry/npm/@denotest/augments-global/1.0.0/other.d.ts new file mode 100644 index 0000000000..91dd7fa2d2 --- /dev/null +++ b/tests/registry/npm/@denotest/augments-global/1.0.0/other.d.ts @@ -0,0 +1,6 @@ +export {} +declare global { + interface Array { + augmented(): void + } +} \ No newline at end of file diff --git a/tests/registry/npm/@denotest/augments-global/1.0.0/package.json b/tests/registry/npm/@denotest/augments-global/1.0.0/package.json new file mode 100644 index 0000000000..a63e420d68 --- /dev/null +++ b/tests/registry/npm/@denotest/augments-global/1.0.0/package.json @@ -0,0 +1,13 @@ +{ + "name": "@denotest/augments-global", + "version": "1.0.0", + "types": "./index.d.ts", + "exports": { + ".": { + "types": "./index.d.ts" + }, + "./import-meta": { + "types": "./import-meta.d.ts" + } + } +} \ No newline at end of file diff --git a/tests/registry/npm/@denotest/augments-global/1.0.0/real-import-meta.d.ts b/tests/registry/npm/@denotest/augments-global/1.0.0/real-import-meta.d.ts new file mode 100644 index 0000000000..06875eeef3 --- /dev/null +++ b/tests/registry/npm/@denotest/augments-global/1.0.0/real-import-meta.d.ts @@ -0,0 +1,8 @@ +interface ImportMetaEnv { + TEST: string; +} + +interface ImportMeta { + env: ImportMetaEnv; + bar: number; +} \ No newline at end of file diff --git a/tests/registry/npm/@opentelemetry/sdk-metrics/registry.json b/tests/registry/npm/@opentelemetry/sdk-metrics/registry.json deleted file mode 100644 index 1e55892f95..0000000000 --- a/tests/registry/npm/@opentelemetry/sdk-metrics/registry.json +++ /dev/null @@ -1 +0,0 @@ -{"_id":"@opentelemetry/sdk-metrics","_rev":"32-fd2f541de5aecbe413589147b6cc22fc","name":"@opentelemetry/sdk-metrics","dist-tags":{"next":"1.8.0","latest":"1.28.0"},"versions":{"0.32.0":{"name":"@opentelemetry/sdk-metrics","version":"0.32.0","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@0.32.0","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"463cd3a2b267f044db9aaab85887a171710345a0","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-0.32.0.tgz","fileCount":480,"integrity":"sha512-zC9RCOIsXRqOHWmWfcxArtDHbip2/jaIH1yu/OKau/shDZYFluAxY6zAEYIb4YEAzKKEF+fpaoRgpodDWNGVGA==","signatures":[{"sig":"MEUCIHBrzbDjk66vVi3mOQOqt4aIRr90QWqLXe7z6pqSOS6GAiEAxRW5Nt/5Uo5aJhfbXMPZUZSd1f5UYsLkrC5WVFl9u0o=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1364783,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjBmODACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqU5Q//X8u5PAiNpAJrFIXflu/338sR9oMsluNoiuoPba0zw6ikiPUv\r\nXCYlQMw1XBSE63X2CVpSDakAhG4WtkWXbsi2zRCfOLUze5CuQPf+TqikvwM/\r\nFOGeHl67KjYw20u1K0H0kxB1qAsBQNBV0lWIM8aF6Yty2J05kP7dACmT6o4v\r\nUn6n2+fjQFMlhRA0WeCrEk+6usmFQDBaZSieZofKGm9C3KCeasPZRfnAJZq3\r\nQvbINhGXDOfFdXrwQPNRqZEIDI5/9frr9dJuRsL+h59AEBizdkezofZGvJPr\r\n860MZqidZhyrzC8NBpodJK0sGxQutbssmSKDT2dptVEd9jjj7mj7iKhNPEFy\r\ntUQDgD/4ltCoLyqraDQi+twaE9gFDhol6EwwdRTIMV8pvazMXFuQ1ik6lsC8\r\nPMt4UDYjtOwDkOGqOjtK/AebAOkJWhoEOuz3znl4VAowL5+qPblVRUEOm7HY\r\nKM/I5DEJltVpWJymDlvRNyvN/ysah+p3b6QtAz5ZcXlipFBh/qFozY7GpemB\r\nIHNryYjSZiAvRCsbnWgHsNg2dIDHJQvN440q6cWfX49Hs03r1rYuKlJjkBpy\r\nFFxrzMAoUejzJ/4j9lVc0rfacQrIoUtQ+j4uLJVPCqy4BPk1LMTnyWY16zb4\r\nIvRTJJH4pe1bz0ucrcj7GawkrVRaoxvNO2U=\r\n=wJDK\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"a5abee69119cc41d9d34f6beb5c1826eef1ac0dd","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.all.json","watch":"tsc --build --watch tsconfig.all.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../../","compile":"tsc --build tsconfig.all.json","version":"node ../../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../../scripts/version-update.js","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/5.4.3/node@v14.18.1+x64 (darwin)","description":"Work in progress OpenTelemetry metrics SDK","directories":{},"_nodeVersion":"14.18.1","dependencies":{"lodash.merge":"4.6.2","@opentelemetry/core":"1.6.0","@opentelemetry/resources":"1.6.0","@opentelemetry/api-metrics":"0.32.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"10.0.0","sinon":"14.0.0","rimraf":"3.0.2","codecov":"3.8.3","ts-mocha":"10.0.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"9.1.1","@types/sinon":"10.0.13","karma-webpack":"4.0.2","@opentelemetry/api":"^1.0.0","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":"^1.0.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_0.32.0_1661363075429_0.18961817621798693","host":"s3://npm-registry-packages"}},"0.33.0":{"name":"@opentelemetry/sdk-metrics","version":"0.33.0","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@0.33.0","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"c4e51decc6e3bb0e1e97c7b081955d357e46c2fe","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-0.33.0.tgz","fileCount":489,"integrity":"sha512-ZXPixOlTd/FHLwpkmm5nTpJE7bZOPfmbSz8hBVFCEHkXE1aKEKaM38UFnZ+2xzOY1tDsDwyxEiiBiDX8y3039A==","signatures":[{"sig":"MEUCIBeHiozEczRdIpEbB1UwgCro3jj+tB2iGk+FQ+CZuc3LAiEA97t2teODixmkZuRZk4z+IPqaULq8SBNRrV8c3JVlTys=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1425603,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjJGjCACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrNERAAjSfh3/c433lR4GMa9u1DjMIVy7MYOZe0YftxnQ9VPGs2jgfa\r\nWC4r/3Qbantsq49xoVj8GjmiZnIrhzm833P8L7lNLes8LDtI8TEbv+6SPfsq\r\nRLBvUdPHww4UlbfShEo5hnGXVIC3qudVRlvGv2DKxFD9AF2QZszGKsrNQ+P8\r\nB5A/lWp4dqY+IhB0xMk3y7asdEggiF/isxMsCGhNFpDiyL8iHQWuW3ylt5pq\r\nZmPLY23ax1kWkTSvj7Us9X7tgIjGuGgzU+cBSf29WI0L2gyVu5TBBRk5NY5x\r\nryXCnzi1MoNdY669ToCEVcCxJoWb4DY9Mg2ihhJq2argdUPzwEBThC1EecAP\r\nJ/786fw+PKmQAzKGVGEXRmDZljF4+3Zk/KIujlHZK7RP6h1kaMCRAKYwnBLT\r\nR9v3W4ljHnbPgV0OmX+W0suV8oEoYtIJxe/7yyznWsLxcndndZq6WFqzcJQN\r\nVdPk6kxtXdSx7hzcnn1CXxckq+fiG0EdZX32ZRGEi1X4EXmTeNL8s2CMiVUl\r\ndGQm+vbP517Nj2oQvOcnO+YSf55XGNtv49cbusZ8JHVGQhHE26HXCK6A2ci1\r\nhEgPOMtjRH43f3kncjdQXW/vTsS/vMiacwyM94686CkEOaJJNnTv8R2DlV2s\r\nkvO54QGc0KDggcsxEqzpfo9OuQEFKWUe0lU=\r\n=fhUv\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"ad88c3d9aa0100fe259b93f4b660e84417b757ac","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.all.json","watch":"tsc --build --watch tsconfig.all.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../../","compile":"tsc --build tsconfig.all.json","version":"node ../../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../../scripts/version-update.js","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/5.4.3/node@v14.18.1+x64 (darwin)","description":"Work in progress OpenTelemetry metrics SDK","directories":{},"_nodeVersion":"14.18.1","dependencies":{"lodash.merge":"4.6.2","@opentelemetry/core":"1.7.0","@opentelemetry/resources":"1.7.0","@opentelemetry/api-metrics":"0.33.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"10.0.0","sinon":"14.0.0","rimraf":"3.0.2","codecov":"3.8.3","ts-mocha":"10.0.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"9.1.1","@types/sinon":"10.0.13","karma-webpack":"4.0.2","@opentelemetry/api":"^1.0.0","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":"^1.0.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_0.33.0_1663330498049_0.15542963522751552","host":"s3://npm-registry-packages"}},"1.8.0":{"name":"@opentelemetry/sdk-metrics","version":"1.8.0","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.8.0","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"d061060f03861ab3f345d0f924922bc1a6396157","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.8.0.tgz","fileCount":489,"integrity":"sha512-+KYb+uj0vHhl8xzJO+oChS4oP1e+/2Wl3SXoHoIdcEjd1TQfDV+lxOm4oqxWq6wykXvI35/JHyejxSoT+qxGmg==","signatures":[{"sig":"MEYCIQDsOqqaWHTqJVYLyeRb+ZNiGkJbd34UCyCqyHX6UgwbCAIhAMvGlF7I5klQng1omsJ/Nk8Nzz0TlqjJqpvJj76kcBV2","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1416962,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjbANeACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqikQ/9EWJ03wBF//CwkzW46y4mBkSgukPe+k9sfS4+cd4/+nErVF2O\r\nMTKRhSpoDQcVLBdmTfeaObKRmgYg2p3PeOrGPphcfkEmZjrRv6342ubUWjRW\r\nm39DSPq8NmZp7J5hRf2hLYSg6tXKZnflCmj+T8upYC/KmW7kOKtx/B3tTy7c\r\nq6q1Kc6vBToqid7yNdFLsIYTjVHM8xSvtg0QVx84S6mtzR2iO8uAzL3ucu34\r\nfLXyN2MzbqJIO516Jt1vE0ix9q/xmt7TrbqCi5k5yZ8cIOianx1Yl7MFGOAX\r\nKwaGILDNoBnb7c8mQITWnP286rsO4NMNnBoXt7ZJCmIavKe8XlbxFZAwuM/q\r\nl0bC9nG8l4r+182xF5XKV2/wnRPQ3j8+uQyBx/8+7YGoIVbowgd4GvJEZGRm\r\n83hxM4/xGxmHiWbkngJlyspY7s86o1MTuwPgwns73cgAhNZsuti2SVgtdoFc\r\n4prfRtGRXUtHJkBQMItiPDEG+Mnfq9hBxHh2F1zuvDLzyN93nCs22gBY79jT\r\n33kticfFECGRLhuCIhZIuV+yzBu4ciYXk0fg9hMY6wagCqQ+tPRs4HPqO92f\r\nuVGhapMpKJPclhvOvlbY4d4Ixm4mo5rrnJx0BPkn445hV6JwJbUC3PAU9yPp\r\nJhIpEHNdZQc8ntThHRpYRCSBmecy8YkzSdo=\r\n=haC6\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"7972edf6659fb6e0d5928a5cf7a35f26683e168f","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.all.json","watch":"tsc --build --watch tsconfig.all.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.all.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/5.4.3/node@v14.18.1+x64 (darwin)","description":"Work in progress OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"14.18.1","dependencies":{"lodash.merge":"4.6.2","@opentelemetry/core":"1.8.0","@opentelemetry/resources":"1.8.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"10.0.0","sinon":"14.0.0","rimraf":"3.0.2","codecov":"3.8.3","ts-mocha":"10.0.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.0","@types/sinon":"10.0.13","karma-webpack":"4.0.2","@opentelemetry/api":">=1.3.0 <1.4.0","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.4.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.8.0_1668023134085_0.198580524230221","host":"s3://npm-registry-packages"}},"1.9.0":{"name":"@opentelemetry/sdk-metrics","version":"1.9.0","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.9.0","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"1c3a51abeb7f45ea25b91daf7e05e43d25ddd20a","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.9.0.tgz","fileCount":489,"integrity":"sha512-fSlJWhp86kCan1zuxdH6LTyUBYlohQwDKnxep5qHMnRTNErkYmdjgsmjZvSMdAfUFtQqfZmTXe2Lap7a5AIf9Q==","signatures":[{"sig":"MEUCIGoaNR3oyipKjYbn2fxyiZ4BKdIFiSOmx699LRzKo0vWAiEAyTvGUxH0WbB1bXUpv9AlkibTlQ51uAHPzOa9yFD7L7A=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1432686,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjvy41ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrSjg//czBDsjkHKhMQ+UP70UHKKTG+xRRSxL0WB8vcvSu2U1VFJldP\r\nBiEOUKKfXMNMTlwB6fuo8mdBnwT/Pn6rmbYyW30mkRtc0n9rpakFtdvASSUg\r\nSsLAROHI+NpaNG3lygIpwXu6wLNGzh1ejL8/1/sfRFKBZIGlb/4l9eHtLj8z\r\nNEZ2r0IAOVOQ2JWnMon0gSM1yjplES4pF30tt5j+UeJbNqgbu9CxD8mUOt/E\r\nV4KT3XawHrjMB5VmPlUhZ66OwbF4P7dZF3ukETA/ezK2XBQeUBBNCiJbW6C0\r\np6WdlJZ/1chyseR9hKiBm8bOrx9XQlNcKyM8brOL9G0joCa/YDX12z0lK5xg\r\nlv/As+8IcQUBkcMsBnzl/BVZUnVQ/qacyWXsYpuMmSCfCOCcCAfLXP/kkVDG\r\nNtNpb3RWySMTuqhYBNxQ2wSBmu0TnXxc3y7ubWfqVNh8SJu9kLZQo8fRFyrM\r\nrVATAIjhFPpZAGBeDca3YHuElfFhXdxtklvHX4ATh3yN0DlVqaaWxQXp6W/I\r\n671fbqRQWCy29YlLoS7k4WR8CGkvNFPYedOgIPinE/g3Qv4oTF0z8vcFYI9G\r\nP2PyfHSre1bHm/5rTIiB9xWEK+XUb+9uV/33gGfTkZqz+6oGd4E0pg9q16cy\r\nEZrSABE83nfpxgpbmLMjACClgyQWshGNr4I=\r\n=qh/2\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"08f597f3a3d71a4852b0afbba120af15ca038121","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.0.3/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"14.18.1","dependencies":{"lodash.merge":"4.6.2","@opentelemetry/core":"1.9.0","@opentelemetry/resources":"1.9.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"10.0.0","sinon":"15.0.0","rimraf":"3.0.2","codecov":"3.8.3","ts-mocha":"10.0.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.0","@types/sinon":"10.0.13","karma-webpack":"4.0.2","@opentelemetry/api":">=1.3.0 <1.5.0","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.9.0_1673473589677_0.62979083795101","host":"s3://npm-registry-packages"}},"1.9.1":{"name":"@opentelemetry/sdk-metrics","version":"1.9.1","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.9.1","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"babc162a81df9884c16b1e67c2dd26ab478f3080","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.9.1.tgz","fileCount":543,"integrity":"sha512-AyhKDcA8NuV7o1+9KvzRMxNbATJ8AcrutKilJ6hWSo9R5utnzxgffV4y+Hp4mJn84iXxkv+CBb99GOJ2A5OMzA==","signatures":[{"sig":"MEYCIQCYUyFLpMVK/wDHg6lU87nZ3MQB9nQh8JvM/VryTCdksgIhAKZDK2iXOPbTaQ6GOK3qt6u560bXhXh+VmFjYH9uiaHo","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1556782,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj1+KFACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmpp3w//cVciehkq5CKoOUjcEovwgleHJd+eCwOEc40/05fiVn6NmDuW\r\nHAs1UekoxG9cc+MHhvp/38o5o1WFK2sFGXO7ymvMluXheGXx7nI6U+qnqkb9\r\nWWvI53gNcfN5GUgJGarHX6kt+DoyV5+0ig0R/2U37hk6DWm89kZArd+X8xEI\r\nD+2GADx/m1uTUO/PJnaJ8LB1LLK2SJ2vQmViYTP8icykDzIJT5flZyBeb+hk\r\nRqgaFcx7Qa+XecZIjTUXfY5ZQCOc5IYf3JAVea/0kAosP63vSaK9TU+p4GG6\r\n4mYBEANc4Inn4ocav0UoYb5kDNntNo/wAusSI4gH/sByMaQhW/EGy9qmKTA+\r\nKpsIPqZO/FPXZEUJZsEUBOD7GxGp8rUB38JEvW3d3ACDFPfVl/AAuIJ4wipt\r\nM4cKsHtewTdDbDGrkO7o9EDG+OACTTBbvAQ/vxWoC8lDZ+vVWbc0pT+taLcs\r\nlimhIk0XDHJGZ+vxL/T7ib0nOCE1qgt6TL5F0Mmx/Juen4Go2NhOa9dbZG1Y\r\nSI6b/SXe5izJQR6vGhyx2mo3OOXrBQmQc/jjcJbwaRRzLshUY/GmZeqrsPLO\r\n91kJNQIUfFRZLhY0tLPlUaYoFjUY+HL4d0RHWKxLoenZ1POPTBwbrfTpwTRD\r\nOTqOB4P/zL3AutUyuX+FOPevSBguIKxq7wA=\r\n=AXfq\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"279458e7ddf16f7ddca5fe60c78672e05fafce66","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.0.3/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"14.18.1","dependencies":{"lodash.merge":"4.6.2","@opentelemetry/core":"1.9.1","@opentelemetry/resources":"1.9.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"10.0.0","sinon":"15.0.0","rimraf":"4.1.2","codecov":"3.8.3","ts-mocha":"10.0.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.0","@types/sinon":"10.0.13","karma-webpack":"4.0.2","@opentelemetry/api":">=1.3.0 <1.5.0","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.9.1_1675092613192_0.7361446399809115","host":"s3://npm-registry-packages"}},"1.10.0":{"name":"@opentelemetry/sdk-metrics","version":"1.10.0","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.10.0","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"627f164036ad053551b3e75447adf9a902b066aa","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.10.0.tgz","fileCount":543,"integrity":"sha512-vOB3khvj894ppOwafNqKNavpChZYR2S2IZyy8PmL0DwNgFPGYwkWxZkv7YJduBNzcCd+Ao+ug93jdSFFhnpIhQ==","signatures":[{"sig":"MEUCIQDL/qHYi9VPBH3poMg/gvlnmTAxuK7zGkYo7FXRK1XAMgIgPAiYWDmawt1pshH1UtUsHcw9izgXdV8pWQMROlpkKEQ=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1571910,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkD0cTACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpZ/w/9G8OISP56mEsFRcrjWT+zXdW4zgKR3RBzQcZ+RjfqhV2Gq51K\r\nkwhYJ/bIk/xXtSJkpZ+gHjQIy1lwNXU9ux62RcZXzO/EcDLEg1aDDBD+d7G4\r\naYN81H49JVfrstGQzxduGK1vamLm2EBg0PbQGK7r8oNiNkK/Rt+qRY0ZYi6f\r\neYFhc8Nvbh9MKquBU21z/En/IhrxlbUQyetJ0TKfoonVsoj9VK1F7BBf/7cD\r\nYirI9GZzNKfk+y3IPmQ3aalntJmoN+aWWGYFn3hbE2IIo48N1EOkv3ZPXLwm\r\nHIaEN4MbK1vIjbjaS0LHC6lWYDooa5GCvVEXSl1ZJimyIpdx3FV5z0mVgusJ\r\nyb2PuPPm2okM7FM4xg0sDOqajIBbTy253Q8F+dqEBiZah1ELX/HTXV+3TG8l\r\nUJjlP6oE1CQwW43F+o46Pmf9eF0qi3pPEPwFpuX6JQfnWgWrAgR4LAhAh1UA\r\nhbVTVTBixGvNCZFvMh8Irbj3DNz/6pj2h5akehMBbaENpKj8g8Ij/tFIH7ho\r\nVXKGbDTUrnJPAcm4q1lghjiuBOgvJ3mZxacCayI+5daZBpL1rzXp9TrMSZqq\r\nsk5NuYgpfwBunGAjyeH3J4BirEKMUQElOKUr0oPvGYz11Rz6cs2Xa3U679q6\r\nZ7ZlwIHa3hghQeF62mlagpDWNJ1MweZb3zU=\r\n=fjdK\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"56e6b1bb890f844b8963a146780d0b9cfa8abd0d","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.0.3/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"14.18.1","dependencies":{"lodash.merge":"4.6.2","@opentelemetry/core":"1.10.0","@opentelemetry/resources":"1.10.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"10.0.0","sinon":"15.0.0","rimraf":"4.1.2","codecov":"3.8.3","ts-mocha":"10.0.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.0","@types/sinon":"10.0.13","karma-webpack":"4.0.2","@opentelemetry/api":">=1.3.0 <1.5.0","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.10.0_1678722835367_0.34217119288271447","host":"s3://npm-registry-packages"}},"1.10.1":{"name":"@opentelemetry/sdk-metrics","version":"1.10.1","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.10.1","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"1389a8524ba59dc2e1d9cf627d504119c111fca1","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.10.1.tgz","fileCount":543,"integrity":"sha512-ARAD4e6lZhLwstwW+1HG2Q3XuYFA/t8vn10KK/mA4em1pZYKFn64c45RJZJcntxWp4wOZRbp9iL1RXsg7zIjow==","signatures":[{"sig":"MEQCIF7l8lYSyGXYbwwaiNKB4rSrfukNeC9FI7PrmRetWSCaAiAEvWmV3Mebg7p+TvQxAN44ZzolcH3+uz+10I6dLs+2BA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1571910,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkGIV6ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrjQg//V5N9A3eIarDzrRPXxYMuJ3TO2qYzZxGLjCSbFBab/UFBKK2g\r\n4KS7ImLvfoP7k9S5xKMEQlCgG+0dGWt3SFELbhpLmwjVPM7OUcfF+es8dfAE\r\nQC6aLfq5juKIz/hcNBUGPZfauUQqReb+KptJUlCfvIW1RUi12dCoXSLm89/r\r\nXOUbhsIo3v+Lj5HBvn4lIl/3iJ07SaB3ehaVtypnSmpcgl2sWyMv77USvagd\r\nENNV4IbUFYM9YRnMFCWgSxtZtFDKmkLypkvUyu9jepecvgbXT+J4Z8hl6zgo\r\nv2Sqbi5PjkY035ZgSHqQ09yHGg5azUwn8AN0Yecqq88Mrqt35As1kdJLvrXg\r\nDK5lDQaxPqtaMSzLAg34Ck/Cng8HANjiKGaRA5ITCuJhoVMRt9va+mHscMwv\r\ngdfkJHKyq3wlGPZAvroDkljKROic2cYZv35zSwHXAoQ1PxYgEvbtxYDxsxPk\r\nSv5azrVgUBpKBM33EE+MMQ3AeizxdjCHnl8mPgv5u4C26MfdEd5f8cOKt9BS\r\nlhvukjFyU9DjoyMypt+LZWjWz1WVxircRPkXwSQa7t2FIGSV5XHL5nHSrBt4\r\nam5WwdCTJntt5jdeiL5RHN0myvOBDPB10G9ZoaogPjGUIXJK/XERuVD4/e9w\r\nJMVSLW8zW0CgZaAGWoaA4KhhW2OYXC/OdUk=\r\n=O4i4\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"486df99906958de9b8b666839785b00160a6a229","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.0.3/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"14.18.1","dependencies":{"lodash.merge":"4.6.2","@opentelemetry/core":"1.10.1","@opentelemetry/resources":"1.10.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"10.0.0","sinon":"15.0.0","rimraf":"4.1.2","codecov":"3.8.3","ts-mocha":"10.0.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.0","@types/sinon":"10.0.13","karma-webpack":"4.0.2","@opentelemetry/api":">=1.3.0 <1.5.0","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.10.1_1679328634706_0.9289571491726534","host":"s3://npm-registry-packages"}},"1.11.0":{"name":"@opentelemetry/sdk-metrics","version":"1.11.0","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.11.0","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"0fe347fb39a802ec270315cba0eba2e3ce64c4a2","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.11.0.tgz","fileCount":561,"integrity":"sha512-knuq3pwU0+46FEMdw9Ses+alXL9cbcLUUTdYBBBsaKkqKwoVMHfhBufW7u6YCu4i+47Wg6ZZTN/eGc4LbTbK5Q==","signatures":[{"sig":"MEUCICcPE7ow3GH80M4VwObQJPDkCO3SK4VTYmZkd1STJ+uZAiEA35ZtKgFt5GMZa3WnCxdCI7yWWkwAk9QYu88ktlLJYVk=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1839857,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkJaswACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmrzcg/9FdLBYGIFXRPNUEc+CsQRabaC90KOwOp+7HV39/LXozs0FSB1\r\niKe3uUkfFBCLhcRSCQns1EVifv+Xda02Wa/Y0r28uhKc1y/N7uGQWLFpR7Iu\r\ngVVKTxpLt2QPsTYyQuuj4a6XGpGk7frKzv+uss7ByMKXUsC7YmzMS1DUJt+4\r\nekB8LXK7MEMrsN1ze0pp9+r9KTPGMDQXT9I64a/AuWR7IhM4RuPqjpriq/7R\r\nV38kOjgp4I6uj1H4hAB3FQ1NwdVOSajrDQ2HHLUvT4lv22LKIABQr0TDtQsN\r\naJq9rK7IfWSAE5zj5q9t8VfpNkhph3pFPPgg/l1Mnryr+VYhvErInyIuuPcM\r\n6X3csId2wFKauJR4oSXTLDxE6IMfvPk1ln2aXe3u/bSDrjEkd8bJvAS45yhW\r\n8JxegGRcA3SMuTtJcy85S6mVc/rksLjDSGDGpBaL4eYnR1qQ1hGYLljdpbuy\r\nbDRNcL2ZERMu3CmmXsFEmDqfTdFaMIzGTXXN20+ti6HtcBL9WFsKgVudxD5O\r\nTU40gKMtkAc+kfQ7cheqj+WjbH6ED0dPA7BHCE8Mo7kQTuGCVR1pMZZHh50h\r\nb/CaOKc7PCzVltN0PRnNPouwHzSM00LFqU4O2dvfnDkM6yyNJ86Je01ls6Fu\r\nQooqG9QlA64TxWqtWwXfGRY/w5p7wZSrXrE=\r\n=KFj4\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"1328ee04ae78f9f6cf143af7050c00aaa6d2eb3b","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.0.3/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"14.18.1","dependencies":{"lodash.merge":"4.6.2","@opentelemetry/core":"1.11.0","@opentelemetry/resources":"1.11.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"10.0.0","sinon":"15.0.0","rimraf":"4.1.2","codecov":"3.8.3","ts-mocha":"10.0.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.0","@types/sinon":"10.0.13","karma-webpack":"4.0.2","@opentelemetry/api":">=1.3.0 <1.5.0","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.11.0_1680190255856_0.4488883258029981","host":"s3://npm-registry-packages"}},"1.12.0":{"name":"@opentelemetry/sdk-metrics","version":"1.12.0","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.12.0","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"52c135b8ca6af677a3e93b6721bc866a74c98b4b","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.12.0.tgz","fileCount":561,"integrity":"sha512-zOy88Jfk88eTxqu+9ypHLs184dGydJocSWtvWMY10QKVVaxhC3SLKa0uxI/zBtD9S+x0LP65wxrTSfSoUNtCOA==","signatures":[{"sig":"MEQCIEAfZBHAMQVNInXN1E0ihfClv5NylKPFc0jrD34SRJMvAiBzpMnq2Iu5C00sNF1GPtmv10V2RrlKn7msJG8pBtnd5g==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1839857,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkOEYtACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmobXQ/6AsboU2mCpdhs/tPwnXUqcjmoBV3/aVWoXwM22/jxCszCX8vk\r\nRFoTQHvvMZOMjqOLOPW2S3U2sPumqm7tj7V2aT/tVoZ7En09afYCbKO1fClj\r\ndtm9zB4H/GeL9uT4j8E7mFzPGMkgl/Wo8xZzrifKGknDwoO5sITFwXYCb1XI\r\nVprJn7eNMQEeMuGNd8WG2SFiI+VwVDfRz9eCmaI6ozABBw+Xd/Ae2SzPRfqo\r\nlbV46b6MN47oJHPNNjvPDPpQ8PUu+usZ2CZZR0/DYvHryjJnsTEaBOEqefXl\r\nvL7ommVdZW6DNSzMEQ5k4DQIMIHrvYYL/j8Cwkl7UcpmzrXgWoHNfQLlP3zk\r\nOqHvW+AEAYeiAs1ZrLRwNId+SpdNdERohMR70BxyU1ZXXx6NcpzJv6V+a+4q\r\nrtfX4oazI7rldM1BHO3sJM3g0cCyUtllFGTb5Mg8EI1qXBZppQF33jLvj20n\r\n4Ulb6wpsteaDDlBOK1TmN0s8VftM4ekrz2b5+UvE5yYq7RX+FVRFWb8U5xiZ\r\nHRc/5H4txVGZXLFvmSCJm6WmzUy83njG0qSF3wS6dOetNRXlrJrhS0tnHBqM\r\nnC4RbTqtdrp4EDi4F521hcdm6uo2cAmCxHbVhwgL+3lM2me9VmAtxB/BJacp\r\nvupg+95/zDYgsEWSTaFE/0t7TGuFe0UJ9j4=\r\n=5rhT\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"a04090010ee18e17487b449984807cc2b7b6e3e6","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.0.3/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"14.18.1","dependencies":{"lodash.merge":"4.6.2","@opentelemetry/core":"1.12.0","@opentelemetry/resources":"1.12.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"10.0.0","sinon":"15.0.0","rimraf":"4.1.2","codecov":"3.8.3","ts-mocha":"10.0.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.0","@types/sinon":"10.0.13","karma-webpack":"4.0.2","@opentelemetry/api":">=1.3.0 <1.5.0","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.12.0_1681409581531_0.31698151736882196","host":"s3://npm-registry-packages"}},"1.13.0":{"name":"@opentelemetry/sdk-metrics","version":"1.13.0","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.13.0","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"4e859107a7a4389bcda7b37d3952bc7dd34211d7","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.13.0.tgz","fileCount":561,"integrity":"sha512-MOjZX6AnSOqLliCcZUrb+DQKjAWXBiGeICGbHAGe5w0BB18PJIeIo995lO5JSaFfHpmUMgJButTPfJJD27W3Vg==","signatures":[{"sig":"MEYCIQCUeO+qPBpw+CVNlqlTfDO++08VfOb0W3UdO9pIYolUCAIhAJH6JOYZuj9SxAwhyK86XMhqrxGloVuk7E7pzmTPdjJr","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1839834},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"8fc76896595aac912bf9e15d4f19c167317844c8","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.0.3/node@v18.12.1+x64 (linux)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"18.12.1","dependencies":{"lodash.merge":"4.6.2","@opentelemetry/core":"1.13.0","@opentelemetry/resources":"1.13.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"10.0.0","sinon":"15.0.0","codecov":"3.8.3","ts-mocha":"10.0.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.0","@types/sinon":"10.0.13","karma-webpack":"4.0.2","@opentelemetry/api":">=1.3.0 <1.5.0","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.13.0_1683811806809_0.022001801192962578","host":"s3://npm-registry-packages"}},"1.14.0":{"name":"@opentelemetry/sdk-metrics","version":"1.14.0","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.14.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"ee51d72eb32a74108e6632681ce2df46cddc0714","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.14.0.tgz","fileCount":561,"integrity":"sha512-F0JXmLqT4LmsaiaE28fl0qMtc5w0YuMWTHt1hnANTNX8hxW4IKSv9+wrYG7BZd61HEbPm032Re7fXyzzNA6nIw==","signatures":[{"sig":"MEUCIQDZy6AZC4gsrIqvrLyc0L21UL/+PakTzlDTNsuwjRpDhwIgMSf9ZJoCKDB8uD708TqJtggoPZ9cpVP/LIthheTWDWM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1839834},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"edebbcc757535bc88f01340409dbbecc0bb6ccf8","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.0.3/node@v18.12.1+x64 (linux)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"18.12.1","dependencies":{"lodash.merge":"4.6.2","@opentelemetry/core":"1.14.0","@opentelemetry/resources":"1.14.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"10.0.0","sinon":"15.0.0","codecov":"3.8.3","ts-mocha":"10.0.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.0","@types/sinon":"10.0.13","karma-webpack":"4.0.2","@opentelemetry/api":">=1.3.0 <1.5.0","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.14.0_1686031255514_0.6205545095237606","host":"s3://npm-registry-packages"}},"1.15.0":{"name":"@opentelemetry/sdk-metrics","version":"1.15.0","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.15.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"e47ad688882fc2daedcbbe3db16a5c110feb23e8","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.15.0.tgz","fileCount":561,"integrity":"sha512-fFUnAcPvlXO39nlIduGuaeCuiZyFtSLCn9gW/0djFRO5DFst4m4gcT6+llXvNWuUvtGB49s56NP10B9IZRN0Rw==","signatures":[{"sig":"MEQCIA6mPFnkdT47rCrHsCh4ePv+jy+q7abH27EHpIw2DKE0AiB9rZUo59MjzXY9Uih4EbPVSQZ5I/uFRmYTdzVsP7a68g==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1803014},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"06e919d6c909e8cc8e28b6624d9843f401d9b059","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/7.1.1/node@v18.12.1+x64 (linux)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"18.12.1","dependencies":{"tslib":"^2.3.1","lodash.merge":"^4.6.2","@opentelemetry/core":"1.15.0","@opentelemetry/resources":"1.15.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"7.1.1","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","ts-mocha":"10.0.0","cross-var":"1.1.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.1","@types/sinon":"10.0.15","karma-webpack":"4.0.2","@opentelemetry/api":">=1.3.0 <1.5.0","@types/lodash.merge":"4.6.7","karma-spec-reporter":"0.0.36","karma-chrome-launcher":"3.1.0","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.15.0_1688642828881_0.612950022765163","host":"s3://npm-registry-packages"}},"1.15.1":{"name":"@opentelemetry/sdk-metrics","version":"1.15.1","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.15.1","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"e0d2844191ecd7fce3fccf18ae50ed35389f0885","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.15.1.tgz","fileCount":561,"integrity":"sha512-ojcrzexOQfto83NvKfIvsJap4SHH3ZvLjsDGhQ04AfvWWGR7mPcqLSlLedoSkEdIe0k1H6uBEsHBtIprkMpTHA==","signatures":[{"sig":"MEYCIQCBwveTbaE79v4tJk8CdBffRh5H6Loc8hSu+ysnZzK1YAIhAMHsh5T/As5lzxnmYm6j7V704gjjvyvEm2CaH1bpx5cO","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1841179},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"9f71800fdc2a5ee5055684037a12498af71955f2","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/7.1.3/node@v18.4.0+x64 (darwin)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"18.4.0","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"1.15.1","@opentelemetry/resources":"1.15.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"7.1.3","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@babel/core":"7.22.9","@types/node":"18.6.5","karma-mocha":"2.0.1","webpack-cli":"4.10.0","@types/mocha":"10.0.1","@types/sinon":"10.0.15","karma-webpack":"4.0.2","webpack-merge":"5.9.0","karma-coverage":"2.2.1","@opentelemetry/api":">=1.3.0 <1.5.0","@types/lodash.merge":"4.6.7","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.15.1_1690209168814_0.4696021233708716","host":"s3://npm-registry-packages"}},"1.15.2":{"name":"@opentelemetry/sdk-metrics","version":"1.15.2","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.15.2","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"eadd0a049de9cd860e1e0d49eea01156469c4b60","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.15.2.tgz","fileCount":561,"integrity":"sha512-9aIlcX8GnhcsAHW/Wl8bzk4ZnWTpNlLtud+fxUfBtFATu6OZ6TrGrF4JkT9EVrnoxwtPIDtjHdEsSjOqisY/iA==","signatures":[{"sig":"MEUCIQCFKX9DaFzjXDXPu/N+lf5A+VZoJEIuX5BlwqR2YxqIPQIgTriFUfsIieNy4ajXosd23GlEnVapJ9nRDMUvRFJYIGk=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1848194},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"48fb15862e801b742059a3e39dbcc8ef4c10b2e2","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/7.1.4/node@v18.12.1+x64 (linux)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"18.12.1","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"1.15.2","@opentelemetry/resources":"1.15.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"7.1.4","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@babel/core":"7.22.10","@types/node":"18.6.5","karma-mocha":"2.0.1","webpack-cli":"4.10.0","@types/mocha":"10.0.1","@types/sinon":"10.0.16","karma-webpack":"4.0.2","webpack-merge":"5.9.0","karma-coverage":"2.2.1","@opentelemetry/api":">=1.3.0 <1.5.0","@types/lodash.merge":"4.6.7","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.15.2_1691500878806_0.21964542929012487","host":"s3://npm-registry-packages"}},"1.16.0":{"name":"@opentelemetry/sdk-metrics","version":"1.16.0","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.16.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"6c413c6abb1d68dbfe59984384d4031feeccbe1e","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.16.0.tgz","fileCount":561,"integrity":"sha512-58obaKzBY0CB6ZQS/sxcGvihqZk2zL2KDCQe734NofVfE7JpKMn/TtyzA8O4nw9sXIO2N9Wx2zzKRyGFXVGrcw==","signatures":[{"sig":"MEUCIGu4l4M/yMtx2D8TpJeVo1nvcoCzRr6o5+wZtJj2W23YAiEAzPdInj1ng6V1HXJhfyT/sRzxXuC3taYmiuKCASO4G2g=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1872545},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"5fcd8cf136e2235903dde3df9ba03ced594f0e95","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/7.1.5/node@v18.12.1+x64 (linux)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"18.12.1","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"1.16.0","@opentelemetry/resources":"1.16.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"7.1.5","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@babel/core":"7.22.17","@types/node":"18.6.5","karma-mocha":"2.0.1","webpack-cli":"4.10.0","@types/mocha":"10.0.1","@types/sinon":"10.0.16","karma-webpack":"4.0.2","webpack-merge":"5.9.0","karma-coverage":"2.2.1","@opentelemetry/api":">=1.3.0 <1.6.0","@types/lodash.merge":"4.6.7","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.6.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.16.0_1694434471320_0.42251452448444704","host":"s3://npm-registry-packages"}},"1.17.0":{"name":"@opentelemetry/sdk-metrics","version":"1.17.0","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.17.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"e51d39e0bb749780d17f9b1df12f0490438dec1a","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.17.0.tgz","fileCount":561,"integrity":"sha512-HlWM27yGmYuwCoVRe3yg2PqKnIsq0kEF0HQgvkeDWz2NYkq9fFaSspR6kvjxUTbghAlZrabiqbgyKoYpYaXS3w==","signatures":[{"sig":"MEQCIEGFsgaNt88vPUiItoys14mI96KUmsfCU3V9/M9zEFrHAiAgibedup1xc0Uh7HFSGEe8a8IEZbYsRxYQhUM7mMJJmQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1872545},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"faf939c77591f709afbc23fadbe629c9d3607ef6","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/7.1.5/node@v18.12.1+x64 (linux)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"18.12.1","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"1.17.0","@opentelemetry/resources":"1.17.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"7.1.5","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@babel/core":"7.22.17","@types/node":"18.6.5","karma-mocha":"2.0.1","webpack-cli":"4.10.0","@types/mocha":"10.0.1","@types/sinon":"10.0.16","karma-webpack":"4.0.2","webpack-merge":"5.9.0","karma-coverage":"2.2.1","@opentelemetry/api":">=1.3.0 <1.7.0","@types/lodash.merge":"4.6.7","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.7.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.17.0_1694524354547_0.27289065421627656","host":"s3://npm-registry-packages"}},"1.17.1":{"name":"@opentelemetry/sdk-metrics","version":"1.17.1","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.17.1","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"9c4d13d845bcc82be8684050d9db7cce10f61580","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.17.1.tgz","fileCount":561,"integrity":"sha512-eHdpsMCKhKhwznxvEfls8Wv3y4ZBWkkXlD3m7vtHIiWBqsMHspWSfie1s07mM45i/bBCf6YBMgz17FUxIXwmZA==","signatures":[{"sig":"MEUCIQC6T+my/2xzI2vaedMangtbqdpdAHiTTnwC85I9zGxvdwIgJwgxV8Jz14/su/N16gkO8rU//itJPXSzxcx7YCPtM6U=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1883659},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"f8e187b473274cc2011e7385992f07d319d667dc","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/7.1.5/node@v18.12.1+x64 (linux)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"18.12.1","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"1.17.1","@opentelemetry/resources":"1.17.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"7.1.5","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@babel/core":"7.22.20","@types/node":"18.6.5","karma-mocha":"2.0.1","webpack-cli":"4.10.0","@types/mocha":"10.0.2","@types/sinon":"10.0.18","karma-webpack":"4.0.2","webpack-merge":"5.9.0","karma-coverage":"2.2.1","@opentelemetry/api":">=1.3.0 <1.7.0","@types/lodash.merge":"4.6.7","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.7.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.17.1_1696947498625_0.4798664177082872","host":"s3://npm-registry-packages"}},"1.18.0":{"name":"@opentelemetry/sdk-metrics","version":"1.18.0","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.18.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"f84fffcabdb0e9504e3b219635c1099aabc9e207","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.18.0.tgz","fileCount":561,"integrity":"sha512-wK5zdNCo5cJvZog/lsqXCg9/Dt9UeNXQsskgqX8Yz+40t13Kb5CKFFkAMU8tNUxkvidHnD6G6sT6xeVCHQYe4A==","signatures":[{"sig":"MEUCIQCMiT/6j2k3CLJNS9PVe/gMQM/shgZfXDwNLg9l7E3QdgIgFnmCSIgxrXYgrtIppJgyKJkGNUzsbBET1HwAZBRXfG8=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1890396},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"73b446688f10fd8dc4cf403a085f0a39070df7b4","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.18.2+x64 (linux)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"18.18.2","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"1.18.0","@opentelemetry/resources":"1.18.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"6.6.2","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@babel/core":"7.22.20","@types/node":"18.6.5","karma-mocha":"2.0.1","webpack-cli":"4.10.0","@types/mocha":"10.0.3","@types/sinon":"10.0.20","karma-webpack":"4.0.2","webpack-merge":"5.9.0","karma-coverage":"2.2.1","@opentelemetry/api":">=1.3.0 <1.8.0","@types/lodash.merge":"4.6.8","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.8.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.18.0_1699353886784_0.2402177673494048","host":"s3://npm-registry-packages"}},"1.18.1":{"name":"@opentelemetry/sdk-metrics","version":"1.18.1","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.18.1","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"1dd334744a1e5d2eec27e9e9765c73cd2f43aef3","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.18.1.tgz","fileCount":561,"integrity":"sha512-TEFgeNFhdULBYiCoHbz31Y4PDsfjjxRp8Wmdp6ybLQZPqMNEb+dRq+XN8Xw3ivIgTaf9gYsomgV5ensX99RuEQ==","signatures":[{"sig":"MEUCIQDZiuGHcrjzMGF/TJ452D+P3TvNuhbyNQDLJOkdYsDPFQIgKtcP2GNoTjs9raH1wfRgj93Kw4tqRy7FLSmt98YetyQ=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1892649},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"f665499096189390e691cf1a772e677fa67812d7","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.18.2+x64 (linux)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"18.18.2","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"1.18.1","@opentelemetry/resources":"1.18.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"6.6.2","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@babel/core":"7.22.20","@types/node":"18.6.5","karma-mocha":"2.0.1","webpack-cli":"4.10.0","@types/mocha":"10.0.3","@types/sinon":"10.0.20","karma-webpack":"4.0.2","webpack-merge":"5.9.0","karma-coverage":"2.2.1","@opentelemetry/api":">=1.3.0 <1.8.0","@types/lodash.merge":"4.6.8","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.8.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.18.1_1699466949698_0.2731195093463463","host":"s3://npm-registry-packages"}},"1.19.0":{"name":"@opentelemetry/sdk-metrics","version":"1.19.0","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.19.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"fe8029af29402563eb8dba75a85fc02006ea92c4","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.19.0.tgz","fileCount":561,"integrity":"sha512-FiMii40zr0Fmys4F1i8gmuCvbinBnBsDeGBr4FQemOf0iPCLytYQm5AZJ/nn4xSc71IgKBQwTFQRAGJI7JvZ4Q==","signatures":[{"sig":"MEUCIQCQbl3KfCIEDQc8lHtdKlCRprXMXq1iqFxWHzS7fhRAMQIgOOpi/ti3SCJMstM0WHGr81bNA0QPpltVs/+OuHKDlyw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1892648},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"d3c311aec24137084dc820805a2597e120335672","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.18.2+x64 (linux)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"18.18.2","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"1.19.0","@opentelemetry/resources":"1.19.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"6.6.2","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"5.89.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@babel/core":"7.23.6","@types/node":"18.6.5","karma-mocha":"2.0.1","webpack-cli":"5.1.4","@types/mocha":"10.0.6","@types/sinon":"10.0.20","karma-webpack":"4.0.2","webpack-merge":"5.10.0","karma-coverage":"2.2.1","@opentelemetry/api":">=1.3.0 <1.8.0","@types/lodash.merge":"4.6.9","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.8.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.19.0_1702557329935_0.360745159718469","host":"s3://npm-registry-packages"}},"1.20.0":{"name":"@opentelemetry/sdk-metrics","version":"1.20.0","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.20.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"472d723d986a0a0cc1ee1170ed086dc18269d7e0","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.20.0.tgz","fileCount":561,"integrity":"sha512-07bFOQUrpN/Q5biJ/cuBePztKwkc1VGkFblZxAcVkuvCLDAPJfsyr0NNWegWeYe0bpGt1jmXScpUWnVD+t8Q0w==","signatures":[{"sig":"MEUCIC3XY/+kezXMIGl3icXMEXdu0pKWhpKhJ7kpzNi6cW5lAiEAtKlujqgWTX99ep+IDoNQKi5a4BEjbPjw6yGUGzBa6hU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1892648},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"57008533aba7ccd51ea80f38ff4f29404d47eb9c","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.19.0+x64 (linux)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"18.19.0","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"1.20.0","@opentelemetry/resources":"1.20.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"6.6.2","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"5.89.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@babel/core":"7.23.6","@types/node":"18.6.5","karma-mocha":"2.0.1","webpack-cli":"5.1.4","@types/mocha":"10.0.6","@types/sinon":"10.0.20","karma-webpack":"4.0.2","webpack-merge":"5.10.0","karma-coverage":"2.2.1","@opentelemetry/api":">=1.3.0 <1.8.0","@types/lodash.merge":"4.6.9","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.8.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.20.0_1705313747415_0.3264673460411951","host":"s3://npm-registry-packages"}},"1.21.0":{"name":"@opentelemetry/sdk-metrics","version":"1.21.0","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.21.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"40d71aaec5b696e58743889ce6d5bf2593f9a23d","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.21.0.tgz","fileCount":561,"integrity":"sha512-on1jTzIHc5DyWhRP+xpf+zrgrREXcHBH4EDAfaB5mIG7TWpKxNXooQ1JCylaPsswZUv4wGnVTinr4HrBdGARAQ==","signatures":[{"sig":"MEQCIGpBDMhU8lTH5TE6aUTa3/f+ZAAJNZyvJR4W+y34uKgyAiA9nbAm4W2G9iFlp1OSXMtF3+Qs3M8RTAz9dMzR/gPTXA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1898573},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"828f2ed730e4d26d71f92e220f96b60a552a673a","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.19.0+x64 (linux)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"18.19.0","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"1.21.0","@opentelemetry/resources":"1.21.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"6.6.2","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"5.89.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@babel/core":"7.23.6","@types/node":"18.6.5","karma-mocha":"2.0.1","webpack-cli":"5.1.4","@types/mocha":"10.0.6","@types/sinon":"10.0.20","karma-webpack":"4.0.2","webpack-merge":"5.10.0","karma-coverage":"2.2.1","@babel/preset-env":"7.22.20","@opentelemetry/api":">=1.3.0 <1.8.0","@types/lodash.merge":"4.6.9","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.8.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.21.0_1706249469816_0.2681154592027921","host":"s3://npm-registry-packages"}},"1.22.0":{"name":"@opentelemetry/sdk-metrics","version":"1.22.0","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.22.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"b94c62403013e4c72b96dc747d71d786073efafc","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.22.0.tgz","fileCount":561,"integrity":"sha512-k6iIx6H3TZ+BVMr2z8M16ri2OxWaljg5h8ihGJxi/KQWcjign6FEaEzuigXt5bK9wVEhqAcWLCfarSftaNWkkg==","signatures":[{"sig":"MEUCIQDNXgVv9Uxbxg3/33/6F66wijwbwDd7GOiqKURWpli14gIgE4NQsN1CjuPkQcHMyQ25CAKybwbYPJODQxdspPHt3+E=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1903538},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"7be35c7845e206b27b682e8ce1cee850b09cec04","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.19.0+x64 (linux)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"18.19.0","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"1.22.0","@opentelemetry/resources":"1.22.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"6.6.2","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"5.89.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@babel/core":"7.23.6","@types/node":"18.6.5","karma-mocha":"2.0.1","webpack-cli":"5.1.4","@types/mocha":"10.0.6","@types/sinon":"10.0.20","karma-webpack":"4.0.2","webpack-merge":"5.10.0","karma-coverage":"2.2.1","@babel/preset-env":"7.22.20","@opentelemetry/api":">=1.3.0 <1.9.0","@types/lodash.merge":"4.6.9","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.9.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.22.0_1709198294535_0.21078722486314505","host":"s3://npm-registry-packages"}},"1.23.0":{"name":"@opentelemetry/sdk-metrics","version":"1.23.0","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.23.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"b4cf3cc86b6dedf5c438c67c829df7399bf64be1","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.23.0.tgz","fileCount":561,"integrity":"sha512-4OkvW6+wST4h6LFG23rXSTf6nmTf201h9dzq7bE0z5R9ESEVLERZz6WXwE7PSgg1gdjlaznm1jLJf8GttypFDg==","signatures":[{"sig":"MEUCIQCRviOtBHY4cxAbFmlSe5/d1UlZwJANaHyzFmHvAstAfgIgcfcrCMSSgbzKnYncXB5RxmguAOFxcmRGxTgWETblVvM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1914895},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"5231aa255047fbc6ee3d6a299f4423ab2f8a5fbc","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.19.0+x64 (linux)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"18.19.0","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"1.23.0","@opentelemetry/resources":"1.23.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"6.6.2","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"5.89.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@babel/core":"7.23.6","@types/node":"18.6.5","karma-mocha":"2.0.1","webpack-cli":"5.1.4","@types/mocha":"10.0.6","@types/sinon":"10.0.20","karma-webpack":"4.0.2","webpack-merge":"5.10.0","karma-coverage":"2.2.1","@babel/preset-env":"7.22.20","@opentelemetry/api":">=1.3.0 <1.9.0","@types/lodash.merge":"4.6.9","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.9.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.23.0_1712131805787_0.6556898049242013","host":"s3://npm-registry-packages"}},"1.24.0":{"name":"@opentelemetry/sdk-metrics","version":"1.24.0","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.24.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"205c19b6d18e385039d0a261c784a203c644fc28","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.24.0.tgz","fileCount":561,"integrity":"sha512-4tJ+E6N019OZVB/nUW/LoK9xHxfeh88TCoaTqHeLBE9wLYfi6irWW6J9cphMav7J8Qk0D5b7/RM4VEY4dArWOA==","signatures":[{"sig":"MEUCIFw7C6N1PHTi2sUnPwYd6pb4MEYB0sdDPAfLyVHSEEL0AiEAhRBkWnU/RMsb1e2pd8JuT67Zi9eH87TbDc40JN74Plg=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1914895},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"3ab4f765d8d696327b7d139ae6a45e7bd7edd924","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.19.0+x64 (linux)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"18.19.0","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"1.24.0","@opentelemetry/resources":"1.24.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"6.6.2","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"5.89.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@babel/core":"7.23.6","@types/node":"18.6.5","karma-mocha":"2.0.1","webpack-cli":"5.1.4","@types/mocha":"10.0.6","@types/sinon":"10.0.20","karma-webpack":"4.0.2","webpack-merge":"5.10.0","karma-coverage":"2.2.1","@babel/preset-env":"7.22.20","@opentelemetry/api":">=1.3.0 <1.9.0","@types/lodash.merge":"4.6.9","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.9.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.24.0_1713969585182_0.37633556794494494","host":"s3://npm-registry-packages"}},"1.24.1":{"name":"@opentelemetry/sdk-metrics","version":"1.24.1","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.24.1","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"82ee3069b2ca9bb7c1e91272ff81536dc2e9bc8d","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.24.1.tgz","fileCount":561,"integrity":"sha512-FrAqCbbGao9iKI+Mgh+OsC9+U2YMoXnlDHe06yH7dvavCKzE3S892dGtX54+WhSFVxHR/TMRVJiK/CV93GR0TQ==","signatures":[{"sig":"MEUCIQCTMSUw6bs+C6f+azmvQBAAOS2F2zkdYmTaUA0WsSSESgIgVgEsIIBcrrCeUZGl8a4ziCe01KmMiEcyeTk5/btVJww=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1914895},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"41c2626fe0ed03e2e83bd79ee43c9bdf0ffd80d8","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.19.0+x64 (linux)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"18.19.0","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"1.24.1","@opentelemetry/resources":"1.24.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"6.6.2","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"5.89.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@babel/core":"7.23.6","@types/node":"18.6.5","karma-mocha":"2.0.1","webpack-cli":"5.1.4","@types/mocha":"10.0.6","@types/sinon":"10.0.20","karma-webpack":"4.0.2","webpack-merge":"5.10.0","karma-coverage":"2.2.1","@babel/preset-env":"7.22.20","@opentelemetry/api":">=1.3.0 <1.9.0","@types/lodash.merge":"4.6.9","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.9.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.24.1_1715093558847_0.03178144750682588","host":"s3://npm-registry-packages"}},"1.25.0":{"name":"@opentelemetry/sdk-metrics","version":"1.25.0","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.25.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"0c954d580c17821ae4385d29447718df09e80b79","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.25.0.tgz","fileCount":561,"integrity":"sha512-IF+Sv4VHgBr/BPMKabl+GouJIhEqAOexCHgXVTISdz3q9P9H/uA8ScCF+22gitQ69aFtESbdYOV+Fen5+avQng==","signatures":[{"sig":"MEUCIQCTGV0/dFktbxE5zP6XFH0Eu0/cZ7CGkU7c5BAAq4CVjAIgG3QIuMsMnEWURsoo1SS0GKQqtBcHiCbSGaaBzrbsXaE=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1914152},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"c4d3351b6b3f5593c8d7cbfec97b45cea9fe1511","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"karma start --single-run","align-api-deps":"node ../../scripts/align-api-deps.js","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.19.0+x64 (linux)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"18.19.0","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"1.25.0","@opentelemetry/resources":"1.25.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.3","lerna":"6.6.2","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"5.89.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"9.5.1","typescript":"4.4.4","@babel/core":"7.24.6","@types/node":"18.6.5","karma-mocha":"2.0.1","webpack-cli":"5.1.4","@types/mocha":"10.0.6","@types/sinon":"17.0.3","karma-webpack":"5.0.1","webpack-merge":"5.10.0","karma-coverage":"2.2.1","@babel/preset-env":"7.24.6","@opentelemetry/api":">=1.3.0 <1.10.0","@types/lodash.merge":"4.6.9","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.10.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.25.0_1717607758345_0.42159719696026543","host":"s3://npm-registry-packages"}},"1.25.1":{"name":"@opentelemetry/sdk-metrics","version":"1.25.1","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.25.1","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"50c985ec15557a9654334e7fa1018dc47a8a56b7","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.25.1.tgz","fileCount":561,"integrity":"sha512-9Mb7q5ioFL4E4dDrc4wC/A3NTHDat44v4I3p2pLPSxRvqUbDIQyMVr9uK+EU69+HWhlET1VaSrRzwdckWqY15Q==","signatures":[{"sig":"MEUCIQCNZXU0MM/EDXNSq8ZV/6psCW97vGmYrurc/e/iYg7LOAIgS3/fl7W9LtXeIauAqM5ZL24hsmc39zaKuX+90I3Edn8=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1914152},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"0608f405573901e54db01e44c533009cf28be262","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"karma start --single-run","align-api-deps":"node ../../scripts/align-api-deps.js","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.19.0+x64 (linux)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"18.19.0","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"1.25.1","@opentelemetry/resources":"1.25.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.3","lerna":"6.6.2","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"5.89.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"9.5.1","typescript":"4.4.4","@babel/core":"7.24.7","@types/node":"18.6.5","karma-mocha":"2.0.1","webpack-cli":"5.1.4","@types/mocha":"10.0.6","@types/sinon":"17.0.3","karma-webpack":"5.0.1","webpack-merge":"5.10.0","karma-coverage":"2.2.1","@babel/preset-env":"7.24.7","@opentelemetry/api":">=1.3.0 <1.10.0","@types/lodash.merge":"4.6.9","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.10.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.25.1_1718875163722_0.02638450999168529","host":"s3://npm-registry-packages"}},"1.26.0":{"name":"@opentelemetry/sdk-metrics","version":"1.26.0","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.26.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"37bb0afb1d4447f50aab9cdd05db6f2d8b86103e","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.26.0.tgz","fileCount":561,"integrity":"sha512-0SvDXmou/JjzSDOjUmetAAvcKQW6ZrvosU0rkbDGpXvvZN+pQF6JbK/Kd4hNdK4q/22yeruqvukXEJyySTzyTQ==","signatures":[{"sig":"MEQCICUUc6/yySv2TiNLcq7AT6pbNR/Hi6zEZwTkoKabjKDXAiBJffQVgekh2F9ABx6OLgxEpstV/+ZyN55vBGwjKtK3bg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":1922196},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"720bc8c70d47029cb6b41a34ffdc3d25cbaa2f80","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc mocha 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"karma start --single-run","align-api-deps":"node ../../scripts/align-api-deps.js","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.20.4+x64 (linux)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"18.20.4","dependencies":{"@opentelemetry/core":"1.26.0","@opentelemetry/resources":"1.26.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.4","lerna":"6.6.2","mocha":"10.7.3","sinon":"15.1.2","codecov":"3.8.3","webpack":"5.89.0","cross-var":"1.1.0","ts-loader":"9.5.1","typescript":"4.4.4","@babel/core":"7.25.2","@types/node":"18.6.5","karma-mocha":"2.0.1","webpack-cli":"5.1.4","@types/mocha":"10.0.7","@types/sinon":"17.0.3","karma-webpack":"5.0.1","webpack-merge":"5.10.0","karma-coverage":"2.2.1","@babel/preset-env":"7.25.3","@opentelemetry/api":">=1.3.0 <1.10.0","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"7.0.0","karma-chrome-launcher":"3.1.0"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.10.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.26.0_1724836642462_0.8363214110577704","host":"s3://npm-registry-packages"}},"1.27.0":{"name":"@opentelemetry/sdk-metrics","version":"1.27.0","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-metrics@1.27.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"fb4f55017dc95a95ee00260262952b18e3e7c25c","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.27.0.tgz","fileCount":561,"integrity":"sha512-JzWgzlutoXCydhHWIbLg+r76m+m3ncqvkCcsswXAQ4gqKS+LOHKhq+t6fx1zNytvLuaOUBur7EvWxECc4jPQKg==","signatures":[{"sig":"MEQCICee8j7NTKwwuMDYrj9aQl8y/q4kq6aAAzlgQtPxV3QOAiBvOudBQcJ+lEOSc3vaMLEPFzNp4YjETGVxdyID8KO5GQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@opentelemetry%2fsdk-metrics@1.27.0","provenance":{"predicateType":"https://slsa.dev/provenance/v0.2"}},"unpackedSize":1920417},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","engines":{"node":">=14"},"gitHead":"eb3ca4fb07ee31c62093f5fcec56575573c902ce","scripts":{"tdd":"npm run test -- --watch-extensions ts --watch","lint":"eslint . --ext .ts","test":"nyc mocha 'test/**/*.test.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"node ../../scripts/version-update.js","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"karma start --single-run","align-api-deps":"node ../../scripts/align-api-deps.js","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.20.4+x64 (linux)","description":"OpenTelemetry metrics SDK","directories":{},"sideEffects":false,"_nodeVersion":"18.20.4","dependencies":{"@opentelemetry/core":"1.27.0","@opentelemetry/resources":"1.27.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.4","lerna":"6.6.2","mocha":"10.7.3","sinon":"15.1.2","webpack":"5.94.0","cross-var":"1.1.0","ts-loader":"9.5.1","typescript":"4.4.4","@babel/core":"7.25.2","@types/node":"18.6.5","karma-mocha":"2.0.1","webpack-cli":"5.1.4","@types/mocha":"10.0.8","@types/sinon":"17.0.3","karma-webpack":"5.0.1","webpack-merge":"5.10.0","karma-coverage":"2.2.1","@babel/preset-env":"7.25.4","@opentelemetry/api":">=1.3.0 <1.10.0","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"7.0.0","karma-chrome-launcher":"3.1.0"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.10.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-metrics_1.27.0_1729695104075_0.2954021766849051","host":"s3://npm-registry-packages"}},"1.28.0":{"name":"@opentelemetry/sdk-metrics","version":"1.28.0","description":"OpenTelemetry metrics SDK","main":"build/src/index.js","module":"build/esm/index.js","esnext":"build/esnext/index.js","types":"build/src/index.d.ts","repository":{"type":"git","url":"git+https://github.com/open-telemetry/opentelemetry-js.git"},"scripts":{"prepublishOnly":"npm run compile","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","test":"nyc mocha 'test/**/*.test.ts'","test:browser":"karma start --single-run","tdd":"npm run test -- --watch-extensions ts --watch","tdd:browser":"karma start","lint":"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix","version":"node ../../scripts/version-update.js","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","prewatch":"node ../../scripts/version-update.js","peer-api-check":"node ../../scripts/peer-api-check.js","align-api-deps":"node ../../scripts/align-api-deps.js"},"keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","engines":{"node":">=14"},"publishConfig":{"access":"public"},"devDependencies":{"@babel/core":"7.26.0","@babel/preset-env":"7.26.0","@opentelemetry/api":">=1.3.0 <1.10.0","@types/mocha":"10.0.9","@types/node":"18.6.5","@types/sinon":"17.0.3","babel-plugin-istanbul":"7.0.0","cross-var":"1.1.0","karma":"6.4.4","karma-chrome-launcher":"3.1.0","karma-coverage":"2.2.1","karma-mocha":"2.0.1","karma-spec-reporter":"0.0.36","karma-webpack":"5.0.1","lerna":"6.6.2","mocha":"10.8.2","nyc":"15.1.0","sinon":"15.1.2","ts-loader":"9.5.1","typescript":"4.4.4","webpack":"5.96.1","webpack-cli":"5.1.4","webpack-merge":"5.10.0"},"peerDependencies":{"@opentelemetry/api":">=1.3.0 <1.10.0"},"dependencies":{"@opentelemetry/core":"1.28.0","@opentelemetry/resources":"1.28.0"},"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","sideEffects":false,"gitHead":"4b1ad3fda0cde58907e30fab25c3c767546708e5","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"_id":"@opentelemetry/sdk-metrics@1.28.0","_nodeVersion":"18.20.4","_npmVersion":"lerna/6.6.2/node@v18.20.4+x64 (linux)","dist":{"integrity":"sha512-43tqMK/0BcKTyOvm15/WQ3HLr0Vu/ucAl/D84NO7iSlv6O4eOprxSHa3sUtmYkaZWHqdDJV0AHVz/R6u4JALVQ==","shasum":"257b5295bbe9de1ad31c5e8cb43a660c25911d20","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.28.0.tgz","fileCount":561,"unpackedSize":1922324,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@opentelemetry%2fsdk-metrics@1.28.0","provenance":{"predicateType":"https://slsa.dev/provenance/v0.2"}},"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIH/Z6d+HyDNtyNUtpuzVdAyqhlTCfvqGItbZ06UPzbGwAiEA1ZqqIIyQTA5ZM/DN/dHtZc0GZcZv5TtaAtdiIAF0eZI="}]},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"directories":{},"maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/sdk-metrics_1.28.0_1731926513320_0.5425586601271688"},"_hasShrinkwrap":false}},"time":{"created":"2022-08-24T17:44:35.369Z","modified":"2024-11-18T10:41:53.964Z","0.32.0":"2022-08-24T17:44:35.717Z","0.33.0":"2022-09-16T12:14:58.301Z","1.8.0":"2022-11-09T19:45:34.297Z","1.9.0":"2023-01-11T21:46:29.914Z","1.9.1":"2023-01-30T15:30:13.362Z","1.10.0":"2023-03-13T15:53:55.612Z","1.10.1":"2023-03-20T16:10:34.822Z","1.11.0":"2023-03-30T15:30:56.074Z","1.12.0":"2023-04-13T18:13:01.808Z","1.13.0":"2023-05-11T13:30:07.116Z","1.14.0":"2023-06-06T06:00:55.809Z","1.15.0":"2023-07-06T11:27:09.167Z","1.15.1":"2023-07-24T14:32:49.159Z","1.15.2":"2023-08-08T13:21:18.974Z","1.16.0":"2023-09-11T12:14:31.689Z","1.17.0":"2023-09-12T13:12:34.838Z","1.17.1":"2023-10-10T14:18:19.024Z","1.18.0":"2023-11-07T10:44:47.115Z","1.18.1":"2023-11-08T18:09:09.980Z","1.19.0":"2023-12-14T12:35:30.166Z","1.20.0":"2024-01-15T10:15:47.729Z","1.21.0":"2024-01-26T06:11:10.039Z","1.22.0":"2024-02-29T09:18:14.841Z","1.23.0":"2024-04-03T08:10:06.050Z","1.24.0":"2024-04-24T14:39:45.460Z","1.24.1":"2024-05-07T14:52:39.090Z","1.25.0":"2024-06-05T17:15:58.569Z","1.25.1":"2024-06-20T09:19:23.925Z","1.26.0":"2024-08-28T09:17:22.703Z","1.27.0":"2024-10-23T14:51:44.571Z","1.28.0":"2024-11-18T10:41:53.564Z"},"bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/sdk-metrics","keywords":["opentelemetry","nodejs","metrics","stats","profiling"],"repository":{"type":"git","url":"git+https://github.com/open-telemetry/opentelemetry-js.git"},"description":"OpenTelemetry metrics SDK","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"readme":"# OpenTelemetry Metrics SDK\n\n[![NPM Published Version][npm-img]][npm-url]\n[![Apache License][license-image]][license-image]\n\nThis module contains the Metrics SDK of [opentelemetry-js](https://github.com/open-telemetry/opentelemetry-js).\n\nUsed standalone, this module provides methods for manual instrumentation of code, offering full control over recording metrics for client-side JavaScript (browser) and Node.js.\n\nIt does **not** provide automated instrumentation of known libraries or host environment metrics out-of-the-box.\n\n## Installation\n\n```bash\nnpm install --save @opentelemetry/api\nnpm install --save @opentelemetry/sdk-metrics\n```\n\n## Usage\n\nThe basic setup of the SDK can be seen as followings:\n\n```js\nconst opentelemetry = require('@opentelemetry/api');\nconst { MeterProvider } = require('@opentelemetry/sdk-metrics');\n\n// To create an instrument, you first need to initialize the Meter provider.\n// NOTE: The default OpenTelemetry meter provider does not record any metric instruments.\n// Registering a working meter provider allows the API methods to record instruments.\nopentelemetry.metrics.setGlobalMeterProvider(new MeterProvider());\n\n// To record a metric event, we used the global singleton meter to create an instrument.\nconst counter = opentelemetry.metrics.getMeter('default').createCounter('foo');\n\n// record a metric event.\ncounter.add(1, { attributeKey: 'attribute-value' });\n```\n\nIn conditions, we may need to setup an async instrument to observe costly events:\n\n```js\n// Creating an async instrument, similar to synchronous instruments\nconst observableCounter = opentelemetry.metrics.getMeter('default')\n .createObservableCounter('observable-counter');\n\n// Register a single-instrument callback to the async instrument.\nobservableCounter.addCallback(async (observableResult) => {\n // ... do async stuff\n observableResult.observe(1, { attributeKey: 'attribute-value' });\n});\n\n// Register a multi-instrument callback and associate it with a set of async instruments.\nopentelemetry.metrics.getMeter('default')\n .addBatchObservableCallback(batchObservableCallback, [ observableCounter ]);\nasync function batchObservableCallback(batchObservableResult) {\n // ... do async stuff\n batchObservableResult.observe(observableCounter, 1, { attributeKey: 'attribute-value' });\n}\n```\n\nViews can be registered when instantiating a `MeterProvider`:\n\n```js\nconst meterProvider = new MeterProvider({\n views: [\n // override the bucket boundaries on `my.histogram` to [0, 50, 100]\n new View({ aggregation: new ExplicitBucketHistogramAggregation([0, 50, 100]), instrumentName: 'my.histogram'}),\n // rename 'my.counter' to 'my.renamed.counter'\n new View({ name: 'my.renamed.counter', instrumentName: 'my.counter'})\n ]\n})\n```\n\n## Example\n\nSee [examples/prometheus](https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/examples/prometheus) for an end-to-end example, including exporting metrics.\n\n## Useful links\n\n- For more information on OpenTelemetry, visit: \n- For more about OpenTelemetry JavaScript: \n- For help or feedback on this project, join us in [GitHub Discussions][discussions-url]\n\n## License\n\nApache 2.0 - See [LICENSE][license-url] for more information.\n\n[discussions-url]: https://github.com/open-telemetry/opentelemetry-js/discussions\n[license-url]: https://github.com/open-telemetry/opentelemetry-js/blob/main/LICENSE\n[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat\n[npm-url]: https://www.npmjs.com/package/@opentelemetry/sdk-metrics\n[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Fsdk%2Dmetrics.svg\n","readmeFilename":"README.md"} \ No newline at end of file diff --git a/tests/registry/npm/@opentelemetry/sdk-trace-base/registry.json b/tests/registry/npm/@opentelemetry/sdk-trace-base/registry.json deleted file mode 100644 index df5892a53b..0000000000 --- a/tests/registry/npm/@opentelemetry/sdk-trace-base/registry.json +++ /dev/null @@ -1 +0,0 @@ -{"_id":"@opentelemetry/sdk-trace-base","_rev":"65-20c7afee9d8d681944f1419799e365d9","name":"@opentelemetry/sdk-trace-base","dist-tags":{"canary":"0.25.1-alpha.23","next":"1.8.0","latest":"1.28.0"},"versions":{"0.24.1-alpha.4":{"name":"@opentelemetry/sdk-trace-base","version":"0.24.1-alpha.4","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@0.24.1-alpha.4","maintainers":[{"name":"mayurkale22","email":"mayurkale22@gmail.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"},{"name":"obecny","email":"bobecny@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"8ad47864d4fd534b5a24f3d9b36aa91b348586f1","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-0.24.1-alpha.4.tgz","fileCount":147,"integrity":"sha512-dRMAseFliUOYuKoHha+3/qdNsU0JyY8085xzrRyJP7TvXo6KQKzotRCtMTMvXgv3UOufeZTMHyO13J3cuB+eSg==","signatures":[{"sig":"MEQCIA7Tcl+88PcVrNMkgkaAbIhBNLaDuB6ol0YEz/lQu/SPAiB9VqTx7RX1pJT9c2zbFfw0RPOaHeljtad8c+NBp9C5HA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":230456,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhDDvUCRA9TVsSAnZWagAAwZMP/iLkavfZlJi3bwI7VOqY\n9dMwmFZXKZvBsrH2uGGD025BEAtA1p2NTARa1h2UTr+Zx5yI04ziJUkuZ7MH\n4t7QpMtHJCOAzavVzSFuy3WNFjG7qq8sK20loQL1NpmwVCC/Fz2+EohD5Wkj\nmxmizEdH+DkUNpKbsuLMlEYkPz3ZGW+h4b4nkeCt3MylOvuO0/1wW+NOvjk+\np8baQh3roC+JFZ445yQAQek90YylXzvtvhMuf4NYSedtfABAB3w08iy9I/sZ\nR+KlcC3px8zMsxUq2BdqV3EOiTwaqAZbCfaaPma1yjTSxHum1C2HuWjkUqMc\nxG/PctI398iEeAe0YtwKqK+BrjdV3RnlHNSS0rOZiRDqAqBKqPu8uvB43g5e\nhpEJW6QG34KGfO85mNgJwp8gMtrhQ30o5cetTJ6GBQBjySOgF5SUN4DCQmmb\nsZyR3UHNarAQIQWR5A2DTeqK60BTz2jjCKMIA+EGerhDbEm4kgc62Hml1O+a\nFzqycPereLxTLqRQybK0CSSe8IaZkdUQxir8FMH1UFkzM5jlQINpsa80u1fy\nDpVZ8QDFf2Yv74IqMmHjtOSrbh81IWx7GEAslvyNyvz8TxtpcVWpntd2Tveh\nzJwqF6xwYbFzc7kKYA7R9MpaPoQLeHvxFpPJjasjcswVDRxTEnonXXqBxHHu\nK/LE\r\n=dotJ\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js"},"engines":{"node":">=8.0.0"},"gitHead":"a8d39317b5daad727f2116ca314db0d1420ec488","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","tdd:node":"npm run test -- --watch-extensions ts --watch","tdd:browser":"karma start","test:browser":"nyc karma start --single-run"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.17.4+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.17.4","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"^0.24.1-alpha.4+a8d39317","@opentelemetry/resources":"^0.24.1-alpha.4+a8d39317","@opentelemetry/semantic-conventions":"^0.24.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"5.2.3","mocha":"7.2.0","sinon":"11.1.2","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"8.0.0","ts-loader":"8.3.0","typescript":"4.3.5","@types/node":"14.17.6","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.2","karma-webpack":"4.0.2","@opentelemetry/api":"^1.0.2","@types/webpack-env":"1.16.2","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_0.24.1-alpha.4_1628191700214_0.39586224494227173","host":"s3://npm-registry-packages"}},"0.24.1-alpha.5":{"name":"@opentelemetry/sdk-trace-base","version":"0.24.1-alpha.5","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@0.24.1-alpha.5","maintainers":[{"name":"mayurkale22","email":"mayurkale22@gmail.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"},{"name":"obecny","email":"bobecny@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"5801c08684013d9cd72ce6ca781f0fea2f5eb776","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-0.24.1-alpha.5.tgz","fileCount":147,"integrity":"sha512-V5N8VEc6IUQP9CH5NPOPjdwhnX94Bboe+AKje/aQLyageVYoHFxkqLklI3EfbeuDCAoDQ1cSRC2PuqEQJGlBBg==","signatures":[{"sig":"MEQCIGoA1de87lUaFgMYQO6M31GSBowdvSJUcfMWYmZjl9WbAiBz4e7nYoJs/y8Eg/7vOVFT5uf6fpzxdgjqPpswdYAcLA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":230473,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhDR2bCRA9TVsSAnZWagAAMmIP/iCQEezryq1P/10oM7l/\nQvh6jsYykBh9vZvXDvExS8TPKO49HZojjwFNBraqmJJSjQKgxIIB939N7EQw\n5Swfp9dUEMx71YaiigGF9r3pwQ15R+sN+HJPnTKEXIXvoTlutmTY1TDb1SGV\nhL+pviT97v9sUeT4NOphZ+eWkEzGepM/VM4No5O2w0KPFCsMu7cXFLC0UZPQ\n9DEHY+zAtpwJ9J0oSpQO4ci4cj7cp+6pKHGNxSzZPbkHwT9F8pCjM0CXx2O9\nnHs/HQhD99BIGyrmaQ45Q9lz2LOwIdFvtcPMZOfnfSYMM2yOvU7svHFugFCM\n3dbnPBp8U9gk7CMzDfR098vwQ+naW+1fovStECk/cLCzGPVTrJOMs6oknvnk\nuAHeyv/TI6THT+VyIphzlZu1R/NodGTkjV9oTOl4KodIfCIJ7nVm5mNlR2Ym\nlYvbKQWcLdrtbftq8Yzberd48DOYa3tgj7HKAZOZL/Op8jnElpK+M1gApkBa\nUOJ/TYyrAVhOXhPv4IItUKj9unTUn0ixT+zW41agKvOoEc0oNuj5SydsB5HZ\nUC88UQPNL+zWxtf3YEUYQh/cfgcFTzS0Oe3L9n1CeBYUi+j9JO9kvFMA49IC\no8a7MXMeANuxSynGSXQF8TH5VV7yLkiHEmbEadcal+GUpD0b/jhY6UjS1MAp\nwKmg\r\n=ogTt\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js"},"engines":{"node":">=8.0.0"},"gitHead":"b69ff35e90a33d20a0154dcd326f1467dfd39e2a","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","tdd:node":"npm run test -- --watch-extensions ts --watch","tdd:browser":"karma start","test:browser":"nyc karma start --single-run"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.17.4+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.17.4","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"^0.24.1-alpha.5+b69ff35e","@opentelemetry/resources":"^0.24.1-alpha.5+b69ff35e","@opentelemetry/semantic-conventions":"^0.24.1-alpha.5+b69ff35e"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"15.1.0","karma":"5.2.3","mocha":"7.2.0","sinon":"11.1.2","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"8.0.0","ts-loader":"8.3.0","typescript":"4.3.5","@types/node":"14.17.9","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.2","karma-webpack":"4.0.2","@opentelemetry/api":"^1.0.2","@types/webpack-env":"1.16.2","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_0.24.1-alpha.5_1628249499147_0.1555991669652872","host":"s3://npm-registry-packages"}},"0.24.1-alpha.7":{"name":"@opentelemetry/sdk-trace-base","version":"0.24.1-alpha.7","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@0.24.1-alpha.7","maintainers":[{"name":"mayurkale22","email":"mayurkale22@gmail.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"},{"name":"obecny","email":"bobecny@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"e1a60e391fdfaeb647b83318319f15e6b80fac73","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-0.24.1-alpha.7.tgz","fileCount":147,"integrity":"sha512-tenqp2xjKQqTxoO4+1S/VEDmdIJYIoWlOnCskibN86Am6UaSxryDtEaXzv4yVAoQJHF6c7QA308dgV45rAU4Ng==","signatures":[{"sig":"MEYCIQC0BMKRFFm4Xntj28BRWnEKOrdJMTRwty3ypoxV3T45+gIhAOyfi84y+2/dZdPwkzS8/GRgattYPgeoW6DoBy83c3eE","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":230473,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhDouQCRA9TVsSAnZWagAAKWEP/1nv1RMnwNq8l2paxhGt\nMg2271/nrnAfCYD/H6+HSo/5I9AbLrHZKzN+QL+BDRC16OHnpCSEpjRqzuy3\nW8Gw38fSwWV5f72l5hs9pzSfqEpXGwobGlHLONHsrEnLgd6GIGNZhwNp/UjQ\nSEJ8Z93Fg/Yp5WwbsTuAHpiSaJ8IEHIlmTA15d93OJAZ8O1qOcAW2BszacIV\ngrWOzFtnuD29o36rQtO4Q8FMyTseCMfoxGqDcTXM9UweXq26A42QbPD2mx9W\nCaPNd5gA5RcA9KWI0pEM9SBtngmbVUA3wPh/T67eZ+xV5wUIxxc3zkz0Z8/2\n0XQDEG9Hd6vYFe2x9Sybj1bWCievDMMmrwjNCIMoBKCZJsBVLd0RsFSwb7/P\nYCxq7MmZhKAFkt7c5W2aUL9wOQEVlAmT7sxez5m6kgxNtxbC3kZn7+vEfEp6\nXPekhMdVHnIdeADWLEn1l1KWXghpE1eK0jUIzs4FNJzCBGvIRHBRVmVaglvH\nn1krQ+6kga6APLro4T+IwbrneSNMTKmmiKSVxW9dZAY0ECz9OWaDPvib8d7B\nSY8q0BHDcZCysnfwhMdmqDoGr0s0GPV2tvdhUv1k0fiFjd627uLh60TgwcH9\nic0sNdBBd2blhygx2TEtBXFurcnjScvNprRQCQQtgS6D7YOUVcAdQaIwAmgD\n3o9l\r\n=JzYM\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js"},"engines":{"node":">=8.0.0"},"gitHead":"365d502eaa0ba1f9799998f050d36073e943032e","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","tdd:node":"npm run test -- --watch-extensions ts --watch","tdd:browser":"karma start","test:browser":"nyc karma start --single-run"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.17.4+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.17.4","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"^0.24.1-alpha.7+365d502e","@opentelemetry/resources":"^0.24.1-alpha.7+365d502e","@opentelemetry/semantic-conventions":"^0.24.1-alpha.7+365d502e"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"15.1.0","karma":"5.2.3","mocha":"7.2.0","sinon":"11.1.2","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"8.0.0","ts-loader":"8.3.0","typescript":"4.3.5","@types/node":"14.17.9","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.2","karma-webpack":"4.0.2","@opentelemetry/api":"^1.0.2","@types/webpack-env":"1.16.2","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_0.24.1-alpha.7_1628343184139_0.5476851490956296","host":"s3://npm-registry-packages"}},"0.24.1-alpha.9":{"name":"@opentelemetry/sdk-trace-base","version":"0.24.1-alpha.9","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@0.24.1-alpha.9","maintainers":[{"name":"mayurkale22","email":"mayurkale22@gmail.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"},{"name":"obecny","email":"bobecny@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"40822431d49ba09e480715241ce32a600ebbd2b5","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-0.24.1-alpha.9.tgz","fileCount":147,"integrity":"sha512-yU1c7NvvJMbNxlzL59OZ2mf1PYPcqNkxXcAL5D4UD04PfmS6d/NIVfzYmAs/leGhZukMiTofHn/KKw2RTs2cdA==","signatures":[{"sig":"MEUCICM6jKq78kih88ikV05KI25KywAyHyO6jp3PBZGmFbIqAiEA9UFwNt6nOazWH8/ZCGq8gGixg6P9FFMRuG3B8XiE62Y=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":231300,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhDpQ/CRA9TVsSAnZWagAAdfcP/RBEDRX9XNfxwhOEx3Xc\nZyDOEW/F9iWRJ6IMmUPB6xjThi6h3I8pdAeXqgRTCDEJdBLuT6Ja0dXJd26X\niBanP3KBWQAZubTDzSGlR31BLg2oeFPZvcuKHmfEHXCB7hyLCnI76WO/71P1\nL3lj60b3jw8/F0y9HKg0bKVhJSnCoNSTKIt5KcH9hLbOrPusRvWc8t9CRCfX\nAaHDlGz81M+AgIIr2ibMH8z5OrRK1U9Bd5lUD1V4pgxujH+tjeq27KXI//JX\npHtJlv/SbELg/0pU0JrqZKQpS5TfwV/L2Z8qWXQmDYMnxdYcUa+tjDOwo/zs\nFLIs4OecNpFpZAyEVeVzGMgbgcGgTOAGixZOzDGBqL7ZbOqKHn/njvA3WX70\nG/nZKBThXAl29+Kl2OHk5i0FfO4BDUZWN6KqpFX7zVnUJIlpVj/5DCDo7gc9\nOGCp8pNpN/kSqocaD8XeQ8U4CAoWUqQ5g2/fnLl4Mui191Rngtp7q8RiswIf\n2qAaWf1AJvRVr3nDycfrhw2FPU2sMgMSTHnWEVpS30mfkPwPaR68rkYQvzYx\na+eH7qvwXwnIBtUfb1Dal3njr8g34NfOp7rBUONHs6JFV07Jq/4IVLvkoGWI\nmZ0GqVIn8iqrAkfHef2fTPUQr+i89L6ItXiFdfrPXL29qpNwPd9CfdIfx8Qm\nbi/V\r\n=h0kW\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js"},"engines":{"node":">=8.0.0"},"gitHead":"46a42a18570da8a0b2ae027c80018ebfb6c8096f","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","tdd:node":"npm run test -- --watch-extensions ts --watch","tdd:browser":"karma start","test:browser":"nyc karma start --single-run"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.17.4+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.17.4","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"^0.24.0","@opentelemetry/resources":"^0.24.0","@opentelemetry/semantic-conventions":"^0.24.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"15.1.0","karma":"5.2.3","mocha":"7.2.0","sinon":"11.1.2","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"8.0.0","ts-loader":"8.3.0","typescript":"4.3.5","@types/node":"14.17.9","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.2","karma-webpack":"4.0.2","@opentelemetry/api":"^1.0.2","@types/webpack-env":"1.16.2","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_0.24.1-alpha.9_1628345406996_0.3167053382863443","host":"s3://npm-registry-packages"}},"0.24.1-alpha.14":{"name":"@opentelemetry/sdk-trace-base","version":"0.24.1-alpha.14","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@0.24.1-alpha.14","maintainers":[{"name":"mayurkale22","email":"mayurkale22@gmail.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"},{"name":"obecny","email":"bobecny@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"b670fd695883a066d7783c43af630c5e6b13d558","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-0.24.1-alpha.14.tgz","fileCount":147,"integrity":"sha512-98OBTMreg/uqFobh5u3A95fILVzaRDsixo4YR/QwIbjslLjyXt2+iJgUOtMN9W4O62tp4eeedrGqnINpOwfZPQ==","signatures":[{"sig":"MEUCIQC0zLhhndrpHsprXHc/NlLTppr59Plb6Uj3PNUl7lgN5gIgMwFK/IGoPqqcXjXWMAdWJqAA5OtrmqWa/MKWdnqdFwE=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":231337,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhE+POCRA9TVsSAnZWagAAgpUP+gKVAuimNG145WYxTnlQ\n2aMnt4P8TqAKtSToIaJtUZLCkQypCs+CM8EtQcJfbwh4xgQFLdqGxA6D4gPp\ntQ22hVMQlp4TyM56aepWk50Egh1niZaJJG8fzbIwHhEOiP54mD+2yP6wGE9S\nBZZO7ytJBOg6jlGum7KnGvgqVTF+h4h6kK+4rxmH+/HpyOwZLk+JGsABQLQl\nrnpglO6QzMocf0uuEkcK/BVHMd6cD8MLOaJ/ZSFD1UdvaVE+pyk3xuoK+3/u\nTtoUmgYZxObBRNBbHuhNfKzQCULFzMElnFpAZWk3dYo6AG/P5+N2ARpCjfZJ\n0jHyeeElYdK3j6lL0mjfTmYNYs+4DlFjU+Yz6jQevjLSJaGopWnXTaekVZwq\nSx010v3QPh2nOTfGci7eFwuILNrHQRy8MWq30rw99li55z2Uoa68kWIbDPsn\nfsmhTh8k4VWFVF3TSWDEZuLBbU/n+vVhVRkLk56bXsxWZ7xQOSYWAOQGbjJS\nmztmVq/5jC+4WGeZM9Z3geCbo/QlJrUampC6L5izl+3PIXanbuOw/PYISJ5b\nteE1wjWbdqTfA+8zABiI506kR6ssXZHi3w6TPJA4x3Jq80vIFfmv5h6rF9Oo\nEW4xBx0fyxpOruWeY6YZNOc0uGXOZpR6FXXiAzaSr6l256cJ/6rVGpPNRevn\n0vgT\r\n=lqQF\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js"},"engines":{"node":">=8.0.0"},"gitHead":"4553b29d4a04b5b7e4bf87cad64dc2fc8c740d8e","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","tdd:node":"npm run test -- --watch-extensions ts --watch","tdd:browser":"karma start","test:browser":"nyc karma start --single-run"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.17.4+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.17.4","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"^0.24.1-alpha.14+4553b29d","@opentelemetry/resources":"^0.24.1-alpha.14+4553b29d","@opentelemetry/semantic-conventions":"^0.24.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"15.1.0","karma":"5.2.3","mocha":"7.2.0","sinon":"11.1.2","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"8.0.0","ts-loader":"8.3.0","typescript":"4.3.5","@types/node":"14.17.9","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.2","karma-webpack":"4.0.2","@opentelemetry/api":"^1.0.2","@types/webpack-env":"1.16.2","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_0.24.1-alpha.14_1628693454833_0.767569219106649","host":"s3://npm-registry-packages"}},"0.24.1-alpha.18":{"name":"@opentelemetry/sdk-trace-base","version":"0.24.1-alpha.18","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@0.24.1-alpha.18","maintainers":[{"name":"mayurkale22","email":"mayurkale22@gmail.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"},{"name":"obecny","email":"bobecny@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"d06ff14f49cea7c13b31bc3553c1315d9c434a9b","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-0.24.1-alpha.18.tgz","fileCount":147,"integrity":"sha512-QE0ZqebO4BJpm611b0165kvR40LkHvTfps406bv/wDO7SNz/nMXIv2sUKhJBqGSRK+2/jUG0vMvpOkBK7HxRZQ==","signatures":[{"sig":"MEUCIFToWHfCxokuNtSvaj4t8JR3GTRFdGOLf1iy8g33VW1vAiEAlSReugAeVdszYsfnrs+VI2Dd5XxVT4++YH7PJZnUMyU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":231319,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhF3vJCRA9TVsSAnZWagAAiRwP/1YNDd+IH2bLR2ut+boE\n6PAa/4KiFKMpw4j4Go89kGpTfOBz5nTZWQu4+A9omScvVvBY7XBpQLqRTyRl\n1fmS3lSPELQtMv+102sIcGkz8zvnow5tVg2HNUBMG2xLXDSjR7LX9ruoMKgY\nAqMTCjSRxvTey6s+N0PBrpGZio+7oaQQocDqxKitiLkMX8EiHtcieY1zAskC\nElrtb2hg2najiDB3U1LKehREnNpbgjT3MWAiIJDWpyaL4SCG0zl127ERZfNO\ngv3y8m3S2ndB3MrKghC5bQ0xxfMYjBWGfVh5zPZAjiRwMAjXyXVeLgiHioH/\nwKWwQcWqEAcFOh3z/S0Xkx/MDNXZL+yQCXtE7WOzxvb+GT9errzYPFMzyBUq\nG+wShRLftqrEGzbo36fCHULYXGEaxfm2TF6HF/wTyR8JsNsNSzX2szdvUnG2\noWNE1owerG13zMQPqQqNk0H4qZbvLXE8F4MWPCVdsaWuyxX1Lhll9eknbBq4\nx5RQxfBQNGrI1Iw2sR8wGkMO7liZRqLBkAa/FlO0M0/n5ODxqT9QMBPk/I+2\nlT/fg1k6BuO7I3rgVAAYPDqv7nHLD1hCKbZ9dnkonZPssHxtY5ZLedoYk/G6\nfCSklauAiAjmvvZvVDzvxLtaYOfNnF0O+dyi5va77RMaaLu5AjHmG3Zv+9TR\nBNgS\r\n=gw2o\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js"},"engines":{"node":">=8.0.0"},"gitHead":"bdb12daeb2e4ca3761d1411125f5d883471709ce","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","tdd:node":"npm run test -- --watch-extensions ts --watch","tdd:browser":"karma start","test:browser":"nyc karma start --single-run"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.17.4+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.17.4","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"^0.24.0","@opentelemetry/resources":"^0.24.1-alpha.18+bdb12dae","@opentelemetry/semantic-conventions":"^0.24.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"15.1.0","karma":"5.2.3","mocha":"7.2.0","sinon":"11.1.2","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"8.0.0","ts-loader":"8.3.0","typescript":"4.3.5","@types/node":"14.17.9","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.2","karma-webpack":"4.0.2","@opentelemetry/api":"^1.0.2","@types/webpack-env":"1.16.2","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_0.24.1-alpha.18_1628928969813_0.9380634139248278","host":"s3://npm-registry-packages"}},"0.24.1-alpha.20":{"name":"@opentelemetry/sdk-trace-base","version":"0.24.1-alpha.20","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@0.24.1-alpha.20","maintainers":[{"name":"mayurkale22","email":"mayurkale22@gmail.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"},{"name":"obecny","email":"bobecny@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"de349f8b90e4987906b14f064680403eefd73f40","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-0.24.1-alpha.20.tgz","fileCount":147,"integrity":"sha512-T4JgUpq3fRoHqL8RI6vghZ0Rf8Yusm7y5j+ZeS4gKq31KedB2AzZBNK6jRWprJc22IJ5/YP+0HTBA17euvlkCg==","signatures":[{"sig":"MEYCIQCVUqO1X93DZhqXTmIXc+aU8CiF0cDSHzoHjXz/1VsyRwIhAKBtjWBbfY4bKko6tzQDg1dDWc6N9gZQ7wecvsRn4PAO","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":231337,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhHCT7CRA9TVsSAnZWagAAL38P/RXZXrIkyb9DVgqFbcRH\nzNfnDhVtGTMNJbgXkZdVATXsWy4X6IAiKKZEc7rYIRjaYslOKdYyB5lgqTty\n8BL1J1LNRIXu2H/X/qviyGcV1P0+M1otFZ1v/edn8qCbO8iWjLHJ23Guweb8\nxQfkKeZEETeL13KzxZhm6Gy328e3o0Bd5fZBnyZ9jG0vWesS1HBkjHqBxLKd\ng0qADSfgPtSSlJxKweLGqrqQBKjHpZtBmOKJdXLgLHKEsSfPxgl8Si5tHRPa\nvLX8zYVDFCk8rryu5fqLpWe5d2o0RQRzWnVcw3FA56CZBxUpvNR3WlgFOgil\nWntcmJoGH1uUwWq3d6VqIPfVrapMiQknmGI3+HgzjzWFIphGaScawwnOjIVl\nWlXYR7CECUSrGqa1jwtspbfNO0SfIg922CBxWsC6iysJLsyfa6ziPyzwjJRB\nqnmc/bYyIpbEYiQ+4dOT1TJIK8ewtRJcTAVcDwl9/VSsn+GZ76/NdZldD+/p\n/tg8WZfPfp4cBjLhwBoBZ+a+rJ1naB64wc66J7aIfM2eRpUY0TexCGYx4USz\nzON5xTVvqlzpqvJKU+K+HctdzBsv0wxYs4/kQ4suR0NqfFVvpB2BZIe9KzH0\n/f4U9smqyocc0yHybZxG6HbF2HsbRR0vn+Yn1iQdieh8g16Wljk1vtq+QhDL\n6rYy\r\n=9wQp\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js"},"engines":{"node":">=8.0.0"},"gitHead":"f12913899ff5c588e10830e5ba7183d9115c3442","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","tdd:node":"npm run test -- --watch-extensions ts --watch","tdd:browser":"karma start","test:browser":"nyc karma start --single-run"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.17.4+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.17.4","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"^0.24.1-alpha.20+f1291389","@opentelemetry/resources":"^0.24.1-alpha.20+f1291389","@opentelemetry/semantic-conventions":"^0.24.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"15.1.0","karma":"5.2.3","mocha":"7.2.0","sinon":"11.1.2","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"8.0.0","ts-loader":"8.3.0","typescript":"4.3.5","@types/node":"14.17.9","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.2","karma-webpack":"4.0.2","@opentelemetry/api":"^1.0.2","@types/webpack-env":"1.16.2","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_0.24.1-alpha.20_1629234427062_0.7964990125133731","host":"s3://npm-registry-packages"}},"0.25.1-alpha.21":{"name":"@opentelemetry/sdk-trace-base","version":"0.25.1-alpha.21","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@0.25.1-alpha.21","maintainers":[{"name":"mayurkale22","email":"mayurkale22@gmail.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"},{"name":"obecny","email":"bobecny@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"90130b88074239b003905ee68653a8a62aad8ca2","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-0.25.1-alpha.21.tgz","fileCount":147,"integrity":"sha512-W44WsBbrmkNKzHlbrjnoHlE8JLl419V5Vdhave+IJ6AmAdmsZQi7i99DgfcVVCyPiXDEXRGT1D6VI6d6MaRWHA==","signatures":[{"sig":"MEYCIQDNiLqpu8u+Cs1lTRYS6RSu8slzRafP58p5LM6Nx3wOzQIhAMhg8xKg2GTIQic/3j4xSjcKfJuZRhndoRhISTpOY7wh","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":231355,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhHWqqCRA9TVsSAnZWagAAOAoP/R+kSqbk2lLBLgSfS4tM\nW3P+ESNSTUKhzNGPD7zvhtFXa6p4lzLLUk6q8AIviCtXfHg8FryZL/94r0Sg\n2o9+PEY2MoR8dOdMw95ywLXJa4UfaY1QUOFaMYCV5fGigEfhLZXlniauYVEW\n2LQb5dTdiTsXGW3FLdnqLYPAtsnE7NQ/aoaDrHGIAThtSMnv97VMpz5lKk/Z\nEeVWdzLQ/VZjxtxxbgrnk8VqcjYq0bz49PC2HdzqeSq1EOT7hShW9cZ/BIkf\nKkD5vZZA90fvgduG0as7yc+KwMVeqGTkTcecdykS/cflls0ptJ9UDOvTpYgZ\nrSggs9J5/TW6UE62HNYyiSzNbKFC94OX+SactQ0zRp72yJs74wpD4UpQut8c\nHoeqLsmrWh7Xtz5uvgwt4100uhW2FV15jkwinhMMK4IYcIV+iN0M9CiouKbt\nA9wD0dOMlvC3rifnF8fn5D0PYe69QkEli6gJxrsiRfzOAXoO52KutFcDsQPW\n12U6XfLNhdgoL9kahXgEa+g/8U8s4IUXVYztF3DqIKRMBkGhf1R8cOwL0lo1\nIGYp3BmpyF7NQ3IKmV4mn/4d/qjXu1AetYErAIjcktgs8tCgR2Uz0+6A0pCR\nh6Qc1ZOlinidoiuzlLem7VUIQsuP26zaD6xJgf8BWg1Oekjroy3+KuL2S/XT\nwnjN\r\n=ah+v\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js"},"engines":{"node":">=8.0.0"},"gitHead":"0ef1fc28d366b74d98b73b5d6334ffdc75342fe2","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","tdd:node":"npm run test -- --watch-extensions ts --watch","tdd:browser":"karma start","test:browser":"nyc karma start --single-run"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.17.4+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.17.4","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"^0.25.1-alpha.21+0ef1fc28","@opentelemetry/resources":"^0.25.1-alpha.21+0ef1fc28","@opentelemetry/semantic-conventions":"^0.25.1-alpha.21+0ef1fc28"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"15.1.0","karma":"5.2.3","mocha":"7.2.0","sinon":"11.1.2","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"8.0.0","ts-loader":"8.3.0","typescript":"4.3.5","@types/node":"14.17.9","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.2","karma-webpack":"4.0.2","@opentelemetry/api":"^1.0.2","@types/webpack-env":"1.16.2","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_0.25.1-alpha.21_1629317802400_0.8977428987171272","host":"s3://npm-registry-packages"}},"0.25.0":{"name":"@opentelemetry/sdk-trace-base","version":"0.25.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@0.25.0","maintainers":[{"name":"mayurkale22","email":"mayurkale22@gmail.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"},{"name":"obecny","email":"bobecny@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"4393903a7db8a5ae81a99c4a34121df67e4fdfbe","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-0.25.0.tgz","fileCount":147,"integrity":"sha512-TInkLSF/ThM3GNVM+9tgnCVjyNLnRxvAkG585Fhu0HNwaEtCTUwI0r7AvMRIREOreeRWttBG6kvT0LOKdo8yjw==","signatures":[{"sig":"MEYCIQCti4VKK/PEN3BO7Ga65nTpCQWZUAuemjlsTmlgLCCXYQIhANG5iAycgkYjQtzcEkRDDSLBlDon1b+0nKg68xzEpiov","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":231280,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhHXi+CRA9TVsSAnZWagAAZnQP/2uVRo0am5dw3Xuz6WG4\nQhlmd9qcn6htXQYGAPH7eJ6ctlEl0xtSXDbkCf0IL2RU62nAhac794wKLdfp\ned9yI5B9HghS5LdapNWxeOVJbUhlfHUo3GKMagps1CTkpuElW/bPbWPgK5JM\nuRbHCx9O0MdY1iSzQm6yMd38xjI8EzA6RSo8xg0Z4AkH8OwANCsNvblW28OG\n9UZe+iAWYKOo0bJbe0WB1zKb41YMAhKczKMvo+yoHFPfsuyZYErktOsfje10\nMHuO/LmcSClwrX49MyDmXT3OKb6p6/bKubCqNvYWWQx/jDTua4Hjmj8OgSXh\nziD8rNObdGCLAqltz/buPhb/B7N27f6jzjB5jNkm/LVmL9Ujfkvwth9vfqk5\nE9g/x/pjHvyTaAX42UtJov8hDy9iEaQUqKIaUoDa5URlgzpYXaV4Hz5Cahc7\n7JyUi7M5cDK535/rbEfXUErpstOmpvvv0ATPhZuqNBzAOkAViyuLRgjFEVqO\nSOLCL/DCmhwcO3KOIzJRH0Z0h5CojstFXbCKsA0E0uLNLAl1UnzgAPFEbt/2\nmlhjPRIThzYOFwJysMXAOaJNtjk4ZBSlXan0t1sxj2eQplG+1gxpin29yDfB\n8gEKMkW0V6IZ0PVMwN/b0PSHvcnuOPEg1A1WKvW09xe/h44ww6z+Tf2VfeAu\nV/HP\r\n=aFb+\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js"},"engines":{"node":">=8.0.0"},"gitHead":"0ef1fc28d366b74d98b73b5d6334ffdc75342fe2","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","tdd:node":"npm run test -- --watch-extensions ts --watch","tdd:browser":"karma start","test:browser":"nyc karma start --single-run"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.8.0+x64 (darwin)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.8.0","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"0.25.0","@opentelemetry/resources":"0.25.0","@opentelemetry/semantic-conventions":"0.25.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"5.2.3","mocha":"7.2.0","sinon":"11.1.2","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"8.0.0","ts-loader":"8.3.0","typescript":"4.3.5","@types/node":"14.17.9","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.2","karma-webpack":"4.0.2","@opentelemetry/api":"^1.0.2","@types/webpack-env":"1.16.2","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_0.25.0_1629321406548_0.048648051511765544","host":"s3://npm-registry-packages"}},"0.25.1-alpha.2":{"name":"@opentelemetry/sdk-trace-base","version":"0.25.1-alpha.2","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@0.25.1-alpha.2","maintainers":[{"name":"mayurkale22","email":"mayurkale22@gmail.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"},{"name":"obecny","email":"bobecny@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"4de3a67970ff6eadf12b06710f5ac77e6c407d89","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-0.25.1-alpha.2.tgz","fileCount":147,"integrity":"sha512-OhXgn/tsEtvxOVZ5SQXIAV3d6pFd5rMMTPRsUK8QTHsSBVSOsKALygTvcRwPQJlUdSdJkxGA6NfUg8pOx1OjHw==","signatures":[{"sig":"MEYCIQCR/JgLC31LcnbSaR3Sn6LRjqitnzJq1b7eT4nBZ/apcAIhANLoKitgEA5BztqHIcLVhrvML97Bk2baz8xORcry+cG/","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":238819,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhJBX2CRA9TVsSAnZWagAAUUYP/1l0sLT+uC/JTj1TfINp\ndWHrPZhqeMMiEVARoPTILwDF2mZ6lWUn4OWe2m7waueZhQw1i9mlD6QKtNeA\nkps1z+L/WUHqlPzT2HKHG5JTi2OwkNfoO5lNoU9tpuvhd7t7/PWSg3O3S2rY\nBSPt+0pOne0mBD6uRi4yO9X4iasOS31QZJvNmkEdCBRy5K0yx2u1m7LzLzcA\nfrb49X5PJMsAywkJKEyExq0nbkcllod5fw36noniLe5uXiScWwrGohxWlnL2\nEzgRqYqcoWMZg6MRVoh3K/VwymhIyxfB/kailGv4dr6wU0dUpiBwVtBdADW8\nkoMx2LS/vDTva2sMp/W/4P5mt3Wqcy503X07N9V10vQolUvRR0hcoXV+OU41\neRbZVWdFWXo4Q5I4D3E5UTgIAloSlVNkanra66/p3nNWtTLakNcf9EfQRl/P\n34n5E8eTN3Wl0O8NiSimEVHexew26ac9aSEj74BuKBWEntPDQqGAWS5cg5/t\nzUCFSzDIjMNDlNRBH8bprcJKNWsG0V3ko9LsngyW8eA+CCwRhEOAcOqvdEwb\nfeBK3PC7TMNo4WuNufVgCm8ejH+yP9u7c3dTtU4Z60y/BGvvLdMZA9UMhABD\nFEUQ0lGoOVX2ALBNQh5KSMk/085WuGWj3dT5E83OKnVy1uD3mgslbdcNpj/Q\neOKC\r\n=tFMf\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js"},"engines":{"node":">=8.0.0"},"gitHead":"78a78c093c2df24b66c47af4e037da9a6098fedb","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","tdd:node":"npm run test -- --watch-extensions ts --watch","tdd:browser":"karma start","test:browser":"nyc karma start --single-run"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.17.5+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.17.5","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"^0.25.1-alpha.2+78a78c09","@opentelemetry/resources":"^0.25.1-alpha.2+78a78c09","@opentelemetry/semantic-conventions":"^0.25.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"15.1.0","karma":"5.2.3","mocha":"7.2.0","sinon":"11.1.2","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"8.0.0","ts-loader":"8.3.0","typescript":"4.3.5","@types/node":"14.17.9","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.2","karma-webpack":"4.0.2","@opentelemetry/api":"^1.0.2","@types/webpack-env":"1.16.2","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_0.25.1-alpha.2_1629754870123_0.17987001772703892","host":"s3://npm-registry-packages"}},"0.25.1-alpha.4":{"name":"@opentelemetry/sdk-trace-base","version":"0.25.1-alpha.4","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@0.25.1-alpha.4","maintainers":[{"name":"mayurkale22","email":"mayurkale22@gmail.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"},{"name":"obecny","email":"bobecny@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"29ba973f0f357c64da5ece13e2565f2745500ef3","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-0.25.1-alpha.4.tgz","fileCount":147,"integrity":"sha512-xwUOlftFr1dN4Utp9Scu0+eDbQ9oEsQPJ5cUu6I5WW8wxURqV/d4f6UTL1bmTxm5x5FlS9ggQSVBiqHeWoAZEg==","signatures":[{"sig":"MEUCIDIO3X0Ip0Dqcxe7kAgyn4rie4xDhB062Pc/p6GnpywmAiEA0kK9ptzzM93v2jgnVtEt857r0cBWxnTxxDaE585k7vI=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":238837,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhJUl9CRA9TVsSAnZWagAAsmQQAJp5bnBhFSjaYGNcLpjk\nB5rAh/7iqHO4cK/jNHYrlao+r6fp7rhFItt2PLoLrmuhl0TXEVAKbGp+GTIp\nf0Sz1A58zy+7dBlRK3X8VIYNpg+L0m+ujLNzk+DLbpSEHMLDXfhZ62DvYvpc\n0J6IPGhnTdrd/+HlHuhSzduClCAgmLsB/wZZo+GjR0nG52GKv2ZP/l5+ZAfN\n7FOiXgEp3xmYTyNrqfx6gRXpCXyjs4Ot4vAMf+DLsum0fkWtBvT8LyMJSuQs\nZHXEQGzbiBYCJELA7agamKBv5rxPIBYuELbDJXjDNwDL/pQDnB8xUTNoOjIL\nfG3B1m9bE2+6D8CZVI3ItfWmVZw9XhARocXZ6DYaQW9xuJ23ScSgN+CKUK2o\nyls8V5PwBadpJg59jQiAfOvWHCNPWSAGGttIXMbMfKTJ5v4iFv+sHHggS3h4\nvvmkvpUMPkBFHmlBMQLvQcqTuS+hffAylqelzHO445zEU3kDB7LfXy7v7Rx1\nH0zjn1cd0U1kkpGXrpIGW1czR5vChsVcDnUCmS8HzQmSU0+l42N8prjLPo73\nOHoHbGctUsX9j9IOhqIgc5GupPs6x4dJgzbYpQvtXygIra8kxl8bLlZLsJzy\n1CM+5GfaC8CeDreDh0/Y4fTutqMTV/s6ryMFupq43x+ONvyLU4Yf/e9O8bee\nn8f7\r\n=EjCd\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js"},"engines":{"node":">=8.0.0"},"gitHead":"3cbd530f2ee5c06376210402eb87ec9e362853c5","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","tdd:node":"npm run test -- --watch-extensions ts --watch","tdd:browser":"karma start","test:browser":"nyc karma start --single-run"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.17.5+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.17.5","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"^0.25.1-alpha.4+3cbd530f","@opentelemetry/resources":"^0.25.1-alpha.4+3cbd530f","@opentelemetry/semantic-conventions":"^0.25.1-alpha.4+3cbd530f"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"15.1.0","karma":"5.2.3","mocha":"7.2.0","sinon":"11.1.2","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"8.0.0","ts-loader":"8.3.0","typescript":"4.3.5","@types/node":"14.17.11","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.2","karma-webpack":"4.0.2","@opentelemetry/api":"^1.0.2","@types/webpack-env":"1.16.2","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_0.25.1-alpha.4_1629833597428_0.24765430996019488","host":"s3://npm-registry-packages"}},"0.25.1-alpha.7":{"name":"@opentelemetry/sdk-trace-base","version":"0.25.1-alpha.7","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@0.25.1-alpha.7","maintainers":[{"name":"mayurkale22","email":"mayurkale22@gmail.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"},{"name":"obecny","email":"bobecny@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"2df18432d5a71f0e770a8f5bcc5c84eaf4c0c580","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-0.25.1-alpha.7.tgz","fileCount":147,"integrity":"sha512-3UrzA71WObun2L+NbrO6iJGQqSGnXqLKT04owUtWO1fVUVaYulTy45zu7caA4Y8GrO7BKiCglzICu8SfQ8bwxQ==","signatures":[{"sig":"MEUCIQCD4OSgZ7jj2n+j9BFZLCDxoe3drQp5qh+1CxEqKGC11QIgYQHLNxm/CR/1WEeJNhFs4v4oor/75XOXZdOmw0ln0oc=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":238786,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhKSzQCRA9TVsSAnZWagAAp5YP/jVVh5NPgHRzsGtznFca\no/xeMefN3jRoaXbhtbmQbLs14jL3/AuJ3yn0rSx2u62jFSchuEzGh9i13MBH\no4PrKBlzOwnvYtoDjlQ7ys1ACuusXh+ExTwiPO5X5bFnahDVXzfgTpjzK9GG\nb3bWA6O5DzmaX6UA/929snOdPssOBSFYCEBBWonwBmBBJ+IMEjSPy55RChHz\nw8GVt5A0IF5W2ZaLVdScdVuRCoPAZ6LRd8bpI/H5CnmFPxtfX1YW4zjZh89g\n3qWuXKGQM1wtsJT3oesgty/guyiCCrqmeS/fxbY0+L7F5FirWC6Aj0XsGy/j\n+iZYPl/Y41Oi4EixjREKMm/S4lckyMY0gv3EhBMrkg3jGBRZAYIMR3JKW9pN\n9VTGNpG3Fd32ZyViRXtDcfxMUr2P4+yaxHRm6ERFwtTeFuBTgEXWyHMsSWIc\nONmZ1iFb2gvRPh6E9UVpnf3mSjujXIBRzgyjAXNuStbeIXO9MZI+R57Q2PsN\n+vYY1qtHv2/ygw/2Wu985Ky1L0kqOKQwZ1HnX8hvvn0Dd5cPSUlHtA8Oi2HM\n+H+Jiz85aeXsHuFb2beINmoV3g4IO1HKsfrYXxRZOskLHD1BJ4SIZQ+ohhQV\ns+NIaNtRmCLgm81Kila2zo7sstnpVc/Dmv+EqS7KUjYFZFvqSk2RDvKexuIV\nHV7m\r\n=bXAb\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js"},"engines":{"node":">=8.0.0"},"gitHead":"dfb597def863b15b37b24d965018e8c92d2ee70c","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","tdd:node":"npm run test -- --watch-extensions ts --watch","tdd:browser":"karma start","test:browser":"nyc karma start --single-run"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.17.5+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.17.5","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"^0.25.0","@opentelemetry/resources":"^0.25.0","@opentelemetry/semantic-conventions":"^0.25.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"15.1.0","karma":"5.2.3","mocha":"7.2.0","sinon":"11.1.2","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"8.0.0","ts-loader":"8.3.0","typescript":"4.3.5","@types/node":"14.17.11","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.2","karma-webpack":"4.0.2","@opentelemetry/api":"^1.0.2","@types/webpack-env":"1.16.2","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_0.25.1-alpha.7_1630088400146_0.9518154290635452","host":"s3://npm-registry-packages"}},"0.25.1-alpha.12":{"name":"@opentelemetry/sdk-trace-base","version":"0.25.1-alpha.12","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@0.25.1-alpha.12","maintainers":[{"name":"mayurkale22","email":"mayurkale22@gmail.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"},{"name":"obecny","email":"bobecny@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"690d9c2a6996aa8750fd0337ef74b5e30153e965","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-0.25.1-alpha.12.tgz","fileCount":147,"integrity":"sha512-L/bR58bGua4XoVFuBzOmh91UGrM5rhPF8n6LiWPe41EWJv4qyXAJGaCSAJvGjgM+QhKq10ovLIP3MBQnagZEcQ==","signatures":[{"sig":"MEUCIDcQU49VPQ2p1OxrCZnRJRihRmBNOGV76F9zIkvMPDmzAiEAnWJ1gaHQf3MPAi0itikgidfssSjLWuLlL6naPsd085s=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":238817,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhLT3xCRA9TVsSAnZWagAAfm8P/iVFL3CAczgQ4gh3XANX\nxkvZ72MAb69BWMUzzZcUXgHg7h7mJtwFP6AiZtXjwqUt38mVicSTqAjkMxj3\n0v5KbSYCmj/TygAvdFjeGtUnohA+aTx+44GA4LGYMh7yCXwg05hM8kuL/Af1\nZO3PbVkW+zzM+BIoO2rrv2DR+gm8TMhQmT2842k1D8+IbgB98cKpBf7a5qVv\nmPM6fWCVa4WooTwOlJdBeMzfj44yNhhFdvEzOt8asaHtF+EiSzmm9fPi9woT\n1ALWnpy9V4fp21wcNNvbDzfoHqb7A/OTlu+MMntLFmEOzs18HPOL+AFJrpKu\nL+eP0trSPZJF+cMdlwmkxui3J/glPGAg6KEIjJnw2lz5H0w++6nbt91WXeWy\nPeof54TJ6zjjivE+Lukl1s/DcrHWh1oUaPbmvZesasB2AiEw2CeN9waFHSAt\nlSM0Z5W0d6PYzr0OxtTCzVgCQiEG3i5p9sWuBdDktdC/e1fYX8at9KB2amfw\nTHuadJ9LDZpsDPann/BpXw0KdYLPNMecKTwfLAoF91RXCoSJ9lRlGB+6LiX6\nrotDmt5uEpKWS9QkhfOaOZTnNErdWPKfbk8B+ZhdYQ/ACCbDBbHeB04iL7vZ\nNvAH0OQwIR0XmbPuxgaNSqgnuSyPDm2RVp9y86ZgliuEZu/Rv1bBUi/abbS8\nNuqF\r\n=egTX\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js"},"engines":{"node":">=8.0.0"},"gitHead":"7d2c4aaeb08e6c680f8b46cefcdfe955d7abe4b2","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","tdd:node":"npm run test -- --watch-extensions ts --watch","tdd:browser":"karma start","test:browser":"nyc karma start --single-run"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.17.5+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.17.5","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"^0.25.1-alpha.12+7d2c4aae","@opentelemetry/resources":"^0.25.1-alpha.12+7d2c4aae","@opentelemetry/semantic-conventions":"^0.25.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"15.1.0","karma":"5.2.3","mocha":"7.2.0","sinon":"11.1.2","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"8.0.0","ts-loader":"8.3.0","typescript":"4.3.5","@types/node":"14.17.11","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.2","karma-webpack":"4.0.2","@opentelemetry/api":"^1.0.2","@types/webpack-env":"1.16.2","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_0.25.1-alpha.12_1630354928769_0.21178081484243938","host":"s3://npm-registry-packages"}},"0.25.1-alpha.13":{"name":"@opentelemetry/sdk-trace-base","version":"0.25.1-alpha.13","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@0.25.1-alpha.13","maintainers":[{"name":"mayurkale22","email":"mayurkale22@gmail.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"},{"name":"obecny","email":"bobecny@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"df007e5f5653f164069be102c6bcdb5ced6669c1","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-0.25.1-alpha.13.tgz","fileCount":147,"integrity":"sha512-7PotUD3giX/eHFbNvp5UJaQ+YqZ0u3SyLneG7YKk9uyp3YYlU7UFfcBfh3x0z22FPdMArJBefZEHymbKTy3DRA==","signatures":[{"sig":"MEUCIQCpK5kc70OjUqwOaLJEQ20suyEP78oq1igPUb6imueg/wIgeJOCs8SP/YX3PR6BgVbVriWZkIC84r5jJDE1x7uWqN4=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":238972,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhLUJ6CRA9TVsSAnZWagAAnOMP/RLKjP8Dx0ueknV/3Hx9\naaZtc6QtAxqzRoSLIp09C9EHhbXHEu/VdCFKYnfWmqdhraU90m+RDULLepmN\ntXFJr/sK3hSE6rhgjPxsaZ+mPhE/FxBvfF4K/TPRFOVrdprNasw0KM5CjVFW\n+oM0rbgasDZk9h/ir030Fw5XxzxMFdWFGhOFV7TITIngA2l3aMQwdRWmm5Zx\nP2jiYTBw+JDkBO2wrB3c4nfQmuheKlvHx7trAmmBDktgKluMLsMMYagYlwt9\nqf+AArAUBn+R8NEcBoT14rtl+h8kfKeatJ2BOzgidACkDcSEAiKG/UhU08nn\n6XyFbVLBqb4pfLWN8jeu2WR1CFPvOtfppmV0fOPDPfSnDhnyXP+FpKKo32Bf\nCk7yhyCqGHmSfYD9EDCMed+9UEjTHY5dDjPOPO7z5nJIFgo+Fs9ax5HtNh9U\nnQQOzpKQlwWmrVOheENybm9slkFaQLvGzziZNGZMG62/X/D+fvRUCK/V8vo5\nz94icTsRxCZ4pSbIIb9+Bj9lh4Bx23DuUO+UaMma0FhVImsOhjWY1aCEiV3B\n+hAtC13RON4qT7pqqtrG/5rIKEET53U0gdoggJaV6aiULeoQD5LNWv7SOiEE\nEnnBXPqScP2/n3TtwzoupT2PumMmTFBPKyqel6htr1JhhoJPW5gA/Itq1eTR\npQRk\r\n=wdjK\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js"},"engines":{"node":">=8.0.0"},"gitHead":"f0caa22ffcb26af2a2f05260f138a494e120a955","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-filtered-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.17.5+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.17.5","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"^0.25.1-alpha.13+f0caa22f","@opentelemetry/resources":"^0.25.1-alpha.13+f0caa22f","@opentelemetry/semantic-conventions":"^0.25.1-alpha.13+f0caa22f"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"15.1.0","karma":"5.2.3","mocha":"7.2.0","sinon":"11.1.2","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"8.0.0","ts-loader":"8.3.0","typescript":"4.3.5","@types/node":"14.17.11","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.2","karma-webpack":"4.0.2","@opentelemetry/api":"^1.0.2","@types/webpack-env":"1.16.2","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_0.25.1-alpha.13_1630356089912_0.49133518504216656","host":"s3://npm-registry-packages"}},"0.25.1-alpha.16":{"name":"@opentelemetry/sdk-trace-base","version":"0.25.1-alpha.16","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@0.25.1-alpha.16","maintainers":[{"name":"mayurkale22","email":"mayurkale22@gmail.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"},{"name":"obecny","email":"bobecny@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"3e59bd15213c7ed7a95407ac657190df9013f2bb","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-0.25.1-alpha.16.tgz","fileCount":147,"integrity":"sha512-xYPEm9jw1p9+Y7SPAHDcWIC6t4sewzOxfu5DqMxZE+Ze0MnQMatwCOvdO2EPMy3wkeFY7NJJjxlavVpzXCAVMw==","signatures":[{"sig":"MEUCIQDFwR8aIHNvMiRyvUYQQVlvKKFGnsfwCD+oVEztecBHbwIgFogvaGvTP+WztOJIkbiQukLk4FTcPJXQmxX1hSpbDNw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":239036,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhMyi2CRA9TVsSAnZWagAAVkoP/iuad8ncSZJBEpyUK+Sy\nKYe4lSKqs2mQNAW//AUNRGAWbY95PLIliKCZvserpg1TQlcNJGou2aVsNiaA\nARU5FnQXb3VNgrVBlYGcbyJWmlZ8kGwwxFigb/q9vV6TmLdKUtaOBD+9eGOD\nnz3+5LXPV62uLGGs9L1eX6WgqAlEJRab0IsVGoSN6hqLu+8GnO1cE0zzuc6j\nlDces+kFs6UuYbADMSjnRmac70xkMDuDYWYBycW8Vu/LttXVklSemCtERjgL\nwjU5SIEqyGLmGyp5+YMvO4R31FYThwG2Vxumj10HocJoWi2nEHys+Hhu6fSL\nr6imKBDFxzAXNPtKm8dWpAtPYbSYr7w5D3lPmln45PRdoPXqqD5lR25ywGYp\nXZMi1UaQP/eWZ6kXFsWHwy+VyZT2aX/51BOHFYxlqhtlEFX4aGb4qwEzzP3/\nFnKltC+lEHykB/hSGiMjuXBcnqo47PDpIPSBNKtqZ/K+vnuDr9jAh/lBFdgk\nzNaE1ut507pNckfk77+QVnqyTH+abHmQZkjBUqPEY7Ljuq6IzGiQvPXmR9yq\nM1acS9Kbj2qxlmN8TmXRm0MD+Ncy7Ymayk4E5bkw6CI/mwLF6Ao7LsLGNWbJ\nvk8tOt3HCBm0z12FzQiEAZSZQMcb7ylznYMfNOFE71N4F+OhCP9cbjG4jfNE\nMw6a\r\n=sEuG\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js"},"engines":{"node":">=8.0.0"},"gitHead":"63f6701081e3e4a7eb964bb82cbd8cbc2eaad347","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-filtered-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.17.6+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.17.6","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"^0.25.0","@opentelemetry/resources":"^0.25.0","@opentelemetry/semantic-conventions":"^0.25.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"15.1.0","karma":"5.2.3","mocha":"7.2.0","sinon":"11.1.2","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"8.0.0","ts-loader":"8.3.0","typescript":"4.3.5","@types/node":"14.17.11","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.2","karma-webpack":"4.0.2","@opentelemetry/api":"^1.0.2","@types/webpack-env":"1.16.2","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_0.25.1-alpha.16_1630742710731_0.6843385580327839","host":"s3://npm-registry-packages"}},"0.25.1-alpha.23":{"name":"@opentelemetry/sdk-trace-base","version":"0.25.1-alpha.23","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@0.25.1-alpha.23","maintainers":[{"name":"mayurkale22","email":"mayurkale22@gmail.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"},{"name":"obecny","email":"bobecny@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"678ad69cfe2826f4f497f1fe0484576db5d23e88","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-0.25.1-alpha.23.tgz","fileCount":147,"integrity":"sha512-+nwTWJZoNWoc+zAE4yS+U9q1+qGD3sJGP3qUW9CmObVVW15ySP1tl3BDHiBFcB7ILQAhx/ObeS+pWZN9CL5JTw==","signatures":[{"sig":"MEUCIQCOW2HsF3Q8kw7GWYO+2Xm8AjoSiyYLsaMgzRUUWwVPNwIgFKJkmK5rUEfZxZM+R7Xg991DAuwoJWytg4sPsNJE6iQ=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":244906,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhOTXwCRA9TVsSAnZWagAAt4gQAJ4KGXGYny0wx+AEs5o+\nhpOUqvkyxY0FZBmS/XlF6Rx1MnH3zubA4925uZcK2giaQOMn3Ap5k3UkeDjP\nxT+btSm5hZvjnEjFBhA1zAo4Z1Vz2hqdj6Bc85RU5mUCFDNV8w899h8Xj/F/\nhwSLJwuPEL/MnwptLXf9NEvy9S+nMNy02gt7sbf/fK5dogJXxHAuZXkoHQst\nRl5U0pYESJtFCStYitzP9/vdsxjIv3pbPohrFxym1ifRKi7Is/YZf7Ege81R\nTLGX9aMH70AQnR75LwvPq2ApxQ2F2xbwDOhE6gbVKH+8F8jLBm7S5OBMzEwp\n6/vepagI7gU9xQRu+4j6XbYurnJf2ZmnulOFmARz98hEyWAvtEd9zN0E8zVP\nMjPO89/UVixzYUbXJz5e9EUP60/CoT8ETl4eHF3mmX0/FXmde0xG6KNKEI+u\nd950FsxHQg+WBfcC02eaNsjyYvavO+zxtAIkehnFOfXe1Mgb1/KdTKUhsm6d\nkKR2loyRyLVYxPYCq1YEq/a/NJCJZPofYqJ7nJA/0Y6gpgwKG1rXzPN1kcNQ\n2bZYQDwSCmAsVmBYFCb1fRTzM6w7v3a8/vFKcv4Mf+fZoaW8YrKlxm58lXqL\nOsdPIpiiH6ACsk4JvHTPCxoI+CpDwxCPDl7uu59VdF9ZgIv2M8RJr6EwQFKR\nBa93\r\n=b4/p\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js"},"engines":{"node":">=8.0.0"},"gitHead":"feea5167c15c41f0aeedc60959e36c18315c7ede","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-filtered-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.17.6+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.17.6","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"^0.25.1-alpha.23+feea5167","@opentelemetry/resources":"^0.25.1-alpha.23+feea5167","@opentelemetry/semantic-conventions":"^0.25.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"15.1.0","karma":"5.2.3","mocha":"7.2.0","sinon":"11.1.2","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"8.0.0","ts-loader":"8.3.0","typescript":"4.3.5","@types/node":"14.17.11","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.2","karma-webpack":"4.0.2","@opentelemetry/api":"^1.0.2","@types/webpack-env":"1.16.2","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_0.25.1-alpha.23_1631139312167_0.5525742629314336","host":"s3://npm-registry-packages"}},"0.26.0":{"name":"@opentelemetry/sdk-trace-base","version":"0.26.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@0.26.0","maintainers":[{"name":"mayurkale22","email":"mayurkale22@gmail.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"},{"name":"obecny","email":"bobecny@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"9f8a0b7e290d63eee67c5a5be921ed21d293c70c","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-0.26.0.tgz","fileCount":147,"integrity":"sha512-SqV5pccxJTekOXdE1jp5VWxZ7GYw8rrHy7g0LcxLzn+D8YJ9ZBhE481VrP9EsjyLlJRhicv+z2g1XFxpMkQdmA==","signatures":[{"sig":"MEYCIQDSU95sy8kG+hL60kiMOWHMrqvjMCzH1W9eKUABO3bf7wIhALdpLXNwZ59gj3Dz+YO1EUu6ZL6nTEr5VqN09jbTbkrV","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":244852},"main":"build/src/index.js","types":"build/src/index.d.ts","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js"},"engines":{"node":">=8.0.0"},"gitHead":"fa2e897587a2441205fd085772d80a0a225ee78e","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-filtered-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.8.0+x64 (darwin)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.8.0","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"0.26.0","@opentelemetry/resources":"0.26.0","@opentelemetry/semantic-conventions":"0.26.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"15.1.0","karma":"5.2.3","mocha":"7.2.0","sinon":"11.1.2","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"8.0.0","ts-loader":"8.3.0","typescript":"4.3.5","@types/node":"14.17.11","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.2","karma-webpack":"4.0.2","@opentelemetry/api":"^1.0.2","@types/webpack-env":"1.16.2","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_0.26.0_1633005332268_0.16476052719806322","host":"s3://npm-registry-packages"}},"1.0.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.0.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.0.0","maintainers":[{"name":"mayurkale22","email":"mayurkale22@gmail.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"},{"name":"obecny","email":"bobecny@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"f025d517fa2386ed2ccd534dfafa894ae323dc2e","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.0.0.tgz","fileCount":147,"integrity":"sha512-/rXoyQlDlJTJ4SOVAbP0Gpj89B8oZ2hJApYG2Dq5klkgFAtDifN8271TIzwtM8/ET8HUhgx9eyoUJi42LhIesg==","signatures":[{"sig":"MEYCIQD0Zq61lp2goYcIDSNYrkSWaH2vcZkgym51d8Qv0RnyegIhAIP2T7OO8FtZ4nr9eNSN4CCmgB6oUCf+qdYOyzGHX0Cy","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":244844},"main":"build/src/index.js","types":"build/src/index.d.ts","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js"},"engines":{"node":">=8.0.0"},"gitHead":"69b925d142a4405c7c6bec7deadd8b4e96c7d5d6","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-filtered-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.8.0+x64 (darwin)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.8.0","dependencies":{"lodash.merge":"^4.6.2","@opentelemetry/core":"1.0.0","@opentelemetry/resources":"1.0.0","@opentelemetry/semantic-conventions":"1.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"5.2.3","mocha":"7.2.0","sinon":"11.1.2","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"8.0.0","ts-loader":"8.3.0","typescript":"4.3.5","@types/node":"14.17.11","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.2","karma-webpack":"4.0.2","@opentelemetry/api":"^1.0.2","@types/webpack-env":"1.16.2","@types/lodash.merge":"4.6.6","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.0.0_1633035223758_0.4156184977353712","host":"s3://npm-registry-packages"}},"1.0.1":{"name":"@opentelemetry/sdk-trace-base","version":"1.0.1","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.0.1","maintainers":[{"name":"mayurkale22","email":"mayurkale22@gmail.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"},{"name":"obecny","email":"bobecny@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"b88c72ac768eed58baab41552ce9070c57d5b7bf","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.0.1.tgz","fileCount":147,"integrity":"sha512-JVSAepTpW7dnqfV7XFN0zHj1jXGNd5OcvIGQl76buogqffdgJdgJWQNrOuUJaus56zrOtlzqFH+YtMA9RGEg8w==","signatures":[{"sig":"MEYCIQCC9fuVQZArSWRg+N89DDvJIHnMbymcyIIBAUzJymYEJAIhAKK+sjb0Wu3J5VvFZC39vqGlZ+/poFxV7Xoruc1qW6dd","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":375519,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh2UqlCRA9TVsSAnZWagAAatQP/iWXTWUBoGG4nIFmKkxS\n20Y1VIKi5N3udvMq+gwnTxYXD0sTjV01spACjY86atMx6ZHRn/0CfjaziMkU\nE4VdMnWOceoQlSzqWDLa9NNlAhmH6GV/+c36C9uhoVL8SDemHpX2wvIwv2cI\nyLCc5bdR82lnLePoFRAc34V/7jJHW3ryIbCe4eH/8Y23lNDaL1ofKXitYjfv\n1yOlvTK65xJsdQ+8CmBBQfdMqqpaw7ahrH6CxgXj//9Z3egZN7qiAhTjJWK9\n5midnB313D3jiaS2OKkb/MFrIfIuOpcL9Bd1TciKOTbDTlkFjgL/EpQ1MGSA\nAQJohsQeOYqvFIuouG+56qRqS094kMgvVYkQXLqTVHRvzxptc7Ai1H1YdKCh\nHEdWBIHzM/zdp/wKMDz1IjNrRefK24/yfWxv1YYPoCnPEQ2ZGHmfgMX4UiNH\nLiaVp8rVT6Lnl3hALEuJZrRP1Rxl0lbfPFb/ZxWv457LRJ2jsX58MsTrSScO\n0id/wDTYJcuzzX/auxRzTTfZy/vQtjQyy48tlAZbnJ8/EnTpNU+2whsWsSYR\nfUS8AeW4L5gXw1rfqJiz76QPND0ea7oa3eiiaXCqOHAvcalMzeYfdR/Eye8D\nCSky571jLOzqrHOaFsude/F9jvXgGEMUtqRbKafWNxmkjaFF6FXqyucYcLgh\nlZOZ\r\n=aKC/\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js"},"engines":{"node":">=8.0.0"},"gitHead":"9cf402ee4231ee1446884b5f59958ceafc1b5188","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-filtered-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.18.1","dependencies":{"@opentelemetry/core":"1.0.1","@opentelemetry/resources":"1.0.1","@opentelemetry/semantic-conventions":"1.0.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.7","mocha":"7.2.0","sinon":"12.0.1","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"8.0.0","ts-loader":"8.3.0","typescript":"4.3.5","@types/node":"14.17.11","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.2","karma-webpack":"4.0.2","@opentelemetry/api":"~1.0.3","@types/webpack-env":"1.16.2","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.1.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.0.1_1636642284812_0.1678333829919234","host":"s3://npm-registry-packages"}},"1.1.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.1.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.1.0","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"78833810991679a634f440aa3055b22fab9c033e","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.1.0.tgz","fileCount":75,"integrity":"sha512-L8WTUKVG+E3IVTTJ0FoDo5YwsEkSOGMFOCBJKFH8O7uV1bFny52ASyWaNrhhl5kRPGlkHtsUnWkgnQm9Ne3lRA==","signatures":[{"sig":"MEYCIQCxrsqZRfunV5YR0FGHmGWA6ok09L/bkBxVJhAyHioH2QIhAM4ZoSV///YZjO2/7AZIhJOQmcwMrLNQo/dE+EgbnRA9","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":194582,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiND6VACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrXIQ/9FtTOkR2g4MFiDgnehThC4HE6EDI3YhK5hVSeDlu8a5kEC/Dr\r\nfaNCFDev7W7G07hhnRYf6OaYMXtZHAMSJ3mjIUIJ8HE/R898GPYZi5udmgxY\r\ngPzF0B3GIKNT6fFTnvKQ+auoQUxfa96V5teMUAXWgWvQkgAAcPgtETbG4BlS\r\nGwuXmfxovxsYyI61VvNz3yUNA9MybAGN49Sv7RW13aA95ENT8nnQwBVRHRc+\r\nEViVyVe7cDHJvxvDuGOPcmtqxGTP6Q9JRq81K4VI1P3GQsS8vCWEND0gEE1q\r\nUJkU6QNwO7QuEsOMFklhS/bLruc7kvUpwr2y9+2lp+fHpCVPF1zLzMzyV8+9\r\nzemMXzG/afyRFAjwpYk1VLhRXL+dbwL+hFn31TrwBI+NqkFvB4Bndm/D7IsM\r\n8xNJZm/CsguwKj4oq2fJcCWpGxKZPw1u0a2RoqXabWoF8OoRE+b8DM8e79w0\r\n+ol/VgyOfBL8B8td7RuxN/xzIwCepSMZ5A7RWdkmhDJmHtdOxhtH8xDcekqq\r\n/1PEhvJeqBnqEvV2H0S9zCAZrAHPoVjJSSwPaDSc9guJeeKYSIg6wWcOrQzU\r\nYXU1Thvv4hILbfUK0tc3mdp9MDVSrMxbHnyRjV0B3Yyh/YUYWUddZ6T/imBP\r\ndjQxrAeNtrmBbkWmtXsflLikHSPU30Mqzgo=\r\n=scwK\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=8.0.0"},"gitHead":"f384303ac469914d0dbafde0758ccdae473f336e","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.all.json","watch":"tsc --build --watch tsconfig.all.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.all.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.18.1","dependencies":{"@opentelemetry/core":"1.1.0","@opentelemetry/resources":"1.1.0","@opentelemetry/semantic-conventions":"1.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"7.2.0","sinon":"12.0.1","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"8.0.0","ts-loader":"8.3.0","typescript":"4.4.4","@types/node":"14.17.33","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.6","karma-webpack":"4.0.2","@opentelemetry/api":"~1.1.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.1.0 <1.2.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.1.0_1647591061708_0.7080112200023543","host":"s3://npm-registry-packages"}},"1.1.1":{"name":"@opentelemetry/sdk-trace-base","version":"1.1.1","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.1.1","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"2277e44a8b90815bb3c23515cae9de57ce902595","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.1.1.tgz","fileCount":219,"integrity":"sha512-nj5kFly/d6V2UXZNi3jCaRBw44/7Z91xH0PcemXJTO3B6gyMx8zIHXdnECxrTVR1pglDWYCGs84uXPavu5SULw==","signatures":[{"sig":"MEUCIQDXcQWtqYJJV5tMuOB7wmN/al1uzJBLOH5LbMyGcrtHPwIgMBptxEBJsLebjv3XbdtlJ1TDGW/M5LwieOF/Xd6rpUE=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":552814,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiOij/ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpaKA//T0QbIUoelYuNPxDaBDM0ieilM+eh5Nyy8dP3LRocnfOfGVo6\r\n1+zkp9C58SOO2k0uMNgJ8BcMgXxBd+zcS5W+/J33LCvbP2ZpCMBQrOGa6kny\r\ndV5FZRE73sUBCDkY+/81ehyOiXXLW46313zGCBgpX9p/HwivTjT16PNYrr6k\r\n3ZZiQmb9Tm68VnVLOENIqTspRHzjq7T8+9c3fmdLmiNdrhP6k3y0GE2vdg0P\r\noHNrGD2NQCARK1RLMJNF9a/8/hK6dNERoQKWydjV5y6fTV8HrIHsVLzrNvXs\r\n0YF1N8ZJgHUoqYsTdKQf92kr/j8sgMsUFxx3cku2t9qcQHffY5GxmPgn/fTE\r\n8bZZ7mPhmsf8aXih/F24cInMD/Eu8mKktpov+agemmD5RFEMTUWeDV481din\r\nFOUCRJUDTSserEa580XBRkUsdUr/Gb6dm9JB8mxGQwIWJ6ZUW2K+RqAb+FdR\r\nMCDShq+C8YSwhSIaTeCIJce8NX+ca9NtjUO1sIPqVNIuisyO6NOz0keeVKXH\r\nO0xRTz5l8Jog/Gehka1hwbtUtfcVswEyZg4SvVKWmcrb0HYVW+e4dClEBr1d\r\nAp2QgpnUaIhcVNwjuMkSrGqiTvA+ehBvWMPk6r2zi60fHImod/+0d462yI9D\r\n2rgR//laEPnSI8sHJx7q33Yi1s5qXMUqzaA=\r\n=2PCq\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=8.0.0"},"gitHead":"b0f8a2d36e6d1d3090c3d2380608d2102c826e0b","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.all.json","watch":"tsc --build --watch tsconfig.all.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.all.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","prepublishOnly":"npm run compile"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.18.1","dependencies":{"@opentelemetry/core":"1.1.1","@opentelemetry/resources":"1.1.1","@opentelemetry/semantic-conventions":"1.1.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"7.2.0","sinon":"12.0.1","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"8.0.0","ts-loader":"8.3.0","typescript":"4.4.4","@types/node":"14.17.33","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.6","karma-webpack":"4.0.2","@opentelemetry/api":"~1.1.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.1.0 <1.2.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.1.1_1647978750976_0.4451688237419007","host":"s3://npm-registry-packages"}},"1.2.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.2.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.2.0","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"aac5b79dbaced92a886fb2e348e54f5b681205ed","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.2.0.tgz","fileCount":219,"integrity":"sha512-eHrG9c9OhoDhUmMe63Qzgpcvlgxr2L7BFBbbj2DdZu3vGstayytTT6TDv6mz727lXBqR1HXMbqTGVafS07r3bg==","signatures":[{"sig":"MEQCIHxDeRJ1Y7SkEGT1p7MiTG4y2cOugUZZeZ+XhrikR+tTAiBWEgxMhwJy574hneXGgEi37Y37vhBQlNd/xvWTQr/SVw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":556102,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiYsI/ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmonHBAAj44NYQVANyFTg3YLzIsIJhityCIuLvyhLfar3YpD7IkGrrhZ\r\nT9U/D2fN2wdSfoeD/Z7dGu89Y5/AmmPWWEEe1SV4aPY9u3mXwiS6E27zX5sg\r\nyLkIHYphlU1bDlq/FHYpp5v9ptK6SJa4epgNBFrBNfyQg2vT9EWyyB9W5jOH\r\nQ10w9oEg3DY9MtH06PPh+VLIJqslxHFFTaEC5nDIz/+yfqXjJb2F11G7TL2E\r\nSoisfBXai9rNnUebsTLc8r2J+mWwlcZWHThTZQkeBw0eAw7BWMPIaWWnbl6k\r\nzNS686ldebx1dhQjD2qkuUabqHh4EuJoMvl7KCCYgFjWmRhXv5q9zog5HpsL\r\nkDSCxnLVP4uEjnKcQ7tw2Vru6+7AejaanVDeUVkVmW9MCNCZgyFQrDvq/I6e\r\nnVLTjrh+nLY1b6ulsliiwi0uUglQl6rgX8ei3oe1C/+fKg0H5n4ysL0Wdkak\r\nlEnaryQ9b5Mu+HYOLC4leatb+Ob+Tzre+aspQ8E+I+TbFRPqEYwAk9qTC/27\r\nltLXlSNb3sCzJXIrPg/fRQXDmi3Mq+j5Et3Xr9XiifQLwq+odpd7bh7tJ468\r\nzEiU+7v17c4vB/sq1diy3DL4H+qIcwVTffl5PRDY2p2Mon66Nruumx7vgxnd\r\nCYcdeAhqcXuo2O6XPltblnFADHHs56BOMCo=\r\n=MSTB\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=8.12.0"},"gitHead":"a0a670a03fd35b0799bee8cc466f79e93b5b6dd2","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.all.json","watch":"tsc --build --watch tsconfig.all.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.all.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.18.1","dependencies":{"@opentelemetry/core":"1.2.0","@opentelemetry/resources":"1.2.0","@opentelemetry/semantic-conventions":"1.2.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"7.2.0","sinon":"12.0.1","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"8.0.0","ts-loader":"8.3.0","typescript":"4.4.4","@types/node":"14.17.33","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.6","karma-webpack":"4.0.2","@opentelemetry/api":">=1.0.0 <1.2.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.2.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.2.0_1650639423630_0.5047606523204053","host":"s3://npm-registry-packages"}},"1.3.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.3.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.3.0","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"eebf6f553e49ceb309d346b8de7c9257686bbec3","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.3.0.tgz","fileCount":219,"integrity":"sha512-BkJEVdx46Boumgy0u6v+pm7spjOq7wCmClDFnHvQs8BS3xjmfwdiReoJFcSjo0cSlxkTJh6el8Or2l2nE3kArw==","signatures":[{"sig":"MEUCIGz/0H3rGWRaHX0jlcn+6uukc3qzgIuKUgwQEgJ/3hoqAiEAzMR9u54IyMmxnMYkD/aoKGBz0H1UhWhby2nzZXGtqFw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":556534,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJikSlkACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpNxw/9HOqfRpUb4IKDqrn+hwiDh+sC4Nbwoz1NLjZVNN8lCqDA7Bt6\r\n7j+sgVk3xxbuTQAKxpIst+8vYkEbY3QiaYEU3Xs+inT92ky2J29s0NUE1u5j\r\n4G8g/vHIuAVb2q6KE1iWi+kTynYE+7LbO7Ao7nRfpqlorKVlMjIOQNCaiOAW\r\n6IwdU34TJXrT3Qya6Z/jWjFnC0e/gG+omiBOnv+UNemQqW5Psz60bRttRAQJ\r\nhY/9U7tgptiurrkCZbj4j5/DsBvLfJKuoXg0nE4jI1Nw5H0qIW0PP8ifZAtx\r\niyw9hoFAeOWb6eA6efQ/UJwXpXEBz/ViX5bIckA/QmDgZPIYrVT2/irowhYY\r\nR9/CAxkSu2UX6tz5lKmQZcYSCmpR2gIvtKV58MwAsH2g5SSkW2biqB0XdTtr\r\nAERTzqJtgrr/kKsSJXtGuBJQ6aRmIUSBGmQUHlU/mkfr+dMfCFxZvjGU5wwl\r\nTfIsifIGkVpytY4YUrQHDEiOA4FfbYNYIA5j8rQVhzcsXAe1kk3iL6+9wQsd\r\nDrI72fSs2KsxPjLhlEyu4LsLhJ51QPdDz9ml96zd2YzCuW1zUrYQ4cPiJuJU\r\nvN4LyaSB5VCMkgpgj9SmcIQsqB9X3JNBr/+2ajElF5HawwmI6NlzADfOQ4F9\r\nAozt+rNMEJKi4bnqab+pMfrux8B7nx3++Os=\r\n=7Hm/\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=8.12.0"},"gitHead":"eda0b092db484855ded8b4837ba7fc19a377c5a7","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.all.json","watch":"tsc --build --watch tsconfig.all.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.all.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.18.1","dependencies":{"@opentelemetry/core":"1.3.0","@opentelemetry/resources":"1.3.0","@opentelemetry/semantic-conventions":"1.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"7.2.0","sinon":"12.0.1","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"9.0.2","ts-loader":"8.3.0","typescript":"4.4.4","@types/node":"14.17.33","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.6","karma-webpack":"4.0.2","@opentelemetry/api":">=1.0.0 <1.2.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.2.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.3.0_1653680484654_0.37952356793618636","host":"s3://npm-registry-packages"}},"1.3.1":{"name":"@opentelemetry/sdk-trace-base","version":"1.3.1","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.3.1","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"958083dbab928eefd17848959ac8810c787bec7f","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.3.1.tgz","fileCount":219,"integrity":"sha512-Or95QZ+9QyvAiwqj+K68z8bDDuyWF50c37w17D10GV1dWzg4Ezcectsu/GB61QcBxm3Y4br0EN5F5TpIFfFliQ==","signatures":[{"sig":"MEQCIALi65Rm/zKG8ZBolugN7azramCkJZwJFqjYpR2IuUmHAiAtSSXm3hpjXUpwcBWKdCGjLnayhLgb27nqMu3p74uF9Q==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":556534,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJinmLqACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo1lhAAiUCOLc4qxk934XKQhQW8My+vNgqPeT/tMdJiJ63yEvtbTwQ+\r\n8elNZzkUfc9a2n04eOKZTpcZBdLmdz8kr/L7+SGXVA3pGGRmvOFp29YTVUQ3\r\nN+/Ub3SVTDyyA9vTIss7XlJYUXvWXp3mEDwfgS2i9VVj5gCYyC5zt/LjYP6s\r\ndnb3OlASri2XaZPDzh/QOhkT4HZUbqhnqGCSJc+8fU6IhyrL7mOnS+oX4o+U\r\nWG2Y0wvx9MlkDX4+QwJdrRlDcG7KZjdoSn6p3ORgy8/UJVAGGoUHI4yPDnFC\r\nu+tEpRgnuzKRvtsyywrWx0h0c+fBxV1cCIrHBxPsWK/TlypEv9WbuD17vdz+\r\n4Jm2ljTlDgZ+K4xnYqIV6GFTZosmUiRbhiX76cRGL0PWQAueUwaBBjHhkloY\r\n4lGbLKWxYFBQglSYwYk/QJg1Cn4hfeMspRY2BbG1MgEdCK8hkOVOhq3Cl7Ic\r\nLDBaZ/H5pH1RrWcK/OPRFuta0lqgt65FkEHl/Xkh55v+l4N5yIOJD28CxXvl\r\nsJFWeWX1xluXfMXmtat6qMBZleIvDjtmLpY4G1VzwR85IKWURJb3ePVg5bvy\r\naf/JYHg8yO4mYcfGx7PmvPIH/CJryVK/kIr+KJmH0M5DYDYPMJD6gQbrFPon\r\n2LSUFlqN+LkjbZPXM29ovaaeO24sXaCEvbI=\r\n=lwEL\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=8.12.0"},"gitHead":"51afd54bd63e46d5d530266761144c7be2f6b3a7","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.all.json","watch":"tsc --build --watch tsconfig.all.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.all.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.18.1","dependencies":{"@opentelemetry/core":"1.3.1","@opentelemetry/resources":"1.3.1","@opentelemetry/semantic-conventions":"1.3.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"7.2.0","sinon":"12.0.1","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"9.0.2","ts-loader":"8.3.0","typescript":"4.4.4","@types/node":"14.17.33","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.6","karma-webpack":"4.0.2","@opentelemetry/api":">=1.0.0 <1.2.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.2.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.3.1_1654547177779_0.44314908261854846","host":"s3://npm-registry-packages"}},"1.4.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.4.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.4.0","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js#readme","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"e54d09c1258cd53d3fe726053ed1cbda9d74f023","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.4.0.tgz","fileCount":219,"integrity":"sha512-l7EEjcOgYlKWK0hfxz4Jtkkk2DuGiqBDWmRZf7g2Is9RVneF1IgcrbYZTKGaVfBKA7lPuVtUiQ2qTv3R+dKJrw==","signatures":[{"sig":"MEYCIQCLqLk4sGs7ZlVm8eZVQO/gEw5B3TPiumDqB01dNJpsJgIhAI7a5bQFkGJly7Ar3CdIQul5vtwyWdO8IL4xekGMZz1g","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":557399,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJixe1qACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpkJQ/9E4JUmYpvdZvT8BmFGBAigK7zC7aBNaV3+jZoUnZBtxnS5pv2\r\nqdydK5nhXffwCWeFMEqdI6Ab5vWmUQJsBWk3PsV2FqtVM1ivv3aWeWLlTFAO\r\nR1wmFQVk9kIBDGVz21klCFauyhbHbj0OdYYlFFCjfMPZ1pfOHjyqNbE3HMYr\r\ny9dxnK9yffCB0U4yfB5GnEj99xC1AvXSkBDm6UFQLfhfioW3iCMfUi4kWPKd\r\nEwrrRg2XgsrNi++xM2iK2tLu3cgcmRnAbo1CriwE40ffSqohVMs6nohicdi7\r\n4V/j+buJJO6gCm9sRnrdmhvvHy6cExNqaE+qF9nJn2phL7YS3bIzjtq1hQyg\r\nvpwIe4nE8mZ7a/2cDCsIGK9uIcvsvgwbkHbH93q1J/l5MasVu2xTTn30bVjX\r\n1T0L0TE8b7193vjf41eki3YGPDC8pgdjdyzE+fB1WQGyogOpcNacwVbz+AmI\r\nZ+9pyjvBhLcMrZByLl6oKtMjosiJi+IAuoUnDDHOQ7GSFOnGKshg9/trbv3r\r\nkQP98YJcnIwc7aKSBYF59C1lSjbLJenJ8Ni5koiipFUQbnz53NLrshMlXq2V\r\nD71MkIfw9MrK15S7W/1uHY46t1B09zkdUC7ILQXXk1/9hi23D4qAn0YwPqNb\r\nRv34ZtYPfb/XaA4b4W05tdN5FqAxmeMuUrY=\r\n=DRGf\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"e39ab883b18636238ef0fd741df4ce5ed53e8d04","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.all.json","watch":"tsc --build --watch tsconfig.all.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.all.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"nyc karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.18.1","dependencies":{"@opentelemetry/core":"1.4.0","@opentelemetry/resources":"1.4.0","@opentelemetry/semantic-conventions":"1.4.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"7.2.0","sinon":"12.0.1","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"9.0.2","ts-loader":"8.3.0","typescript":"4.4.4","@types/node":"14.17.33","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.6","karma-webpack":"4.0.2","@opentelemetry/api":">=1.0.0 <1.2.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.2.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.4.0_1657138538116_0.08054665516123172","host":"s3://npm-registry-packages"}},"1.5.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.5.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.5.0","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"259439009fff5637e7a379ece7446ce5beb84b77","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.5.0.tgz","fileCount":219,"integrity":"sha512-6lx7YDf67HSQYuWnvq3XgSrWikDJLiGCbrpUP6UWJ5Z47HLcJvwZPRH+cQGJu1DFS3dT2cV3GpAR75/OofPNHQ==","signatures":[{"sig":"MEUCIQC1uiO4Uby5qJ5Q4RGt5KojX/NKiuQhrT6XzcGmN5YImAIgYNHGvd7qtO1rZ6/NgtNYF0j2DTITyPg1IWTufbasY3c=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":561100,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJi4FQAACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrCfg//WNcotdRula30Z5YkzhkmwWHZyiBWnHIHOBEOgn36AolkGWE5\r\nM97A0rZ3cfW4DrbdCIjEaavWUjvHpAzER8ta+DiqigspFvT+ko8g5v0fMw2N\r\nbPOXkn0E0zVPCunYFPrcbiG8GEgETjvtPnOlofH6McdgXOyt5tUS/GEI4LwY\r\nObg5BzYs6hRc86X+aQvrLwCA9EroWzfLr4XbmeAkBE5ZEYq0bO/WTz3EujY8\r\nYxW8GnNaxJT70vYlczo5+6IGBASFg1bpALJyidUroNRHDRRQM/MQFZydXaKV\r\nWLEA/1fwTBEB6sfsKY+nzD0tMIRxpZzHvm+qqAO4wEnm8UVx5Y4Oe24baJaZ\r\nYw/Mpi3A8xj/5Glf4G6F0WAuKxEXfbNJ3/OUraE4IofrSKKvv/4JhNxOw+kA\r\nVKX+AnRCdBSPduR/xAyHMQke4Q3YCk50lwSLXYoZeo+VnEYPBe0/hgmFRqzK\r\ngXOsR9ZhxWJ65N3UuOiBYu69OlT31OTxlvDxDOd/SjSngpWeLFEbyq6NPxfF\r\nMkcsnYy6WSaythblJdUebz42u8CX//JSAfT40g2jidnniQgjE35EzrvgX6dp\r\nhB2UoTxrz44DD40jQLAivEMDxL9Sx+GZ1HafxBoxDnp5lgeRaj4r2IBNz4Lp\r\nhCXz5P1ZCR9Ut3YLnhqMRSfMZqvJDQnsD0E=\r\n=lvpO\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"776656b6e0cd0fc49a52b734702bc77110e483f1","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.all.json","watch":"tsc --build --watch tsconfig.all.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.all.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"nyc karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/3.22.1/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.18.1","dependencies":{"@opentelemetry/core":"1.5.0","@opentelemetry/resources":"1.5.0","@opentelemetry/semantic-conventions":"1.5.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"7.2.0","sinon":"12.0.1","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"9.0.2","ts-loader":"8.3.0","typescript":"4.4.4","@types/node":"14.17.33","karma-mocha":"2.0.1","@types/mocha":"8.2.3","@types/sinon":"10.0.6","karma-webpack":"4.0.2","@opentelemetry/api":">=1.0.0 <1.2.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.2.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.5.0_1658868735873_0.36948937296896256","host":"s3://npm-registry-packages"}},"1.6.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.6.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.6.0","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"8b1511c0b0f3e6015e345f5ed4a683adf03e3e3c","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.6.0.tgz","fileCount":291,"integrity":"sha512-yx/uuzHdT0QNRSEbCgXHc0GONk90uvaFcPGaNowIFSl85rTp4or4uIIMkG7R8ckj8xWjDSjsaztH6yQxoZrl5g==","signatures":[{"sig":"MEUCIFGZxkPPycUwga6941/1+5vsL0g57z0IOs9srY9QVTFgAiEA4/3DbZJ+xNNnMd1k9gRasfX+VKzueDJPWlXaDvb6TLY=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":703237,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjBmODACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqCCA//UmDuN/9SBNkotpVIKMbNS/WfQYETlNXctdnZHBP88etrH+Ax\r\nQaM+cxOLvoO8VgneTZa2YcufJmZamgf0N5nnfUBABvNqOxDXfFlnXpgNR+S5\r\n6E1ldhx1sZ286kQqhQfrCSpENUdLxm3puzlJvnOzDrCUBqSAIL4vrE2pifuy\r\nngWrs2LCz+KBb0Oo9Zj+GvXOYKZaITZNVwR5y91aOzzyvhMj7aPumgWpwBOz\r\nnley7aO7CPXY8PyZ6FUUV/5YySSyLxtrGaUzTpwxkAmo8Rp9cB+xDyCKb5hd\r\n1XIZ53XH+XFUH9bK6LMW/NsANgcPvWT+gnXdK9OKg5orV3XEj7ftAWt/r9E4\r\nIWQsv1VO/k1aw4wikslDghIHd9DQGUq8f3qTbZDcIJhoSvfuUrIJWlE6zehv\r\nDWG4nGl9515eNnVvWFGuXLJUZPQPnZrCYS5ocD9viqOGj8Ix6Dp8yEkHA0vm\r\nNQttwwELXX03r0VeEQcFpxXwRzS7avmpRqDfedpl2TJrF/4Bo8TLBkBP1Ht6\r\nVFc408x3eSA3RvJ7gFdhvgqjqYLSLuVP1D/ps66pMi5SG7ykJ3Za05cBznbs\r\nJMp5L33qYYWHjAi2uOm/a0tVpmJMRO3QyLNF24Y4zbuV3apqsXk522MSWWPZ\r\nFsh1V6H5vRKAFEdP5XrBfq1qzaAkwPbw66k=\r\n=8qYD\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"a5abee69119cc41d9d34f6beb5c1826eef1ac0dd","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.all.json","watch":"tsc --build --watch tsconfig.all.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.all.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"nyc karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/5.4.3/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.18.1","dependencies":{"@opentelemetry/core":"1.6.0","@opentelemetry/resources":"1.6.0","@opentelemetry/semantic-conventions":"1.6.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"10.0.0","sinon":"14.0.0","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"9.1.1","@types/sinon":"10.0.13","karma-webpack":"4.0.2","@opentelemetry/api":">=1.0.0 <1.3.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.3.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.6.0_1661363075313_0.24925341140796742","host":"s3://npm-registry-packages"}},"1.7.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.7.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.7.0","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"b498424e0c6340a9d80de63fd408c5c2130a60a5","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.7.0.tgz","fileCount":291,"integrity":"sha512-Iz84C+FVOskmauh9FNnj4+VrA+hG5o+tkMzXuoesvSfunVSioXib0syVFeNXwOm4+M5GdWCuW632LVjqEXStIg==","signatures":[{"sig":"MEQCICxQm5dNE2obRrewbmTbvDUPKjpEDqwe9DMSkjsL+ll7AiBBeL09XWESUAsZEFJqEb/czB9xRqxGSU7ZtYkIxFctxQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":710870,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjJGjCACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmprZg//eVXy8Y9itH7B5owMNIWDUAuuXFpw5t4j4E3Eqsa8PL4MlfLz\r\n3Q8FGv/gMVPNSxTK+Q5olSgI/Dp4d5KuWEzTBPtU2kSSZFQ2hgeMdeLR5zkG\r\n/R0kcPL8z+iFxMsA6eO7uImf5Y9frntttn/el5jfw87X+qjXjV2jwqKJmADa\r\ngQ0TtRLb34gP/LReTYaE6P9pZXAgldTSLku65ztF74lHvPE5Q7HvHs+75uw5\r\nsAKGbVsA5yedjXZ+v8eIE8WL7aQer9VvtkPRXVlFScvim0CCChn5+45seH7c\r\nU+PMzcc97Y4Rg7ntxFy/lcW3OKQaO5yl+gss/WEDx0o7xwlNkITbePhNH0Rv\r\npTBpdcMNeZk1ITbmG1ri8DgjHFJWL5O7pao4yfgyzuFkM4SUYujEZB/Thfek\r\n//fZv8H+t6Ms+MFMciOE++GJS+GVXVgyNXFUWIUWF1eMeO4Y285LygJv453J\r\nN7sld0hrMn4fItZW61Vmj/sRaQuIM8NLUjHTY1jkBFRE39nsrIkWxNJRqjcv\r\n9DQOlzhSAOFOY1EINpYJeW9EAIQkwZ/w0UOd+HPmVDm5bGbCnvqEpiyluj3c\r\nClZr/yjpFoMm9Mx+FwhLaZjW5IXJe1ek9QFDDP61tGWQviV6jNHq5RxjOwm9\r\nOJ2F819hWrl66GKa02rO+gqNugRkAJxpgjE=\r\n=3Nls\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"ad88c3d9aa0100fe259b93f4b660e84417b757ac","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.all.json","watch":"tsc --build --watch tsconfig.all.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.all.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"nyc karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/5.4.3/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry Tracing","directories":{},"_nodeVersion":"14.18.1","dependencies":{"@opentelemetry/core":"1.7.0","@opentelemetry/resources":"1.7.0","@opentelemetry/semantic-conventions":"1.7.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"10.0.0","sinon":"14.0.0","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"9.1.1","@types/sinon":"10.0.13","karma-webpack":"4.0.2","@opentelemetry/api":">=1.0.0 <1.3.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.3.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.7.0_1663330497999_0.322341921882334","host":"s3://npm-registry-packages"}},"1.8.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.8.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.8.0","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"70713aab90978a16dea188c8335209f857be7384","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.8.0.tgz","fileCount":291,"integrity":"sha512-iH41m0UTddnCKJzZx3M85vlhKzRcmT48pUeBbnzsGrq4nIay1oWVHKM5nhB5r8qRDGvd/n7f/YLCXClxwM0tvA==","signatures":[{"sig":"MEUCIGGgOVCWV9iMP+xpoW8qU84MMmAwLSfneZNUCzPnTNKKAiEAzWhHXdc3EDzlA7f34ajtUzAM95QQ/ampFalpD3c5vjw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":709861,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjbANeACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrSvw//ewghTwxojDN+0h1tzWihXLoVTgDtKteumUYoytRWe8RqPLl7\r\nKuzxG5g7KLwqsojCfHp250ofMUwTVR36RuHZTarjpaJ1z3gC/EbROPfsCy2K\r\nIdxiZJLS+5rycgn+P/rqH69Ghqy+O6E1qxAVWNZ3S4px3wGivliDbpj4YlaN\r\nBoTVTuk8THoeg6us5RmM4WMx2lJNIliMtbOF1spyFEL8jfWrhfQFcMGftFAQ\r\nXSSn5fJ0iFWYDkD7psF9MQ/iJW7nEG4Cn4ITjRt0cRgIMUtDRGPJKtY9IwUj\r\nAtZudNs7KQYrZiT3WvaerL4yq6d0iY6lbDXiTvtKof/bRt2xciCaF+5CG3M5\r\nV4JxKS0/YwilsMKebUF9Uz7m5Y/bKr20uMFNgdSSp0vDeReOlcbSOqm1JGf5\r\nH1G1PUnZ7rvuhuYA512plL6sieLNmyhTgktMSL3nMPP9+phj6BEIdWI0eLfV\r\n0xz97XYI+YgKqS2U35vh01qwgJMDcHy1v20e+IVEFi/f6bUUd9NwVJ8y0IXG\r\n3hUikhaCFADqQHDHzNp6mfdNRkJSGzc9zD4mNKBQ+Dg8xEWNQwDq2pjCiKfI\r\nSey6HSU4D39eLnxPV/sB7+NQ/wav1w0vtFUg2GWQl7yQmI/OOROiBfyKYBeW\r\neL4oPyD0Beldz9ejMY4gT8aX6Y+KGU6mc9g=\r\n=fY0q\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"7972edf6659fb6e0d5928a5cf7a35f26683e168f","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.all.json","watch":"tsc --build --watch tsconfig.all.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.all.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"nyc karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/5.4.3/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"14.18.1","dependencies":{"@opentelemetry/core":"1.8.0","@opentelemetry/resources":"1.8.0","@opentelemetry/semantic-conventions":"1.8.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"10.0.0","sinon":"14.0.0","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.0","@types/sinon":"10.0.13","karma-webpack":"4.0.2","@opentelemetry/api":">=1.0.0 <1.4.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.4.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.8.0_1668023134059_0.3756471246154027","host":"s3://npm-registry-packages"}},"1.9.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.9.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.9.0","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"07aad8d3b484f24e45ad6347f74a66d12d69bf00","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.9.0.tgz","fileCount":291,"integrity":"sha512-glNgtJjxAIrDku8DG5Xu3nBK25rT+hkyg7yuXh8RUurp/4BcsXjMyVqpyJvb2kg+lxAX73VJBhncRKGHn9t8QQ==","signatures":[{"sig":"MEUCIQCk148UUg3KdpJvI14wehqmYDos3NaYmQqsaz+40gEBvAIgbGW9IAjfLk1D9uLL1eXth9ZQpdSfqpmZsYm/mJOGug4=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":720397,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjvy41ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrHzw/+MRKqvOeTqf1fwQhfOP+OYxGNWn+/HFIV48ZraIw/eJnPNm9n\r\nrfPXgMjJwhMeRRR4veXg7NzMGhwDub7uMwjpxrFZzvWVLU5XHnuCu0boAGt1\r\nkWF4/KulBnxgOj/6hqJ/+M4/L4zoE+Pb4RlPe7lbqmIl56ZmfWhah28okgnC\r\nqNbR5vgAOAX1NEjrkA52kke1H/S+wTM+/D/IwaSTd9fReOauEEaGRX9M7eJf\r\ncMDSFpiwY3aqWgw8Qjc8XOOox0zi75avU56CjhN4P7SnlvLIQqCdiWa/INA2\r\nCYEFE8KFlwKBXai+WXUms6mTpXG/pSn16/mf44KHh2D0tmXG83FgsTRzex6O\r\nq0bKGX7+UnX1k6opShIWcZF1pekjU83nQwc8c5IKc+7NABXXCYy7bksVwsG3\r\nXW1w06RhJjQcLkydPwfXdSTD7P8zVHo7IlFrTrb9kc+biA2xqr0o7Jh+0nc+\r\n0cGsrohmazhmaRM9VIzhh22XdO+s9ajQgNNg6YEYPw8Tqtk1JIPE5Tj2VmA0\r\nduGpt2CQPeT3xrdnYtA4jJLBAVCCtNO+oBmhxvo9UWNcwf3BM+egVGZr2pDj\r\ng2BOlIUj96iuQ89lpGkrHTTsICxpiZo6XhKzvi0Pyz/kU7vLalYzOFX36Kp3\r\nfrVodW+vrNvDp2xCbRtezdDvCAVbM76VsO0=\r\n=rMZT\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"08f597f3a3d71a4852b0afbba120af15ca038121","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"nyc karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.0.3/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"14.18.1","dependencies":{"@opentelemetry/core":"1.9.0","@opentelemetry/resources":"1.9.0","@opentelemetry/semantic-conventions":"1.9.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"10.0.0","sinon":"15.0.0","rimraf":"3.0.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.0","@types/sinon":"10.0.13","karma-webpack":"4.0.2","@opentelemetry/api":">=1.0.0 <1.5.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.9.0_1673473589665_0.6742613306845624","host":"s3://npm-registry-packages"}},"1.9.1":{"name":"@opentelemetry/sdk-trace-base","version":"1.9.1","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.9.1","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"c349491b432a7e0ae7316f0b48b2d454d79d2b84","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.9.1.tgz","fileCount":291,"integrity":"sha512-Y9gC5M1efhDLYHeeo2MWcDDMmR40z6QpqcWnPCm4Dmh+RHAMf4dnEBBntIe1dDpor686kyU6JV1D29ih1lZpsQ==","signatures":[{"sig":"MEQCIDCpHT2SvFd7SvoiA/2qcUtYH9zFjwJCGPBPCaE/O0/XAiAg9ObFHTNytJHMrIs2fZSuBwq6zkrVyW0zuSXKRpu3Cw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":721180,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj1+KDACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoLHRAAg2YSezWIehGO+yqyz36zRSewcUwKhipwLyD79qHVT8biD3OZ\r\n+LouyTG+pKoIfA0ht/AxcwP/KPKd4HfApZX//J2F5up8Y2HXg4ttHF3ez/MI\r\n59pdZYzIHwvcV24CdShaviNcw1wVF5+fGBdP/AqDDHu+TzTqSyb8p0SLTKnU\r\nm6dqBu0O7/30a7lRuEacaE/RTN10fpXpQzseVyq+yY4fxnihW5WJ4wmKKgz3\r\nN/WcKOla4/hdeEpeQaBMsud+VxN1VTNor8Co+RyB7+T6pHFSIWcuUY4ED0QW\r\n8D9oHXPND8P8AqQG2V3oh/3J7EOsdfqaAhzbURnX/DYPw5GPwvEXHL2xg9SM\r\nEVnwf/amUsxp+KaLbLmJnLdUebv+YSYzU4Cq0b7lgF2Y3ETt4UHzC2aKP1f+\r\n2Qq7VM3XWobSfVQATnb9G7mT3ceET6hhWwx/2bCk8bL8z2nr1A/VFIcGR1/Z\r\njTKUuuf0tWndCgQcAiMgBqsY9gVc5k49BXILciDslFi/VAFPzPNLdgXTJLoc\r\nygkcbFFC/qshloubv3yjTyxbb4sPC8JHaJy7z+JneWFYZIVG1phNiRbUqUNv\r\neasg3/aSyGvuSXZSyE2tEKTvAt0wtOUpnk/LelZoD8xO11whUPlWz5bk5le/\r\nxuTo6bdKcBCPUftxCcET15ohn56htRaQssg=\r\n=4lA/\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"279458e7ddf16f7ddca5fe60c78672e05fafce66","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"nyc karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.0.3/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"14.18.1","dependencies":{"@opentelemetry/core":"1.9.1","@opentelemetry/resources":"1.9.1","@opentelemetry/semantic-conventions":"1.9.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"10.0.0","sinon":"15.0.0","rimraf":"4.1.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.0","@types/sinon":"10.0.13","karma-webpack":"4.0.2","@opentelemetry/api":">=1.0.0 <1.5.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0","istanbul-instrumenter-loader":"3.0.1","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.9.1_1675092611489_0.40379905656518345","host":"s3://npm-registry-packages"}},"1.10.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.10.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.10.0","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"abbffa0ae39234f4c441357edc3f4da45dc73ef5","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.10.0.tgz","fileCount":291,"integrity":"sha512-X4rRShtVQ893LCU4GNKS1TKFua9nSjVmo0VJvigfSFSOmyyOLfiyTWmVL9MKV7Ws0HqLOIWJixJY0x28fw3Tzg==","signatures":[{"sig":"MEUCIQCfH/YhGxM8fNPGzqv85ZBEv+TXK2xG4B3l4BxNeprrcwIgNgdeMoB45zsX6FCHz9OKjjZgeiZpELL7Pl8Jj8iVfsU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":753566,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkD0cLACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrtJxAAjO1H0f8JKNzc9enF2Gb4+9qh/KuB+N6QinsJR5uIKghmG04L\r\nTyyCyEBIlrt5+C8U19xXZRbrtSTfyHD+lv7WRrSeV/fL6tOEV5oHwn0BhijS\r\nJB+Ng65UWSGtPiv9fnsczZN+pluUwzWcpn1eKdM/ev/7j0jFnxbGFJf8XfLb\r\nep+rdVtn2PBZfe66YZP9LtE7nCaHVYCNFdqkXl8PKeyYisl7FJefVRcxejOw\r\nIK1m8uChlMYtjDlMCkg3IrIfiEqlFoAoQinp2gPTEuSM9Z8R6WIW+rc5B680\r\n8MFyMQVy8U44vhZjnLb0fwIAzHpCEzXrsjQ6kwXU9ZhOOw6k6zq/F90W545+\r\nxc0yDu+EQLPLFwSYgVAD8Iutc2OkRWYDBUn2+QLWIc49HSq/XfMyUV36qDpM\r\nNa9JwV5Hzh9sfEPgvnKFDXDz1t/kYP1Y5D2h1Z0vvPYIGfxfpwnhKOtI4jHC\r\nwnnwBxFlBWbyxQ4TUWjV3R8HeChsO3KZ7Dcocjjkhr+dGZbRQwx5j/ZcRgb2\r\n1WS/kKpbXELlv7F16k+myxXVMSughmSmyTBvQesOMODviXrG9QvZ/k6hQDzn\r\n0aIdj7QFVsBqQ8QfLScLcQoGdxaD7PAImPFAJo8IwRIApGUFGoJIMkTAxQnB\r\n3An0ctyqyIqewKwSMDQ/kQkCAZo7nNMKF/k=\r\n=4uMa\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"56e6b1bb890f844b8963a146780d0b9cfa8abd0d","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"nyc karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.0.3/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"14.18.1","dependencies":{"@opentelemetry/core":"1.10.0","@opentelemetry/resources":"1.10.0","@opentelemetry/semantic-conventions":"1.10.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"10.0.0","sinon":"15.0.0","rimraf":"4.1.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.0","@types/sinon":"10.0.13","karma-webpack":"4.0.2","@opentelemetry/api":">=1.0.0 <1.5.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0","istanbul-instrumenter-loader":"3.0.1","@opentelemetry/resources_1.9.0":"npm:@opentelemetry/resources@1.9.0","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.10.0_1678722826858_0.7356588240446413","host":"s3://npm-registry-packages"}},"1.10.1":{"name":"@opentelemetry/sdk-trace-base","version":"1.10.1","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.10.1","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"fce06a810f9052d3c1b935d134979f4254bc8ae2","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.10.1.tgz","fileCount":291,"integrity":"sha512-jutSP5t22wrPKReJKzI5uKht4mJ4cQdF/mGFJkN+emFFsDXru9CuFv/NfUrD0jEqoaaiqjcZtPSyTzMgu9LXvw==","signatures":[{"sig":"MEUCIC5TkRQU4u6vAJo35V80QPiCUtJjFb/AQ6lMRRW3pWVXAiEAvM5UwlwBdiTS/miwGRjsCy4RwNj1Vmv0E44uh035k4s=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":754653,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkGIV6ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoD9Q/9HrqY+zXO5UB2Ajjrnffg1MgeYDLd+x0xsRVwooyC2HXp52/8\r\nmuP2SXq0JbSZOwbqQhSs6r/KqLt2avtTufh20YqFScGBvE0ajk+iPwdViznh\r\nBoWgA7m/cSTfazKwa/y01+rP7u/dHhMhUyp2VuX2Ml+6uytN3+ddvNgrPoB/\r\nV6V/V+G1StRlkrXj/yrI5kwtdbd2lDqsPErYhEWq/JnBamEckJYDUukJHftP\r\nOiYLvPEJGD8nDnZyFZM411BZzMi2c2eAXDTCgdBfczwdgHDq0hi2bBheMb84\r\nE9XDZO0roA+8qqwPOdII+ZhTM+Zy7AWVpgXYzYyn2H+zqt0kKYGAVum01B2P\r\nVwtG8UVJj/0/SXiKpzqaHNeRp1bG3Wwz/SgOdGWO078IoQVGOlQcldCbSc/9\r\nPU+OojbQ29jzwOOXRGq3Gr1S3CWshuDUM/V/gKPYJLQDL97VcP6qgmrGKYjw\r\n4phRWsFMpVtq4vLpciCThNZfdcCpIHKEW393pVNcpoYh8zyrucfR+UNt6gdB\r\nHOuK81d1sf67yI1lj6vuxYBL1Sg2PppgR+kuH8yat+XGV2PHdIp3g3gjaEx2\r\ndBp1tMLkrI8EW5TIgFusMyNuYq6+fH4VQ+6KL769f9zJi6wt5833VS1YjCK8\r\nh3pXzU0oMH3vOTOi+K+MgFdezKn399P7X3s=\r\n=ydap\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"486df99906958de9b8b666839785b00160a6a229","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"nyc karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.0.3/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"14.18.1","dependencies":{"@opentelemetry/core":"1.10.1","@opentelemetry/resources":"1.10.1","@opentelemetry/semantic-conventions":"1.10.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"10.0.0","sinon":"15.0.0","rimraf":"4.1.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.0","@types/sinon":"10.0.13","karma-webpack":"4.0.2","@opentelemetry/api":">=1.0.0 <1.5.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0","istanbul-instrumenter-loader":"3.0.1","@opentelemetry/resources_1.9.0":"npm:@opentelemetry/resources@1.9.0","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.10.1_1679328634722_0.677777763334195","host":"s3://npm-registry-packages"}},"1.11.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.11.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.11.0","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"a962dbe74ae28442501ce804d4a270892e70d862","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.11.0.tgz","fileCount":291,"integrity":"sha512-DV8e5/Qo42V8FMBlQ0Y0Liv6Hl/Pp5bAZ73s7r1euX8w4bpRes1B7ACiA4yujADbWMJxBgSo4fGbi4yjmTMG2A==","signatures":[{"sig":"MEUCIATNLGlPj7nprM/PqoK7yebouzxOOVHabs3pLCi2zF81AiEAnpwJz0aXZGwAS8cwf5tUXbH3Z5M719jhlqJKLHhclE4=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":754653,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkJaswACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoBlg//cAe3wMtepVB6AkYMsdLNGEQdJNykDrEO4K0w2cJORD1OoOSw\r\nRKY69x4MsneZ7DoTy1Yyvrro4nFZVaXcMR4W2I2/VyCM9zuMYdfXfeYW8Xn2\r\nxlBmjjIvotMn3FMLwxd44Xc7RRXgqOYp+F+oYPfxxyB4bLtIjg9UCRWIUkfs\r\nxeHvkfxXhlSE/Ffl+o4+6S5JR8bPRcLKltwfM3sBlySUZ619M2t/3RdgXuN4\r\nKpZM8cj/+8w47iRnPEC5u+mxMgsUiJOPRdMNV8MLR9gAVrt+aycAGs0DveJ+\r\nW800yX76KLskPzXMOhLjY40uAfTmf7ZSMLySPTmjHB86Ao7a+VRof3Lp7F7W\r\nAl53WeR8ktsMkUgol6bYBUxQ6gpaUBcup8OVTq3UvIV0tc1nW9xGift4uyqV\r\n3Zx71db8n7DWQLx5djFNVcGxo4LGBnoac6yID7sAXZmFPKO5wgik9jcSvaes\r\nMefz5zOjllRyaggfDu0qzMl/pV8rP4U/HDyFsUBFkbVrs0H1gq7p4MWOzvA5\r\no+TIwiRqhkNVieFqBguPz6wC6R+xmGDfuMT1OVlErJ37xulLctcFR97cVvo8\r\nNhs/zg+VzSlLA2ffRMZJY8j2xFIIknTNW2XbxO0ynIuw2Qac/ubMyv3L607p\r\njN2vgVxGOy4ijQ4VOX7QzQTJOW9eOnjw9UQ=\r\n=Bvyk\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"1328ee04ae78f9f6cf143af7050c00aaa6d2eb3b","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"nyc karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.0.3/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"14.18.1","dependencies":{"@opentelemetry/core":"1.11.0","@opentelemetry/resources":"1.11.0","@opentelemetry/semantic-conventions":"1.11.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"10.0.0","sinon":"15.0.0","rimraf":"4.1.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.0","@types/sinon":"10.0.13","karma-webpack":"4.0.2","@opentelemetry/api":">=1.0.0 <1.5.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0","istanbul-instrumenter-loader":"3.0.1","@opentelemetry/resources_1.9.0":"npm:@opentelemetry/resources@1.9.0","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.11.0_1680190255784_0.000785890780287346","host":"s3://npm-registry-packages"}},"1.12.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.12.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.12.0","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"62b895dbb5900048a85e4899c38fec5585447d4b","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.12.0.tgz","fileCount":291,"integrity":"sha512-pfCOB3tNDlYVoWuz4D7Ji+Jmy9MHnATWHVpkERdCEiwUGEZ+4IvNPXUcPc37wJVmMpjGLeaWgPPrie0KIpWf1A==","signatures":[{"sig":"MEUCIQDGQNlFDI4aeratpSD5OxDMShZWpHdYTVjWCBnYfpqT7wIgS20kS7BJXFaKBMCcL57pG64sBXgcstHOb/QvJJbZc4c=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":755384,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkOEYtACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr1VxAAgK9Cgr/apKKrJ/8l0FYhazkWFDVijdj6ImBxtPgDYEUJgRCa\r\nXWPxQDsQLJ/n+ZSKLJ9e115m+2mfaLCg0ECNePS29s0tCwNiC0pS+jC5EJxm\r\nDAfJgqHg58HDE1ZwEvK2ssIgz66oCTBS59WwTMARovA4kBn9TyViR9k6wRGU\r\ndJX5LqLpt8E/1MymOyqo9/2HoqCyb1EiKzB/Ur8VdDnp4a/6yKC0r18d0ju3\r\nG6FfNyvgBwrdqOoIbUcut1bwbomwjplJZ63sIKUbC4h/DThjsYOd1jeek4N/\r\nR88hh4GEpZCWW9yHYrQ5oTYiVRtc8DKo+FstoKULy49suV9998uh50vlS+rR\r\nfDvRBInZIi1weDqJvjZVRw2rC24uoTOECiPulSKmrYsIF+jAREqJ1MwOLPdx\r\nvhnPsAmPF0gmRlWpHoXeYxG8NhfCjGycXJM3XcXIjX6+6FgSxKxDPGxiYIP0\r\nFHA7TP6N26re/AcKB1BhbjblKq9znqYbJ4vVG6xfFUEPC6akKwDwBNkwTPN/\r\n3Nq9B5fhF4IB02jHCu2NSGAyWeEXICD349DITHgpeY+WXRK/0Ch/FvKsAiQ2\r\n8DLal2y8VAMn1rX+18wbiJeDgUP0x88y8joyR+SRLlRb0BGbOgZarJ5t6rKY\r\nU8gfYC/v0GR0zNX8sPSWtuZxdQRabqIODas=\r\n=D7K4\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"a04090010ee18e17487b449984807cc2b7b6e3e6","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"nyc karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.0.3/node@v14.18.1+x64 (darwin)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"14.18.1","dependencies":{"@opentelemetry/core":"1.12.0","@opentelemetry/resources":"1.12.0","@opentelemetry/semantic-conventions":"1.12.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"10.0.0","sinon":"15.0.0","rimraf":"4.1.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.0","@types/sinon":"10.0.13","karma-webpack":"4.0.2","@opentelemetry/api":">=1.0.0 <1.5.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0","istanbul-instrumenter-loader":"3.0.1","@opentelemetry/resources_1.9.0":"npm:@opentelemetry/resources@1.9.0","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.12.0_1681409581369_0.41803382504150455","host":"s3://npm-registry-packages"}},"1.13.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.13.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.13.0","maintainers":[{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"096cc2759430d880c5d886e009df2605097403dc","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.13.0.tgz","fileCount":291,"integrity":"sha512-moTiQtc0uPR1hQLt6gLDJH9IIkeBhgRb71OKjNHZPE1VF45fHtD6nBDi5J/DkTHTwYP5X3kBJLa3xN7ub6J4eg==","signatures":[{"sig":"MEUCIQCUuJ4B96xwpSLT8DFKAofaJDlGrXekNXcbsCsQRyYcBQIgdFAq/sIQjSsvEbReUkhFeNBdPC5uB4GXp48ocXDFpTU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":755361},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"8fc76896595aac912bf9e15d4f19c167317844c8","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"nyc karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.0.3/node@v18.12.1+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"18.12.1","dependencies":{"@opentelemetry/core":"1.13.0","@opentelemetry/resources":"1.13.0","@opentelemetry/semantic-conventions":"1.13.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"10.0.0","sinon":"15.0.0","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.0","@types/sinon":"10.0.13","karma-webpack":"4.0.2","@opentelemetry/api":">=1.0.0 <1.5.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0","istanbul-instrumenter-loader":"3.0.1","@opentelemetry/resources_1.9.0":"npm:@opentelemetry/resources@1.9.0","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.13.0_1683811806724_0.20967276776702293","host":"s3://npm-registry-packages"}},"1.14.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.14.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.14.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"831af08f002228a11e577ff860eb6059c8b80fb7","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.14.0.tgz","fileCount":291,"integrity":"sha512-NzRGt3PS+HPKfQYMb6Iy8YYc5OKA73qDwci/6ujOIvyW9vcqBJSWbjZ8FeLEAmuatUB5WrRhEKu9b0sIiIYTrQ==","signatures":[{"sig":"MEQCIGq2NLJF230csI91/HmEoC3vV+PDJAfR6T+ZfR1K5MhUAiBE0zHURoBg3oiLXEQFSYgZRPg4mT6sh7zOyIBPLwqTrQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":759415},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"edebbcc757535bc88f01340409dbbecc0bb6ccf8","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"lerna run version --scope $(npm pkg get name) --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"nyc karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.0.3/node@v18.12.1+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"18.12.1","dependencies":{"@opentelemetry/core":"1.14.0","@opentelemetry/resources":"1.14.0","@opentelemetry/semantic-conventions":"1.14.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.3.16","mocha":"10.0.0","sinon":"15.0.0","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.0","@types/sinon":"10.0.13","karma-webpack":"4.0.2","@opentelemetry/api":">=1.0.0 <1.5.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.32","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0","istanbul-instrumenter-loader":"3.0.1","@opentelemetry/resources_1.9.0":"npm:@opentelemetry/resources@1.9.0","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.14.0_1686031254973_0.05353905101465628","host":"s3://npm-registry-packages"}},"1.15.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.15.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.15.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"92340ded8f9fec1aaa63afb40c6e7e01769c2852","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.15.0.tgz","fileCount":291,"integrity":"sha512-udt1c9VHipbZwvCPIQR1VLg25Z4AMR/g0X8KmcInbFruGWQ/lptVPkz3yvWAsGSta5yHNQ3uoPwcyCygGnQ6Lg==","signatures":[{"sig":"MEQCICYANwEi+W0pUvfm1ry5U2W2dfO2D8QKOxJ6ASiMd9fAAiAJVx8yq45ynFVPddGZXUIDiB+f460P0lH8/PukjsJa9Q==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":751257},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"06e919d6c909e8cc8e28b6624d9843f401d9b059","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"nyc karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"nyc karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/7.1.1/node@v18.12.1+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"18.12.1","dependencies":{"tslib":"^2.3.1","@opentelemetry/core":"1.15.0","@opentelemetry/resources":"1.15.0","@opentelemetry/semantic-conventions":"1.15.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"7.1.1","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.1","@types/sinon":"10.0.15","karma-webpack":"4.0.2","@opentelemetry/api":">=1.0.0 <1.5.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.36","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0","istanbul-instrumenter-loader":"3.0.1","@opentelemetry/resources_1.9.0":"npm:@opentelemetry/resources@1.9.0","karma-coverage-istanbul-reporter":"3.0.3"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.15.0_1688642828714_0.7763914571035175","host":"s3://npm-registry-packages"}},"1.15.1":{"name":"@opentelemetry/sdk-trace-base","version":"1.15.1","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.15.1","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"8eabc0827769d91ac86cde8a86ebf0bf2a7d22ad","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.15.1.tgz","fileCount":291,"integrity":"sha512-5hccBe2yXzzXyExJNkTsIzDe1AM7HK0al+y/D2yEpslJqS1HUzsUSuCMY7Z4+Sfz5Gf0kTa6KYEt1QUQppnoBA==","signatures":[{"sig":"MEQCIAMA9wUFC89WxydgdbzsPHJAC6CJZrcaOKd6WZiMyomlAiAmC3lL7KJpsgZkvBN+kvQdR+/QBXU5aH853Mw0xGsxpQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":759437},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"9f71800fdc2a5ee5055684037a12498af71955f2","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/7.1.3/node@v18.4.0+x64 (darwin)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"18.4.0","dependencies":{"@opentelemetry/core":"1.15.1","@opentelemetry/resources":"1.15.1","@opentelemetry/semantic-conventions":"1.15.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"7.1.3","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.1","@types/sinon":"10.0.15","karma-webpack":"4.0.2","karma-coverage":"2.2.1","@opentelemetry/api":">=1.0.0 <1.5.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0","@opentelemetry/resources_1.9.0":"npm:@opentelemetry/resources@1.9.0"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.15.1_1690209168495_0.9723185712242157","host":"s3://npm-registry-packages"}},"1.15.2":{"name":"@opentelemetry/sdk-trace-base","version":"1.15.2","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.15.2","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"4821f94033c55a6c8bbd35ae387b715b6108517a","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.15.2.tgz","fileCount":291,"integrity":"sha512-BEaxGZbWtvnSPchV98qqqqa96AOcb41pjgvhfzDij10tkBhIu9m0Jd6tZ1tJB5ZHfHbTffqYVYE0AOGobec/EQ==","signatures":[{"sig":"MEUCIEIHVFRfdpxnv3EMAJ4ftYQ+AlgYc1/cZ62e/gv8tkELAiEAnsGkf0w1TCg+Nh+zO9gX/GmMEANl7JYCnR3A8+/VUTY=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":759437},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"48fb15862e801b742059a3e39dbcc8ef4c10b2e2","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/7.1.4/node@v18.12.1+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"18.12.1","dependencies":{"@opentelemetry/core":"1.15.2","@opentelemetry/resources":"1.15.2","@opentelemetry/semantic-conventions":"1.15.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"7.1.4","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.1","@types/sinon":"10.0.16","karma-webpack":"4.0.2","karma-coverage":"2.2.1","@opentelemetry/api":">=1.0.0 <1.5.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0","@opentelemetry/resources_1.9.0":"npm:@opentelemetry/resources@1.9.0"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.15.2_1691500880621_0.5765565023863921","host":"s3://npm-registry-packages"}},"1.16.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.16.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.16.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"243d69767d44646e1d16baa425c35dbabd959c4e","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.16.0.tgz","fileCount":291,"integrity":"sha512-UvV8v8cN0Bx5BI40IJ+sMWcbwWekPa9ngMHSOfCWtSAVKbzwFdDV4Jrs/ejC6uR/SI6CKFQB9ItHp/0nZzVbIQ==","signatures":[{"sig":"MEUCIE0CtdHOn5oxhEmmjk8QOgpa9uN1UcGaKdPZ4BPeSZHEAiEAxBrVmbuOmnEOtXfyBV6smxPj0Fzkzn/FiYy0SDpi+iI=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":762780},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"5fcd8cf136e2235903dde3df9ba03ced594f0e95","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/7.1.5/node@v18.12.1+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"18.12.1","dependencies":{"@opentelemetry/core":"1.16.0","@opentelemetry/resources":"1.16.0","@opentelemetry/semantic-conventions":"1.16.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"7.1.5","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.1","@types/sinon":"10.0.16","karma-webpack":"4.0.2","karma-coverage":"2.2.1","@opentelemetry/api":">=1.0.0 <1.6.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0","@opentelemetry/resources_1.9.0":"npm:@opentelemetry/resources@1.9.0"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.6.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.16.0_1694434471110_0.20239220544943004","host":"s3://npm-registry-packages"}},"1.17.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.17.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.17.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"05a21763c9efa72903c20b8930293cdde344b681","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.17.0.tgz","fileCount":291,"integrity":"sha512-2T5HA1/1iE36Q9eg6D4zYlC4Y4GcycI1J6NsHPKZY9oWfAxWsoYnRlkPfUqyY5XVtocCo/xHpnJvGNHwzT70oQ==","signatures":[{"sig":"MEUCIQDRl4V5Q9HD6NsW3DtOOe+96ou8MwSUKBYi1McLNudswwIgcqEqisIWT6U7qrLdIRH+kQFG05+JTW3HQaitOHqTY5A=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":759485},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"faf939c77591f709afbc23fadbe629c9d3607ef6","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/7.1.5/node@v18.12.1+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"18.12.1","dependencies":{"@opentelemetry/core":"1.17.0","@opentelemetry/resources":"1.17.0","@opentelemetry/semantic-conventions":"1.17.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"7.1.5","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.1","@types/sinon":"10.0.16","karma-webpack":"4.0.2","karma-coverage":"2.2.1","@opentelemetry/api":">=1.0.0 <1.7.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0","@opentelemetry/resources_1.9.0":"npm:@opentelemetry/resources@1.9.0"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.7.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.17.0_1694524353106_0.9941234111275701","host":"s3://npm-registry-packages"}},"1.17.1":{"name":"@opentelemetry/sdk-trace-base","version":"1.17.1","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.17.1","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"8ede213df8b0c957028a869c66964e535193a4fd","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.17.1.tgz","fileCount":291,"integrity":"sha512-pfSJJSjZj5jkCJUQZicSpzN8Iz9UKMryPWikZRGObPnJo6cUSoKkjZh6BM3j+D47G4olMBN+YZKYqkFM1L6zNA==","signatures":[{"sig":"MEQCICJ2bNHS5YUGFypz4AII9j8tSEQ9DlGT6kqLjtoOEsCGAiBvV/Vq4IZpDkaHq2O9HmyppmnPVxpIxrg+Jy1T5IiHDA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":763072},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"f8e187b473274cc2011e7385992f07d319d667dc","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","test:bench":"node test/performance/benchmark/index.js | tee .benchmark-results.txt","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/7.1.5/node@v18.12.1+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"18.12.1","dependencies":{"@opentelemetry/core":"1.17.1","@opentelemetry/resources":"1.17.1","@opentelemetry/semantic-conventions":"1.17.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"7.1.5","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.2","@types/sinon":"10.0.18","karma-webpack":"4.0.2","karma-coverage":"2.2.1","@opentelemetry/api":">=1.0.0 <1.7.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0","@opentelemetry/resources_1.9.0":"npm:@opentelemetry/resources@1.9.0"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.7.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.17.1_1696947498602_0.8314715735448981","host":"s3://npm-registry-packages"}},"1.18.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.18.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.18.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"09e420d24465aaee8e21a8a9a3c4fa2e6f0fd08e","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.18.0.tgz","fileCount":291,"integrity":"sha512-OThpwn8JeU4q7exo0e8kQqs5BZGKQ9NNkes66RCs7yhUKShHEKQIYl/A3+xnGzMrbrtgogcf84brH8XD4ahjMg==","signatures":[{"sig":"MEUCIFQOMg1gSyToxhdxU8T3AviTyjEEw2MbV3NIAaAUmbOCAiEA5XDBvAFEwa4c3eHldor7UtuSWc0QH6+9JPAUmc9laKE=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":762996},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"73b446688f10fd8dc4cf403a085f0a39070df7b4","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","test:bench":"node test/performance/benchmark/index.js | tee .benchmark-results.txt","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.18.2+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"18.18.2","dependencies":{"@opentelemetry/core":"1.18.0","@opentelemetry/resources":"1.18.0","@opentelemetry/semantic-conventions":"1.18.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"6.6.2","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.3","@types/sinon":"10.0.20","karma-webpack":"4.0.2","karma-coverage":"2.2.1","@opentelemetry/api":">=1.0.0 <1.8.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.8.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.18.0_1699353886594_0.7186034490338462","host":"s3://npm-registry-packages"}},"1.18.1":{"name":"@opentelemetry/sdk-trace-base","version":"1.18.1","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.18.1","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"256605d90b202002d5672305c66dbcf377132379","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.18.1.tgz","fileCount":291,"integrity":"sha512-tRHfDxN5dO+nop78EWJpzZwHsN1ewrZRVVwo03VJa3JQZxToRDH29/+MB24+yoa+IArerdr7INFJiX/iN4gjqg==","signatures":[{"sig":"MEUCIQDGgWjUUen2F48lorSLadmIOOAKIpssyEX1QX3AkPnEcgIgZ/6Bk9XnhJDqwrVWwaBzBowhdIMF0BlbAA4G9pfiu3s=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":762996},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"f665499096189390e691cf1a772e677fa67812d7","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","test:bench":"node test/performance/benchmark/index.js | tee .benchmark-results.txt","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.18.2+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"18.18.2","dependencies":{"@opentelemetry/core":"1.18.1","@opentelemetry/resources":"1.18.1","@opentelemetry/semantic-conventions":"1.18.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"6.6.2","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"4.46.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.3","@types/sinon":"10.0.20","karma-webpack":"4.0.2","karma-coverage":"2.2.1","@opentelemetry/api":">=1.0.0 <1.8.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.8.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.18.1_1699466949548_0.8982337926756658","host":"s3://npm-registry-packages"}},"1.19.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.19.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.19.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"87e629e7080945d955d53c2c12352915f5797cd3","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.19.0.tgz","fileCount":291,"integrity":"sha512-+IRvUm+huJn2KqfFW3yW/cjvRwJ8Q7FzYHoUNx5Fr0Lws0LxjMJG1uVB8HDpLwm7mg5XXH2M5MF+0jj5cM8BpQ==","signatures":[{"sig":"MEUCIQCvZye8IyirUNdQZpWpKxno3ZitChFbue9awFFtHELllgIgNyloI4Qyzwns38NU8u3WC0Li1KHoH9j2JOpghwv/it0=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":764145},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"d3c311aec24137084dc820805a2597e120335672","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","test:bench":"node test/performance/benchmark/index.js | tee .benchmark-results.txt","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.18.2+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"18.18.2","dependencies":{"@opentelemetry/core":"1.19.0","@opentelemetry/resources":"1.19.0","@opentelemetry/semantic-conventions":"1.19.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"6.6.2","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"5.89.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.6","@types/sinon":"10.0.20","karma-webpack":"4.0.2","karma-coverage":"2.2.1","@opentelemetry/api":">=1.0.0 <1.8.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.8.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.19.0_1702557329886_0.8961281946707333","host":"s3://npm-registry-packages"}},"1.20.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.20.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.20.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"1771bf7a214924fe1f27ef50395f763b65aae220","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.20.0.tgz","fileCount":291,"integrity":"sha512-BAIZ0hUgnhdb3OBQjn1FKGz/Iwie4l+uOMKklP7FGh7PTqEAbbzDNMJKaZQh6KepF7Fq+CZDRKslD3yrYy2Tzw==","signatures":[{"sig":"MEYCIQCHh3POrnMKj+uhqmw18P6kbzsRGC80c1E4qJMfjLsMDQIhAMGITPFwWQeaDCcCWHsASv07JnvLZjRORCDpN/OnUc8V","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":765977},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"57008533aba7ccd51ea80f38ff4f29404d47eb9c","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","test:bench":"node test/performance/benchmark/index.js | tee .benchmark-results.txt","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.19.0+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"18.19.0","dependencies":{"@opentelemetry/core":"1.20.0","@opentelemetry/resources":"1.20.0","@opentelemetry/semantic-conventions":"1.20.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"6.6.2","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"5.89.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.6","@types/sinon":"10.0.20","karma-webpack":"4.0.2","karma-coverage":"2.2.1","@opentelemetry/api":">=1.0.0 <1.8.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.8.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.20.0_1705313747279_0.982043777281284","host":"s3://npm-registry-packages"}},"1.21.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.21.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.21.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"ffad912e453a92044fb220bd5d2f6743bf37bb8a","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.21.0.tgz","fileCount":291,"integrity":"sha512-yrElGX5Fv0umzp8Nxpta/XqU71+jCAyaLk34GmBzNcrW43nqbrqvdPs4gj4MVy/HcTjr6hifCDCYA3rMkajxxA==","signatures":[{"sig":"MEUCIQCqCEvDM0Ok1Pc+0BKmVi/qGM49XKfMGKMFwmzj72uEbQIgQj2iOSZQ1GktYTNsHsyb8mpoMElXqAgH4R2tc1TYjzg=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":765995},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"828f2ed730e4d26d71f92e220f96b60a552a673a","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","test:bench":"node test/performance/benchmark/index.js | tee .benchmark-results.txt","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.19.0+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"18.19.0","dependencies":{"@opentelemetry/core":"1.21.0","@opentelemetry/resources":"1.21.0","@opentelemetry/semantic-conventions":"1.21.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"6.6.2","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"5.89.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.6","@types/sinon":"10.0.20","karma-webpack":"4.0.2","karma-coverage":"2.2.1","@opentelemetry/api":">=1.0.0 <1.8.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.8.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.21.0_1706249469569_0.5490245065158903","host":"s3://npm-registry-packages"}},"1.22.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.22.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.22.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"7833bf2493a7b49461915ca32aa2884c87afd78c","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.22.0.tgz","fileCount":291,"integrity":"sha512-pfTuSIpCKONC6vkTpv6VmACxD+P1woZf4q0K46nSUvXFvOFqjBYKFaAMkKD3M1mlKUUh0Oajwj35qNjMl80m1Q==","signatures":[{"sig":"MEYCIQCIbs8fApIflGCI1DVtJx4Od7v+UAgxdvD1HYs3Knyn8wIhANZPfqD9CmErmsPHuf+xvLsoRdhkFg7m60o2ydsbiYlH","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":765995},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"7be35c7845e206b27b682e8ce1cee850b09cec04","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","test:bench":"node test/performance/benchmark/index.js | tee .benchmark-results.txt","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.19.0+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"18.19.0","dependencies":{"@opentelemetry/core":"1.22.0","@opentelemetry/resources":"1.22.0","@opentelemetry/semantic-conventions":"1.22.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"6.6.2","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"5.89.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.6","@types/sinon":"10.0.20","karma-webpack":"4.0.2","karma-coverage":"2.2.1","@opentelemetry/api":">=1.0.0 <1.9.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.9.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.22.0_1709198294393_0.7751101530396496","host":"s3://npm-registry-packages"}},"1.23.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.23.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.23.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"ff0a0f8ec47205e0b14b3b765ea2a34de1ad01dd","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.23.0.tgz","fileCount":291,"integrity":"sha512-PzBmZM8hBomUqvCddF/5Olyyviayka44O5nDWq673np3ctnvwMOvNrsUORZjKja1zJbwEuD9niAGbnVrz3jwRQ==","signatures":[{"sig":"MEYCIQCkDxxFrTKMnaGS3uSnxIeqIYW9GUKUsumBHH/5FiMIQQIhAJl43qgE1ESEcqc99k140Qw3ZUyhYy98yujb5J2vrPVz","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":769572},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"5231aa255047fbc6ee3d6a299f4423ab2f8a5fbc","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","test:bench":"node test/performance/benchmark/index.js | tee .benchmark-results.txt","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.19.0+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"18.19.0","dependencies":{"@opentelemetry/core":"1.23.0","@opentelemetry/resources":"1.23.0","@opentelemetry/semantic-conventions":"1.23.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"6.6.2","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"5.89.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.6","@types/sinon":"10.0.20","karma-webpack":"4.0.2","karma-coverage":"2.2.1","@opentelemetry/api":">=1.0.0 <1.9.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.9.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.23.0_1712131805476_0.8181787837823578","host":"s3://npm-registry-packages"}},"1.24.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.24.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.24.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"e2de869e33fd224f6d9f39bafa4172074d1086c8","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.24.0.tgz","fileCount":291,"integrity":"sha512-H9sLETZ4jw9UJ3totV8oM5R0m4CW0ZIOLfp4NV3g0CM8HD5zGZcaW88xqzWDgiYRpctFxd+WmHtGX/Upoa2vRg==","signatures":[{"sig":"MEUCIQC+rEv+MmjVPnMGlU3wd57V5QFFVnW9EfX1PXPig1UglQIgdXMUaQB3puehbvSfKE7sDFk+XhwNKT3dOTs+Pe7BQaA=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":770265},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"3ab4f765d8d696327b7d139ae6a45e7bd7edd924","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","test:bench":"node test/performance/benchmark/index.js | tee .benchmark-results.txt","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.19.0+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"18.19.0","dependencies":{"@opentelemetry/core":"1.24.0","@opentelemetry/resources":"1.24.0","@opentelemetry/semantic-conventions":"1.24.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"6.6.2","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"5.89.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.6","@types/sinon":"10.0.20","karma-webpack":"4.0.2","karma-coverage":"2.2.1","@opentelemetry/api":">=1.0.0 <1.9.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.9.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.24.0_1713969581982_0.6686664599417391","host":"s3://npm-registry-packages"}},"1.24.1":{"name":"@opentelemetry/sdk-trace-base","version":"1.24.1","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.24.1","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"dc2ab89126e75e442913fb5af98803fde67b2536","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.24.1.tgz","fileCount":291,"integrity":"sha512-zz+N423IcySgjihl2NfjBf0qw1RWe11XIAWVrTNOSSI6dtSPJiVom2zipFB2AEEtJWpv0Iz6DY6+TjnyTV5pWg==","signatures":[{"sig":"MEUCIQDTLWH2gw+yHzMuSStW+CjV5Qls++vE6j4ZyXWI8kIlXAIgcZvxmlQmkjw5cG6QCa7MTuRX04iBX07fk3qYK4/O4W0=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":770265},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"41c2626fe0ed03e2e83bd79ee43c9bdf0ffd80d8","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","test:bench":"node test/performance/benchmark/index.js | tee .benchmark-results.txt","tdd:browser":"karma start","test:browser":"karma start --single-run","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.19.0+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"18.19.0","dependencies":{"@opentelemetry/core":"1.24.1","@opentelemetry/resources":"1.24.1","@opentelemetry/semantic-conventions":"1.24.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.2","lerna":"6.6.2","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"5.89.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"8.4.0","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.6","@types/sinon":"10.0.20","karma-webpack":"4.0.2","karma-coverage":"2.2.1","@opentelemetry/api":">=1.0.0 <1.9.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.9.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.24.1_1715093558704_0.0518702076931048","host":"s3://npm-registry-packages"}},"1.25.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.25.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.25.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"263f9ce19001c5cd7a814d0eb40ebc6469ae763d","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.25.0.tgz","fileCount":291,"integrity":"sha512-6+g2fiRQUG39guCsKVeY8ToeuUf3YUnPkN6DXRA1qDmFLprlLvZm9cS6+chgbW70cZJ406FTtSCDnJwxDC5sGQ==","signatures":[{"sig":"MEQCIHH4reSQvuavsAESwWCOjKs3174GY97NApvIwo8zkZdnAiAkX4evqPLOZGIcO2364Kma0IOukWxk2s4rZ7Q1/KWdIA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":772352},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"c4d3351b6b3f5593c8d7cbfec97b45cea9fe1511","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","test:bench":"node test/performance/benchmark/index.js | tee .benchmark-results.txt","tdd:browser":"karma start","test:browser":"karma start --single-run","align-api-deps":"node ../../scripts/align-api-deps.js","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.19.0+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"18.19.0","dependencies":{"@opentelemetry/core":"1.25.0","@opentelemetry/resources":"1.25.0","@opentelemetry/semantic-conventions":"1.25.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.3","lerna":"6.6.2","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"5.89.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"9.5.1","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.6","@types/sinon":"17.0.3","karma-webpack":"5.0.1","karma-coverage":"2.2.1","@opentelemetry/api":">=1.0.0 <1.10.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.10.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.25.0_1717607756250_0.3809624034816559","host":"s3://npm-registry-packages"}},"1.25.1":{"name":"@opentelemetry/sdk-trace-base","version":"1.25.1","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.25.1","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"cbc1e60af255655d2020aa14cde17b37bd13df37","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.25.1.tgz","fileCount":291,"integrity":"sha512-C8k4hnEbc5FamuZQ92nTOp8X/diCY56XUTnMiv9UTuJitCzaNNHAVsdm5+HLCdI8SLQsLWIrG38tddMxLVoftw==","signatures":[{"sig":"MEYCIQCTj2PAtWjS/RCNjK8Gf9jjrAGZC45q4Xe4UC7g9f7wQQIhAMVEucKOdO/kvVF98e1NxnacXHLACTuS62IDNJctBSeh","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":774722},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"0608f405573901e54db01e44c533009cf28be262","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","test:bench":"node test/performance/benchmark/index.js | tee .benchmark-results.txt","tdd:browser":"karma start","test:browser":"karma start --single-run","align-api-deps":"node ../../scripts/align-api-deps.js","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.19.0+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"18.19.0","dependencies":{"@opentelemetry/core":"1.25.1","@opentelemetry/resources":"1.25.1","@opentelemetry/semantic-conventions":"1.25.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.3","lerna":"6.6.2","mocha":"10.2.0","sinon":"15.1.2","codecov":"3.8.3","webpack":"5.89.0","ts-mocha":"10.0.0","cross-var":"1.1.0","ts-loader":"9.5.1","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.6","@types/sinon":"17.0.3","karma-webpack":"5.0.1","karma-coverage":"2.2.1","@opentelemetry/api":">=1.0.0 <1.10.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"6.1.1","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.10.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.25.1_1718875161655_0.9029425309207557","host":"s3://npm-registry-packages"}},"1.26.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.26.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.26.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"0c913bc6d2cfafd901de330e4540952269ae579c","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.26.0.tgz","fileCount":291,"integrity":"sha512-olWQldtvbK4v22ymrKLbIcBi9L2SpMO84sCPY54IVsJhP9fRsxJT194C/AVaAuJzLE30EdhhM1VmvVYR7az+cw==","signatures":[{"sig":"MEYCIQDBmAKg/eAuae/sOfGJddg2bp6XQnx7eLvjy23V8aEtGgIhAN8fMKmoqU5I46KS49TZSYtdGwxd/ucUS3lMOUNFbWO8","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":782749},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"720bc8c70d47029cb6b41a34ffdc3d25cbaa2f80","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc mocha 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","codecov":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","test:bench":"node test/performance/benchmark/index.js | tee .benchmark-results.txt","tdd:browser":"karma start","test:browser":"karma start --single-run","align-api-deps":"node ../../scripts/align-api-deps.js","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"karma start karma.worker.js --single-run","codecov:webworker":"nyc report --reporter=json && codecov -f coverage/*.json -p ../../"},"_npmUser":{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.20.4+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"18.20.4","dependencies":{"@opentelemetry/core":"1.26.0","@opentelemetry/resources":"1.26.0","@opentelemetry/semantic-conventions":"1.27.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.4","lerna":"6.6.2","mocha":"10.7.3","sinon":"15.1.2","codecov":"3.8.3","webpack":"5.89.0","cross-var":"1.1.0","ts-loader":"9.5.1","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.7","@types/sinon":"17.0.3","karma-webpack":"5.0.1","karma-coverage":"2.2.1","@opentelemetry/api":">=1.0.0 <1.10.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"7.0.0","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.10.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.26.0_1724836639726_0.4881073465309367","host":"s3://npm-registry-packages"}},"1.27.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.27.0","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","_id":"@opentelemetry/sdk-trace-base@1.27.0","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"dist":{"shasum":"2276e4cd0d701a8faba77382b2938853a0907b54","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.27.0.tgz","fileCount":291,"integrity":"sha512-btz6XTQzwsyJjombpeqCX6LhiMQYpzt2pIYNPnw0IPO/3AhT6yjnf8Mnv3ZC2A4eRYOjqrg+bfaXg9XHDRJDWQ==","signatures":[{"sig":"MEUCIEZDRp9Rw7P7jVlsdY/bPk1oroAOlQqBPxMQtoLYLwDRAiEAyNSVcrfK4Enpjkh9EGRl4Eggqu0GYDvo0upx7fyeD2o=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@opentelemetry%2fsdk-trace-base@1.27.0","provenance":{"predicateType":"https://slsa.dev/provenance/v0.2"}},"unpackedSize":787865},"main":"build/src/index.js","types":"build/src/index.d.ts","esnext":"build/esnext/index.js","module":"build/esm/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js"},"engines":{"node":">=14"},"gitHead":"eb3ca4fb07ee31c62093f5fcec56575573c902ce","scripts":{"tdd":"npm run tdd:node","lint":"eslint . --ext .ts","test":"nyc mocha 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","version":"node ../../scripts/version-update.js","lint:fix":"eslint . --ext .ts --fix","prewatch":"npm run precompile","tdd:node":"npm run test -- --watch-extensions ts --watch","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","test:bench":"node test/performance/benchmark/index.js | tee .benchmark-results.txt","tdd:browser":"karma start","test:browser":"karma start --single-run","align-api-deps":"node ../../scripts/align-api-deps.js","peer-api-check":"node ../../scripts/peer-api-check.js","prepublishOnly":"npm run compile","test:webworker":"karma start karma.worker.js --single-run"},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"repository":{"url":"git+https://github.com/open-telemetry/opentelemetry-js.git","type":"git"},"_npmVersion":"lerna/6.6.2/node@v18.20.4+x64 (linux)","description":"OpenTelemetry Tracing","directories":{},"sideEffects":false,"_nodeVersion":"18.20.4","dependencies":{"@opentelemetry/core":"1.27.0","@opentelemetry/resources":"1.27.0","@opentelemetry/semantic-conventions":"1.27.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"15.1.0","karma":"6.4.4","lerna":"6.6.2","mocha":"10.7.3","sinon":"15.1.2","webpack":"5.94.0","cross-var":"1.1.0","ts-loader":"9.5.1","typescript":"4.4.4","@types/node":"18.6.5","karma-mocha":"2.0.1","@types/mocha":"10.0.8","@types/sinon":"17.0.3","karma-webpack":"5.0.1","karma-coverage":"2.2.1","@opentelemetry/api":">=1.0.0 <1.10.0","@types/webpack-env":"1.16.3","karma-spec-reporter":"0.0.36","babel-plugin-istanbul":"7.0.0","karma-chrome-launcher":"3.1.0","karma-mocha-webworker":"1.3.0"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.10.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk-trace-base_1.27.0_1729695101194_0.8545382921292937","host":"s3://npm-registry-packages"}},"1.28.0":{"name":"@opentelemetry/sdk-trace-base","version":"1.28.0","description":"OpenTelemetry Tracing","main":"build/src/index.js","module":"build/esm/index.js","esnext":"build/esnext/index.js","browser":{"./src/platform/index.ts":"./src/platform/browser/index.ts","./build/esm/platform/index.js":"./build/esm/platform/browser/index.js","./build/esnext/platform/index.js":"./build/esnext/platform/browser/index.js","./build/src/platform/index.js":"./build/src/platform/browser/index.js"},"types":"build/src/index.d.ts","repository":{"type":"git","url":"git+https://github.com/open-telemetry/opentelemetry-js.git"},"scripts":{"prepublishOnly":"npm run compile","compile":"tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json","clean":"tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json","test":"nyc mocha 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'","test:browser":"karma start --single-run","test:webworker":"karma start karma.worker.js --single-run","test:bench":"node test/performance/benchmark/index.js | tee .benchmark-results.txt","tdd":"npm run tdd:node","tdd:node":"npm run test -- --watch-extensions ts --watch","tdd:browser":"karma start","lint":"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix","version":"node ../../scripts/version-update.js","watch":"tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json","precompile":"cross-var lerna run version --scope $npm_package_name --include-dependencies","prewatch":"npm run precompile","peer-api-check":"node ../../scripts/peer-api-check.js","align-api-deps":"node ../../scripts/align-api-deps.js"},"keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","engines":{"node":">=14"},"publishConfig":{"access":"public"},"devDependencies":{"@opentelemetry/api":">=1.0.0 <1.10.0","@types/mocha":"10.0.9","@types/node":"18.6.5","@types/sinon":"17.0.3","@types/webpack-env":"1.16.3","babel-plugin-istanbul":"7.0.0","cross-var":"1.1.0","karma":"6.4.4","karma-chrome-launcher":"3.1.0","karma-coverage":"2.2.1","karma-mocha":"2.0.1","karma-mocha-webworker":"1.3.0","karma-spec-reporter":"0.0.36","karma-webpack":"5.0.1","lerna":"6.6.2","mocha":"10.8.2","nyc":"15.1.0","sinon":"15.1.2","ts-loader":"9.5.1","typescript":"4.4.4","webpack":"5.96.1"},"peerDependencies":{"@opentelemetry/api":">=1.0.0 <1.10.0"},"dependencies":{"@opentelemetry/core":"1.28.0","@opentelemetry/resources":"1.28.0","@opentelemetry/semantic-conventions":"1.27.0"},"homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","sideEffects":false,"gitHead":"4b1ad3fda0cde58907e30fab25c3c767546708e5","bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"_id":"@opentelemetry/sdk-trace-base@1.28.0","_nodeVersion":"18.20.4","_npmVersion":"lerna/6.6.2/node@v18.20.4+x64 (linux)","dist":{"integrity":"sha512-ceUVWuCpIao7Y5xE02Xs3nQi0tOGmMea17ecBdwtCvdo9ekmO+ijc9RFDgfifMl7XCBf41zne/1POM3LqSTZDA==","shasum":"6195dc8cd78bd74394cf54c67c5cbd8d1528516c","tarball":"https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.28.0.tgz","fileCount":291,"unpackedSize":796305,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@opentelemetry%2fsdk-trace-base@1.28.0","provenance":{"predicateType":"https://slsa.dev/provenance/v0.2"}},"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEyv+TGfQvTgAsZnjL3L4p9Dh+f6tk6Ixvo16zD4UiDQAiEA5yYDGo+Hjd6DCfSj66EP/AB3HNzp6+ehs7BRV0DC9ws="}]},"_npmUser":{"name":"dyladan","email":"dyladan@gmail.com"},"directories":{},"maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/sdk-trace-base_1.28.0_1731926510582_0.963577670721244"},"_hasShrinkwrap":false}},"time":{"created":"2021-08-05T19:28:20.129Z","modified":"2024-11-18T10:41:51.253Z","0.24.1-alpha.4":"2021-08-05T19:28:20.395Z","0.24.1-alpha.5":"2021-08-06T11:31:39.286Z","0.24.1-alpha.7":"2021-08-07T13:33:04.337Z","0.24.1-alpha.9":"2021-08-07T14:10:07.190Z","0.24.1-alpha.14":"2021-08-11T14:50:54.966Z","0.24.1-alpha.18":"2021-08-14T08:16:09.993Z","0.24.1-alpha.20":"2021-08-17T21:07:07.249Z","0.25.1-alpha.21":"2021-08-18T20:16:42.539Z","0.25.0":"2021-08-18T21:16:46.735Z","0.25.1-alpha.2":"2021-08-23T21:41:10.378Z","0.25.1-alpha.4":"2021-08-24T19:33:17.584Z","0.25.1-alpha.7":"2021-08-27T18:20:00.339Z","0.25.1-alpha.12":"2021-08-30T20:22:09.042Z","0.25.1-alpha.13":"2021-08-30T20:41:30.144Z","0.25.1-alpha.16":"2021-09-04T08:05:10.908Z","0.25.1-alpha.23":"2021-09-08T22:15:12.367Z","0.26.0":"2021-09-30T12:35:32.508Z","1.0.0":"2021-09-30T20:53:43.948Z","1.0.1":"2021-11-11T14:51:24.979Z","1.1.0":"2022-03-18T08:11:01.831Z","1.1.1":"2022-03-22T19:52:31.108Z","1.2.0":"2022-04-22T14:57:03.801Z","1.3.0":"2022-05-27T19:41:24.857Z","1.3.1":"2022-06-06T20:26:17.973Z","1.4.0":"2022-07-06T20:15:38.341Z","1.5.0":"2022-07-26T20:52:16.066Z","1.6.0":"2022-08-24T17:44:35.505Z","1.7.0":"2022-09-16T12:14:58.183Z","1.8.0":"2022-11-09T19:45:34.290Z","1.9.0":"2023-01-11T21:46:29.878Z","1.9.1":"2023-01-30T15:30:11.676Z","1.10.0":"2023-03-13T15:53:47.027Z","1.10.1":"2023-03-20T16:10:34.940Z","1.11.0":"2023-03-30T15:30:56.117Z","1.12.0":"2023-04-13T18:13:01.576Z","1.13.0":"2023-05-11T13:30:06.916Z","1.14.0":"2023-06-06T06:00:55.192Z","1.15.0":"2023-07-06T11:27:08.851Z","1.15.1":"2023-07-24T14:32:48.689Z","1.15.2":"2023-08-08T13:21:20.770Z","1.16.0":"2023-09-11T12:14:31.274Z","1.17.0":"2023-09-12T13:12:33.338Z","1.17.1":"2023-10-10T14:18:18.968Z","1.18.0":"2023-11-07T10:44:46.767Z","1.18.1":"2023-11-08T18:09:10.048Z","1.19.0":"2023-12-14T12:35:30.035Z","1.20.0":"2024-01-15T10:15:47.496Z","1.21.0":"2024-01-26T06:11:09.767Z","1.22.0":"2024-02-29T09:18:14.609Z","1.23.0":"2024-04-03T08:10:05.643Z","1.24.0":"2024-04-24T14:39:42.149Z","1.24.1":"2024-05-07T14:52:38.897Z","1.25.0":"2024-06-05T17:15:56.531Z","1.25.1":"2024-06-20T09:19:21.851Z","1.26.0":"2024-08-28T09:17:19.852Z","1.27.0":"2024-10-23T14:51:41.469Z","1.28.0":"2024-11-18T10:41:50.759Z"},"bugs":{"url":"https://github.com/open-telemetry/opentelemetry-js/issues"},"author":{"name":"OpenTelemetry Authors"},"license":"Apache-2.0","homepage":"https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-base","keywords":["opentelemetry","nodejs","tracing","profiling","metrics","stats"],"repository":{"type":"git","url":"git+https://github.com/open-telemetry/opentelemetry-js.git"},"description":"OpenTelemetry Tracing","maintainers":[{"name":"pichlermarc","email":"marc.pichler@dynatrace.com"},{"name":"bogdandrutu","email":"bogdandrutu@gmail.com"},{"name":"dyladan","email":"dyladan@gmail.com"}],"readme":"# OpenTelemetry Tracing SDK\n\n[![NPM Published Version][npm-img]][npm-url]\n[![Apache License][license-image]][license-image]\n\nThe `tracing` module contains the foundation for all tracing SDKs of [opentelemetry-js](https://github.com/open-telemetry/opentelemetry-js).\n\nUsed standalone, this module provides methods for manual instrumentation of code, offering full control over span creation for client-side JavaScript (browser) and Node.js.\n\nIt does **not** provide automated instrumentation of known libraries, context propagation for asynchronous invocations or distributed-context out-of-the-box.\n\nFor automated instrumentation for Node.js, please see\n[@opentelemetry/sdk-trace-node](https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-node).\n\n## Installation\n\n```bash\nnpm install --save @opentelemetry/api\nnpm install --save @opentelemetry/sdk-trace-base\n```\n\n## Usage\n\n```js\nconst opentelemetry = require('@opentelemetry/api');\nconst { BasicTracerProvider } = require('@opentelemetry/sdk-trace-base');\n\n// To start a trace, you first need to initialize the Tracer provider.\n// NOTE: The default OpenTelemetry tracer provider does not record any tracing information.\n// Registering a working tracer provider allows the API methods to record traces.\nnew BasicTracerProvider().register();\n\n// To create a span in a trace, we used the global singleton tracer to start a new span.\nconst span = opentelemetry.trace.getTracer('default').startSpan('foo');\n\n// Set a span attribute\nspan.setAttribute('key', 'value');\n\n// We must end the spans so they become available for exporting.\nspan.end();\n```\n\n## Config\n\nTracing configuration is a merge of user supplied configuration with both the default\nconfiguration as specified in [config.ts](./src/config.ts) and an\nenvironmentally configurable sampling (via `OTEL_TRACES_SAMPLER` and `OTEL_TRACES_SAMPLER_ARG`).\n\n## Built-in Samplers\n\nSampler is used to make decisions on `Span` sampling.\n\n### AlwaysOn Sampler\n\nSamples every trace regardless of upstream sampling decisions.\n\n> This is used as a default Sampler\n\n```js\nconst {\n AlwaysOnSampler,\n BasicTracerProvider,\n} = require(\"@opentelemetry/sdk-trace-base\");\n\nconst tracerProvider = new BasicTracerProvider({\n sampler: new AlwaysOnSampler()\n});\n```\n\n### AlwaysOff Sampler\n\nDoesn't sample any trace, regardless of upstream sampling decisions.\n\n```js\nconst {\n AlwaysOffSampler,\n BasicTracerProvider,\n} = require(\"@opentelemetry/sdk-trace-base\");\n\nconst tracerProvider = new BasicTracerProvider({\n sampler: new AlwaysOffSampler()\n});\n```\n\n### TraceIdRatioBased Sampler\n\nSamples some percentage of traces, calculated deterministically using the trace ID.\nAny trace that would be sampled at a given percentage will also be sampled at any higher percentage.\n\nThe `TraceIDRatioSampler` may be used with the `ParentBasedSampler` to respect the sampled flag of an incoming trace.\n\n```js\nconst {\n BasicTracerProvider,\n TraceIdRatioBasedSampler,\n} = require(\"@opentelemetry/sdk-trace-base\");\n\nconst tracerProvider = new BasicTracerProvider({\n // See details of ParentBasedSampler below\n sampler: new ParentBasedSampler({\n // Trace ID Ratio Sampler accepts a positional argument\n // which represents the percentage of traces which should\n // be sampled.\n root: new TraceIdRatioBasedSampler(0.5)\n });\n});\n```\n\n### ParentBased Sampler\n\n- This is a composite sampler. `ParentBased` helps distinguished between the\nfollowing cases:\n - No parent (root span).\n - Remote parent with `sampled` flag `true`\n - Remote parent with `sampled` flag `false`\n - Local parent with `sampled` flag `true`\n - Local parent with `sampled` flag `false`\n\nRequired parameters:\n\n- `root(Sampler)` - Sampler called for spans with no parent (root spans)\n\nOptional parameters:\n\n- `remoteParentSampled(Sampler)` (default: `AlwaysOn`)\n- `remoteParentNotSampled(Sampler)` (default: `AlwaysOff`)\n- `localParentSampled(Sampler)` (default: `AlwaysOn`)\n- `localParentNotSampled(Sampler)` (default: `AlwaysOff`)\n\n|Parent| parent.isRemote() | parent.isSampled()| Invoke sampler|\n|--|--|--|--|\n|absent| n/a | n/a |`root()`|\n|present|true|true|`remoteParentSampled()`|\n|present|true|false|`remoteParentNotSampled()`|\n|present|false|true|`localParentSampled()`|\n|present|false|false|`localParentNotSampled()`|\n\n```js\nconst {\n AlwaysOffSampler,\n BasicTracerProvider,\n ParentBasedSampler,\n TraceIdRatioBasedSampler,\n} = require(\"@opentelemetry/sdk-trace-base\");\n\nconst tracerProvider = new BasicTracerProvider({\n sampler: new ParentBasedSampler({\n // By default, the ParentBasedSampler will respect the parent span's sampling\n // decision. This is configurable by providing a different sampler to use\n // based on the situation. See configuration details above.\n //\n // This will delegate the sampling decision of all root traces (no parent)\n // to the TraceIdRatioBasedSampler.\n // See details of TraceIdRatioBasedSampler above.\n root: new TraceIdRatioBasedSampler(0.5)\n })\n});\n```\n\n## Example\n\nSee [examples/basic-tracer-node](https://github.com/open-telemetry/opentelemetry-js/tree/main/examples/basic-tracer-node) for an end-to-end example, including exporting created spans.\n\n## Useful links\n\n- For more information on OpenTelemetry, visit: \n- For more about OpenTelemetry JavaScript: \n- For help or feedback on this project, join us in [GitHub Discussions][discussions-url]\n\n## License\n\nApache 2.0 - See [LICENSE][license-url] for more information.\n\n[discussions-url]: https://github.com/open-telemetry/opentelemetry-js/discussions\n[license-url]: https://github.com/open-telemetry/opentelemetry-js/blob/main/LICENSE\n[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat\n[npm-url]: https://www.npmjs.com/package/@opentelemetry/sdk-trace-base\n[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Fsdk-trace-base.svg\n","readmeFilename":"README.md"} \ No newline at end of file diff --git a/tests/registry/npm/npm-check-updates/npm-check-updates-17.1.13.tgz b/tests/registry/npm/npm-check-updates/npm-check-updates-17.1.13.tgz new file mode 100644 index 0000000000..4a95f26159 Binary files /dev/null and b/tests/registry/npm/npm-check-updates/npm-check-updates-17.1.13.tgz differ diff --git a/tests/registry/npm/npm-check-updates/registry.json b/tests/registry/npm/npm-check-updates/registry.json new file mode 100644 index 0000000000..71d96fd83d --- /dev/null +++ b/tests/registry/npm/npm-check-updates/registry.json @@ -0,0 +1,201 @@ +{ + "name": "npm-check-updates", + "dist-tags": { + "latest": "17.1.13" + }, + "versions": { + "17.1.13": { + "name": "npm-check-updates", + "version": "17.1.13", + "author": { + "name": "Tomas Junnonen", + "email": "tomas1@gmail.com" + }, + "license": "Apache-2.0", + "description": "Find newer versions of dependencies than what your package.json allows", + "engines": { + "node": "^18.18.0 || >=20.0.0", + "npm": ">=8.12.1" + }, + "main": "build/index.js", + "types": "build/index.d.ts", + "scripts": { + "build": "rimraf build && npm run build:options && vite build", + "build:options": "vite-node src/scripts/build-options.ts", + "build:analyze": "rimraf build && npm run build:options && ANALYZER=true vite build", + "lint": "cross-env FORCE_COLOR=1 npm-run-all --parallel --aggregate-output lint:*", + "lint:lockfile": "lockfile-lint", + "lint:markdown": "markdownlint \"**/*.md\" --ignore \"**/node_modules/**/*.md\" --ignore build --config .markdownlint.js", + "lint:src": "eslint --cache --cache-location node_modules/.cache/.eslintcache --ignore-path .gitignore --report-unused-disable-directives .", + "prepare": "src/scripts/install-hooks", + "prepublishOnly": "npm run build", + "prettier": "prettier . --check", + "test": "npm run test:unit && npm run test:e2e", + "test:bun": "test/bun-install.sh && mocha test/bun", + "test:unit": "mocha test test/package-managers/*", + "test:e2e": "./test/e2e.sh", + "ncu": "node build/cli.js" + }, + "bin": { + "npm-check-updates": "build/cli.js", + "ncu": "build/cli.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/raineorshine/npm-check-updates.git" + }, + "bugs": { + "url": "https://github.com/raineorshine/npm-check-updates/issues" + }, + "overrides": { + "ip": "2.0.1", + "jsonparse": "https://github.com/ARitz-Cracker/jsonparse/tree/patch-1", + "@yarnpkg/parsers": "2.6.0" + }, + "devDependencies": { + "@trivago/prettier-plugin-sort-imports": "^4.3.0", + "@types/chai": "^4.3.19", + "@types/chai-as-promised": "^8.0.0", + "@types/chai-string": "^1.4.5", + "@types/cli-table": "^0.3.4", + "@types/hosted-git-info": "^3.0.5", + "@types/ini": "^4.1.1", + "@types/js-yaml": "^4.0.9", + "@types/json-parse-helpfulerror": "^1.0.3", + "@types/jsonlines": "^0.1.5", + "@types/lodash": "^4.17.10", + "@types/mocha": "^10.0.9", + "@types/node": "^22.7.5", + "@types/npm-registry-fetch": "^8.0.7", + "@types/parse-github-url": "^1.0.3", + "@types/picomatch": "^3.0.1", + "@types/progress": "^2.0.7", + "@types/prompts": "^2.4.9", + "@types/remote-git-tags": "^4.0.2", + "@types/semver": "^7.5.8", + "@types/semver-utils": "^1.1.3", + "@types/sinon": "^17.0.3", + "@types/update-notifier": "^6.0.8", + "@typescript-eslint/eslint-plugin": "^8.9.0", + "@typescript-eslint/parser": "^8.9.0", + "camelcase": "^6.3.0", + "chai": "^4.3.10", + "chai-as-promised": "^7.1.2", + "chai-string": "^1.5.0", + "chalk": "^5.3.0", + "cli-table3": "^0.6.5", + "commander": "^12.1.0", + "cross-env": "^7.0.3", + "dequal": "^2.0.3", + "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "eslint-config-raine": "^0.5.0", + "eslint-config-standard": "^17.1.0", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jsdoc": "^50.4.1", + "eslint-plugin-n": "^16.6.2", + "eslint-plugin-promise": "^6.6.0", + "fast-glob": "^3.3.2", + "fast-memoize": "^2.5.2", + "find-up": "5.0.0", + "fp-and-or": "^1.0.2", + "hosted-git-info": "^8.0.0", + "ini": "^5.0.0", + "js-yaml": "^4.1.0", + "json-parse-helpfulerror": "^1.0.3", + "jsonlines": "^0.1.1", + "lockfile-lint": "^4.14.0", + "lodash": "^4.17.21", + "markdownlint-cli": "^0.42.0", + "mocha": "^10.7.3", + "npm-registry-fetch": "^18.0.2", + "npm-run-all": "^4.1.5", + "p-map": "^4.0.0", + "parse-github-url": "^1.0.3", + "picomatch": "^4.0.2", + "prettier": "^3.3.3", + "progress": "^2.0.3", + "prompts-ncu": "^3.0.2", + "rc-config-loader": "^4.1.3", + "remote-git-tags": "^3.0.0", + "rfdc": "^1.4.1", + "rimraf": "^6.0.1", + "rollup-plugin-node-externals": "^7.1.3", + "semver": "^7.6.3", + "semver-utils": "^1.1.4", + "should": "^13.2.3", + "sinon": "^19.0.2", + "source-map-support": "^0.5.21", + "spawn-please": "^3.0.0", + "strip-ansi": "^7.1.0", + "strip-json-comments": "^5.0.1", + "ts-node": "^10.9.2", + "typescript": "^5.6.3", + "typescript-json-schema": "^0.65.1", + "untildify": "^4.0.0", + "update-notifier": "^7.3.1", + "verdaccio": "^6.0.1", + "vite": "^5.4.9", + "vite-bundle-analyzer": "^0.12.1", + "vite-node": "^2.1.3", + "vite-plugin-dts": "^4.2.4", + "yarn": "^1.22.22" + }, + "lockfile-lint": { + "allowed-schemes": [ + "https:", + "git+ssh:" + ], + "allowed-hosts": [ + "npm", + "github.com" + ], + "empty-hostname": false, + "type": "npm ", + "path": "package-lock.json" + }, + "mocha": { + "check-leaks": true, + "extension": [ + "test.ts" + ], + "require": [ + "source-map-support/register", + "ts-node/register" + ], + "timeout": 60000, + "trace-deprecation": true, + "trace-warnings": true, + "use_strict": true + }, + "_id": "npm-check-updates@17.1.13", + "gitHead": "f514093647f1833c83653765493c694372d14fea", + "_nodeVersion": "22.0.0", + "_npmVersion": "10.9.1", + "dist": { + "integrity": "sha512-m9Woo2J5XVab0VcQpYvrQ0hx3ySI1mGbiHR595mc6Lr1/FIaTWvv+oU+T1WKSfXRiluKC/V5P6Bdk5agaYpqqg==", + "shasum": "93e1c5fa5b8e11bca0bd143650b14ffcf9fc6b5a", + "tarball": "http://localhost:4260/npm-check-updates/npm-check-updates-17.1.13.tgz", + "fileCount": 19, + "unpackedSize": 5336239 + }, + "directories": {}, + "_hasShrinkwrap": false + } + }, + "bugs": { + "url": "https://github.com/raineorshine/npm-check-updates/issues" + }, + "author": { + "name": "Tomas Junnonen", + "email": "tomas1@gmail.com" + }, + "license": "Apache-2.0", + "homepage": "https://github.com/raineorshine/npm-check-updates", + "repository": { + "type": "git", + "url": "git+https://github.com/raineorshine/npm-check-updates.git" + }, + "description": "Find newer versions of dependencies than what your package.json allows", + "readmeFilename": "README.md" +} diff --git a/tests/registry/npm/trim_registry_files.js b/tests/registry/npm/trim_registry_files.js index 608624b1d3..e6fbe1353f 100644 --- a/tests/registry/npm/trim_registry_files.js +++ b/tests/registry/npm/trim_registry_files.js @@ -1,5 +1,5 @@ #!/usr/bin/env -S deno run --allow-write=. --allow-read=. -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Run this to trim the registry.json files diff --git a/tests/specs/check/compiler_options_types/__test__.jsonc b/tests/specs/check/compiler_options_types/__test__.jsonc new file mode 100644 index 0000000000..f23081fef4 --- /dev/null +++ b/tests/specs/check/compiler_options_types/__test__.jsonc @@ -0,0 +1,53 @@ +{ + "tempDir": true, + "tests": { + "node_modules_dir_none": { + "steps": [ + { + "args": "run -A ./set_node_modules_dir.ts none", + "output": "" + }, + { + "args": "install", + "output": "[WILDCARD]" + }, + { + "args": "check ./main.ts", + "output": "Check [WILDCARD]main.ts\n" + } + ] + }, + "node_modules_dir_auto": { + "steps": [ + { + "args": "run -A ./set_node_modules_dir.ts auto", + "output": "" + }, + { + "args": "install", + "output": "[WILDCARD]" + }, + { + "args": "check ./main.ts", + "output": "Check [WILDCARD]main.ts\n" + } + ] + }, + "node_modules_dir_manual": { + "steps": [ + { + "args": "run -A ./set_node_modules_dir.ts auto", + "output": "" + }, + { + "args": "install", + "output": "[WILDCARD]" + }, + { + "args": "check ./main.ts", + "output": "Check [WILDCARD]main.ts\n" + } + ] + } + } +} diff --git a/tests/specs/check/compiler_options_types/deno.json b/tests/specs/check/compiler_options_types/deno.json new file mode 100644 index 0000000000..9a27ef33a8 --- /dev/null +++ b/tests/specs/check/compiler_options_types/deno.json @@ -0,0 +1,6 @@ +{ + "imports": { + "@denotest/augments-global": "npm:@denotest/augments-global@1" + }, + "compilerOptions": { "types": ["@denotest/augments-global"] } +} diff --git a/tests/specs/check/compiler_options_types/main.ts b/tests/specs/check/compiler_options_types/main.ts new file mode 100644 index 0000000000..ae30721279 --- /dev/null +++ b/tests/specs/check/compiler_options_types/main.ts @@ -0,0 +1,2 @@ +const foo = [1]; +foo.augmented(); diff --git a/tests/specs/check/compiler_options_types/set_node_modules_dir.ts b/tests/specs/check/compiler_options_types/set_node_modules_dir.ts new file mode 100644 index 0000000000..656f215890 --- /dev/null +++ b/tests/specs/check/compiler_options_types/set_node_modules_dir.ts @@ -0,0 +1,8 @@ +if (Deno.args.length !== 1) { + console.error("Usage: set_node_modules_dir.ts "); + Deno.exit(1); +} +const setting = Deno.args[0].trim(); +const denoJson = JSON.parse(Deno.readTextFileSync("./deno.json")); +denoJson["nodeModulesDir"] = setting; +Deno.writeTextFileSync("./deno.json", JSON.stringify(denoJson, null, 2)); diff --git a/tests/specs/check/css_import/__test__.jsonc b/tests/specs/check/css_import/__test__.jsonc index 629dcd3833..4e16560ec2 100644 --- a/tests/specs/check/css_import/__test__.jsonc +++ b/tests/specs/check/css_import/__test__.jsonc @@ -10,6 +10,10 @@ "args": "check not_exists.ts", "output": "not_exists.out", "exitCode": 1 + }, { + "args": "run --check not_exists.ts", + "output": "not_exists.out", + "exitCode": 1 }, { "args": "check exists_and_try_uses.ts", "output": "exists_and_try_uses.out", diff --git a/tests/specs/check/css_import/not_exists.out b/tests/specs/check/css_import/not_exists.out index 95fd14668e..1e9dce6b70 100644 --- a/tests/specs/check/css_import/not_exists.out +++ b/tests/specs/check/css_import/not_exists.out @@ -1,2 +1,3 @@ -error: Module not found "file:///[WILDLINE]/not_exists.css". +Check [WILDLINE]exists.ts +error: TS2307 [ERROR]: Cannot find module 'file:///[WILDLINE]/not_exists.css'. at file:///[WILDLINE]/not_exists.ts:1:8 diff --git a/tests/specs/check/dts_importing_non_existent/check.out b/tests/specs/check/dts_importing_non_existent/check.out index 80ec9593b0..65e27bce83 100644 --- a/tests/specs/check/dts_importing_non_existent/check.out +++ b/tests/specs/check/dts_importing_non_existent/check.out @@ -1,2 +1,3 @@ -error: Module not found "file:///[WILDLINE]/test". +Check file:///[WILDLINE]/dts_importing_non_existent/index.js +error: TS2307 [ERROR]: Cannot find module 'file:///[WILDLINE]/test'. at file:///[WILDLINE]/index.d.ts:1:22 diff --git a/tests/specs/check/import_meta_no_errors/__test__.jsonc b/tests/specs/check/import_meta_no_errors/__test__.jsonc new file mode 100644 index 0000000000..e03edb297f --- /dev/null +++ b/tests/specs/check/import_meta_no_errors/__test__.jsonc @@ -0,0 +1,53 @@ +{ + "tempDir": true, + "tests": { + "node_modules_dir_none": { + "steps": [ + { + "args": "run -A ./set_node_modules_dir.ts none", + "output": "" + }, + { + "args": "install", + "output": "[WILDCARD]" + }, + { + "args": "check --all ./main.ts", + "output": "Check [WILDCARD]main.ts\n" + } + ] + }, + "node_modules_dir_auto": { + "steps": [ + { + "args": "run -A ./set_node_modules_dir.ts auto", + "output": "" + }, + { + "args": "install", + "output": "[WILDCARD]" + }, + { + "args": "check --all ./main.ts", + "output": "Check [WILDCARD]main.ts\n" + } + ] + }, + "node_modules_dir_manual": { + "steps": [ + { + "args": "run -A ./set_node_modules_dir.ts auto", + "output": "" + }, + { + "args": "install", + "output": "[WILDCARD]" + }, + { + "args": "check --all ./main.ts", + "output": "Check [WILDCARD]main.ts\n" + } + ] + } + } +} diff --git a/tests/specs/check/import_meta_no_errors/deno.json b/tests/specs/check/import_meta_no_errors/deno.json new file mode 100644 index 0000000000..4cc5c30d3a --- /dev/null +++ b/tests/specs/check/import_meta_no_errors/deno.json @@ -0,0 +1,5 @@ +{ + "imports": { + "@types/node": "npm:@types/node@*" + } +} diff --git a/tests/specs/check/import_meta_no_errors/main.ts b/tests/specs/check/import_meta_no_errors/main.ts new file mode 100644 index 0000000000..ff1b8e3629 --- /dev/null +++ b/tests/specs/check/import_meta_no_errors/main.ts @@ -0,0 +1,3 @@ +/// + +const _foo = import.meta.dirname; diff --git a/tests/specs/check/import_meta_no_errors/set_node_modules_dir.ts b/tests/specs/check/import_meta_no_errors/set_node_modules_dir.ts new file mode 100644 index 0000000000..656f215890 --- /dev/null +++ b/tests/specs/check/import_meta_no_errors/set_node_modules_dir.ts @@ -0,0 +1,8 @@ +if (Deno.args.length !== 1) { + console.error("Usage: set_node_modules_dir.ts "); + Deno.exit(1); +} +const setting = Deno.args[0].trim(); +const denoJson = JSON.parse(Deno.readTextFileSync("./deno.json")); +denoJson["nodeModulesDir"] = setting; +Deno.writeTextFileSync("./deno.json", JSON.stringify(denoJson, null, 2)); diff --git a/tests/specs/check/import_non_existent_in_remote/__test__.jsonc b/tests/specs/check/import_non_existent_in_remote/__test__.jsonc new file mode 100644 index 0000000000..39cd37ffc0 --- /dev/null +++ b/tests/specs/check/import_non_existent_in_remote/__test__.jsonc @@ -0,0 +1,14 @@ +{ + "tests": { + "not_all": { + "args": "check --allow-import import_remote.ts", + "output": "[WILDCARD]", + "exitCode": 0 + }, + "all": { + "args": "check --all --allow-import import_remote.ts", + "output": "check_all.out", + "exitCode": 1 + } + } +} diff --git a/tests/specs/check/import_non_existent_in_remote/check_all.out b/tests/specs/check/import_non_existent_in_remote/check_all.out new file mode 100644 index 0000000000..a3c3b1759c --- /dev/null +++ b/tests/specs/check/import_non_existent_in_remote/check_all.out @@ -0,0 +1,5 @@ +Download http://localhost:4545/check/import_non_existent.ts +Download http://localhost:4545/check/non-existent-module.ts +Check file:///[WILDLINE]/import_remote.ts +error: TS2307 [ERROR]: Cannot find module 'http://localhost:4545/check/non-existent-module.ts'. + at http://localhost:4545/check/import_non_existent.ts:1:22 diff --git a/tests/specs/check/import_non_existent_in_remote/import_remote.ts b/tests/specs/check/import_non_existent_in_remote/import_remote.ts new file mode 100644 index 0000000000..47c5c654b8 --- /dev/null +++ b/tests/specs/check/import_non_existent_in_remote/import_remote.ts @@ -0,0 +1,3 @@ +import { Other } from "http://localhost:4545/check/import_non_existent.ts"; + +console.log(Other); diff --git a/tests/specs/check/message_chain_formatting/__test__.jsonc b/tests/specs/check/message_chain_formatting/__test__.jsonc new file mode 100644 index 0000000000..1b5b49d8a9 --- /dev/null +++ b/tests/specs/check/message_chain_formatting/__test__.jsonc @@ -0,0 +1,6 @@ +// Regression test for https://github.com/denoland/deno/issues/27411. +{ + "args": "check --quiet message_chain_formatting.ts", + "output": "message_chain_formatting.out", + "exitCode": 1 +} diff --git a/tests/specs/check/message_chain_formatting/message_chain_formatting.out b/tests/specs/check/message_chain_formatting/message_chain_formatting.out new file mode 100644 index 0000000000..ca5c646ccb --- /dev/null +++ b/tests/specs/check/message_chain_formatting/message_chain_formatting.out @@ -0,0 +1,10 @@ +error: TS2769 [ERROR]: No overload matches this call. + Overload 1 of 3, '(s: string, b: boolean): void', gave the following error. + Argument of type 'number' is not assignable to parameter of type 'boolean'. + Overload 2 of 3, '(ss: string[], b: boolean): void', gave the following error. + Argument of type 'string' is not assignable to parameter of type 'string[]'. + Overload 3 of 3, '(ss: string[], b: Date): void', gave the following error. + Argument of type 'string' is not assignable to parameter of type 'string[]'. +foo("hello", 42); +~~~ + at [WILDLINE]/message_chain_formatting.ts:8:1 diff --git a/tests/specs/check/message_chain_formatting/message_chain_formatting.ts b/tests/specs/check/message_chain_formatting/message_chain_formatting.ts new file mode 100644 index 0000000000..ed342629ea --- /dev/null +++ b/tests/specs/check/message_chain_formatting/message_chain_formatting.ts @@ -0,0 +1,8 @@ +function foo(s: string, b: boolean): void; +function foo(ss: string[], b: boolean): void; +function foo(ss: string[], b: Date): void; +function foo(sOrSs: string | string[], b: boolean | Date): void { + console.log(sOrSs, b); +} + +foo("hello", 42); diff --git a/tests/specs/check/module_not_found/__test__.jsonc b/tests/specs/check/module_not_found/__test__.jsonc new file mode 100644 index 0000000000..5e7cfa2e59 --- /dev/null +++ b/tests/specs/check/module_not_found/__test__.jsonc @@ -0,0 +1,24 @@ +{ + "tests": { + "check": { + "args": "check --allow-import main.ts", + "output": "main.out", + "exitCode": 1 + }, + "run": { + "args": "run --check --allow-import main.ts", + "output": "main.out", + "exitCode": 1 + }, + "missing_local_root": { + "args": "check --allow-import non_existent.ts", + "output": "missing_local_root.out", + "exitCode": 1 + }, + "missing_remote_root": { + "args": "check --allow-import http://localhost:4545/missing_non_existent.ts", + "output": "missing_remote_root.out", + "exitCode": 1 + } + } +} diff --git a/tests/specs/check/module_not_found/main.out b/tests/specs/check/module_not_found/main.out new file mode 100644 index 0000000000..6c16183560 --- /dev/null +++ b/tests/specs/check/module_not_found/main.out @@ -0,0 +1,9 @@ +Download http://localhost:4545/remote.ts +Check file:///[WILDLINE]/module_not_found/main.ts +error: TS2307 [ERROR]: Cannot find module 'file:///[WILDLINE]/other.js'. + at file:///[WILDLINE]/main.ts:1:22 + +TS2307 [ERROR]: Cannot find module 'http://localhost:4545/remote.ts'. + at file:///[WILDLINE]/main.ts:2:24 + +Found 2 errors. diff --git a/tests/specs/check/module_not_found/main.ts b/tests/specs/check/module_not_found/main.ts new file mode 100644 index 0000000000..cec9512569 --- /dev/null +++ b/tests/specs/check/module_not_found/main.ts @@ -0,0 +1,5 @@ +import { Test } from "./other.js"; +import { Remote } from "http://localhost:4545/remote.ts"; + +console.log(new Test()); +console.log(new Remote()); diff --git a/tests/specs/check/module_not_found/missing_local_root.out b/tests/specs/check/module_not_found/missing_local_root.out new file mode 100644 index 0000000000..34b150c9a3 --- /dev/null +++ b/tests/specs/check/module_not_found/missing_local_root.out @@ -0,0 +1,2 @@ +Check file:///[WILDLINE]/non_existent.ts +error: TS2307 [ERROR]: Cannot find module 'file:///[WILDLINE]/non_existent.ts'. diff --git a/tests/specs/check/module_not_found/missing_remote_root.out b/tests/specs/check/module_not_found/missing_remote_root.out new file mode 100644 index 0000000000..e408938e41 --- /dev/null +++ b/tests/specs/check/module_not_found/missing_remote_root.out @@ -0,0 +1,3 @@ +Download http://localhost:4545/missing_non_existent.ts +Check http://localhost:4545/missing_non_existent.ts +error: TS2307 [ERROR]: Cannot find module 'http://localhost:4545/missing_non_existent.ts'. diff --git a/tests/specs/check/type_reference_import_meta/__test__.jsonc b/tests/specs/check/type_reference_import_meta/__test__.jsonc new file mode 100644 index 0000000000..f23081fef4 --- /dev/null +++ b/tests/specs/check/type_reference_import_meta/__test__.jsonc @@ -0,0 +1,53 @@ +{ + "tempDir": true, + "tests": { + "node_modules_dir_none": { + "steps": [ + { + "args": "run -A ./set_node_modules_dir.ts none", + "output": "" + }, + { + "args": "install", + "output": "[WILDCARD]" + }, + { + "args": "check ./main.ts", + "output": "Check [WILDCARD]main.ts\n" + } + ] + }, + "node_modules_dir_auto": { + "steps": [ + { + "args": "run -A ./set_node_modules_dir.ts auto", + "output": "" + }, + { + "args": "install", + "output": "[WILDCARD]" + }, + { + "args": "check ./main.ts", + "output": "Check [WILDCARD]main.ts\n" + } + ] + }, + "node_modules_dir_manual": { + "steps": [ + { + "args": "run -A ./set_node_modules_dir.ts auto", + "output": "" + }, + { + "args": "install", + "output": "[WILDCARD]" + }, + { + "args": "check ./main.ts", + "output": "Check [WILDCARD]main.ts\n" + } + ] + } + } +} diff --git a/tests/specs/check/type_reference_import_meta/deno.json b/tests/specs/check/type_reference_import_meta/deno.json new file mode 100644 index 0000000000..bea3f5b73d --- /dev/null +++ b/tests/specs/check/type_reference_import_meta/deno.json @@ -0,0 +1,6 @@ +{ + "imports": { + "@denotest/augments-global": "npm:@denotest/augments-global@1" + }, + "compilerOptions": { "types": ["./types.d.ts"] } +} diff --git a/tests/specs/check/type_reference_import_meta/main.ts b/tests/specs/check/type_reference_import_meta/main.ts new file mode 100644 index 0000000000..c0924e35ef --- /dev/null +++ b/tests/specs/check/type_reference_import_meta/main.ts @@ -0,0 +1,3 @@ +const test = import.meta.env.TEST; +const bar = import.meta.bar; +console.log(test, bar); diff --git a/tests/specs/check/type_reference_import_meta/set_node_modules_dir.ts b/tests/specs/check/type_reference_import_meta/set_node_modules_dir.ts new file mode 100644 index 0000000000..656f215890 --- /dev/null +++ b/tests/specs/check/type_reference_import_meta/set_node_modules_dir.ts @@ -0,0 +1,8 @@ +if (Deno.args.length !== 1) { + console.error("Usage: set_node_modules_dir.ts "); + Deno.exit(1); +} +const setting = Deno.args[0].trim(); +const denoJson = JSON.parse(Deno.readTextFileSync("./deno.json")); +denoJson["nodeModulesDir"] = setting; +Deno.writeTextFileSync("./deno.json", JSON.stringify(denoJson, null, 2)); diff --git a/tests/specs/check/type_reference_import_meta/types.d.ts b/tests/specs/check/type_reference_import_meta/types.d.ts new file mode 100644 index 0000000000..2df7d5371b --- /dev/null +++ b/tests/specs/check/type_reference_import_meta/types.d.ts @@ -0,0 +1 @@ +/// diff --git a/tests/specs/check/types_resolved_relative_config/main.out b/tests/specs/check/types_resolved_relative_config/main.out index 212e1224ca..5763d3298c 100644 --- a/tests/specs/check/types_resolved_relative_config/main.out +++ b/tests/specs/check/types_resolved_relative_config/main.out @@ -1,3 +1,4 @@ [# It should be resolving relative the config in sub_dir instead of the cwd] -error: Module not found "file:///[WILDLINE]/sub_dir/a.d.ts". +Check file:///[WILDLINE]/main.ts +error: TS2307 [ERROR]: Cannot find module 'file:///[WILDLINE]/sub_dir/a.d.ts'. at file:///[WILDLINE]/sub_dir/deno.json:1:1 diff --git a/tests/specs/cli/otel_basic/basic.out b/tests/specs/cli/otel_basic/basic.out index 1e82ba59b3..c16f57a8fc 100644 --- a/tests/specs/cli/otel_basic/basic.out +++ b/tests/specs/cli/otel_basic/basic.out @@ -2,7 +2,7 @@ "spans": [ { "traceId": "00000000000000000000000000000001", - "spanId": "0000000000000002", + "spanId": "0000000000000001", "traceState": "", "parentSpanId": "", "flags": 1, @@ -59,8 +59,8 @@ } }, { - "traceId": "00000000000000000000000000000003", - "spanId": "0000000000000004", + "traceId": "00000000000000000000000000000002", + "spanId": "0000000000000002", "traceState": "", "parentSpanId": "", "flags": 1, @@ -117,10 +117,10 @@ } }, { - "traceId": "00000000000000000000000000000003", - "spanId": "1000000000000001", + "traceId": "00000000000000000000000000000002", + "spanId": "0000000000000003", "traceState": "", - "parentSpanId": "0000000000000004", + "parentSpanId": "0000000000000002", "flags": 1, "name": "outer span", "kind": 1, @@ -138,10 +138,10 @@ } }, { - "traceId": "00000000000000000000000000000003", - "spanId": "1000000000000002", + "traceId": "00000000000000000000000000000002", + "spanId": "0000000000000004", "traceState": "", - "parentSpanId": "1000000000000001", + "parentSpanId": "0000000000000003", "flags": 1, "name": "inner span", "kind": 1, @@ -171,8 +171,8 @@ "attributes": [], "droppedAttributesCount": 0, "flags": 1, - "traceId": "00000000000000000000000000000003", - "spanId": "1000000000000002" + "traceId": "00000000000000000000000000000002", + "spanId": "0000000000000004" }, { "timeUnixNano": "0", @@ -185,8 +185,8 @@ "attributes": [], "droppedAttributesCount": 0, "flags": 1, - "traceId": "00000000000000000000000000000003", - "spanId": "1000000000000002" + "traceId": "00000000000000000000000000000002", + "spanId": "0000000000000004" } ], "metrics": [] diff --git a/tests/specs/cli/otel_basic/basic.ts b/tests/specs/cli/otel_basic/basic.ts index 5c4ae43cd8..6f19867d96 100644 --- a/tests/specs/cli/otel_basic/basic.ts +++ b/tests/specs/cli/otel_basic/basic.ts @@ -1,7 +1,6 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { trace } from "npm:@opentelemetry/api@1.9.0"; -import "jsr:@deno/otel@0.0.2/register"; const tracer = trace.getTracer("example-tracer"); diff --git a/tests/specs/cli/otel_basic/context.ts b/tests/specs/cli/otel_basic/context.ts index cef0dbd81a..16b08835ff 100644 --- a/tests/specs/cli/otel_basic/context.ts +++ b/tests/specs/cli/otel_basic/context.ts @@ -2,9 +2,7 @@ import { assertEquals } from "@std/assert"; const { ContextManager } = Deno.telemetry; -const cm = new ContextManager(); - -const a = cm.active(); +const a = ContextManager.active(); const b = a.setValue("b", 1); const c = b.setValue("c", 2); diff --git a/tests/specs/cli/otel_basic/main.ts b/tests/specs/cli/otel_basic/main.ts index 634727cea7..921c39911b 100644 --- a/tests/specs/cli/otel_basic/main.ts +++ b/tests/specs/cli/otel_basic/main.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. const data = { spans: [], @@ -21,8 +21,13 @@ const server = Deno.serve( stdout: "null", }); const child = command.spawn(); - child.output() - .then(() => server.shutdown()) + child.status + .then((status) => { + if (status.signal) { + throw new Error("child process failed: " + JSON.stringify(status)); + } + return server.shutdown(); + }) .then(() => { data.logs.sort((a, b) => Number( diff --git a/tests/specs/cli/otel_basic/metric.ts b/tests/specs/cli/otel_basic/metric.ts index 2b472a6fb8..f95c0cb802 100644 --- a/tests/specs/cli/otel_basic/metric.ts +++ b/tests/specs/cli/otel_basic/metric.ts @@ -1,6 +1,6 @@ import { metrics } from "npm:@opentelemetry/api@1"; -metrics.setGlobalMeterProvider(new Deno.telemetry.MeterProvider()); +metrics.setGlobalMeterProvider(Deno.telemetry.meterProvider); const meter = metrics.getMeter("m"); diff --git a/tests/specs/compile/case_insensitive_building/__test__.jsonc b/tests/specs/compile/case_insensitive_building/__test__.jsonc new file mode 100644 index 0000000000..38636dc273 --- /dev/null +++ b/tests/specs/compile/case_insensitive_building/__test__.jsonc @@ -0,0 +1,24 @@ +{ + "tempDir": true, + "steps": [{ + "if": "mac", + "args": "compile --output main --include file.txt --include FILE.txt main.js", + "output": "compile.out" + }, { + "if": "mac", + "commandName": "./main", + "args": [], + "output": "main.out", + "exitCode": 0 + }, { + "if": "windows", + "args": "compile --output main.exe --include file.txt --include FILE.txt main.js", + "output": "compile.out" + }, { + "if": "windows", + "commandName": "./main.exe", + "args": [], + "output": "main.out", + "exitCode": 0 + }] +} diff --git a/tests/specs/compile/case_insensitive_building/compile.out b/tests/specs/compile/case_insensitive_building/compile.out new file mode 100644 index 0000000000..895c2f1d46 --- /dev/null +++ b/tests/specs/compile/case_insensitive_building/compile.out @@ -0,0 +1,10 @@ +Compile file:///[WILDLINE]/main.js to main[WILDLINE] + +Embedded Files + +main[WILDLINE] +├── file.txt ([WILDLINE]) +└── main.js ([WILDLINE]) + +Size: [WILDLINE] + diff --git a/tests/specs/compile/case_insensitive_building/file.txt b/tests/specs/compile/case_insensitive_building/file.txt new file mode 100644 index 0000000000..40816a2b5a --- /dev/null +++ b/tests/specs/compile/case_insensitive_building/file.txt @@ -0,0 +1 @@ +Hi \ No newline at end of file diff --git a/tests/specs/compile/case_insensitive_building/main.js b/tests/specs/compile/case_insensitive_building/main.js new file mode 100644 index 0000000000..0fafe8a4dd --- /dev/null +++ b/tests/specs/compile/case_insensitive_building/main.js @@ -0,0 +1 @@ +console.log(Deno.readTextFileSync(import.meta.dirname + "/file.txt")); diff --git a/tests/specs/compile/case_insensitive_building/main.out b/tests/specs/compile/case_insensitive_building/main.out new file mode 100644 index 0000000000..b14df6442e --- /dev/null +++ b/tests/specs/compile/case_insensitive_building/main.out @@ -0,0 +1 @@ +Hi diff --git a/tests/specs/info/import_map/__test__.jsonc b/tests/specs/info/import_map/__test__.jsonc index 7aba603e0b..275f8000dc 100644 --- a/tests/specs/info/import_map/__test__.jsonc +++ b/tests/specs/info/import_map/__test__.jsonc @@ -1,9 +1,5 @@ { - "steps": [ - { - "args": "info preact/debug", - "output": "with_import_map.out", - "exitCode": 0 - } - ] + "args": "info --allow-import myentry/welcome.ts", + "output": "with_import_map.out", + "exitCode": 0 } diff --git a/tests/specs/info/import_map/deno.json b/tests/specs/info/import_map/deno.json index aaf7260c64..9741f29622 100644 --- a/tests/specs/info/import_map/deno.json +++ b/tests/specs/info/import_map/deno.json @@ -1,6 +1,5 @@ { "imports": { - "preact": "https://esm.sh/preact@10.15.1", - "preact/": "https://esm.sh/preact@10.15.1/" + "myentry/": "http://localhost:4545/" } } diff --git a/tests/specs/info/import_map/deno.lock b/tests/specs/info/import_map/deno.lock index cb5c6ca45d..b7b217cd6a 100644 --- a/tests/specs/info/import_map/deno.lock +++ b/tests/specs/info/import_map/deno.lock @@ -1,10 +1,6 @@ { - "version": "3", + "version": "4", "remote": { - "https://esm.sh/preact@10.15.1": "4bfd0b2c5a2d432e0c8cda295d6b7304152ae08c85f7d0a22f91289c97085b89", - "https://esm.sh/preact@10.15.1/debug": "4bfd0b2c5a2d432e0c8cda295d6b7304152ae08c85f7d0a22f91289c97085b89", - "https://esm.sh/stable/preact@10.15.1/denonext/debug.js": "e8e5e198bd48c93d484c91c4c78af1900bd81d9bfcfd543e8ac75216f5404c10", - "https://esm.sh/stable/preact@10.15.1/denonext/devtools.js": "f61430e179a84483f8ea8dc098d7d0d46b2f0546de4027518bfcef197cd665c9", - "https://esm.sh/stable/preact@10.15.1/denonext/preact.mjs": "30710ac1d5ff3711ae0c04eddbeb706f34f82d97489f61aaf09897bc75d2a628" + "http://localhost:4545/welcome.ts": "7353d5fcbc36c45d26bcbca478cf973092523b07c45999f41319820092b4de31" } } diff --git a/tests/specs/info/import_map/with_import_map.out b/tests/specs/info/import_map/with_import_map.out index 29dc17737a..ef2f53d623 100644 --- a/tests/specs/info/import_map/with_import_map.out +++ b/tests/specs/info/import_map/with_import_map.out @@ -1,16 +1,7 @@ -Download https://esm.sh/preact@10.15.1/debug -Download https://esm.sh/stable/preact@10.15.1/denonext/preact.mjs -Download https://esm.sh/stable/preact@10.15.1/denonext/devtools.js -Download https://esm.sh/stable/preact@10.15.1/denonext/debug.js -local: [WILDCARD] -type: JavaScript -dependencies: 3 unique -size: [WILDCARD] +Download http://localhost:4545/welcome.ts +local: [WILDLINE] +type: TypeScript +dependencies: 0 unique +size: [WILDLINE] -https://esm.sh/preact@10.15.1/debug [WILDCARD] -├── https://esm.sh/stable/preact@10.15.1/denonext/preact.mjs [WILDCARD] -├─┬ https://esm.sh/stable/preact@10.15.1/denonext/devtools.js [WILDCARD] -│ └── https://esm.sh/stable/preact@10.15.1/denonext/preact.mjs [WILDCARD] -└─┬ https://esm.sh/stable/preact@10.15.1/denonext/debug.js [WILDCARD] - ├── https://esm.sh/stable/preact@10.15.1/denonext/preact.mjs [WILDCARD] - └── https://esm.sh/stable/preact@10.15.1/denonext/devtools.js [WILDCARD] +http://localhost:4545/welcome.ts ([WILDLINE]) diff --git a/tests/specs/lint/with_malformed_config/with_malformed_config.out b/tests/specs/lint/with_malformed_config/with_malformed_config.out index 1c0f0fff6e..928ec02fb1 100644 --- a/tests/specs/lint/with_malformed_config/with_malformed_config.out +++ b/tests/specs/lint/with_malformed_config/with_malformed_config.out @@ -1,4 +1,4 @@ error: Failed to parse "lint" configuration Caused by: - unknown field `dont_know_this_field`, expected one of `rules`, `include`, `exclude`, `files`, `report` + unknown field `dont_know_this_field`, expected one of `rules`, `include`, `exclude`, `files`, `report`, `plugins` diff --git a/tests/specs/lint/with_malformed_config2/with_malformed_config2.out b/tests/specs/lint/with_malformed_config2/with_malformed_config2.out index 1c0f0fff6e..928ec02fb1 100644 --- a/tests/specs/lint/with_malformed_config2/with_malformed_config2.out +++ b/tests/specs/lint/with_malformed_config2/with_malformed_config2.out @@ -1,4 +1,4 @@ error: Failed to parse "lint" configuration Caused by: - unknown field `dont_know_this_field`, expected one of `rules`, `include`, `exclude`, `files`, `report` + unknown field `dont_know_this_field`, expected one of `rules`, `include`, `exclude`, `files`, `report`, `plugins` diff --git a/tests/specs/mod.rs b/tests/specs/mod.rs index 985a6c7c40..4da5a87d14 100644 --- a/tests/specs/mod.rs +++ b/tests/specs/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::cell::RefCell; use std::collections::BTreeMap; diff --git a/tests/specs/npm/npm_check_updates/__test__.jsonc b/tests/specs/npm/npm_check_updates/__test__.jsonc new file mode 100644 index 0000000000..27b84c5f05 --- /dev/null +++ b/tests/specs/npm/npm_check_updates/__test__.jsonc @@ -0,0 +1,7 @@ +{ + "tempDir": true, + "steps": [{ + "args": "run -A npm:npm-check-updates", + "output": "output.out" + }] +} diff --git a/tests/specs/npm/npm_check_updates/output.out b/tests/specs/npm/npm_check_updates/output.out new file mode 100644 index 0000000000..b8c1ae4957 --- /dev/null +++ b/tests/specs/npm/npm_check_updates/output.out @@ -0,0 +1,2 @@ +[WILDCARD] +All dependencies match the latest package versions[WILDCARD] \ No newline at end of file diff --git a/tests/specs/npm/npm_check_updates/package.json b/tests/specs/npm/npm_check_updates/package.json new file mode 100644 index 0000000000..82afc391cd --- /dev/null +++ b/tests/specs/npm/npm_check_updates/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "chalk": "^5.0.1" + } +} diff --git a/tests/specs/npm/npmrc_tarball_other_server/fail/main.out b/tests/specs/npm/npmrc_tarball_other_server/fail/main.out index 2c68dba54e..d49bc148ea 100644 --- a/tests/specs/npm/npmrc_tarball_other_server/fail/main.out +++ b/tests/specs/npm/npmrc_tarball_other_server/fail/main.out @@ -1,6 +1,6 @@ Download http://localhost:4261/@denotest%2ftarballs-privateserver2 Download http://localhost:4262/@denotest/tarballs-privateserver2/1.0.0.tgz -error: Failed caching npm package '@denotest/tarballs-privateserver2@1.0.0'. +error: Failed caching npm package '@denotest/tarballs-privateserver2@1.0.0' Caused by: No auth for tarball URI, but present for scoped registry. diff --git a/tests/specs/npm/npmrc_tarball_other_server/success/main.out b/tests/specs/npm/npmrc_tarball_other_server/success/main.out index 5322a1a17d..239f1d525b 100644 --- a/tests/specs/npm/npmrc_tarball_other_server/success/main.out +++ b/tests/specs/npm/npmrc_tarball_other_server/success/main.out @@ -4,7 +4,7 @@ Download http://localhost:4262/@denotest/tarballs-privateserver2/1.0.0.tgz [# to serve proper checksums for a package at another registry. That's fine] [# though because this shows us that we're making it to this step instead of] [# failing sooner on an auth issue.] -error: Failed caching npm package '@denotest/tarballs-privateserver2@1.0.0'. +error: Failed caching npm package '@denotest/tarballs-privateserver2@1.0.0' Caused by: Tarball checksum did not match [WILDCARD] diff --git a/tests/specs/permission/allow_import_cached_only/__test__.jsonc b/tests/specs/permission/allow_import_cached_only/__test__.jsonc new file mode 100644 index 0000000000..a86a8796c2 --- /dev/null +++ b/tests/specs/permission/allow_import_cached_only/__test__.jsonc @@ -0,0 +1,22 @@ +{ + "tempDir": true, + "tests": { + "no_flag": { + // ensure what we're testing will fail without the flags + "args": "run main.ts", + "output": "fail.out", + "exitCode": 1 + }, + "with_flags": { + "steps": [{ + "args": "cache --allow-import main.ts", + "output": "[WILDLINE]", + "exitCode": 0 + }, { + "args": "run --cached-only main.ts", + "output": "success.out", + "exitCode": 0 + }] + } + } +} diff --git a/tests/specs/permission/allow_import_cached_only/deno.jsonc b/tests/specs/permission/allow_import_cached_only/deno.jsonc new file mode 100644 index 0000000000..090481af96 --- /dev/null +++ b/tests/specs/permission/allow_import_cached_only/deno.jsonc @@ -0,0 +1,3 @@ +{ + "lock": true +} diff --git a/tests/specs/permission/allow_import_cached_only/fail.out b/tests/specs/permission/allow_import_cached_only/fail.out new file mode 100644 index 0000000000..517f53b9f4 --- /dev/null +++ b/tests/specs/permission/allow_import_cached_only/fail.out @@ -0,0 +1,2 @@ +error: Requires import access to "localhost:4545", run again with the --allow-import flag + at file:///[WILDLINE]/main.ts:1:8 diff --git a/tests/specs/permission/allow_import_cached_only/main.ts b/tests/specs/permission/allow_import_cached_only/main.ts new file mode 100644 index 0000000000..7556f22667 --- /dev/null +++ b/tests/specs/permission/allow_import_cached_only/main.ts @@ -0,0 +1 @@ +import "http://localhost:4545/welcome.ts"; diff --git a/tests/specs/permission/allow_import_cached_only/success.out b/tests/specs/permission/allow_import_cached_only/success.out new file mode 100644 index 0000000000..8432170eee --- /dev/null +++ b/tests/specs/permission/allow_import_cached_only/success.out @@ -0,0 +1 @@ +Welcome to Deno! diff --git a/tests/specs/permission/allow_import_info/__test__.jsonc b/tests/specs/permission/allow_import_info/__test__.jsonc new file mode 100644 index 0000000000..adcd0f2190 --- /dev/null +++ b/tests/specs/permission/allow_import_info/__test__.jsonc @@ -0,0 +1,22 @@ +{ + "envs": { + "JSR_URL": "" + }, + "tests": { + "implicit": { + "args": "info http://localhost:4545/welcome.ts", + "output": "success.out", + "exitCode": 0 + }, + "via_import_not_allowed": { + "args": "info main.ts", + "output": "import_not_allowed.out", + "exitCode": 0 + }, + "via_import_allowed": { + "args": "info --allow-import main.ts", + "output": "import_allowed.out", + "exitCode": 0 + } + } +} diff --git a/tests/specs/permission/allow_import_info/import_allowed.out b/tests/specs/permission/allow_import_info/import_allowed.out new file mode 100644 index 0000000000..95b61b27ef --- /dev/null +++ b/tests/specs/permission/allow_import_info/import_allowed.out @@ -0,0 +1,8 @@ +Download http://localhost:4545/welcome.ts +local: [WILDLINE] +type: TypeScript +dependencies: [WILDLINE] +size: [WILDLINE] + +file:///[WILDLINE]/main.ts ([WILDLINE]) +└── http://localhost:4545/welcome.ts ([WILDLINE]B) diff --git a/tests/specs/permission/allow_import_info/import_not_allowed.out b/tests/specs/permission/allow_import_info/import_not_allowed.out new file mode 100644 index 0000000000..c73eced93a --- /dev/null +++ b/tests/specs/permission/allow_import_info/import_not_allowed.out @@ -0,0 +1,7 @@ +local: [WILDLINE] +type: TypeScript +dependencies: [WILDLINE] +size: [WILDLINE] + +file:///[WILDLINE]/allow_import_info/main.ts ([WILDLINE]) +└── http://localhost:4545/welcome.ts (not capable, requires --allow-import) diff --git a/tests/specs/permission/allow_import_info/main.ts b/tests/specs/permission/allow_import_info/main.ts new file mode 100644 index 0000000000..7556f22667 --- /dev/null +++ b/tests/specs/permission/allow_import_info/main.ts @@ -0,0 +1 @@ +import "http://localhost:4545/welcome.ts"; diff --git a/tests/specs/permission/allow_import_info/success.out b/tests/specs/permission/allow_import_info/success.out new file mode 100644 index 0000000000..1b43d71444 --- /dev/null +++ b/tests/specs/permission/allow_import_info/success.out @@ -0,0 +1,7 @@ +Download http://localhost:4545/welcome.ts +local: [WILDLINE] +type: TypeScript +dependencies: [WILDLINE] +size: [WILDLINE] + +http://localhost:4545/welcome.ts ([WILDLINE]B) diff --git a/tests/specs/publish/sloppy_imports/sloppy_imports_not_enabled.out b/tests/specs/publish/sloppy_imports/sloppy_imports_not_enabled.out index 4eacbea655..8388e4751e 100644 --- a/tests/specs/publish/sloppy_imports/sloppy_imports_not_enabled.out +++ b/tests/specs/publish/sloppy_imports/sloppy_imports_not_enabled.out @@ -1,2 +1,3 @@ -error: [WILDCARD] Maybe specify path to 'index.ts' file in directory instead or run with --unstable-sloppy-imports - at file:///[WILDCARD]/mod.ts:1:20 +Check file:///[WILDLINE]/mod.ts +error: TS2307 [ERROR]: Cannot find module 'file:///[WILDLINE]/b'. Maybe specify path to 'index.ts' file in directory instead or run with --unstable-sloppy-imports + at file:///[WILDLINE]/mod.ts:1:20 diff --git a/tests/specs/repl/console_log/093_console_log_format.js b/tests/specs/repl/console_log/093_console_log_format.js index 15022411ca..3ac9988023 100644 --- a/tests/specs/repl/console_log/093_console_log_format.js +++ b/tests/specs/repl/console_log/093_console_log_format.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. class Frac { constructor(num, den) { this.num = num; diff --git a/tests/specs/run/045_proxy/programmatic_proxy_client.ts b/tests/specs/run/045_proxy/programmatic_proxy_client.ts index 73af590c71..c238440755 100644 --- a/tests/specs/run/045_proxy/programmatic_proxy_client.ts +++ b/tests/specs/run/045_proxy/programmatic_proxy_client.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. const client = Deno.createHttpClient({ proxy: { diff --git a/tests/specs/run/045_proxy/proxy_client.ts b/tests/specs/run/045_proxy/proxy_client.ts index 41deae2a5d..13fcc134ba 100644 --- a/tests/specs/run/045_proxy/proxy_client.ts +++ b/tests/specs/run/045_proxy/proxy_client.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. const res = await fetch( "http://localhost:4545/run/045_mod.ts", ); diff --git a/tests/specs/run/045_proxy/proxy_test.ts b/tests/specs/run/045_proxy/proxy_test.ts index 22115a3aa8..04f4c9d06d 100644 --- a/tests/specs/run/045_proxy/proxy_test.ts +++ b/tests/specs/run/045_proxy/proxy_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. const addr = Deno.args[1] || "localhost:4555"; function proxyServer() { diff --git a/tests/specs/run/finalization_registry/finalization_registry.js b/tests/specs/run/finalization_registry/finalization_registry.js index ee9dc384f5..76d68d6df5 100644 --- a/tests/specs/run/finalization_registry/finalization_registry.js +++ b/tests/specs/run/finalization_registry/finalization_registry.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. "use strict"; function assertEquals(a, b) { diff --git a/tests/specs/run/heapstats/heapstats.js b/tests/specs/run/heapstats/heapstats.js index b93c9c120d..c0dc0da81c 100644 --- a/tests/specs/run/heapstats/heapstats.js +++ b/tests/specs/run/heapstats/heapstats.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. "use strict"; function allocTest(alloc, allocAssert, deallocAssert) { diff --git a/tests/specs/run/jsx_import_source/jsx_import_source_error.out b/tests/specs/run/jsx_import_source/jsx_import_source_error.out index 634a5b09ba..cb673c6bc9 100644 --- a/tests/specs/run/jsx_import_source/jsx_import_source_error.out +++ b/tests/specs/run/jsx_import_source/jsx_import_source_error.out @@ -1,2 +1,3 @@ -error: Module not found "file:///[WILDCARD]/nonexistent/jsx-runtime". - at file:///[WILDCARD]/jsx_import_source_no_pragma.tsx:1:1 +Check file:///[WILDLINE]/jsx_import_source_no_pragma.tsx +error: TS2307 [ERROR]: Cannot find module 'file:///[WILDCARD]/nonexistent/jsx-runtime'. + at file:///[WILDLINE]/jsx_import_source_no_pragma.tsx:1:1 diff --git a/tests/specs/run/node_prefix_missing/__test__.jsonc b/tests/specs/run/node_prefix_missing/__test__.jsonc index 305020ed97..fa4504fdc2 100644 --- a/tests/specs/run/node_prefix_missing/__test__.jsonc +++ b/tests/specs/run/node_prefix_missing/__test__.jsonc @@ -5,6 +5,11 @@ "output": "main.ts.out", "exitCode": 1 }, + "basic_no_config": { + "args": "run --quiet --no-config main.ts", + "output": "main_no_config.out", + "exitCode": 1 + }, "unstable_bare_node_builtins_enabled": { "args": "run --unstable-bare-node-builtins main.ts", "output": "feature_enabled.out" diff --git a/tests/specs/run/node_prefix_missing/config.json b/tests/specs/run/node_prefix_missing/config.json index 72f40aaf36..52f5f4d4f4 100644 --- a/tests/specs/run/node_prefix_missing/config.json +++ b/tests/specs/run/node_prefix_missing/config.json @@ -1,3 +1,4 @@ { + "imports": {}, "unstable": ["bare-node-builtins"] } diff --git a/tests/specs/run/node_prefix_missing/deno.json b/tests/specs/run/node_prefix_missing/deno.json new file mode 100644 index 0000000000..f6ca8454c5 --- /dev/null +++ b/tests/specs/run/node_prefix_missing/deno.json @@ -0,0 +1,3 @@ +{ + "imports": {} +} diff --git a/tests/specs/run/node_prefix_missing/main.ts.out b/tests/specs/run/node_prefix_missing/main.ts.out index 48b4e37e27..c7067c6026 100644 --- a/tests/specs/run/node_prefix_missing/main.ts.out +++ b/tests/specs/run/node_prefix_missing/main.ts.out @@ -1,3 +1,3 @@ -error: Relative import path "fs" not prefixed with / or ./ or ../ +error: Relative import path "fs" not prefixed with / or ./ or ../ and not in import map from "[WILDLINE]/main.ts" hint: If you want to use a built-in Node module, add a "node:" prefix (ex. "node:fs"). at file:///[WILDCARD]/main.ts:1:16 diff --git a/tests/specs/run/node_prefix_missing/main_no_config.out b/tests/specs/run/node_prefix_missing/main_no_config.out new file mode 100644 index 0000000000..48b4e37e27 --- /dev/null +++ b/tests/specs/run/node_prefix_missing/main_no_config.out @@ -0,0 +1,3 @@ +error: Relative import path "fs" not prefixed with / or ./ or ../ + hint: If you want to use a built-in Node module, add a "node:" prefix (ex. "node:fs"). + at file:///[WILDCARD]/main.ts:1:16 diff --git a/tests/specs/run/reference_types_error/reference_types_error.js.out b/tests/specs/run/reference_types_error/reference_types_error.js.out index 86055f3ac3..3f22354915 100644 --- a/tests/specs/run/reference_types_error/reference_types_error.js.out +++ b/tests/specs/run/reference_types_error/reference_types_error.js.out @@ -1,2 +1,3 @@ -error: Module not found "file:///[WILDCARD]/nonexistent.d.ts". - at file:///[WILDCARD]/reference_types_error.js:1:22 +Check file:///[WILDLINE]/reference_types_error.js +error: TS2307 [ERROR]: Cannot find module 'file:///[WILDLINE]/nonexistent.d.ts'. + at file:///[WILDLINE]/reference_types_error.js:1:22 diff --git a/tests/specs/run/reference_types_error_vendor_dir/reference_types_error.js.out b/tests/specs/run/reference_types_error_vendor_dir/reference_types_error.js.out index 86055f3ac3..3f22354915 100644 --- a/tests/specs/run/reference_types_error_vendor_dir/reference_types_error.js.out +++ b/tests/specs/run/reference_types_error_vendor_dir/reference_types_error.js.out @@ -1,2 +1,3 @@ -error: Module not found "file:///[WILDCARD]/nonexistent.d.ts". - at file:///[WILDCARD]/reference_types_error.js:1:22 +Check file:///[WILDLINE]/reference_types_error.js +error: TS2307 [ERROR]: Cannot find module 'file:///[WILDLINE]/nonexistent.d.ts'. + at file:///[WILDLINE]/reference_types_error.js:1:22 diff --git a/tests/specs/run/sloppy_imports/no_sloppy.out b/tests/specs/run/sloppy_imports/no_sloppy.out index d3a205e990..f28d9181ff 100644 --- a/tests/specs/run/sloppy_imports/no_sloppy.out +++ b/tests/specs/run/sloppy_imports/no_sloppy.out @@ -1,2 +1,26 @@ -error: Module not found "file:///[WILDCARD]/a.js". Maybe change the extension to '.ts' or run with --unstable-sloppy-imports +Check file:///[WILDLINE]/main.ts +error: TS2307 [ERROR]: Cannot find module 'file:///[WILDLINE]/a.js'. Maybe change the extension to '.ts' or run with --unstable-sloppy-imports at file:///[WILDLINE]/main.ts:1:20 + +TS2307 [ERROR]: Cannot find module 'file:///[WILDLINE]/b'. Maybe add a '.js' extension or run with --unstable-sloppy-imports + at file:///[WILDLINE]/main.ts:2:20 + +TS2307 [ERROR]: Cannot find module 'file:///[WILDLINE]/c'. Maybe add a '.mts' extension or run with --unstable-sloppy-imports + at file:///[WILDLINE]/main.ts:3:20 + +TS2307 [ERROR]: Cannot find module 'file:///[WILDLINE]/d'. Maybe add a '.mjs' extension or run with --unstable-sloppy-imports + at file:///[WILDLINE]/main.ts:4:20 + +TS2307 [ERROR]: Cannot find module 'file:///[WILDLINE]/e'. Maybe add a '.tsx' extension or run with --unstable-sloppy-imports + at file:///[WILDLINE]/main.ts:5:20 + +TS2307 [ERROR]: Cannot find module 'file:///[WILDLINE]/e.js'. Maybe change the extension to '.tsx' or run with --unstable-sloppy-imports + at file:///[WILDLINE]/main.ts:6:21 + +TS2307 [ERROR]: Cannot find module 'file:///[WILDLINE]/f'. Maybe add a '.jsx' extension or run with --unstable-sloppy-imports + at file:///[WILDLINE]/main.ts:7:20 + +TS2307 [ERROR]: Cannot find module 'file:///[WILDLINE]/dir'. Maybe specify path to 'index.tsx' file in directory instead or run with --unstable-sloppy-imports + at file:///[WILDLINE]/main.ts:8:20 + +Found 8 errors. diff --git a/tests/specs/run/tls_connecttls/textproto.ts b/tests/specs/run/tls_connecttls/textproto.ts index 9e0f5f5f0a..6b8ac92ecb 100644 --- a/tests/specs/run/tls_connecttls/textproto.ts +++ b/tests/specs/run/tls_connecttls/textproto.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/tests/specs/run/tls_starttls/textproto.ts b/tests/specs/run/tls_starttls/textproto.ts index 9e0f5f5f0a..6b8ac92ecb 100644 --- a/tests/specs/run/tls_starttls/textproto.ts +++ b/tests/specs/run/tls_starttls/textproto.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/tests/specs/run/wasm_module/import_file_not_found/__test__.jsonc b/tests/specs/run/wasm_module/import_file_not_found/__test__.jsonc index a27fcfa82b..0141f9828c 100644 --- a/tests/specs/run/wasm_module/import_file_not_found/__test__.jsonc +++ b/tests/specs/run/wasm_module/import_file_not_found/__test__.jsonc @@ -1,5 +1,14 @@ { - "args": "--allow-import main.js", - "output": "main.out", - "exitCode": 1 + "tests": { + "run": { + "args": "--allow-import main.js", + "output": "main.out", + "exitCode": 1 + }, + "check": { + "args": "check --all --allow-import main.js", + "output": "check.out", + "exitCode": 1 + } + } } diff --git a/tests/specs/run/wasm_module/import_file_not_found/check.out b/tests/specs/run/wasm_module/import_file_not_found/check.out new file mode 100644 index 0000000000..59c052297c --- /dev/null +++ b/tests/specs/run/wasm_module/import_file_not_found/check.out @@ -0,0 +1,4 @@ +Download http://localhost:4545/wasm/math_with_import.wasm +Check file:///[WILDLINE]/main.js +error: TS2307 [ERROR]: Cannot find module 'file:///[WILDLINE]/local_math.ts'. + at http://localhost:4545/wasm/math_with_import.wasm:1:87 diff --git a/tests/specs/run/wasm_module/import_file_not_found/main.js b/tests/specs/run/wasm_module/import_file_not_found/main.js index 9ad66df35b..b55405bd31 100644 --- a/tests/specs/run/wasm_module/import_file_not_found/main.js +++ b/tests/specs/run/wasm_module/import_file_not_found/main.js @@ -1,3 +1,4 @@ +// @ts-check import { add, subtract, diff --git a/tests/specs/run/wasm_module/import_file_not_found/main.out b/tests/specs/run/wasm_module/import_file_not_found/main.out index 54343673f1..ed021b9a21 100644 --- a/tests/specs/run/wasm_module/import_file_not_found/main.out +++ b/tests/specs/run/wasm_module/import_file_not_found/main.out @@ -1,3 +1,3 @@ Download http://localhost:4545/wasm/math_with_import.wasm error: Module not found "file:///[WILDLINE]/local_math.ts". - at http://localhost:4545/wasm/math_with_import.wasm:1:8 + at http://localhost:4545/wasm/math_with_import.wasm:1:87 diff --git a/tests/specs/run/wasm_module/import_named_export_not_found/__test__.jsonc b/tests/specs/run/wasm_module/import_named_export_not_found/__test__.jsonc index a27fcfa82b..0141f9828c 100644 --- a/tests/specs/run/wasm_module/import_named_export_not_found/__test__.jsonc +++ b/tests/specs/run/wasm_module/import_named_export_not_found/__test__.jsonc @@ -1,5 +1,14 @@ { - "args": "--allow-import main.js", - "output": "main.out", - "exitCode": 1 + "tests": { + "run": { + "args": "--allow-import main.js", + "output": "main.out", + "exitCode": 1 + }, + "check": { + "args": "check --all --allow-import main.js", + "output": "check.out", + "exitCode": 1 + } + } } diff --git a/tests/specs/run/wasm_module/import_named_export_not_found/check.out b/tests/specs/run/wasm_module/import_named_export_not_found/check.out new file mode 100644 index 0000000000..d7cc2ea0fb --- /dev/null +++ b/tests/specs/run/wasm_module/import_named_export_not_found/check.out @@ -0,0 +1,9 @@ +Download http://localhost:4545/wasm/math_with_import.wasm +Check file:///[WILDLINE]/main.js +error: TS2305 [ERROR]: Module '"file:///[WILDLINE]/local_math.ts"' has no exported member '"add"'. + at http://localhost:4545/wasm/math_with_import.wasm:1:1 + +TS2305 [ERROR]: Module '"file:///[WILDLINE]/local_math.ts"' has no exported member '"subtract"'. + at http://localhost:4545/wasm/math_with_import.wasm:1:1 + +Found 2 errors. diff --git a/tests/specs/run/wasm_module/import_named_export_not_found/main.js b/tests/specs/run/wasm_module/import_named_export_not_found/main.js index 9ad66df35b..b55405bd31 100644 --- a/tests/specs/run/wasm_module/import_named_export_not_found/main.js +++ b/tests/specs/run/wasm_module/import_named_export_not_found/main.js @@ -1,3 +1,4 @@ +// @ts-check import { add, subtract, diff --git a/tests/specs/run/worker_close_in_wasm_reactions/worker_close_in_wasm_reactions.js b/tests/specs/run/worker_close_in_wasm_reactions/worker_close_in_wasm_reactions.js index 2f62707eff..38508c31c4 100644 --- a/tests/specs/run/worker_close_in_wasm_reactions/worker_close_in_wasm_reactions.js +++ b/tests/specs/run/worker_close_in_wasm_reactions/worker_close_in_wasm_reactions.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // https://github.com/denoland/deno/issues/12263 // Test for a panic that happens when a worker is closed in the reactions of a diff --git a/tests/specs/run/worker_close_nested/close_nested_child.js b/tests/specs/run/worker_close_nested/close_nested_child.js index 97980c689e..1f2b2091a6 100644 --- a/tests/specs/run/worker_close_nested/close_nested_child.js +++ b/tests/specs/run/worker_close_nested/close_nested_child.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. console.log("Starting the child worker"); diff --git a/tests/specs/run/worker_close_nested/close_nested_parent.js b/tests/specs/run/worker_close_nested/close_nested_parent.js index d1fe47553e..ddb9aec26d 100644 --- a/tests/specs/run/worker_close_nested/close_nested_parent.js +++ b/tests/specs/run/worker_close_nested/close_nested_parent.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. console.log("Starting the parent worker"); diff --git a/tests/specs/run/worker_close_nested/worker_close_nested.js b/tests/specs/run/worker_close_nested/worker_close_nested.js index 8d9c88d1cf..179eb48fa1 100644 --- a/tests/specs/run/worker_close_nested/worker_close_nested.js +++ b/tests/specs/run/worker_close_nested/worker_close_nested.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Test that closing a worker which has living child workers will automatically // close the children. diff --git a/tests/specs/run/worker_close_race/close_race_worker.js b/tests/specs/run/worker_close_race/close_race_worker.js index 6964be34a0..945fed9dd0 100644 --- a/tests/specs/run/worker_close_race/close_race_worker.js +++ b/tests/specs/run/worker_close_race/close_race_worker.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. setTimeout(() => { self.postMessage(""); diff --git a/tests/specs/run/worker_close_race/worker_close_race.js b/tests/specs/run/worker_close_race/worker_close_race.js index 188cd9ed88..b39062df50 100644 --- a/tests/specs/run/worker_close_race/worker_close_race.js +++ b/tests/specs/run/worker_close_race/worker_close_race.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // https://github.com/denoland/deno/issues/11416 // Test for a race condition between a worker's `close()` and the main thread's diff --git a/tests/specs/run/worker_drop_handle_race/worker_drop_handle_race.js b/tests/specs/run/worker_drop_handle_race/worker_drop_handle_race.js index ef9bcbe072..bfacc332ac 100644 --- a/tests/specs/run/worker_drop_handle_race/worker_drop_handle_race.js +++ b/tests/specs/run/worker_drop_handle_race/worker_drop_handle_race.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // https://github.com/denoland/deno/issues/11342 // Test for a panic that happens when the main thread's event loop finishes diff --git a/tests/specs/run/worker_drop_handle_race_terminate/worker_drop_handle_race_terminate.js b/tests/specs/run/worker_drop_handle_race_terminate/worker_drop_handle_race_terminate.js index 7c4e0b1099..85a3c51072 100644 --- a/tests/specs/run/worker_drop_handle_race_terminate/worker_drop_handle_race_terminate.js +++ b/tests/specs/run/worker_drop_handle_race_terminate/worker_drop_handle_race_terminate.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Test that the panic in https://github.com/denoland/deno/issues/11342 does not // happen when calling worker.terminate() after fixing diff --git a/tests/specs/update/deno_json/filtered/deno.json.out b/tests/specs/update/deno_json/filtered/deno.json.out index 4458e2d037..2ad36ca1ec 100644 --- a/tests/specs/update/deno_json/filtered/deno.json.out +++ b/tests/specs/update/deno_json/filtered/deno.json.out @@ -5,7 +5,7 @@ "@denotest/subtract": "jsr:@denotest/subtract@^0.2.0", "@denotest/with-subpath": "jsr:@denotest/multiple-exports@0.5.0/data-json", "@denotest/breaking-change-between-versions": "npm:@denotest/breaking-change-between-versions@1.0.0", - "@denotest/bin": "npm:@denotest/bin@^1.0.0", + "@denotest/bin": "npm:@denotest/bin@1.0.0", "@denotest/has-patch-versions": "npm:@denotest/has-patch-versions@^0.1.0" }, "scopes": { diff --git a/tests/specs/update/deno_json/update_latest/deno.json.out b/tests/specs/update/deno_json/update_latest/deno.json.out index 5e4e99bd66..2b5d1f95d7 100644 --- a/tests/specs/update/deno_json/update_latest/deno.json.out +++ b/tests/specs/update/deno_json/update_latest/deno.json.out @@ -3,9 +3,9 @@ "@denotest/add": "jsr:@denotest/add@^1.0.0", "@denotest/add/": "jsr:/@denotest/add@^1.0.0/", "@denotest/subtract": "jsr:@denotest/subtract@^1.0.0", - "@denotest/with-subpath": "jsr:@denotest/multiple-exports@^1.0.0/data-json", - "@denotest/breaking-change-between-versions": "npm:@denotest/breaking-change-between-versions@^2.0.0", - "@denotest/bin": "npm:@denotest/bin@^1.0.0", + "@denotest/with-subpath": "jsr:@denotest/multiple-exports@1.0.0/data-json", + "@denotest/breaking-change-between-versions": "npm:@denotest/breaking-change-between-versions@2.0.0", + "@denotest/bin": "npm:@denotest/bin@1.0.0", "@denotest/has-patch-versions": "npm:@denotest/has-patch-versions@^0.2.0" }, "scopes": { @@ -13,7 +13,7 @@ "@denotest/add": "jsr:@denotest/add@^1.0.0", "@denotest/add/": "jsr:/@denotest/add@^1.0.0/", "@denotest/subtract": "jsr:@denotest/subtract@^1.0.0", - "@denotest/with-subpath": "jsr:@denotest/multiple-exports@^1.0.0/data-json" + "@denotest/with-subpath": "jsr:@denotest/multiple-exports@1.0.0/data-json" } } } diff --git a/tests/specs/update/deno_json/update_latest/deno.lock.out b/tests/specs/update/deno_json/update_latest/deno.lock.out index ad83546ab1..88403fc77e 100644 --- a/tests/specs/update/deno_json/update_latest/deno.lock.out +++ b/tests/specs/update/deno_json/update_latest/deno.lock.out @@ -2,10 +2,10 @@ "version": "4", "specifiers": { "jsr:@denotest/add@1": "1.0.0", - "jsr:@denotest/multiple-exports@1": "1.0.0", + "jsr:@denotest/multiple-exports@1.0.0": "1.0.0", "jsr:@denotest/subtract@1": "1.0.0", - "npm:@denotest/bin@1": "1.0.0", - "npm:@denotest/breaking-change-between-versions@2": "2.0.0", + "npm:@denotest/bin@1.0.0": "1.0.0", + "npm:@denotest/breaking-change-between-versions@2.0.0": "2.0.0", "npm:@denotest/has-patch-versions@0.2": "0.2.0" }, "jsr": { @@ -33,10 +33,10 @@ "workspace": { "dependencies": [ "jsr:@denotest/add@1", - "jsr:@denotest/multiple-exports@1", + "jsr:@denotest/multiple-exports@1.0.0", "jsr:@denotest/subtract@1", - "npm:@denotest/bin@1", - "npm:@denotest/breaking-change-between-versions@2", + "npm:@denotest/bin@1.0.0", + "npm:@denotest/breaking-change-between-versions@2.0.0", "npm:@denotest/has-patch-versions@0.2" ] } diff --git a/tests/specs/update/external_import_map/import_map.json.out b/tests/specs/update/external_import_map/import_map.json.out index b4e24decbc..998f49eec7 100644 --- a/tests/specs/update/external_import_map/import_map.json.out +++ b/tests/specs/update/external_import_map/import_map.json.out @@ -2,7 +2,7 @@ "imports": { "@denotest/add": "jsr:@denotest/add@^1.0.0", "@denotest/subtract": "jsr:@denotest/subtract@^1.0.0", - "@denotest/breaking-change-between-versions": "npm:@denotest/breaking-change-between-versions@^2.0.0", + "@denotest/breaking-change-between-versions": "npm:@denotest/breaking-change-between-versions@2.0.0", "@denotest/has-patch-versions": "npm:@denotest/has-patch-versions@^0.2.0" } } diff --git a/tests/specs/update/latest_not_pre_release/__test__.jsonc b/tests/specs/update/latest_not_pre_release/__test__.jsonc new file mode 100644 index 0000000000..2bfb7a3aa5 --- /dev/null +++ b/tests/specs/update/latest_not_pre_release/__test__.jsonc @@ -0,0 +1,13 @@ +{ + "tempDir": true, + "steps": [ + { + "args": "install", + "output": "[WILDCARD]" + }, + { + "args": "outdated", + "output": "" + } + ] +} diff --git a/tests/specs/update/latest_not_pre_release/package.json b/tests/specs/update/latest_not_pre_release/package.json new file mode 100644 index 0000000000..581e10cce7 --- /dev/null +++ b/tests/specs/update/latest_not_pre_release/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "@denotest/has-pre-release": "1.0.0" + } +} diff --git a/tests/specs/update/mixed_workspace/filtered/member_b_package.json.out b/tests/specs/update/mixed_workspace/filtered/member_b_package.json.out index 7e582feeab..ee3c0a8548 100644 --- a/tests/specs/update/mixed_workspace/filtered/member_b_package.json.out +++ b/tests/specs/update/mixed_workspace/filtered/member_b_package.json.out @@ -3,6 +3,6 @@ "version": "0.1.0", "dependencies": { "@denotest/has-patch-versions": "0.1.0", - "aliased": "npm:@denotest/bin@^1.0.0" + "aliased": "npm:@denotest/bin@1.0.0" } } diff --git a/tests/specs/update/mixed_workspace/update_latest/subdir/member_a_deno.json.out b/tests/specs/update/mixed_workspace/update_latest/subdir/member_a_deno.json.out index 9210123b82..bda55c6ec5 100644 --- a/tests/specs/update/mixed_workspace/update_latest/subdir/member_a_deno.json.out +++ b/tests/specs/update/mixed_workspace/update_latest/subdir/member_a_deno.json.out @@ -4,7 +4,7 @@ "imports": { "@denotest/add": "jsr:@denotest/add@^1.0.0", "@denotest/add/": "jsr:/@denotest/add@^1.0.0/", - "@denotest/with-subpath": "jsr:@denotest/multiple-exports@^1.0.0/data-json", - "@denotest/breaking-change-between-versions": "npm:@denotest/breaking-change-between-versions@^2.0.0" + "@denotest/with-subpath": "jsr:@denotest/multiple-exports@1.0.0/data-json", + "@denotest/breaking-change-between-versions": "npm:@denotest/breaking-change-between-versions@2.0.0" } } diff --git a/tests/specs/update/mixed_workspace/update_latest/subdir/member_b_package.json.out b/tests/specs/update/mixed_workspace/update_latest/subdir/member_b_package.json.out index 1426fcd7f8..9118e94654 100644 --- a/tests/specs/update/mixed_workspace/update_latest/subdir/member_b_package.json.out +++ b/tests/specs/update/mixed_workspace/update_latest/subdir/member_b_package.json.out @@ -2,7 +2,7 @@ "name": "@denotest/member-b", "version": "0.1.0", "dependencies": { - "@denotest/has-patch-versions": "^0.2.0", - "aliased": "npm:@denotest/bin@^1.0.0" + "@denotest/has-patch-versions": "0.2.0", + "aliased": "npm:@denotest/bin@1.0.0" } } diff --git a/tests/specs/update/package_json/update_latest/deno.lock.out b/tests/specs/update/package_json/update_latest/deno.lock.out index 9a9b1bad5e..6723c8d475 100644 --- a/tests/specs/update/package_json/update_latest/deno.lock.out +++ b/tests/specs/update/package_json/update_latest/deno.lock.out @@ -2,7 +2,7 @@ "version": "4", "specifiers": { "npm:@denotest/bin@1": "1.0.0", - "npm:@denotest/breaking-change-between-versions@2": "2.0.0", + "npm:@denotest/breaking-change-between-versions@2.0.0": "2.0.0", "npm:@denotest/has-patch-versions@0.2": "0.2.0" }, "npm": { @@ -20,7 +20,7 @@ "packageJson": { "dependencies": [ "npm:@denotest/bin@1", - "npm:@denotest/breaking-change-between-versions@2", + "npm:@denotest/breaking-change-between-versions@2.0.0", "npm:@denotest/has-patch-versions@0.2" ] } diff --git a/tests/specs/update/package_json/update_latest/package.json.out b/tests/specs/update/package_json/update_latest/package.json.out index fb483d78bd..ac3c3ff460 100644 --- a/tests/specs/update/package_json/update_latest/package.json.out +++ b/tests/specs/update/package_json/update_latest/package.json.out @@ -1,7 +1,7 @@ { "dependencies": { "@denotest/has-patch-versions": "^0.2.0", - "@denotest/breaking-change-between-versions": "^2.0.0" + "@denotest/breaking-change-between-versions": "2.0.0" }, "devDependencies": { "aliased": "npm:@denotest/bin@^1.0.0" diff --git a/tests/testdata/check/import_non_existent.ts b/tests/testdata/check/import_non_existent.ts new file mode 100644 index 0000000000..ae511bca8a --- /dev/null +++ b/tests/testdata/check/import_non_existent.ts @@ -0,0 +1,5 @@ +import { Test } from "./non-existent-module.ts"; + +console.log(Test); + +export class Other {} diff --git a/tests/testdata/commonjs/example.js b/tests/testdata/commonjs/example.js index d2f89d3f02..0feedb12d4 100644 --- a/tests/testdata/commonjs/example.js +++ b/tests/testdata/commonjs/example.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore no-undef const processMod = require("process"); const osMod = require("node:os"); diff --git a/tests/testdata/run/textproto.ts b/tests/testdata/run/textproto.ts index 9e0f5f5f0a..6b8ac92ecb 100644 --- a/tests/testdata/run/textproto.ts +++ b/tests/testdata/run/textproto.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/tests/testdata/subdir/imports_declaration/imports_interface.ts b/tests/testdata/subdir/imports_declaration/imports_interface.ts new file mode 100644 index 0000000000..5eb2e64d51 --- /dev/null +++ b/tests/testdata/subdir/imports_declaration/imports_interface.ts @@ -0,0 +1,3 @@ +import type { SomeInterface } from "./interface.d.ts"; + +export const someObject: SomeInterface = { someField: "someValue" }; diff --git a/tests/testdata/subdir/imports_declaration/interface.d.ts b/tests/testdata/subdir/imports_declaration/interface.d.ts new file mode 100644 index 0000000000..e1531905b9 --- /dev/null +++ b/tests/testdata/subdir/imports_declaration/interface.d.ts @@ -0,0 +1,3 @@ +export interface SomeInterface { + someField: string; +} diff --git a/tests/testdata/workers/close_nested_child.js b/tests/testdata/workers/close_nested_child.js index 97980c689e..1f2b2091a6 100644 --- a/tests/testdata/workers/close_nested_child.js +++ b/tests/testdata/workers/close_nested_child.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. console.log("Starting the child worker"); diff --git a/tests/testdata/workers/close_nested_parent.js b/tests/testdata/workers/close_nested_parent.js index d1fe47553e..ddb9aec26d 100644 --- a/tests/testdata/workers/close_nested_parent.js +++ b/tests/testdata/workers/close_nested_parent.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. console.log("Starting the parent worker"); diff --git a/tests/testdata/workers/close_race_worker.js b/tests/testdata/workers/close_race_worker.js index 6964be34a0..945fed9dd0 100644 --- a/tests/testdata/workers/close_race_worker.js +++ b/tests/testdata/workers/close_race_worker.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. setTimeout(() => { self.postMessage(""); diff --git a/tests/testdata/workers/http_worker.js b/tests/testdata/workers/http_worker.js index 27bc9c038c..fd11641feb 100644 --- a/tests/testdata/workers/http_worker.js +++ b/tests/testdata/workers/http_worker.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-deprecated-deno-api diff --git a/tests/unit/__snapshots__/lint_plugin_test.ts.snap b/tests/unit/__snapshots__/lint_plugin_test.ts.snap new file mode 100644 index 0000000000..337fcecc8f --- /dev/null +++ b/tests/unit/__snapshots__/lint_plugin_test.ts.snap @@ -0,0 +1,8608 @@ +export const snapshot = {}; + +snapshot[`Plugin - Program 1`] = ` +{ + body: [], + range: [ + 1, + 1, + ], + sourceType: "script", + type: "Program", +} +`; + +snapshot[`Plugin - ImportDeclaration 1`] = ` +{ + attributes: [], + importKind: "value", + range: [ + 1, + 14, + ], + source: { + range: [ + 8, + 13, + ], + raw: '"foo"', + type: "Literal", + value: "foo", + }, + specifiers: [], + type: "ImportDeclaration", +} +`; + +snapshot[`Plugin - ImportDeclaration 2`] = ` +{ + attributes: [], + importKind: "value", + range: [ + 1, + 23, + ], + source: { + range: [ + 17, + 22, + ], + raw: '"foo"', + type: "Literal", + value: "foo", + }, + specifiers: [ + { + local: { + name: "foo", + optional: false, + range: [ + 8, + 11, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 8, + 11, + ], + type: "ImportDefaultSpecifier", + }, + ], + type: "ImportDeclaration", +} +`; + +snapshot[`Plugin - ImportDeclaration 3`] = ` +{ + attributes: [], + importKind: "value", + range: [ + 1, + 28, + ], + source: { + range: [ + 22, + 27, + ], + raw: '"foo"', + type: "Literal", + value: "foo", + }, + specifiers: [ + { + local: { + name: "foo", + optional: false, + range: [ + 13, + 16, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 8, + 16, + ], + type: "ImportNamespaceSpecifier", + }, + ], + type: "ImportDeclaration", +} +`; + +snapshot[`Plugin - ImportDeclaration 4`] = ` +{ + attributes: [], + importKind: "value", + range: [ + 1, + 39, + ], + source: { + range: [ + 33, + 38, + ], + raw: '"foo"', + type: "Literal", + value: "foo", + }, + specifiers: [ + { + importKind: "value", + imported: { + name: "foo", + optional: false, + range: [ + 10, + 13, + ], + type: "Identifier", + typeAnnotation: null, + }, + local: { + name: "foo", + optional: false, + range: [ + 10, + 13, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 10, + 13, + ], + type: "ImportSpecifier", + }, + { + importKind: "value", + imported: { + name: "bar", + optional: false, + range: [ + 15, + 18, + ], + type: "Identifier", + typeAnnotation: null, + }, + local: { + name: "baz", + optional: false, + range: [ + 22, + 25, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 15, + 25, + ], + type: "ImportSpecifier", + }, + ], + type: "ImportDeclaration", +} +`; + +snapshot[`Plugin - ImportDeclaration 5`] = ` +{ + attributes: [ + { + key: { + name: "type", + optional: false, + range: [ + 30, + 34, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 30, + 42, + ], + type: "ImportAttribute", + value: { + range: [ + 36, + 42, + ], + raw: '"json"', + type: "Literal", + value: "json", + }, + }, + ], + importKind: "value", + range: [ + 1, + 45, + ], + source: { + range: [ + 17, + 22, + ], + raw: '"foo"', + type: "Literal", + value: "foo", + }, + specifiers: [ + { + local: { + name: "foo", + optional: false, + range: [ + 8, + 11, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 8, + 11, + ], + type: "ImportDefaultSpecifier", + }, + ], + type: "ImportDeclaration", +} +`; + +snapshot[`Plugin - ExportNamedDeclaration 1`] = ` +{ + attributes: [], + range: [ + 1, + 27, + ], + source: { + range: [ + 21, + 26, + ], + raw: '"foo"', + type: "Literal", + value: "foo", + }, + specifiers: [ + { + exportKind: "value", + exported: { + name: "foo", + optional: false, + range: [ + 10, + 13, + ], + type: "Identifier", + typeAnnotation: null, + }, + local: { + name: "foo", + optional: false, + range: [ + 10, + 13, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 10, + 13, + ], + type: "ExportSpecifier", + }, + ], + type: "ExportNamedDeclaration", +} +`; + +snapshot[`Plugin - ExportNamedDeclaration 2`] = ` +{ + attributes: [], + range: [ + 1, + 34, + ], + source: { + range: [ + 28, + 33, + ], + raw: '"foo"', + type: "Literal", + value: "foo", + }, + specifiers: [ + { + exportKind: "value", + exported: { + name: "baz", + optional: false, + range: [ + 17, + 20, + ], + type: "Identifier", + typeAnnotation: null, + }, + local: { + name: "bar", + optional: false, + range: [ + 10, + 13, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 10, + 20, + ], + type: "ExportSpecifier", + }, + ], + type: "ExportNamedDeclaration", +} +`; + +snapshot[`Plugin - ExportNamedDeclaration 3`] = ` +{ + attributes: [ + { + key: { + name: "type", + optional: false, + range: [ + 34, + 38, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 34, + 46, + ], + type: "ImportAttribute", + value: { + range: [ + 40, + 46, + ], + raw: '"json"', + type: "Literal", + value: "json", + }, + }, + ], + range: [ + 1, + 49, + ], + source: { + range: [ + 21, + 26, + ], + raw: '"foo"', + type: "Literal", + value: "foo", + }, + specifiers: [ + { + exportKind: "value", + exported: { + name: "foo", + optional: false, + range: [ + 10, + 13, + ], + type: "Identifier", + typeAnnotation: null, + }, + local: { + name: "foo", + optional: false, + range: [ + 10, + 13, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 10, + 13, + ], + type: "ExportSpecifier", + }, + ], + type: "ExportNamedDeclaration", +} +`; + +snapshot[`Plugin - ExportDefaultDeclaration 1`] = ` +{ + declaration: { + async: false, + body: { + body: [], + range: [ + 31, + 33, + ], + type: "BlockStatement", + }, + declare: false, + generator: false, + id: { + name: "foo", + optional: false, + range: [ + 25, + 28, + ], + type: "Identifier", + typeAnnotation: null, + }, + params: [], + range: [ + 16, + 33, + ], + returnType: null, + type: "FunctionDeclaration", + typeParameters: null, + }, + exportKind: "value", + range: [ + 1, + 33, + ], + type: "ExportDefaultDeclaration", +} +`; + +snapshot[`Plugin - ExportDefaultDeclaration 2`] = ` +{ + declaration: { + async: false, + body: { + body: [], + range: [ + 28, + 30, + ], + type: "BlockStatement", + }, + declare: false, + generator: false, + id: null, + params: [], + range: [ + 16, + 30, + ], + returnType: null, + type: "FunctionDeclaration", + typeParameters: null, + }, + exportKind: "value", + range: [ + 1, + 30, + ], + type: "ExportDefaultDeclaration", +} +`; + +snapshot[`Plugin - ExportDefaultDeclaration 3`] = ` +{ + declaration: { + abstract: false, + body: { + body: [], + range: [ + 16, + 28, + ], + type: "ClassBody", + }, + declare: false, + id: { + name: "Foo", + optional: false, + range: [ + 22, + 25, + ], + type: "Identifier", + typeAnnotation: null, + }, + implements: [], + range: [ + 16, + 28, + ], + superClass: null, + type: "ClassDeclaration", + }, + exportKind: "value", + range: [ + 1, + 28, + ], + type: "ExportDefaultDeclaration", +} +`; + +snapshot[`Plugin - ExportDefaultDeclaration 4`] = ` +{ + declaration: { + abstract: false, + body: { + body: [], + range: [ + 16, + 24, + ], + type: "ClassBody", + }, + declare: false, + id: null, + implements: [], + range: [ + 16, + 24, + ], + superClass: null, + type: "ClassDeclaration", + }, + exportKind: "value", + range: [ + 1, + 24, + ], + type: "ExportDefaultDeclaration", +} +`; + +snapshot[`Plugin - ExportDefaultDeclaration 5`] = ` +{ + declaration: { + name: "bar", + optional: false, + range: [ + 16, + 19, + ], + type: "Identifier", + typeAnnotation: null, + }, + exportKind: "value", + range: [ + 1, + 20, + ], + type: "ExportDefaultDeclaration", +} +`; + +snapshot[`Plugin - ExportDefaultDeclaration 6`] = ` +{ + declaration: { + body: { + body: [], + range: [ + 30, + 32, + ], + type: "TSInterfaceBody", + }, + declare: false, + extends: null, + id: { + name: "Foo", + optional: false, + range: [ + 26, + 29, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 16, + 32, + ], + type: "TSInterfaceDeclaration", + typeParameters: [], + }, + exportKind: "type", + range: [ + 1, + 32, + ], + type: "ExportDefaultDeclaration", +} +`; + +snapshot[`Plugin - ExportAllDeclaration 1`] = ` +{ + attributes: [], + exportKind: "value", + exported: null, + range: [ + 1, + 21, + ], + source: { + range: [ + 15, + 20, + ], + raw: '"foo"', + type: "Literal", + value: "foo", + }, + type: "ExportAllDeclaration", +} +`; + +snapshot[`Plugin - ExportAllDeclaration 2`] = ` +{ + attributes: [], + exportKind: "value", + exported: { + range: [ + 22, + 27, + ], + raw: '"foo"', + type: "Literal", + value: "foo", + }, + range: [ + 1, + 28, + ], + source: { + name: "foo", + optional: false, + range: [ + 13, + 16, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "ExportAllDeclaration", +} +`; + +snapshot[`Plugin - ExportAllDeclaration 3`] = ` +{ + attributes: [ + { + key: { + name: "type", + optional: false, + range: [ + 28, + 32, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 28, + 40, + ], + type: "ImportAttribute", + value: { + range: [ + 34, + 40, + ], + raw: '"json"', + type: "Literal", + value: "json", + }, + }, + ], + exportKind: "value", + exported: null, + range: [ + 1, + 43, + ], + source: { + range: [ + 15, + 20, + ], + raw: '"foo"', + type: "Literal", + value: "foo", + }, + type: "ExportAllDeclaration", +} +`; + +snapshot[`Plugin - TSExportAssignment 1`] = ` +{ + expression: { + name: "foo", + optional: false, + range: [ + 10, + 13, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 14, + ], + type: "TSExportAssignment", +} +`; + +snapshot[`Plugin - TSNamespaceExportDeclaration 1`] = ` +{ + id: { + name: "A", + optional: false, + range: [ + 21, + 22, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 23, + ], + type: "TSNamespaceExportDeclaration", +} +`; + +snapshot[`Plugin - TSImportEqualsDeclaration 1`] = ` +{ + id: { + name: "a", + optional: false, + range: [ + 8, + 9, + ], + type: "Identifier", + typeAnnotation: null, + }, + importKind: "value", + moduleReference: { + name: "b", + optional: false, + range: [ + 12, + 13, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 13, + ], + type: "TSImportEqualsDeclaration", +} +`; + +snapshot[`Plugin - TSImportEqualsDeclaration 2`] = ` +{ + id: { + name: "a", + optional: false, + range: [ + 8, + 9, + ], + type: "Identifier", + typeAnnotation: null, + }, + importKind: "value", + moduleReference: { + expression: { + range: [ + 20, + 25, + ], + raw: '"foo"', + type: "Literal", + value: "foo", + }, + range: [ + 12, + 26, + ], + type: "TSExternalModuleReference", + }, + range: [ + 1, + 26, + ], + type: "TSImportEqualsDeclaration", +} +`; + +snapshot[`Plugin - BlockStatement 1`] = ` +{ + body: [ + { + expression: { + name: "foo", + optional: false, + range: [ + 3, + 6, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 3, + 7, + ], + type: "ExpressionStatement", + }, + ], + range: [ + 1, + 9, + ], + type: "BlockStatement", +} +`; + +snapshot[`Plugin - BreakStatement 1`] = ` +{ + label: null, + range: [ + 15, + 21, + ], + type: "BreakStatement", +} +`; + +snapshot[`Plugin - BreakStatement 2`] = ` +{ + label: { + name: "foo", + optional: false, + range: [ + 26, + 29, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 20, + 30, + ], + type: "BreakStatement", +} +`; + +snapshot[`Plugin - ContinueStatement 1`] = ` +{ + label: null, + range: [ + 1, + 10, + ], + type: "ContinueStatement", +} +`; + +snapshot[`Plugin - ContinueStatement 2`] = ` +{ + label: { + name: "foo", + optional: false, + range: [ + 10, + 13, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 14, + ], + type: "ContinueStatement", +} +`; + +snapshot[`Plugin - DebuggerStatement 1`] = ` +{ + range: [ + 1, + 10, + ], + type: "DebuggerStatement", +} +`; + +snapshot[`Plugin - DoWhileStatement 1`] = ` +{ + body: { + body: [], + range: [ + 4, + 6, + ], + type: "BlockStatement", + }, + range: [ + 1, + 19, + ], + test: { + name: "foo", + optional: false, + range: [ + 14, + 17, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "DoWhileStatement", +} +`; + +snapshot[`Plugin - ExpressionStatement 1`] = ` +{ + expression: { + name: "foo", + optional: false, + range: [ + 1, + 4, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 5, + ], + type: "ExpressionStatement", +} +`; + +snapshot[`Plugin - ForInStatement 1`] = ` +{ + body: { + body: [], + range: [ + 14, + 16, + ], + type: "BlockStatement", + }, + left: { + name: "a", + optional: false, + range: [ + 6, + 7, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 16, + ], + right: { + name: "b", + optional: false, + range: [ + 11, + 12, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "ForInStatement", +} +`; + +snapshot[`Plugin - ForOfStatement 1`] = ` +{ + await: false, + body: { + body: [], + range: [ + 14, + 16, + ], + type: "BlockStatement", + }, + left: { + name: "a", + optional: false, + range: [ + 6, + 7, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 16, + ], + right: { + name: "b", + optional: false, + range: [ + 11, + 12, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "ForOfStatement", +} +`; + +snapshot[`Plugin - ForOfStatement 2`] = ` +{ + await: true, + body: { + body: [], + range: [ + 20, + 22, + ], + type: "BlockStatement", + }, + left: { + name: "a", + optional: false, + range: [ + 12, + 13, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 22, + ], + right: { + name: "b", + optional: false, + range: [ + 17, + 18, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "ForOfStatement", +} +`; + +snapshot[`Plugin - ForStatement 1`] = ` +{ + body: { + body: [], + range: [ + 10, + 12, + ], + type: "BlockStatement", + }, + init: null, + range: [ + 1, + 12, + ], + test: null, + type: "ForStatement", + update: null, +} +`; + +snapshot[`Plugin - ForStatement 2`] = ` +{ + body: { + body: [], + range: [ + 15, + 17, + ], + type: "BlockStatement", + }, + init: { + name: "a", + optional: false, + range: [ + 6, + 7, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 17, + ], + test: { + name: "b", + optional: false, + range: [ + 9, + 10, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "ForStatement", + update: { + name: "c", + optional: false, + range: [ + 12, + 13, + ], + type: "Identifier", + typeAnnotation: null, + }, +} +`; + +snapshot[`Plugin - IfStatement 1`] = ` +{ + alternate: null, + consequent: { + body: [], + range: [ + 10, + 12, + ], + type: "BlockStatement", + }, + range: [ + 1, + 12, + ], + test: { + name: "foo", + optional: false, + range: [ + 5, + 8, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "IfStatement", +} +`; + +snapshot[`Plugin - IfStatement 2`] = ` +{ + alternate: { + body: [], + range: [ + 18, + 20, + ], + type: "BlockStatement", + }, + consequent: { + body: [], + range: [ + 10, + 12, + ], + type: "BlockStatement", + }, + range: [ + 1, + 20, + ], + test: { + name: "foo", + optional: false, + range: [ + 5, + 8, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "IfStatement", +} +`; + +snapshot[`Plugin - LabeledStatement 1`] = ` +{ + body: { + body: [], + range: [ + 6, + 8, + ], + type: "BlockStatement", + }, + label: { + name: "foo", + optional: false, + range: [ + 1, + 4, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 8, + ], + type: "LabeledStatement", +} +`; + +snapshot[`Plugin - ReturnStatement 1`] = ` +{ + argument: null, + range: [ + 1, + 7, + ], + type: "ReturnStatement", +} +`; + +snapshot[`Plugin - ReturnStatement 2`] = ` +{ + argument: { + name: "foo", + optional: false, + range: [ + 8, + 11, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 12, + ], + type: "ReturnStatement", +} +`; + +snapshot[`Plugin - SwitchStatement 1`] = ` +{ + cases: [ + { + consequent: [], + range: [ + 22, + 31, + ], + test: { + name: "foo", + optional: false, + range: [ + 27, + 30, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "SwitchCase", + }, + { + consequent: [ + { + label: null, + range: [ + 56, + 62, + ], + type: "BreakStatement", + }, + ], + range: [ + 38, + 62, + ], + test: { + name: "bar", + optional: false, + range: [ + 43, + 46, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "SwitchCase", + }, + { + consequent: [ + { + body: [], + range: [ + 86, + 88, + ], + type: "BlockStatement", + }, + ], + range: [ + 69, + 88, + ], + test: null, + type: "SwitchCase", + }, + ], + discriminant: { + name: "foo", + optional: false, + range: [ + 9, + 12, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 94, + ], + type: "SwitchStatement", +} +`; + +snapshot[`Plugin - ThrowStatement 1`] = ` +{ + argument: { + name: "foo", + optional: false, + range: [ + 7, + 10, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 11, + ], + type: "ThrowStatement", +} +`; + +snapshot[`Plugin - TryStatement 1`] = ` +{ + block: { + body: [], + range: [ + 5, + 7, + ], + type: "BlockStatement", + }, + finalizer: null, + handler: { + body: { + body: [], + range: [ + 14, + 16, + ], + type: "BlockStatement", + }, + param: null, + range: [ + 8, + 16, + ], + type: "CatchClause", + }, + range: [ + 1, + 16, + ], + type: "TryStatement", +} +`; + +snapshot[`Plugin - TryStatement 2`] = ` +{ + block: { + body: [], + range: [ + 5, + 7, + ], + type: "BlockStatement", + }, + finalizer: null, + handler: { + body: { + body: [], + range: [ + 18, + 20, + ], + type: "BlockStatement", + }, + param: { + name: "e", + optional: false, + range: [ + 15, + 16, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 8, + 20, + ], + type: "CatchClause", + }, + range: [ + 1, + 20, + ], + type: "TryStatement", +} +`; + +snapshot[`Plugin - TryStatement 3`] = ` +{ + block: { + body: [], + range: [ + 5, + 7, + ], + type: "BlockStatement", + }, + finalizer: { + body: [], + range: [ + 16, + 18, + ], + type: "BlockStatement", + }, + handler: null, + range: [ + 1, + 18, + ], + type: "TryStatement", +} +`; + +snapshot[`Plugin - WhileStatement 1`] = ` +{ + body: { + body: [], + range: [ + 13, + 15, + ], + type: "BlockStatement", + }, + range: [ + 1, + 15, + ], + test: { + name: "foo", + optional: false, + range: [ + 8, + 11, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "WhileStatement", +} +`; + +snapshot[`Plugin - WithStatement 1`] = ` +{ + body: { + body: [], + range: [ + 11, + 13, + ], + type: "BlockStatement", + }, + object: { + elements: [], + range: [ + 7, + 9, + ], + type: "ArrayExpression", + }, + range: [ + 1, + 13, + ], + type: "WithStatement", +} +`; + +snapshot[`Plugin - ArrayExpression 1`] = ` +{ + elements: [ + { + elements: [], + range: [ + 2, + 4, + ], + type: "ArrayExpression", + }, + ], + range: [ + 1, + 9, + ], + type: "ArrayExpression", +} +`; + +snapshot[`Plugin - ArrowFunctionExpression 1`] = ` +{ + async: false, + body: { + body: [], + range: [ + 7, + 9, + ], + type: "BlockStatement", + }, + generator: false, + params: [], + range: [ + 1, + 9, + ], + returnType: null, + type: "ArrowFunctionExpression", + typeParameters: null, +} +`; + +snapshot[`Plugin - ArrowFunctionExpression 2`] = ` +{ + async: true, + body: { + body: [], + range: [ + 13, + 15, + ], + type: "BlockStatement", + }, + generator: false, + params: [], + range: [ + 1, + 15, + ], + returnType: null, + type: "ArrowFunctionExpression", + typeParameters: null, +} +`; + +snapshot[`Plugin - ArrowFunctionExpression 3`] = ` +{ + async: false, + body: { + body: [], + range: [ + 34, + 36, + ], + type: "BlockStatement", + }, + generator: false, + params: [ + { + name: "a", + optional: false, + range: [ + 2, + 11, + ], + type: "Identifier", + typeAnnotation: { + range: [ + 3, + 11, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + range: [ + 5, + 11, + ], + type: "TSNumberKeyword", + }, + }, + }, + { + argument: { + name: "b", + optional: false, + range: [ + 16, + 17, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 13, + 24, + ], + type: "RestElement", + typeAnnotation: { + range: [ + 17, + 24, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + elementType: { + range: [ + 19, + 22, + ], + type: "TSAnyKeyword", + }, + range: [ + 19, + 24, + ], + type: "TSArrayType", + }, + }, + }, + ], + range: [ + 1, + 36, + ], + returnType: { + range: [ + 25, + 30, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + range: [ + 27, + 30, + ], + type: "TSAnyKeyword", + }, + }, + type: "ArrowFunctionExpression", + typeParameters: null, +} +`; + +snapshot[`Plugin - AssignmentExpression 1`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "=", + range: [ + 1, + 6, + ], + right: { + name: "b", + optional: false, + range: [ + 5, + 6, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "AssignmentExpression", +} +`; + +snapshot[`Plugin - AssignmentExpression 2`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "=", + range: [ + 1, + 12, + ], + right: { + left: { + name: "a", + optional: false, + range: [ + 5, + 6, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "??=", + range: [ + 5, + 12, + ], + right: { + name: "b", + optional: false, + range: [ + 11, + 12, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "AssignmentExpression", + }, + type: "AssignmentExpression", +} +`; + +snapshot[`Plugin - AwaitExpression 1`] = ` +{ + argument: { + name: "foo", + optional: false, + range: [ + 7, + 10, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 10, + ], + type: "AwaitExpression", +} +`; + +snapshot[`Plugin - BinaryExpression 1`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: ">", + range: [ + 1, + 6, + ], + right: { + name: "b", + optional: false, + range: [ + 5, + 6, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "BinaryExpression", +} +`; + +snapshot[`Plugin - BinaryExpression 2`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: ">=", + range: [ + 1, + 7, + ], + right: { + name: "b", + optional: false, + range: [ + 6, + 7, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "BinaryExpression", +} +`; + +snapshot[`Plugin - BinaryExpression 3`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "<", + range: [ + 1, + 6, + ], + right: { + name: "b", + optional: false, + range: [ + 5, + 6, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "BinaryExpression", +} +`; + +snapshot[`Plugin - BinaryExpression 4`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "<=", + range: [ + 1, + 7, + ], + right: { + name: "b", + optional: false, + range: [ + 6, + 7, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "BinaryExpression", +} +`; + +snapshot[`Plugin - BinaryExpression 5`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "==", + range: [ + 1, + 7, + ], + right: { + name: "b", + optional: false, + range: [ + 6, + 7, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "BinaryExpression", +} +`; + +snapshot[`Plugin - BinaryExpression 6`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "===", + range: [ + 1, + 8, + ], + right: { + name: "b", + optional: false, + range: [ + 7, + 8, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "BinaryExpression", +} +`; + +snapshot[`Plugin - BinaryExpression 7`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "!=", + range: [ + 1, + 7, + ], + right: { + name: "b", + optional: false, + range: [ + 6, + 7, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "BinaryExpression", +} +`; + +snapshot[`Plugin - BinaryExpression 8`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "!=", + range: [ + 1, + 8, + ], + right: { + name: "b", + optional: false, + range: [ + 7, + 8, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "BinaryExpression", +} +`; + +snapshot[`Plugin - BinaryExpression 9`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "<<", + range: [ + 1, + 7, + ], + right: { + name: "b", + optional: false, + range: [ + 6, + 7, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "BinaryExpression", +} +`; + +snapshot[`Plugin - BinaryExpression 10`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: ">>", + range: [ + 1, + 7, + ], + right: { + name: "b", + optional: false, + range: [ + 6, + 7, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "BinaryExpression", +} +`; + +snapshot[`Plugin - BinaryExpression 11`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: ">>>", + range: [ + 1, + 8, + ], + right: { + name: "b", + optional: false, + range: [ + 7, + 8, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "BinaryExpression", +} +`; + +snapshot[`Plugin - BinaryExpression 12`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "+", + range: [ + 1, + 6, + ], + right: { + name: "b", + optional: false, + range: [ + 5, + 6, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "BinaryExpression", +} +`; + +snapshot[`Plugin - BinaryExpression 13`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "-", + range: [ + 1, + 6, + ], + right: { + name: "b", + optional: false, + range: [ + 5, + 6, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "BinaryExpression", +} +`; + +snapshot[`Plugin - BinaryExpression 14`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "*", + range: [ + 1, + 6, + ], + right: { + name: "b", + optional: false, + range: [ + 5, + 6, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "BinaryExpression", +} +`; + +snapshot[`Plugin - BinaryExpression 15`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "/", + range: [ + 1, + 6, + ], + right: { + name: "b", + optional: false, + range: [ + 5, + 6, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "BinaryExpression", +} +`; + +snapshot[`Plugin - BinaryExpression 16`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "%", + range: [ + 1, + 6, + ], + right: { + name: "b", + optional: false, + range: [ + 5, + 6, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "BinaryExpression", +} +`; + +snapshot[`Plugin - BinaryExpression 17`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "|", + range: [ + 1, + 6, + ], + right: { + name: "b", + optional: false, + range: [ + 5, + 6, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "BinaryExpression", +} +`; + +snapshot[`Plugin - BinaryExpression 18`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "^", + range: [ + 1, + 6, + ], + right: { + name: "b", + optional: false, + range: [ + 5, + 6, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "BinaryExpression", +} +`; + +snapshot[`Plugin - BinaryExpression 19`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "&", + range: [ + 1, + 6, + ], + right: { + name: "b", + optional: false, + range: [ + 5, + 6, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "BinaryExpression", +} +`; + +snapshot[`Plugin - BinaryExpression 20`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "in", + range: [ + 1, + 7, + ], + right: { + name: "b", + optional: false, + range: [ + 6, + 7, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "BinaryExpression", +} +`; + +snapshot[`Plugin - BinaryExpression 21`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "**", + range: [ + 1, + 7, + ], + right: { + name: "b", + optional: false, + range: [ + 6, + 7, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "BinaryExpression", +} +`; + +snapshot[`Plugin - CallExpression 1`] = ` +{ + arguments: [], + callee: { + name: "foo", + optional: false, + range: [ + 1, + 4, + ], + type: "Identifier", + typeAnnotation: null, + }, + optional: false, + range: [ + 1, + 6, + ], + type: "CallExpression", + typeArguments: null, +} +`; + +snapshot[`Plugin - CallExpression 2`] = ` +{ + arguments: [ + { + name: "a", + optional: false, + range: [ + 5, + 6, + ], + type: "Identifier", + typeAnnotation: null, + }, + { + argument: { + name: "b", + optional: false, + range: [ + 11, + 12, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 8, + 11, + ], + type: "SpreadElement", + }, + ], + callee: { + name: "foo", + optional: false, + range: [ + 1, + 4, + ], + type: "Identifier", + typeAnnotation: null, + }, + optional: false, + range: [ + 1, + 13, + ], + type: "CallExpression", + typeArguments: null, +} +`; + +snapshot[`Plugin - CallExpression 3`] = ` +{ + arguments: [], + callee: { + name: "foo", + optional: false, + range: [ + 1, + 4, + ], + type: "Identifier", + typeAnnotation: null, + }, + optional: true, + range: [ + 1, + 8, + ], + type: "CallExpression", + typeArguments: null, +} +`; + +snapshot[`Plugin - CallExpression 4`] = ` +{ + arguments: [], + callee: { + name: "foo", + optional: false, + range: [ + 1, + 4, + ], + type: "Identifier", + typeAnnotation: null, + }, + optional: false, + range: [ + 1, + 9, + ], + type: "CallExpression", + typeArguments: { + params: [ + { + range: [ + 5, + 6, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "T", + optional: false, + range: [ + 5, + 6, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + ], + range: [ + 4, + 7, + ], + type: "TSTypeParameterInstantiation", + }, +} +`; + +snapshot[`Plugin - ChainExpression 1`] = ` +{ + expression: { + computed: false, + object: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + optional: true, + property: { + name: "b", + optional: false, + range: [ + 4, + 5, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 5, + ], + type: "MemberExpression", + }, + range: [ + 1, + 5, + ], + type: "ChainExpression", +} +`; + +snapshot[`Plugin - ClassExpression 1`] = ` +{ + abstract: false, + body: { + body: [], + range: [ + 5, + 13, + ], + type: "ClassBody", + }, + declare: false, + id: null, + implements: [], + range: [ + 5, + 13, + ], + superClass: null, + type: "ClassExpression", +} +`; + +snapshot[`Plugin - ClassExpression 2`] = ` +{ + abstract: false, + body: { + body: [], + range: [ + 5, + 17, + ], + type: "ClassBody", + }, + declare: false, + id: { + name: "Foo", + optional: false, + range: [ + 11, + 14, + ], + type: "Identifier", + typeAnnotation: null, + }, + implements: [], + range: [ + 5, + 17, + ], + superClass: null, + type: "ClassExpression", +} +`; + +snapshot[`Plugin - ClassExpression 3`] = ` +{ + abstract: false, + body: { + body: [], + range: [ + 5, + 29, + ], + type: "ClassBody", + }, + declare: false, + id: { + name: "Foo", + optional: false, + range: [ + 11, + 14, + ], + type: "Identifier", + typeAnnotation: null, + }, + implements: [], + range: [ + 5, + 29, + ], + superClass: { + name: "Bar", + optional: false, + range: [ + 23, + 26, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "ClassExpression", +} +`; + +snapshot[`Plugin - ClassExpression 4`] = ` +{ + abstract: false, + body: { + body: [], + range: [ + 5, + 50, + ], + type: "ClassBody", + }, + declare: false, + id: { + name: "Foo", + optional: false, + range: [ + 11, + 14, + ], + type: "Identifier", + typeAnnotation: null, + }, + implements: [ + { + expression: { + name: "Baz", + optional: false, + range: [ + 38, + 41, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 38, + 41, + ], + type: "TSClassImplements", + typeArguments: null, + }, + { + expression: { + name: "Baz2", + optional: false, + range: [ + 43, + 47, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 43, + 47, + ], + type: "TSClassImplements", + typeArguments: null, + }, + ], + range: [ + 5, + 50, + ], + superClass: { + name: "Bar", + optional: false, + range: [ + 23, + 26, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "ClassExpression", +} +`; + +snapshot[`Plugin - ClassExpression 5`] = ` +{ + abstract: false, + body: { + body: [], + range: [ + 5, + 20, + ], + type: "ClassBody", + }, + declare: false, + id: { + name: "Foo", + optional: false, + range: [ + 11, + 14, + ], + type: "Identifier", + typeAnnotation: null, + }, + implements: [], + range: [ + 5, + 20, + ], + superClass: null, + type: "ClassExpression", +} +`; + +snapshot[`Plugin - ClassExpression 6`] = ` +{ + abstract: false, + body: { + body: [ + { + accessibility: undefined, + computed: false, + declare: false, + key: { + name: "foo", + optional: false, + range: [ + 13, + 16, + ], + type: "Identifier", + typeAnnotation: null, + }, + kind: "method", + optional: false, + override: false, + range: [ + 13, + 21, + ], + static: false, + type: "MethodDefinition", + value: { + async: false, + body: { + body: [], + range: [ + 19, + 21, + ], + type: "BlockStatement", + }, + generator: false, + id: null, + params: [], + range: [ + 13, + 21, + ], + returnType: null, + type: "FunctionExpression", + typeParameters: null, + }, + }, + ], + range: [ + 5, + 23, + ], + type: "ClassBody", + }, + declare: false, + id: null, + implements: [], + range: [ + 5, + 23, + ], + superClass: null, + type: "ClassExpression", +} +`; + +snapshot[`Plugin - ClassExpression 7`] = ` +{ + abstract: false, + body: { + body: [ + { + accessibility: undefined, + computed: false, + declare: false, + key: { + name: "foo", + range: [ + 13, + 17, + ], + type: "PrivateIdentifier", + }, + kind: "method", + optional: false, + override: false, + range: [ + 13, + 22, + ], + static: false, + type: "MethodDefinition", + value: { + async: false, + body: { + body: [], + range: [ + 20, + 22, + ], + type: "BlockStatement", + }, + generator: false, + id: null, + params: [], + range: [ + 13, + 22, + ], + returnType: null, + type: "FunctionExpression", + typeParameters: null, + }, + }, + ], + range: [ + 5, + 24, + ], + type: "ClassBody", + }, + declare: false, + id: null, + implements: [], + range: [ + 5, + 24, + ], + superClass: null, + type: "ClassExpression", +} +`; + +snapshot[`Plugin - ClassExpression 8`] = ` +{ + abstract: false, + body: { + body: [ + { + accessibility: undefined, + computed: false, + declare: false, + decorators: [], + key: { + name: "foo", + optional: false, + range: [ + 13, + 16, + ], + type: "Identifier", + typeAnnotation: null, + }, + optional: false, + override: false, + range: [ + 13, + 24, + ], + readonly: false, + static: false, + type: "PropertyDefinition", + value: null, + }, + ], + range: [ + 5, + 26, + ], + type: "ClassBody", + }, + declare: false, + id: null, + implements: [], + range: [ + 5, + 26, + ], + superClass: null, + type: "ClassExpression", +} +`; + +snapshot[`Plugin - ClassExpression 9`] = ` +{ + abstract: false, + body: { + body: [ + { + accessibility: undefined, + computed: false, + declare: false, + decorators: [], + key: { + name: "foo", + optional: false, + range: [ + 13, + 16, + ], + type: "Identifier", + typeAnnotation: null, + }, + optional: false, + override: false, + range: [ + 13, + 22, + ], + readonly: false, + static: false, + type: "PropertyDefinition", + value: { + name: "bar", + optional: false, + range: [ + 19, + 22, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + ], + range: [ + 5, + 24, + ], + type: "ClassBody", + }, + declare: false, + id: null, + implements: [], + range: [ + 5, + 24, + ], + superClass: null, + type: "ClassExpression", +} +`; + +snapshot[`Plugin - ClassExpression 10`] = ` +{ + abstract: false, + body: { + body: [ + { + accessibility: undefined, + computed: false, + declare: false, + key: { + name: "constructor", + optional: false, + range: [ + 13, + 24, + ], + type: "Identifier", + typeAnnotation: null, + }, + kind: "constructor", + optional: false, + override: false, + range: [ + 13, + 47, + ], + static: false, + type: "MethodDefinition", + value: { + async: false, + body: { + body: [], + range: [ + 45, + 47, + ], + type: "BlockStatement", + }, + generator: false, + id: null, + params: [ + { + accessibility: undefined, + decorators: [], + override: false, + parameter: { + name: "foo", + optional: false, + range: [ + 32, + 35, + ], + type: "Identifier", + typeAnnotation: { + range: [ + 35, + 43, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + range: [ + 37, + 43, + ], + type: "TSStringKeyword", + }, + }, + }, + range: [ + 25, + 43, + ], + readonly: false, + static: false, + type: "TSParameterProperty", + }, + ], + range: [ + 13, + 47, + ], + returnType: null, + type: "FunctionExpression", + typeParameters: null, + }, + }, + ], + range: [ + 5, + 49, + ], + type: "ClassBody", + }, + declare: false, + id: null, + implements: [], + range: [ + 5, + 49, + ], + superClass: null, + type: "ClassExpression", +} +`; + +snapshot[`Plugin - ClassExpression 11`] = ` +{ + abstract: false, + body: { + body: [ + { + accessibility: undefined, + computed: false, + declare: false, + decorators: [], + key: { + name: "foo", + range: [ + 13, + 17, + ], + type: "PrivateIdentifier", + }, + optional: false, + override: false, + range: [ + 13, + 31, + ], + readonly: false, + static: false, + type: "PropertyDefinition", + value: { + name: "bar", + optional: false, + range: [ + 28, + 31, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + ], + range: [ + 5, + 33, + ], + type: "ClassBody", + }, + declare: false, + id: null, + implements: [], + range: [ + 5, + 33, + ], + superClass: null, + type: "ClassExpression", +} +`; + +snapshot[`Plugin - ClassExpression 12`] = ` +{ + abstract: false, + body: { + body: [ + { + accessibility: undefined, + computed: false, + declare: false, + decorators: [], + key: { + name: "foo", + optional: false, + range: [ + 20, + 23, + ], + type: "Identifier", + typeAnnotation: null, + }, + optional: false, + override: false, + range: [ + 13, + 29, + ], + readonly: false, + static: true, + type: "PropertyDefinition", + value: { + name: "bar", + optional: false, + range: [ + 26, + 29, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + ], + range: [ + 5, + 31, + ], + type: "ClassBody", + }, + declare: false, + id: null, + implements: [], + range: [ + 5, + 31, + ], + superClass: null, + type: "ClassExpression", +} +`; + +snapshot[`Plugin - ClassExpression 13`] = ` +{ + abstract: false, + body: { + body: [ + { + accessibility: undefined, + computed: false, + declare: false, + decorators: [], + key: { + name: "foo", + optional: false, + range: [ + 20, + 23, + ], + type: "Identifier", + typeAnnotation: null, + }, + optional: false, + override: false, + range: [ + 13, + 24, + ], + readonly: false, + static: true, + type: "PropertyDefinition", + value: null, + }, + { + body: { + body: [ + { + expression: { + left: { + name: "foo", + optional: false, + range: [ + 34, + 37, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "=", + range: [ + 34, + 43, + ], + right: { + name: "bar", + optional: false, + range: [ + 40, + 43, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "AssignmentExpression", + }, + range: [ + 34, + 43, + ], + type: "ExpressionStatement", + }, + ], + range: [ + 32, + 45, + ], + type: "BlockStatement", + }, + range: [ + 25, + 45, + ], + type: "StaticBlock", + }, + ], + range: [ + 5, + 47, + ], + type: "ClassBody", + }, + declare: false, + id: null, + implements: [], + range: [ + 5, + 47, + ], + superClass: null, + type: "ClassExpression", +} +`; + +snapshot[`Plugin - ConditionalExpression 1`] = ` +{ + alternate: { + name: "c", + optional: false, + range: [ + 9, + 10, + ], + type: "Identifier", + typeAnnotation: null, + }, + consequent: { + name: "b", + optional: false, + range: [ + 5, + 6, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 10, + ], + test: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "ConditionalExpression", +} +`; + +snapshot[`Plugin - FunctionExpression 1`] = ` +{ + async: false, + body: { + body: [], + range: [ + 17, + 19, + ], + type: "BlockStatement", + }, + generator: false, + id: null, + params: [], + range: [ + 5, + 19, + ], + returnType: null, + type: "FunctionExpression", + typeParameters: null, +} +`; + +snapshot[`Plugin - FunctionExpression 2`] = ` +{ + async: false, + body: { + body: [], + range: [ + 20, + 22, + ], + type: "BlockStatement", + }, + generator: false, + id: { + name: "foo", + optional: false, + range: [ + 14, + 17, + ], + type: "Identifier", + typeAnnotation: null, + }, + params: [], + range: [ + 5, + 22, + ], + returnType: null, + type: "FunctionExpression", + typeParameters: null, +} +`; + +snapshot[`Plugin - FunctionExpression 3`] = ` +{ + async: false, + body: { + body: [], + range: [ + 45, + 47, + ], + type: "BlockStatement", + }, + generator: false, + id: null, + params: [ + { + name: "a", + optional: true, + range: [ + 15, + 16, + ], + type: "Identifier", + typeAnnotation: { + range: [ + 17, + 25, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + range: [ + 19, + 25, + ], + type: "TSNumberKeyword", + }, + }, + }, + { + argument: { + name: "b", + optional: false, + range: [ + 30, + 31, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 27, + 38, + ], + type: "RestElement", + typeAnnotation: { + range: [ + 31, + 38, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + elementType: { + range: [ + 33, + 36, + ], + type: "TSAnyKeyword", + }, + range: [ + 33, + 38, + ], + type: "TSArrayType", + }, + }, + }, + ], + range: [ + 5, + 47, + ], + returnType: { + range: [ + 39, + 44, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + range: [ + 41, + 44, + ], + type: "TSAnyKeyword", + }, + }, + type: "FunctionExpression", + typeParameters: null, +} +`; + +snapshot[`Plugin - FunctionExpression 4`] = ` +{ + async: true, + body: { + body: [], + range: [ + 24, + 26, + ], + type: "BlockStatement", + }, + generator: true, + id: null, + params: [], + range: [ + 5, + 26, + ], + returnType: null, + type: "FunctionExpression", + typeParameters: null, +} +`; + +snapshot[`Plugin - Identifier 1`] = ` +{ + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, +} +`; + +snapshot[`Plugin - ImportExpression 1`] = ` +{ + options: { + properties: [ + { + computed: false, + key: { + name: "with", + optional: false, + range: [ + 17, + 21, + ], + type: "Identifier", + typeAnnotation: null, + }, + kind: "init", + method: false, + range: [ + 17, + 39, + ], + shorthand: false, + type: "Property", + value: { + properties: [ + { + computed: false, + key: { + name: "type", + optional: false, + range: [ + 25, + 29, + ], + type: "Identifier", + typeAnnotation: null, + }, + kind: "init", + method: false, + range: [ + 25, + 37, + ], + shorthand: false, + type: "Property", + value: { + range: [ + 31, + 37, + ], + raw: "'json'", + type: "Literal", + value: "json", + }, + }, + ], + range: [ + 23, + 39, + ], + type: "ObjectExpression", + }, + }, + ], + range: [ + 15, + 41, + ], + type: "ObjectExpression", + }, + range: [ + 1, + 42, + ], + source: { + range: [ + 8, + 13, + ], + raw: "'foo'", + type: "Literal", + value: "foo", + }, + type: "ImportExpression", +} +`; + +snapshot[`Plugin - LogicalExpression 1`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "&&", + range: [ + 1, + 7, + ], + right: { + name: "b", + optional: false, + range: [ + 6, + 7, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "LogicalExpression", +} +`; + +snapshot[`Plugin - LogicalExpression 2`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "||", + range: [ + 1, + 7, + ], + right: { + name: "b", + optional: false, + range: [ + 6, + 7, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "LogicalExpression", +} +`; + +snapshot[`Plugin - LogicalExpression 3`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "??", + range: [ + 1, + 7, + ], + right: { + name: "b", + optional: false, + range: [ + 6, + 7, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "LogicalExpression", +} +`; + +snapshot[`Plugin - MemberExpression 1`] = ` +{ + computed: false, + object: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + optional: false, + property: { + name: "b", + optional: false, + range: [ + 3, + 4, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 4, + ], + type: "MemberExpression", +} +`; + +snapshot[`Plugin - MemberExpression 2`] = ` +{ + computed: true, + object: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + optional: false, + property: { + range: [ + 3, + 6, + ], + raw: "'b'", + type: "Literal", + value: "b", + }, + range: [ + 1, + 7, + ], + type: "MemberExpression", +} +`; + +snapshot[`Plugin - MetaProperty 1`] = ` +{ + property: { + name: "meta", + optional: false, + range: [ + 1, + 12, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 12, + ], + type: "MetaProperty", +} +`; + +snapshot[`Plugin - NewExpression 1`] = ` +{ + arguments: [], + callee: { + name: "Foo", + optional: false, + range: [ + 5, + 8, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 10, + ], + type: "NewExpression", + typeArguments: null, +} +`; + +snapshot[`Plugin - NewExpression 2`] = ` +{ + arguments: [ + { + name: "a", + optional: false, + range: [ + 12, + 13, + ], + type: "Identifier", + typeAnnotation: null, + }, + { + argument: { + name: "b", + optional: false, + range: [ + 18, + 19, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 15, + 18, + ], + type: "SpreadElement", + }, + ], + callee: { + name: "Foo", + optional: false, + range: [ + 5, + 8, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 20, + ], + type: "NewExpression", + typeArguments: { + params: [ + { + range: [ + 9, + 10, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "T", + optional: false, + range: [ + 9, + 10, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + ], + range: [ + 8, + 11, + ], + type: "TSTypeParameterInstantiation", + }, +} +`; + +snapshot[`Plugin - ObjectExpression 1`] = ` +{ + properties: [], + range: [ + 5, + 7, + ], + type: "ObjectExpression", +} +`; + +snapshot[`Plugin - ObjectExpression 2`] = ` +{ + properties: [ + { + computed: false, + key: { + name: "a", + optional: false, + range: [ + 7, + 8, + ], + type: "Identifier", + typeAnnotation: null, + }, + kind: "init", + method: false, + range: [ + 7, + 8, + ], + shorthand: true, + type: "Property", + value: { + name: "a", + optional: false, + range: [ + 7, + 8, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + ], + range: [ + 5, + 10, + ], + type: "ObjectExpression", +} +`; + +snapshot[`Plugin - ObjectExpression 3`] = ` +{ + properties: [ + { + computed: false, + key: { + name: "b", + optional: false, + range: [ + 7, + 8, + ], + type: "Identifier", + typeAnnotation: null, + }, + kind: "init", + method: false, + range: [ + 7, + 11, + ], + shorthand: false, + type: "Property", + value: { + name: "c", + optional: false, + range: [ + 10, + 11, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + { + computed: true, + key: { + name: "c", + optional: false, + range: [ + 14, + 15, + ], + type: "Identifier", + typeAnnotation: null, + }, + kind: "init", + method: false, + range: [ + 13, + 19, + ], + shorthand: false, + type: "Property", + value: { + name: "d", + optional: false, + range: [ + 18, + 19, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + ], + range: [ + 5, + 21, + ], + type: "ObjectExpression", +} +`; + +snapshot[`Plugin - PrivateIdentifier 1`] = ` +{ + name: "foo", + range: [ + 13, + 17, + ], + type: "PrivateIdentifier", +} +`; + +snapshot[`Plugin - SequenceExpression 1`] = ` +{ + expressions: [ + { + name: "a", + optional: false, + range: [ + 2, + 3, + ], + type: "Identifier", + typeAnnotation: null, + }, + { + name: "b", + optional: false, + range: [ + 5, + 6, + ], + type: "Identifier", + typeAnnotation: null, + }, + ], + range: [ + 2, + 6, + ], + type: "SequenceExpression", +} +`; + +snapshot[`Plugin - Super 1`] = ` +{ + range: [ + 41, + 46, + ], + type: "Super", +} +`; + +snapshot[`Plugin - TaggedTemplateExpression 1`] = ` +{ + quasi: { + expressions: [ + { + name: "bar", + optional: false, + range: [ + 11, + 14, + ], + type: "Identifier", + typeAnnotation: null, + }, + ], + quasis: [ + { + cooked: "foo ", + range: [ + 5, + 9, + ], + raw: "foo ", + tail: false, + type: "TemplateElement", + }, + { + cooked: " baz", + range: [ + 15, + 19, + ], + raw: " baz", + tail: true, + type: "TemplateElement", + }, + ], + range: [ + 4, + 20, + ], + type: "TemplateLiteral", + }, + range: [ + 1, + 20, + ], + tag: { + name: "foo", + optional: false, + range: [ + 1, + 4, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "TaggedTemplateExpression", + typeArguments: null, +} +`; + +snapshot[`Plugin - TemplateLiteral 1`] = ` +{ + expressions: [ + { + name: "bar", + optional: false, + range: [ + 8, + 11, + ], + type: "Identifier", + typeAnnotation: null, + }, + ], + quasis: [ + { + cooked: "foo ", + range: [ + 2, + 6, + ], + raw: "foo ", + tail: false, + type: "TemplateElement", + }, + { + cooked: " baz", + range: [ + 12, + 16, + ], + raw: " baz", + tail: true, + type: "TemplateElement", + }, + ], + range: [ + 1, + 17, + ], + type: "TemplateLiteral", +} +`; + +snapshot[`Plugin - ThisExpression 1`] = ` +{ + range: [ + 1, + 5, + ], + type: "ThisExpression", +} +`; + +snapshot[`Plugin - TSAsExpression 1`] = ` +{ + expression: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 7, + ], + type: "TSAsExpression", + typeAnnotation: { + range: [ + 6, + 7, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "b", + optional: false, + range: [ + 6, + 7, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, +} +`; + +snapshot[`Plugin - TSAsExpression 2`] = ` +{ + expression: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 11, + ], + type: "TSAsExpression", + typeAnnotation: { + range: [ + 1, + 11, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "const", + optional: false, + range: [ + 1, + 11, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, +} +`; + +snapshot[`Plugin - TSNonNullExpression 1`] = ` +{ + expression: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 3, + ], + type: "TSNonNullExpression", +} +`; + +snapshot[`Plugin - TSSatisfiesExpression 1`] = ` +{ + expression: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 14, + ], + type: "TSSatisfiesExpression", + typeAnnotation: { + range: [ + 13, + 14, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "b", + optional: false, + range: [ + 13, + 14, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, +} +`; + +snapshot[`Plugin - UnaryExpression 1`] = ` +{ + argument: { + name: "a", + optional: false, + range: [ + 8, + 9, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "typeof", + range: [ + 1, + 9, + ], + type: "UnaryExpression", +} +`; + +snapshot[`Plugin - UnaryExpression 2`] = ` +{ + argument: { + range: [ + 6, + 7, + ], + raw: "0", + type: "Literal", + value: 0, + }, + operator: "void", + range: [ + 1, + 7, + ], + type: "UnaryExpression", +} +`; + +snapshot[`Plugin - UnaryExpression 3`] = ` +{ + argument: { + name: "a", + optional: false, + range: [ + 2, + 3, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "-", + range: [ + 1, + 3, + ], + type: "UnaryExpression", +} +`; + +snapshot[`Plugin - UnaryExpression 4`] = ` +{ + argument: { + name: "a", + optional: false, + range: [ + 2, + 3, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "+", + range: [ + 1, + 3, + ], + type: "UnaryExpression", +} +`; + +snapshot[`Plugin - UpdateExpression 1`] = ` +{ + argument: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "++", + prefix: false, + range: [ + 1, + 4, + ], + type: "UpdateExpression", +} +`; + +snapshot[`Plugin - UpdateExpression 2`] = ` +{ + argument: { + name: "a", + optional: false, + range: [ + 3, + 4, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "++", + prefix: true, + range: [ + 1, + 4, + ], + type: "UpdateExpression", +} +`; + +snapshot[`Plugin - UpdateExpression 3`] = ` +{ + argument: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "--", + prefix: false, + range: [ + 1, + 4, + ], + type: "UpdateExpression", +} +`; + +snapshot[`Plugin - UpdateExpression 4`] = ` +{ + argument: { + name: "a", + optional: false, + range: [ + 3, + 4, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "--", + prefix: true, + range: [ + 1, + 4, + ], + type: "UpdateExpression", +} +`; + +snapshot[`Plugin - YieldExpression 1`] = ` +{ + argument: { + name: "bar", + optional: false, + range: [ + 25, + 28, + ], + type: "Identifier", + typeAnnotation: null, + }, + delegate: false, + range: [ + 19, + 28, + ], + type: "YieldExpression", +} +`; + +snapshot[`Plugin - Literal 1`] = ` +{ + range: [ + 1, + 2, + ], + raw: "1", + type: "Literal", + value: 1, +} +`; + +snapshot[`Plugin - Literal 2`] = ` +{ + range: [ + 1, + 6, + ], + raw: "'foo'", + type: "Literal", + value: "foo", +} +`; + +snapshot[`Plugin - Literal 3`] = ` +{ + range: [ + 1, + 6, + ], + raw: '"foo"', + type: "Literal", + value: "foo", +} +`; + +snapshot[`Plugin - Literal 4`] = ` +{ + range: [ + 1, + 5, + ], + raw: "true", + type: "Literal", + value: true, +} +`; + +snapshot[`Plugin - Literal 5`] = ` +{ + range: [ + 1, + 6, + ], + raw: "false", + type: "Literal", + value: false, +} +`; + +snapshot[`Plugin - Literal 6`] = ` +{ + range: [ + 1, + 5, + ], + raw: "null", + type: "Literal", + value: null, +} +`; + +snapshot[`Plugin - Literal 7`] = ` +{ + bigint: "1", + range: [ + 1, + 3, + ], + raw: "1n", + type: "Literal", + value: 1n, +} +`; + +snapshot[`Plugin - Literal 8`] = ` +{ + range: [ + 1, + 7, + ], + raw: "/foo/g", + regex: { + flags: "g", + pattern: "foo", + }, + type: "Literal", + value: /foo/g, +} +`; + +snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr 1`] = ` +{ + children: [], + closingElement: null, + openingElement: { + attributes: [], + name: { + name: "div", + range: [ + 2, + 5, + ], + type: "JSXIdentifier", + }, + range: [ + 1, + 8, + ], + selfClosing: true, + type: "JSXOpeningElement", + typeArguments: null, + }, + range: [ + 1, + 8, + ], + type: "JSXElement", +} +`; + +snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr 2`] = ` +{ + children: [], + closingElement: { + name: { + name: "div", + range: [ + 8, + 11, + ], + type: "JSXIdentifier", + }, + range: [ + 6, + 12, + ], + type: "JSXClosingElement", + }, + openingElement: { + attributes: [], + name: { + name: "div", + range: [ + 2, + 5, + ], + type: "JSXIdentifier", + }, + range: [ + 1, + 6, + ], + selfClosing: false, + type: "JSXOpeningElement", + typeArguments: null, + }, + range: [ + 1, + 12, + ], + type: "JSXElement", +} +`; + +snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr 3`] = ` +{ + children: [], + closingElement: { + name: { + name: "div", + range: [ + 10, + 13, + ], + type: "JSXIdentifier", + }, + range: [ + 8, + 14, + ], + type: "JSXClosingElement", + }, + openingElement: { + attributes: [ + { + name: { + name: "a", + range: [ + 6, + 7, + ], + type: "JSXIdentifier", + }, + range: [ + 6, + 7, + ], + type: "JSXAttribute", + value: null, + }, + ], + name: { + name: "div", + range: [ + 2, + 5, + ], + type: "JSXIdentifier", + }, + range: [ + 1, + 8, + ], + selfClosing: false, + type: "JSXOpeningElement", + typeArguments: null, + }, + range: [ + 1, + 14, + ], + type: "JSXElement", +} +`; + +snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr 4`] = ` +{ + children: [], + closingElement: null, + openingElement: { + attributes: [ + { + name: { + name: "a", + range: [ + 6, + 7, + ], + type: "JSXIdentifier", + }, + range: [ + 6, + 11, + ], + type: "JSXAttribute", + value: { + range: [ + 8, + 11, + ], + raw: '"b"', + type: "Literal", + value: "b", + }, + }, + ], + name: { + name: "div", + range: [ + 2, + 5, + ], + type: "JSXIdentifier", + }, + range: [ + 1, + 14, + ], + selfClosing: true, + type: "JSXOpeningElement", + typeArguments: null, + }, + range: [ + 1, + 14, + ], + type: "JSXElement", +} +`; + +snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr 5`] = ` +{ + children: [], + closingElement: null, + openingElement: { + attributes: [ + { + name: { + name: "a", + range: [ + 6, + 7, + ], + type: "JSXIdentifier", + }, + range: [ + 6, + 11, + ], + type: "JSXAttribute", + value: { + expression: { + range: [ + 9, + 10, + ], + raw: "2", + type: "Literal", + value: 2, + }, + range: [ + 8, + 11, + ], + type: "JSXExpressionContainer", + }, + }, + ], + name: { + name: "div", + range: [ + 2, + 5, + ], + type: "JSXIdentifier", + }, + range: [ + 1, + 14, + ], + selfClosing: true, + type: "JSXOpeningElement", + typeArguments: null, + }, + range: [ + 1, + 14, + ], + type: "JSXElement", +} +`; + +snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr 6`] = ` +{ + children: [ + { + range: [ + 6, + 9, + ], + raw: "foo", + type: "JSXText", + value: "foo", + }, + { + expression: { + range: [ + 10, + 11, + ], + raw: "2", + type: "Literal", + value: 2, + }, + range: [ + 9, + 12, + ], + type: "JSXExpressionContainer", + }, + ], + closingElement: { + name: { + name: "div", + range: [ + 14, + 17, + ], + type: "JSXIdentifier", + }, + range: [ + 12, + 18, + ], + type: "JSXClosingElement", + }, + openingElement: { + attributes: [], + name: { + name: "div", + range: [ + 2, + 5, + ], + type: "JSXIdentifier", + }, + range: [ + 1, + 6, + ], + selfClosing: false, + type: "JSXOpeningElement", + typeArguments: null, + }, + range: [ + 1, + 18, + ], + type: "JSXElement", +} +`; + +snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr 7`] = ` +{ + children: [], + closingElement: null, + openingElement: { + attributes: [], + name: { + object: { + name: "a", + range: [ + 2, + 3, + ], + type: "JSXIdentifier", + }, + property: { + name: "b", + range: [ + 4, + 5, + ], + type: "JSXIdentifier", + }, + range: [ + 2, + 5, + ], + type: "JSXMemberExpression", + }, + range: [ + 1, + 8, + ], + selfClosing: true, + type: "JSXOpeningElement", + typeArguments: null, + }, + range: [ + 1, + 8, + ], + type: "JSXElement", +} +`; + +snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr 8`] = ` +{ + children: [], + closingElement: null, + openingElement: { + attributes: [ + { + name: { + name: { + name: "b", + range: [ + 8, + 9, + ], + type: "JSXIdentifier", + }, + namespace: { + name: "a", + range: [ + 6, + 7, + ], + type: "JSXIdentifier", + }, + range: [ + 6, + 9, + ], + type: "JSXNamespacedName", + }, + range: [ + 6, + 13, + ], + type: "JSXAttribute", + value: { + expression: { + range: [ + 11, + 12, + ], + raw: "2", + type: "Literal", + value: 2, + }, + range: [ + 10, + 13, + ], + type: "JSXExpressionContainer", + }, + }, + ], + name: { + name: "div", + range: [ + 2, + 5, + ], + type: "JSXIdentifier", + }, + range: [ + 1, + 16, + ], + selfClosing: true, + type: "JSXOpeningElement", + typeArguments: null, + }, + range: [ + 1, + 16, + ], + type: "JSXElement", +} +`; + +snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr 9`] = ` +{ + children: [], + closingElement: null, + openingElement: { + attributes: [], + name: { + name: "Foo", + range: [ + 2, + 5, + ], + type: "JSXIdentifier", + }, + range: [ + 1, + 8, + ], + selfClosing: true, + type: "JSXOpeningElement", + typeArguments: null, + }, + range: [ + 1, + 8, + ], + type: "JSXElement", +} +`; + +snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr 10`] = ` +{ + children: [], + closingElement: null, + openingElement: { + attributes: [], + name: { + name: "Foo", + range: [ + 2, + 5, + ], + type: "JSXIdentifier", + }, + range: [ + 1, + 11, + ], + selfClosing: true, + type: "JSXOpeningElement", + typeArguments: { + params: [ + { + range: [ + 6, + 7, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "T", + optional: false, + range: [ + 6, + 7, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + ], + range: [ + 5, + 8, + ], + type: "TSTypeParameterInstantiation", + }, + }, + range: [ + 1, + 11, + ], + type: "JSXElement", +} +`; + +snapshot[`Plugin - JSXFragment + JSXOpeningFragment + JSXClosingFragment 1`] = ` +{ + children: [], + closingFragment: { + range: [ + 3, + 6, + ], + type: "JSXClosingFragment", + }, + openingFragment: { + range: [ + 1, + 3, + ], + type: "JSXOpeningFragment", + }, + range: [ + 1, + 6, + ], + type: "JSXFragment", +} +`; + +snapshot[`Plugin - JSXFragment + JSXOpeningFragment + JSXClosingFragment 2`] = ` +{ + children: [ + { + range: [ + 3, + 6, + ], + raw: "foo", + type: "JSXText", + value: "foo", + }, + { + expression: { + range: [ + 7, + 8, + ], + raw: "2", + type: "Literal", + value: 2, + }, + range: [ + 6, + 9, + ], + type: "JSXExpressionContainer", + }, + ], + closingFragment: { + range: [ + 9, + 12, + ], + type: "JSXClosingFragment", + }, + openingFragment: { + range: [ + 1, + 3, + ], + type: "JSXOpeningFragment", + }, + range: [ + 1, + 12, + ], + type: "JSXFragment", +} +`; + +snapshot[`Plugin - TSAsExpression 3`] = ` +{ + expression: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 9, + ], + type: "TSAsExpression", + typeAnnotation: { + range: [ + 6, + 9, + ], + type: "TSAnyKeyword", + }, +} +`; + +snapshot[`Plugin - TSAsExpression 4`] = ` +{ + expression: { + range: [ + 1, + 6, + ], + raw: '"foo"', + type: "Literal", + value: "foo", + }, + range: [ + 1, + 15, + ], + type: "TSAsExpression", + typeAnnotation: { + range: [ + 1, + 15, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "const", + optional: false, + range: [ + 1, + 15, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, +} +`; + +snapshot[`Plugin - TSEnumDeclaration 1`] = ` +{ + body: { + members: [], + range: [ + 1, + 12, + ], + type: "TSEnumBody", + }, + const: false, + declare: false, + id: { + name: "Foo", + optional: false, + range: [ + 6, + 9, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 12, + ], + type: "TSEnumDeclaration", +} +`; + +snapshot[`Plugin - TSEnumDeclaration 2`] = ` +{ + body: { + members: [], + range: [ + 1, + 18, + ], + type: "TSEnumBody", + }, + const: true, + declare: false, + id: { + name: "Foo", + optional: false, + range: [ + 12, + 15, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 18, + ], + type: "TSEnumDeclaration", +} +`; + +snapshot[`Plugin - TSEnumDeclaration 3`] = ` +{ + body: { + members: [ + { + id: { + name: "A", + optional: false, + range: [ + 12, + 13, + ], + type: "Identifier", + typeAnnotation: null, + }, + initializer: null, + range: [ + 12, + 13, + ], + type: "TSEnumMember", + }, + { + id: { + name: "B", + optional: false, + range: [ + 15, + 16, + ], + type: "Identifier", + typeAnnotation: null, + }, + initializer: null, + range: [ + 15, + 16, + ], + type: "TSEnumMember", + }, + ], + range: [ + 1, + 18, + ], + type: "TSEnumBody", + }, + const: false, + declare: false, + id: { + name: "Foo", + optional: false, + range: [ + 6, + 9, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 18, + ], + type: "TSEnumDeclaration", +} +`; + +snapshot[`Plugin - TSEnumDeclaration 4`] = ` +{ + body: { + members: [ + { + id: { + range: [ + 12, + 17, + ], + raw: '"a-b"', + type: "Literal", + value: "a-b", + }, + initializer: null, + range: [ + 12, + 17, + ], + type: "TSEnumMember", + }, + ], + range: [ + 1, + 19, + ], + type: "TSEnumBody", + }, + const: false, + declare: false, + id: { + name: "Foo", + optional: false, + range: [ + 6, + 9, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 19, + ], + type: "TSEnumDeclaration", +} +`; + +snapshot[`Plugin - TSEnumDeclaration 5`] = ` +{ + body: { + members: [ + { + id: { + name: "A", + optional: false, + range: [ + 12, + 13, + ], + type: "Identifier", + typeAnnotation: null, + }, + initializer: { + range: [ + 16, + 17, + ], + raw: "1", + type: "Literal", + value: 1, + }, + range: [ + 12, + 17, + ], + type: "TSEnumMember", + }, + { + id: { + name: "B", + optional: false, + range: [ + 19, + 20, + ], + type: "Identifier", + typeAnnotation: null, + }, + initializer: { + range: [ + 23, + 24, + ], + raw: "2", + type: "Literal", + value: 2, + }, + range: [ + 19, + 24, + ], + type: "TSEnumMember", + }, + { + id: { + name: "C", + optional: false, + range: [ + 26, + 27, + ], + type: "Identifier", + typeAnnotation: null, + }, + initializer: { + left: { + name: "A", + optional: false, + range: [ + 30, + 31, + ], + type: "Identifier", + typeAnnotation: null, + }, + operator: "|", + range: [ + 30, + 35, + ], + right: { + name: "B", + optional: false, + range: [ + 34, + 35, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "BinaryExpression", + }, + range: [ + 26, + 35, + ], + type: "TSEnumMember", + }, + ], + range: [ + 1, + 37, + ], + type: "TSEnumBody", + }, + const: false, + declare: false, + id: { + name: "Foo", + optional: false, + range: [ + 6, + 9, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 37, + ], + type: "TSEnumDeclaration", +} +`; + +snapshot[`Plugin - TSInterface 1`] = ` +{ + body: { + body: [], + range: [ + 13, + 15, + ], + type: "TSInterfaceBody", + }, + declare: false, + extends: null, + id: { + name: "A", + optional: false, + range: [ + 11, + 12, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 15, + ], + type: "TSInterface", + typeParameters: [], +} +`; + +snapshot[`Plugin - TSInterface 2`] = ` +{ + body: { + body: [], + range: [ + 16, + 18, + ], + type: "TSInterfaceBody", + }, + declare: false, + extends: { + params: [ + { + const: false, + constraint: null, + default: null, + in: false, + name: { + name: "T", + optional: false, + range: [ + 13, + 14, + ], + type: "Identifier", + typeAnnotation: null, + }, + out: false, + range: [ + 13, + 14, + ], + type: "TSTypeParameter", + }, + ], + range: [ + 12, + 15, + ], + type: "TSTypeParameterDeclaration", + }, + id: { + name: "A", + optional: false, + range: [ + 11, + 12, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 18, + ], + type: "TSInterface", + typeParameters: [], +} +`; + +snapshot[`Plugin - TSInterface 3`] = ` +{ + body: { + body: [], + range: [ + 36, + 38, + ], + type: "TSInterfaceBody", + }, + declare: false, + extends: null, + id: { + name: "A", + optional: false, + range: [ + 11, + 12, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 38, + ], + type: "TSInterface", + typeParameters: [ + { + expression: { + name: "Foo", + optional: false, + range: [ + 21, + 24, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 21, + 27, + ], + type: "TSInterfaceHeritage", + typeArguments: { + params: [ + { + range: [ + 25, + 26, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "T", + optional: false, + range: [ + 25, + 26, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + ], + range: [ + 24, + 27, + ], + type: "TSTypeParameterInstantiation", + }, + }, + { + expression: { + name: "Bar", + optional: false, + range: [ + 29, + 32, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 29, + 35, + ], + type: "TSInterfaceHeritage", + typeArguments: { + params: [ + { + range: [ + 33, + 34, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "T", + optional: false, + range: [ + 33, + 34, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + ], + range: [ + 32, + 35, + ], + type: "TSTypeParameterInstantiation", + }, + }, + ], +} +`; + +snapshot[`Plugin - TSInterface 4`] = ` +{ + body: { + body: [ + { + computed: false, + key: { + name: "foo", + optional: false, + range: [ + 15, + 18, + ], + type: "Identifier", + typeAnnotation: null, + }, + optional: false, + range: [ + 15, + 24, + ], + readonly: false, + static: false, + type: "TSPropertySignature", + typeAnnotation: { + range: [ + 18, + 23, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + range: [ + 20, + 23, + ], + type: "TSAnyKeyword", + }, + }, + }, + { + computed: false, + key: { + name: "bar", + optional: false, + range: [ + 25, + 28, + ], + type: "Identifier", + typeAnnotation: null, + }, + optional: true, + range: [ + 25, + 34, + ], + readonly: false, + static: false, + type: "TSPropertySignature", + typeAnnotation: { + range: [ + 29, + 34, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + range: [ + 31, + 34, + ], + type: "TSAnyKeyword", + }, + }, + }, + ], + range: [ + 13, + 36, + ], + type: "TSInterfaceBody", + }, + declare: false, + extends: null, + id: { + name: "A", + optional: false, + range: [ + 11, + 12, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 36, + ], + type: "TSInterface", + typeParameters: [], +} +`; + +snapshot[`Plugin - TSInterface 5`] = ` +{ + body: { + body: [ + { + parameters: [ + { + name: "key", + optional: false, + range: [ + 25, + 36, + ], + type: "Identifier", + typeAnnotation: { + range: [ + 28, + 36, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + range: [ + 30, + 36, + ], + type: "TSStringKeyword", + }, + }, + }, + ], + range: [ + 15, + 42, + ], + readonly: true, + type: "TSIndexSignature", + typeAnnotation: { + range: [ + 37, + 42, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + range: [ + 39, + 42, + ], + type: "TSAnyKeyword", + }, + }, + }, + ], + range: [ + 13, + 44, + ], + type: "TSInterfaceBody", + }, + declare: false, + extends: null, + id: { + name: "A", + optional: false, + range: [ + 11, + 12, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 44, + ], + type: "TSInterface", + typeParameters: [], +} +`; + +snapshot[`Plugin - TSInterface 6`] = ` +{ + body: { + body: [ + { + computed: false, + key: { + name: "a", + optional: false, + range: [ + 24, + 25, + ], + type: "Identifier", + typeAnnotation: null, + }, + optional: false, + range: [ + 15, + 30, + ], + readonly: true, + static: false, + type: "TSPropertySignature", + typeAnnotation: { + range: [ + 25, + 30, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + range: [ + 27, + 30, + ], + type: "TSAnyKeyword", + }, + }, + }, + ], + range: [ + 13, + 32, + ], + type: "TSInterfaceBody", + }, + declare: false, + extends: null, + id: { + name: "A", + optional: false, + range: [ + 11, + 12, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 32, + ], + type: "TSInterface", + typeParameters: [], +} +`; + +snapshot[`Plugin - TSInterface 7`] = ` +{ + body: { + body: [ + { + params: [ + { + name: "a", + optional: false, + range: [ + 19, + 20, + ], + type: "Identifier", + typeAnnotation: { + range: [ + 20, + 23, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + range: [ + 22, + 23, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "T", + optional: false, + range: [ + 22, + 23, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + }, + }, + ], + range: [ + 15, + 27, + ], + returnType: { + range: [ + 24, + 27, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + range: [ + 26, + 27, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "T", + optional: false, + range: [ + 26, + 27, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + }, + type: "TSCallSignatureDeclaration", + typeAnnotation: { + params: [ + { + const: false, + constraint: null, + default: null, + in: false, + name: { + name: "T", + optional: false, + range: [ + 16, + 17, + ], + type: "Identifier", + typeAnnotation: null, + }, + out: false, + range: [ + 16, + 17, + ], + type: "TSTypeParameter", + }, + ], + range: [ + 15, + 18, + ], + type: "TSTypeParameterDeclaration", + }, + }, + ], + range: [ + 13, + 29, + ], + type: "TSInterfaceBody", + }, + declare: false, + extends: null, + id: { + name: "A", + optional: false, + range: [ + 11, + 12, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 29, + ], + type: "TSInterface", + typeParameters: [], +} +`; + +snapshot[`Plugin - TSInterface 8`] = ` +{ + body: { + body: [ + { + params: [ + { + name: "a", + optional: false, + range: [ + 23, + 24, + ], + type: "Identifier", + typeAnnotation: { + range: [ + 24, + 27, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + range: [ + 26, + 27, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "T", + optional: false, + range: [ + 26, + 27, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + }, + }, + ], + range: [ + 15, + 31, + ], + returnType: { + range: [ + 28, + 31, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + range: [ + 30, + 31, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "T", + optional: false, + range: [ + 30, + 31, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + }, + type: "TSConstructSignatureDeclaration", + typeParameters: { + params: [ + { + const: false, + constraint: null, + default: null, + in: false, + name: { + name: "T", + optional: false, + range: [ + 20, + 21, + ], + type: "Identifier", + typeAnnotation: null, + }, + out: false, + range: [ + 20, + 21, + ], + type: "TSTypeParameter", + }, + ], + range: [ + 19, + 22, + ], + type: "TSTypeParameterDeclaration", + }, + }, + ], + range: [ + 13, + 33, + ], + type: "TSInterfaceBody", + }, + declare: false, + extends: null, + id: { + name: "A", + optional: false, + range: [ + 11, + 12, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 33, + ], + type: "TSInterface", + typeParameters: [], +} +`; + +snapshot[`Plugin - TSInterface 9`] = ` +{ + body: { + body: [ + { + computed: false, + key: { + name: "a", + optional: false, + range: [ + 15, + 16, + ], + type: "Identifier", + typeAnnotation: null, + }, + optional: false, + range: [ + 15, + 36, + ], + readonly: false, + static: false, + type: "TSPropertySignature", + typeAnnotation: { + range: [ + 16, + 36, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + params: [ + { + name: "a", + optional: false, + range: [ + 26, + 27, + ], + type: "Identifier", + typeAnnotation: { + range: [ + 27, + 30, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + range: [ + 29, + 30, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "T", + optional: false, + range: [ + 29, + 30, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + }, + }, + ], + range: [ + 18, + 36, + ], + returnType: { + range: [ + 32, + 36, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + range: [ + 35, + 36, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "T", + optional: false, + range: [ + 35, + 36, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + }, + type: "TSConstructSignatureDeclaration", + typeParameters: { + params: [ + { + const: false, + constraint: null, + default: null, + in: false, + name: { + name: "T", + optional: false, + range: [ + 23, + 24, + ], + type: "Identifier", + typeAnnotation: null, + }, + out: false, + range: [ + 23, + 24, + ], + type: "TSTypeParameter", + }, + ], + range: [ + 22, + 25, + ], + type: "TSTypeParameterDeclaration", + }, + }, + }, + }, + ], + range: [ + 13, + 38, + ], + type: "TSInterfaceBody", + }, + declare: false, + extends: null, + id: { + name: "A", + optional: false, + range: [ + 11, + 12, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 38, + ], + type: "TSInterface", + typeParameters: [], +} +`; + +snapshot[`Plugin - TSInterface 10`] = ` +{ + body: { + body: [ + { + computed: false, + key: { + name: "a", + optional: false, + range: [ + 19, + 20, + ], + type: "Identifier", + typeAnnotation: null, + }, + kind: "getter", + optional: false, + range: [ + 15, + 30, + ], + readonly: false, + returnType: { + range: [ + 22, + 30, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + range: [ + 24, + 30, + ], + type: "TSStringKeyword", + }, + }, + static: false, + type: "TSMethodSignature", + }, + ], + range: [ + 13, + 32, + ], + type: "TSInterfaceBody", + }, + declare: false, + extends: null, + id: { + name: "A", + optional: false, + range: [ + 11, + 12, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 32, + ], + type: "TSInterface", + typeParameters: [], +} +`; + +snapshot[`Plugin - TSInterface 11`] = ` +{ + body: { + body: [ + { + computed: false, + key: { + name: "a", + optional: false, + range: [ + 19, + 20, + ], + type: "Identifier", + typeAnnotation: null, + }, + kind: "setter", + optional: false, + params: [ + { + name: "v", + optional: false, + range: [ + 21, + 22, + ], + type: "Identifier", + typeAnnotation: { + range: [ + 22, + 30, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + range: [ + 24, + 30, + ], + type: "TSStringKeyword", + }, + }, + }, + ], + range: [ + 15, + 31, + ], + readonly: false, + static: false, + type: "TSMethodSignature", + }, + ], + range: [ + 13, + 33, + ], + type: "TSInterfaceBody", + }, + declare: false, + extends: null, + id: { + name: "A", + optional: false, + range: [ + 11, + 12, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 33, + ], + type: "TSInterface", + typeParameters: [], +} +`; + +snapshot[`Plugin - TSInterface 12`] = ` +{ + body: { + body: [ + { + computed: false, + key: { + name: "a", + optional: false, + range: [ + 15, + 16, + ], + type: "Identifier", + typeAnnotation: null, + }, + kind: "method", + optional: false, + params: [ + { + name: "arg", + optional: true, + range: [ + 20, + 23, + ], + type: "Identifier", + typeAnnotation: { + range: [ + 24, + 29, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + range: [ + 26, + 29, + ], + type: "TSAnyKeyword", + }, + }, + }, + { + argument: { + name: "args", + optional: false, + range: [ + 34, + 38, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 31, + 45, + ], + type: "RestElement", + typeAnnotation: { + range: [ + 38, + 45, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + elementType: { + range: [ + 40, + 43, + ], + type: "TSAnyKeyword", + }, + range: [ + 40, + 45, + ], + type: "TSArrayType", + }, + }, + }, + ], + range: [ + 15, + 51, + ], + readonly: false, + returnType: { + range: [ + 46, + 51, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + range: [ + 48, + 51, + ], + type: "TSAnyKeyword", + }, + }, + static: false, + type: "TSMethodSignature", + typeParameters: { + params: [ + { + const: false, + constraint: null, + default: null, + in: false, + name: { + name: "T", + optional: false, + range: [ + 17, + 18, + ], + type: "Identifier", + typeAnnotation: null, + }, + out: false, + range: [ + 17, + 18, + ], + type: "TSTypeParameter", + }, + ], + range: [ + 16, + 19, + ], + type: "TSTypeParameterDeclaration", + }, + }, + ], + range: [ + 13, + 53, + ], + type: "TSInterfaceBody", + }, + declare: false, + extends: null, + id: { + name: "A", + optional: false, + range: [ + 11, + 12, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 53, + ], + type: "TSInterface", + typeParameters: [], +} +`; + +snapshot[`Plugin - TSSatisfiesExpression 2`] = ` +{ + expression: { + properties: [], + range: [ + 11, + 13, + ], + type: "ObjectExpression", + }, + range: [ + 11, + 25, + ], + type: "TSSatisfiesExpression", + typeAnnotation: { + range: [ + 24, + 25, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "A", + optional: false, + range: [ + 24, + 25, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, +} +`; + +snapshot[`Plugin - TSTypeAliasDeclaration 1`] = ` +{ + declare: false, + id: { + name: "A", + optional: false, + range: [ + 6, + 7, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 13, + ], + type: "TSTypeAliasDeclaration", + typeAnnotation: { + range: [ + 10, + 13, + ], + type: "TSAnyKeyword", + }, + typeParameters: null, +} +`; + +snapshot[`Plugin - TSTypeAliasDeclaration 2`] = ` +{ + declare: false, + id: { + name: "A", + optional: false, + range: [ + 6, + 7, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 16, + ], + type: "TSTypeAliasDeclaration", + typeAnnotation: { + range: [ + 13, + 16, + ], + type: "TSAnyKeyword", + }, + typeParameters: { + params: [ + { + const: false, + constraint: null, + default: null, + in: false, + name: { + name: "T", + optional: false, + range: [ + 8, + 9, + ], + type: "Identifier", + typeAnnotation: null, + }, + out: false, + range: [ + 8, + 9, + ], + type: "TSTypeParameter", + }, + ], + range: [ + 7, + 10, + ], + type: "TSTypeParameterDeclaration", + }, +} +`; + +snapshot[`Plugin - TSTypeAliasDeclaration 3`] = ` +{ + declare: true, + id: { + name: "A", + optional: false, + range: [ + 14, + 15, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 24, + ], + type: "TSTypeAliasDeclaration", + typeAnnotation: { + range: [ + 21, + 24, + ], + type: "TSAnyKeyword", + }, + typeParameters: { + params: [ + { + const: false, + constraint: null, + default: null, + in: false, + name: { + name: "T", + optional: false, + range: [ + 16, + 17, + ], + type: "Identifier", + typeAnnotation: null, + }, + out: false, + range: [ + 16, + 17, + ], + type: "TSTypeParameter", + }, + ], + range: [ + 15, + 18, + ], + type: "TSTypeParameterDeclaration", + }, +} +`; + +snapshot[`Plugin - TSNonNullExpression 2`] = ` +{ + expression: { + name: "a", + optional: false, + range: [ + 1, + 2, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 3, + ], + type: "TSNonNullExpression", +} +`; + +snapshot[`Plugin - TSUnionType 1`] = ` +{ + range: [ + 10, + 15, + ], + type: "TSUnionType", + types: [ + { + range: [ + 10, + 11, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "B", + optional: false, + range: [ + 10, + 11, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + { + range: [ + 14, + 15, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "C", + optional: false, + range: [ + 14, + 15, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + ], +} +`; + +snapshot[`Plugin - TSIntersectionType 1`] = ` +{ + range: [ + 10, + 15, + ], + type: "TSIntersectionType", + types: [ + { + range: [ + 10, + 11, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "B", + optional: false, + range: [ + 10, + 11, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + { + range: [ + 14, + 15, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "C", + optional: false, + range: [ + 14, + 15, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + ], +} +`; + +snapshot[`Plugin - TSModuleDeclaration 1`] = ` +{ + body: { + body: [], + range: [ + 10, + 12, + ], + type: "TSModuleBlock", + }, + declare: false, + global: false, + id: { + name: "A", + optional: false, + range: [ + 8, + 9, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 12, + ], + type: "TSModuleDeclaration", +} +`; + +snapshot[`Plugin - TSModuleDeclaration 2`] = ` +{ + body: { + body: [ + { + declaration: { + async: false, + body: null, + declare: false, + generator: false, + id: { + name: "A", + optional: false, + range: [ + 36, + 37, + ], + type: "Identifier", + typeAnnotation: null, + }, + params: [], + range: [ + 27, + 45, + ], + returnType: { + range: [ + 39, + 45, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + range: [ + 41, + 45, + ], + type: "TSVoidKeyword", + }, + }, + type: "FunctionDeclaration", + typeParameters: null, + }, + range: [ + 20, + 45, + ], + type: "ExportNamedDeclaration", + }, + ], + range: [ + 18, + 47, + ], + type: "TSModuleBlock", + }, + declare: true, + global: false, + id: { + name: "A", + optional: false, + range: [ + 16, + 17, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 47, + ], + type: "TSModuleDeclaration", +} +`; + +snapshot[`Plugin - TSModuleDeclaration + TSModuleBlock 1`] = ` +{ + body: { + body: [], + range: [ + 10, + 12, + ], + type: "TSModuleBlock", + }, + declare: false, + global: false, + id: { + name: "A", + optional: false, + range: [ + 8, + 9, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 12, + ], + type: "TSModuleDeclaration", +} +`; + +snapshot[`Plugin - TSModuleDeclaration + TSModuleBlock 2`] = ` +{ + body: { + body: [ + { + body: { + body: [], + range: [ + 27, + 29, + ], + type: "TSModuleBlock", + }, + declare: false, + global: false, + id: { + name: "B", + optional: false, + range: [ + 25, + 26, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 15, + 29, + ], + type: "TSModuleDeclaration", + }, + ], + range: [ + 13, + 31, + ], + type: "TSModuleBlock", + }, + declare: false, + global: false, + id: { + name: "A", + optional: false, + range: [ + 11, + 12, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 1, + 31, + ], + type: "TSModuleDeclaration", +} +`; + +snapshot[`Plugin - TSQualifiedName 1`] = ` +{ + left: { + name: "a", + optional: false, + range: [ + 10, + 11, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 10, + 13, + ], + right: { + name: "b", + optional: false, + range: [ + 12, + 13, + ], + type: "Identifier", + typeAnnotation: null, + }, + type: "TSQualifiedName", +} +`; + +snapshot[`Plugin - TSTypeLiteral 1`] = ` +{ + members: [ + { + computed: false, + key: { + name: "a", + optional: false, + range: [ + 12, + 13, + ], + type: "Identifier", + typeAnnotation: null, + }, + optional: false, + range: [ + 12, + 16, + ], + readonly: false, + static: false, + type: "TSPropertySignature", + typeAnnotation: { + range: [ + 13, + 16, + ], + type: "TSTypeAnnotation", + typeAnnotation: { + literal: { + range: [ + 15, + 16, + ], + raw: "1", + type: "Literal", + value: 1, + }, + range: [ + 15, + 16, + ], + type: "TSLiteralType", + }, + }, + }, + ], + range: [ + 10, + 18, + ], + type: "TSTypeLiteral", +} +`; + +snapshot[`Plugin - TSOptionalType 1`] = ` +{ + range: [ + 11, + 18, + ], + type: "TSOptionalType", + typeAnnotation: { + range: [ + 11, + 17, + ], + type: "TSNumberKeyword", + }, +} +`; + +snapshot[`Plugin - TSRestType 1`] = ` +{ + range: [ + 11, + 22, + ], + type: "TSRestType", + typeAnnotation: { + elementType: { + range: [ + 14, + 20, + ], + type: "TSNumberKeyword", + }, + range: [ + 14, + 22, + ], + type: "TSArrayType", + }, +} +`; + +snapshot[`Plugin - TSConditionalType 1`] = ` +{ + checkType: { + range: [ + 10, + 11, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "B", + optional: false, + range: [ + 10, + 11, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + extendsType: { + range: [ + 20, + 21, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "C", + optional: false, + range: [ + 20, + 21, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + falseType: { + range: [ + 33, + 39, + ], + type: "TSStringKeyword", + }, + range: [ + 10, + 39, + ], + trueType: { + range: [ + 24, + 30, + ], + type: "TSNumberKeyword", + }, + type: "TSConditionalType", +} +`; + +snapshot[`Plugin - TSInferType 1`] = ` +{ + range: [ + 29, + 39, + ], + type: "TSInferType", + typeParameter: { + const: false, + constraint: null, + default: null, + in: false, + name: { + name: "Item", + optional: false, + range: [ + 35, + 39, + ], + type: "Identifier", + typeAnnotation: null, + }, + out: false, + range: [ + 35, + 39, + ], + type: "TSTypeParameter", + }, +} +`; + +snapshot[`Plugin - TSTypeOperator 1`] = ` +{ + operator: "keyof", + range: [ + 10, + 17, + ], + type: "TSTypeOperator", + typeAnnotation: { + range: [ + 16, + 17, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "B", + optional: false, + range: [ + 16, + 17, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, +} +`; + +snapshot[`Plugin - TSTypeOperator 2`] = ` +{ + operator: "unique", + range: [ + 21, + 34, + ], + type: "TSTypeOperator", + typeAnnotation: { + range: [ + 28, + 34, + ], + type: "TSSymbolKeyword", + }, +} +`; + +snapshot[`Plugin - TSTypeOperator 3`] = ` +{ + operator: "readonly", + range: [ + 10, + 21, + ], + type: "TSTypeOperator", + typeAnnotation: { + elementTypes: [], + range: [ + 19, + 21, + ], + type: "TSTupleType", + }, +} +`; + +snapshot[`Plugin - TSMappedType 1`] = ` +{ + nameType: null, + optional: undefined, + range: [ + 13, + 41, + ], + readonly: undefined, + type: "TSMappedType", + typeAnnotation: { + range: [ + 31, + 38, + ], + type: "TSBooleanKeyword", + }, + typeParameter: { + const: false, + constraint: { + operator: "keyof", + range: [ + 21, + 28, + ], + type: "TSTypeOperator", + typeAnnotation: { + range: [ + 27, + 28, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "T", + optional: false, + range: [ + 27, + 28, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + }, + default: null, + in: false, + name: { + name: "P", + optional: false, + range: [ + 16, + 17, + ], + type: "Identifier", + typeAnnotation: null, + }, + out: false, + range: [ + 16, + 28, + ], + type: "TSTypeParameter", + }, +} +`; + +snapshot[`Plugin - TSMappedType 2`] = ` +{ + nameType: null, + optional: undefined, + range: [ + 13, + 45, + ], + readonly: true, + type: "TSMappedType", + typeAnnotation: { + elementTypes: [], + range: [ + 40, + 42, + ], + type: "TSTupleType", + }, + typeParameter: { + const: false, + constraint: { + operator: "keyof", + range: [ + 30, + 37, + ], + type: "TSTypeOperator", + typeAnnotation: { + range: [ + 36, + 37, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "T", + optional: false, + range: [ + 36, + 37, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + }, + default: null, + in: false, + name: { + name: "P", + optional: false, + range: [ + 25, + 26, + ], + type: "Identifier", + typeAnnotation: null, + }, + out: false, + range: [ + 25, + 37, + ], + type: "TSTypeParameter", + }, +} +`; + +snapshot[`Plugin - TSMappedType 3`] = ` +{ + nameType: null, + optional: undefined, + range: [ + 13, + 46, + ], + readonly: "-", + type: "TSMappedType", + typeAnnotation: { + elementTypes: [], + range: [ + 41, + 43, + ], + type: "TSTupleType", + }, + typeParameter: { + const: false, + constraint: { + operator: "keyof", + range: [ + 31, + 38, + ], + type: "TSTypeOperator", + typeAnnotation: { + range: [ + 37, + 38, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "T", + optional: false, + range: [ + 37, + 38, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + }, + default: null, + in: false, + name: { + name: "P", + optional: false, + range: [ + 26, + 27, + ], + type: "Identifier", + typeAnnotation: null, + }, + out: false, + range: [ + 26, + 38, + ], + type: "TSTypeParameter", + }, +} +`; + +snapshot[`Plugin - TSMappedType 4`] = ` +{ + nameType: null, + optional: undefined, + range: [ + 13, + 46, + ], + readonly: "+", + type: "TSMappedType", + typeAnnotation: { + elementTypes: [], + range: [ + 41, + 43, + ], + type: "TSTupleType", + }, + typeParameter: { + const: false, + constraint: { + operator: "keyof", + range: [ + 31, + 38, + ], + type: "TSTypeOperator", + typeAnnotation: { + range: [ + 37, + 38, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "T", + optional: false, + range: [ + 37, + 38, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + }, + default: null, + in: false, + name: { + name: "P", + optional: false, + range: [ + 26, + 27, + ], + type: "Identifier", + typeAnnotation: null, + }, + out: false, + range: [ + 26, + 38, + ], + type: "TSTypeParameter", + }, +} +`; + +snapshot[`Plugin - TSMappedType 5`] = ` +{ + nameType: null, + optional: true, + range: [ + 13, + 42, + ], + readonly: undefined, + type: "TSMappedType", + typeAnnotation: { + range: [ + 32, + 39, + ], + type: "TSBooleanKeyword", + }, + typeParameter: { + const: false, + constraint: { + operator: "keyof", + range: [ + 21, + 28, + ], + type: "TSTypeOperator", + typeAnnotation: { + range: [ + 27, + 28, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "T", + optional: false, + range: [ + 27, + 28, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + }, + default: null, + in: false, + name: { + name: "P", + optional: false, + range: [ + 16, + 17, + ], + type: "Identifier", + typeAnnotation: null, + }, + out: false, + range: [ + 16, + 28, + ], + type: "TSTypeParameter", + }, +} +`; + +snapshot[`Plugin - TSMappedType 6`] = ` +{ + nameType: null, + optional: "-", + range: [ + 13, + 43, + ], + readonly: undefined, + type: "TSMappedType", + typeAnnotation: { + range: [ + 33, + 40, + ], + type: "TSBooleanKeyword", + }, + typeParameter: { + const: false, + constraint: { + operator: "keyof", + range: [ + 21, + 28, + ], + type: "TSTypeOperator", + typeAnnotation: { + range: [ + 27, + 28, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "T", + optional: false, + range: [ + 27, + 28, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + }, + default: null, + in: false, + name: { + name: "P", + optional: false, + range: [ + 16, + 17, + ], + type: "Identifier", + typeAnnotation: null, + }, + out: false, + range: [ + 16, + 28, + ], + type: "TSTypeParameter", + }, +} +`; + +snapshot[`Plugin - TSMappedType 7`] = ` +{ + nameType: null, + optional: "+", + range: [ + 13, + 43, + ], + readonly: undefined, + type: "TSMappedType", + typeAnnotation: { + range: [ + 33, + 40, + ], + type: "TSBooleanKeyword", + }, + typeParameter: { + const: false, + constraint: { + operator: "keyof", + range: [ + 21, + 28, + ], + type: "TSTypeOperator", + typeAnnotation: { + range: [ + 27, + 28, + ], + type: "TSTypeReference", + typeArguments: null, + typeName: { + name: "T", + optional: false, + range: [ + 27, + 28, + ], + type: "Identifier", + typeAnnotation: null, + }, + }, + }, + default: null, + in: false, + name: { + name: "P", + optional: false, + range: [ + 16, + 17, + ], + type: "Identifier", + typeAnnotation: null, + }, + out: false, + range: [ + 16, + 28, + ], + type: "TSTypeParameter", + }, +} +`; + +snapshot[`Plugin - TSLiteralType 1`] = ` +{ + literal: { + range: [ + 10, + 14, + ], + raw: "true", + type: "Literal", + value: true, + }, + range: [ + 10, + 14, + ], + type: "TSLiteralType", +} +`; + +snapshot[`Plugin - TSLiteralType 2`] = ` +{ + literal: { + range: [ + 10, + 15, + ], + raw: "false", + type: "Literal", + value: false, + }, + range: [ + 10, + 15, + ], + type: "TSLiteralType", +} +`; + +snapshot[`Plugin - TSLiteralType 3`] = ` +{ + literal: { + range: [ + 10, + 11, + ], + raw: "1", + type: "Literal", + value: 1, + }, + range: [ + 10, + 11, + ], + type: "TSLiteralType", +} +`; + +snapshot[`Plugin - TSLiteralType 4`] = ` +{ + literal: { + range: [ + 10, + 15, + ], + raw: '"foo"', + type: "Literal", + value: "foo", + }, + range: [ + 10, + 15, + ], + type: "TSLiteralType", +} +`; + +snapshot[`Plugin - TSTemplateLiteralType 1`] = ` +{ + quasis: [ + { + cooked: "a ", + range: [ + 11, + 13, + ], + raw: "a ", + tail: false, + type: "TemplateElement", + }, + { + cooked: "", + range: [ + 22, + 22, + ], + raw: "", + tail: true, + type: "TemplateElement", + }, + ], + range: [ + 10, + 23, + ], + type: "TSTemplateLiteralType", + types: [ + { + range: [ + 15, + 21, + ], + type: "TSStringKeyword", + }, + ], +} +`; + +snapshot[`Plugin - TSTupleType + TSArrayType 1`] = ` +{ + elementTypes: [ + { + range: [ + 11, + 17, + ], + type: "TSNumberKeyword", + }, + ], + range: [ + 10, + 18, + ], + type: "TSTupleType", +} +`; + +snapshot[`Plugin - TSTupleType + TSArrayType 2`] = ` +{ + elementTypes: [ + { + elementType: { + range: [ + 14, + 20, + ], + type: "TSNumberKeyword", + }, + label: { + name: "x", + optional: false, + range: [ + 11, + 12, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 11, + 20, + ], + type: "TSNamedTupleMember", + }, + ], + range: [ + 10, + 21, + ], + type: "TSTupleType", +} +`; + +snapshot[`Plugin - TSTupleType + TSArrayType 3`] = ` +{ + elementTypes: [ + { + elementType: { + range: [ + 14, + 20, + ], + type: "TSNumberKeyword", + }, + label: { + name: "x", + optional: false, + range: [ + 11, + 12, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 11, + 20, + ], + type: "TSNamedTupleMember", + }, + ], + range: [ + 10, + 21, + ], + type: "TSTupleType", +} +`; + +snapshot[`Plugin - TSTupleType + TSArrayType 4`] = ` +{ + elementTypes: [ + { + elementType: { + elementType: { + range: [ + 17, + 23, + ], + type: "TSNumberKeyword", + }, + range: [ + 17, + 25, + ], + type: "TSArrayType", + }, + label: { + argument: { + name: "x", + optional: false, + range: [ + 14, + 15, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 11, + 16, + ], + type: "RestElement", + typeAnnotation: null, + }, + range: [ + 11, + 25, + ], + type: "TSNamedTupleMember", + }, + ], + range: [ + 10, + 26, + ], + type: "TSTupleType", +} +`; + +snapshot[`Plugin - TSArrayType 1`] = ` +{ + elementType: { + range: [ + 10, + 16, + ], + type: "TSNumberKeyword", + }, + range: [ + 10, + 18, + ], + type: "TSArrayType", +} +`; + +snapshot[`Plugin - TSTypeQuery 1`] = ` +{ + exprName: { + name: "B", + optional: false, + range: [ + 17, + 18, + ], + type: "Identifier", + typeAnnotation: null, + }, + range: [ + 10, + 18, + ], + type: "TSTypeQuery", + typeArguments: null, +} +`; + +snapshot[`Plugin - TS keywords 1`] = ` +{ + range: [ + 10, + 13, + ], + type: "TSAnyKeyword", +} +`; + +snapshot[`Plugin - TS keywords 2`] = ` +{ + range: [ + 10, + 16, + ], + type: "TSBigIntKeyword", +} +`; + +snapshot[`Plugin - TS keywords 3`] = ` +{ + range: [ + 10, + 17, + ], + type: "TSBooleanKeyword", +} +`; + +snapshot[`Plugin - TS keywords 4`] = ` +{ + range: [ + 10, + 19, + ], + type: "TSIntrinsicKeyword", +} +`; + +snapshot[`Plugin - TS keywords 5`] = ` +{ + range: [ + 10, + 15, + ], + type: "TSNeverKeyword", +} +`; + +snapshot[`Plugin - TS keywords 6`] = ` +{ + range: [ + 10, + 14, + ], + type: "TSNullKeyword", +} +`; + +snapshot[`Plugin - TS keywords 7`] = ` +{ + range: [ + 10, + 16, + ], + type: "TSNumberKeyword", +} +`; + +snapshot[`Plugin - TS keywords 8`] = ` +{ + range: [ + 10, + 16, + ], + type: "TSObjectKeyword", +} +`; + +snapshot[`Plugin - TS keywords 9`] = ` +{ + range: [ + 10, + 16, + ], + type: "TSStringKeyword", +} +`; + +snapshot[`Plugin - TS keywords 10`] = ` +{ + range: [ + 10, + 16, + ], + type: "TSSymbolKeyword", +} +`; + +snapshot[`Plugin - TS keywords 11`] = ` +{ + range: [ + 10, + 19, + ], + type: "TSUndefinedKeyword", +} +`; + +snapshot[`Plugin - TS keywords 12`] = ` +{ + range: [ + 10, + 17, + ], + type: "TSUnknownKeyword", +} +`; + +snapshot[`Plugin - TS keywords 13`] = ` +{ + range: [ + 10, + 14, + ], + type: "TSVoidKeyword", +} +`; diff --git a/tests/unit/abort_controller_test.ts b/tests/unit/abort_controller_test.ts index 60ea6aa245..52a1bad803 100644 --- a/tests/unit/abort_controller_test.ts +++ b/tests/unit/abort_controller_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals } from "./test_util.ts"; diff --git a/tests/unit/blob_test.ts b/tests/unit/blob_test.ts index b578253142..b89f4703e2 100644 --- a/tests/unit/blob_test.ts +++ b/tests/unit/blob_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, assertStringIncludes } from "./test_util.ts"; import { concat } from "@std/bytes/concat"; diff --git a/tests/unit/body_test.ts b/tests/unit/body_test.ts index fb51fd0076..28a1c697b1 100644 --- a/tests/unit/body_test.ts +++ b/tests/unit/body_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, assertRejects } from "./test_util.ts"; // just a hack to get a body object diff --git a/tests/unit/broadcast_channel_test.ts b/tests/unit/broadcast_channel_test.ts index dce5f10867..f4efe68c4f 100644 --- a/tests/unit/broadcast_channel_test.ts +++ b/tests/unit/broadcast_channel_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals } from "@std/assert"; Deno.test("BroadcastChannel worker", async () => { diff --git a/tests/unit/build_test.ts b/tests/unit/build_test.ts index f697b64d39..9f4e3a5cbf 100644 --- a/tests/unit/build_test.ts +++ b/tests/unit/build_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert } from "./test_util.ts"; Deno.test(function buildInfo() { diff --git a/tests/unit/cache_api_test.ts b/tests/unit/cache_api_test.ts index 08f768e334..ec84e9c908 100644 --- a/tests/unit/cache_api_test.ts +++ b/tests/unit/cache_api_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, diff --git a/tests/unit/chmod_test.ts b/tests/unit/chmod_test.ts index 9ff6301e28..6d815ea1eb 100644 --- a/tests/unit/chmod_test.ts +++ b/tests/unit/chmod_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, diff --git a/tests/unit/chown_test.ts b/tests/unit/chown_test.ts index eda4d34037..99e7dd445a 100644 --- a/tests/unit/chown_test.ts +++ b/tests/unit/chown_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertRejects, assertThrows } from "./test_util.ts"; // chown on Windows is noop for now, so ignore its testing on Windows diff --git a/tests/unit/command_test.ts b/tests/unit/command_test.ts index 8345548f85..268b0c25ba 100644 --- a/tests/unit/command_test.ts +++ b/tests/unit/command_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, diff --git a/tests/unit/console_test.ts b/tests/unit/console_test.ts index 06f5dd7e61..7b19e49cbd 100644 --- a/tests/unit/console_test.ts +++ b/tests/unit/console_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // TODO(ry) The unit test functions in this module are too coarse. They should // be broken up into smaller bits. diff --git a/tests/unit/copy_file_test.ts b/tests/unit/copy_file_test.ts index 9405184e33..fa4a9d837c 100644 --- a/tests/unit/copy_file_test.ts +++ b/tests/unit/copy_file_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertRejects, assertThrows } from "./test_util.ts"; function readFileString(filename: string | URL): string { diff --git a/tests/unit/cron_test.ts b/tests/unit/cron_test.ts index 5f14f6c784..325ee5535d 100644 --- a/tests/unit/cron_test.ts +++ b/tests/unit/cron_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertThrows } from "./test_util.ts"; // @ts-ignore This is not publicly typed namespace, but it's there for sure. diff --git a/tests/unit/custom_event_test.ts b/tests/unit/custom_event_test.ts index b72084eb23..ddefd4cce6 100644 --- a/tests/unit/custom_event_test.ts +++ b/tests/unit/custom_event_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals } from "./test_util.ts"; Deno.test(function customEventInitializedWithDetail() { diff --git a/tests/unit/dir_test.ts b/tests/unit/dir_test.ts index 1e702f549a..dbf88609c2 100644 --- a/tests/unit/dir_test.ts +++ b/tests/unit/dir_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, assertThrows } from "./test_util.ts"; Deno.test({ permissions: { read: true } }, function dirCwdNotNull() { diff --git a/tests/unit/dom_exception_test.ts b/tests/unit/dom_exception_test.ts index 4e894f5fc8..2e0c9f71e1 100644 --- a/tests/unit/dom_exception_test.ts +++ b/tests/unit/dom_exception_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, diff --git a/tests/unit/error_stack_test.ts b/tests/unit/error_stack_test.ts index 7188b9f53d..fea8913494 100644 --- a/tests/unit/error_stack_test.ts +++ b/tests/unit/error_stack_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertMatch } from "./test_util.ts"; Deno.test(function errorStackMessageLine() { diff --git a/tests/unit/error_test.ts b/tests/unit/error_test.ts index bf0ef50627..48e1f7879b 100644 --- a/tests/unit/error_test.ts +++ b/tests/unit/error_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertThrows, fail } from "./test_util.ts"; Deno.test("Errors work", () => { diff --git a/tests/unit/esnext_test.ts b/tests/unit/esnext_test.ts index 1d5759aafa..2c597ef7ba 100644 --- a/tests/unit/esnext_test.ts +++ b/tests/unit/esnext_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals } from "./test_util.ts"; // TODO(@kitsonk) remove when we are no longer patching TypeScript to have diff --git a/tests/unit/event_source_test.ts b/tests/unit/event_source_test.ts index 242c12d6e8..2ce7178b00 100644 --- a/tests/unit/event_source_test.ts +++ b/tests/unit/event_source_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertStrictEquals } from "./test_util.ts"; Deno.test( diff --git a/tests/unit/event_target_test.ts b/tests/unit/event_target_test.ts index 3f7d8ee24a..ca1c496143 100644 --- a/tests/unit/event_target_test.ts +++ b/tests/unit/event_target_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertThrows } from "./test_util.ts"; diff --git a/tests/unit/event_test.ts b/tests/unit/event_test.ts index bd398fd410..d022e1c1d1 100644 --- a/tests/unit/event_test.ts +++ b/tests/unit/event_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertStringIncludes } from "./test_util.ts"; Deno.test(function eventInitializedWithType() { diff --git a/tests/unit/fetch_test.ts b/tests/unit/fetch_test.ts index 298a266903..094b963e19 100644 --- a/tests/unit/fetch_test.ts +++ b/tests/unit/fetch_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console diff --git a/tests/unit/ffi_test.ts b/tests/unit/ffi_test.ts index 98338b15e6..9db0ad0c26 100644 --- a/tests/unit/ffi_test.ts +++ b/tests/unit/ffi_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertRejects, assertThrows } from "./test_util.ts"; diff --git a/tests/unit/file_test.ts b/tests/unit/file_test.ts index 1af3a3f84d..38e4dce64a 100644 --- a/tests/unit/file_test.ts +++ b/tests/unit/file_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals } from "./test_util.ts"; // deno-lint-ignore no-explicit-any diff --git a/tests/unit/filereader_test.ts b/tests/unit/filereader_test.ts index 158cf53835..21ca25ed48 100644 --- a/tests/unit/filereader_test.ts +++ b/tests/unit/filereader_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals } from "./test_util.ts"; Deno.test(function fileReaderConstruct() { diff --git a/tests/unit/files_test.ts b/tests/unit/files_test.ts index c22d3deb77..aa211b224d 100644 --- a/tests/unit/files_test.ts +++ b/tests/unit/files_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, diff --git a/tests/unit/fs_events_test.ts b/tests/unit/fs_events_test.ts index 7489626b9f..d9bdf454d5 100644 --- a/tests/unit/fs_events_test.ts +++ b/tests/unit/fs_events_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, assertThrows, delay } from "./test_util.ts"; diff --git a/tests/unit/get_random_values_test.ts b/tests/unit/get_random_values_test.ts index 75aaf4c1b2..47ba78a325 100644 --- a/tests/unit/get_random_values_test.ts +++ b/tests/unit/get_random_values_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertNotEquals, assertStrictEquals } from "./test_util.ts"; Deno.test(function getRandomValuesInt8Array() { diff --git a/tests/unit/globals_test.ts b/tests/unit/globals_test.ts index 6de228e1c9..84773dbf47 100644 --- a/tests/unit/globals_test.ts +++ b/tests/unit/globals_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-node-globals import { diff --git a/tests/unit/headers_test.ts b/tests/unit/headers_test.ts index ea72f784b5..969b2a36f4 100644 --- a/tests/unit/headers_test.ts +++ b/tests/unit/headers_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, assertThrows } from "./test_util.ts"; const { inspectArgs, diff --git a/tests/unit/http_test.ts b/tests/unit/http_test.ts index 355b155afd..809b36227b 100644 --- a/tests/unit/http_test.ts +++ b/tests/unit/http_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-nocheck `Deno.serveHttp()` was soft-removed in Deno 2. // deno-lint-ignore-file no-deprecated-deno-api diff --git a/tests/unit/image_bitmap_test.ts b/tests/unit/image_bitmap_test.ts index 0066311820..ca5b85c178 100644 --- a/tests/unit/image_bitmap_test.ts +++ b/tests/unit/image_bitmap_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals } from "./test_util.ts"; diff --git a/tests/unit/image_data_test.ts b/tests/unit/image_data_test.ts index 7156301a05..c6dfb0d372 100644 --- a/tests/unit/image_data_test.ts +++ b/tests/unit/image_data_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals } from "./test_util.ts"; diff --git a/tests/unit/internals_test.ts b/tests/unit/internals_test.ts index bb4c21793e..7ca9b6d336 100644 --- a/tests/unit/internals_test.ts +++ b/tests/unit/internals_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert } from "./test_util.ts"; Deno.test(function internalsExists() { diff --git a/tests/unit/intl_test.ts b/tests/unit/intl_test.ts index 6e4de378c9..e177dc45b0 100644 --- a/tests/unit/intl_test.ts +++ b/tests/unit/intl_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals } from "./test_util.ts"; Deno.test("Intl.v8BreakIterator should be undefined", () => { diff --git a/tests/unit/jupyter_test.ts b/tests/unit/jupyter_test.ts index 07defe2305..e29bb2b300 100644 --- a/tests/unit/jupyter_test.ts +++ b/tests/unit/jupyter_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertThrows } from "./test_util.ts"; diff --git a/tests/unit/kv_queue_test.ts b/tests/unit/kv_queue_test.ts index d92977169f..569eb92800 100644 --- a/tests/unit/kv_queue_test.ts +++ b/tests/unit/kv_queue_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertFalse } from "./test_util.ts"; Deno.test({}, async function queueTestDbClose() { diff --git a/tests/unit/kv_queue_test_no_db_close.ts b/tests/unit/kv_queue_test_no_db_close.ts index 947e1c5e62..7c4bbf271e 100644 --- a/tests/unit/kv_queue_test_no_db_close.ts +++ b/tests/unit/kv_queue_test_no_db_close.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, assertNotEquals } from "./test_util.ts"; Deno.test({ diff --git a/tests/unit/kv_queue_undelivered_test.ts b/tests/unit/kv_queue_undelivered_test.ts index 1fcefe7e26..2fbfefbd69 100644 --- a/tests/unit/kv_queue_undelivered_test.ts +++ b/tests/unit/kv_queue_undelivered_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals } from "./test_util.ts"; const sleep = (time: number) => new Promise((r) => setTimeout(r, time)); diff --git a/tests/unit/kv_test.ts b/tests/unit/kv_test.ts index e603bc196d..47e1305c94 100644 --- a/tests/unit/kv_test.ts +++ b/tests/unit/kv_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, @@ -1951,14 +1951,14 @@ dbTest("Invalid backoffSchedule", async (db) => { await db.enqueue("foo", { backoffSchedule: [1, 1, 1, 1, 1, 1] }); }, TypeError, - "Invalid backoffSchedule", + "Invalid backoffSchedule, max 5 intervals allowed", ); await assertRejects( async () => { await db.enqueue("foo", { backoffSchedule: [3600001] }); }, TypeError, - "Invalid backoffSchedule", + "Invalid backoffSchedule, interval at index 0 is invalid", ); }); diff --git a/tests/unit/link_test.ts b/tests/unit/link_test.ts index dfa72479c5..5093c5720d 100644 --- a/tests/unit/link_test.ts +++ b/tests/unit/link_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, diff --git a/tests/unit/lint_plugin_test.ts b/tests/unit/lint_plugin_test.ts index 38a7e1b091..6c71501c46 100644 --- a/tests/unit/lint_plugin_test.ts +++ b/tests/unit/lint_plugin_test.ts @@ -1,6 +1,7 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals } from "./test_util.ts"; +import { assertSnapshot } from "@std/testing/snapshot"; // TODO(@marvinhagemeister) Remove once we land "official" types export interface LintReportData { @@ -85,9 +86,12 @@ function testVisit( return result; } -function testLintNode(source: string, ...selectors: string[]) { - // deno-lint-ignore no-explicit-any - const log: any[] = []; +async function testSnapshot( + t: Deno.TestContext, + source: string, + ...selectors: string[] +) { + const log: unknown[] = []; testPlugin(source, { create() { @@ -103,7 +107,8 @@ function testLintNode(source: string, ...selectors: string[]) { }, }); - return log; + assertEquals(log.length > 0, true); + await assertSnapshot(t, log[0]); } Deno.test("Plugin - visitor enter/exit", () => { @@ -313,303 +318,157 @@ Deno.test("Plugin - visitor :nth-child", () => { assertEquals(result[1].node.name, "foobar"); }); -Deno.test("Plugin - Program", () => { - const node = testLintNode("", "Program"); - assertEquals(node[0], { - type: "Program", - sourceType: "script", - range: [1, 1], - body: [], - }); +Deno.test("Plugin - Program", async (t) => { + await testSnapshot(t, "", "Program"); }); -Deno.test("Plugin - BlockStatement", () => { - const node = testLintNode("{ foo; }", "BlockStatement"); - assertEquals(node[0], { - type: "BlockStatement", - range: [1, 9], - body: [{ - type: "ExpressionStatement", - range: [3, 7], - expression: { - type: "Identifier", - name: "foo", - range: [3, 6], - }, - }], - }); +Deno.test("Plugin - ImportDeclaration", async (t) => { + await testSnapshot(t, 'import "foo";', "ImportDeclaration"); + await testSnapshot(t, 'import foo from "foo";', "ImportDeclaration"); + await testSnapshot(t, 'import * as foo from "foo";', "ImportDeclaration"); + await testSnapshot( + t, + 'import { foo, bar as baz } from "foo";', + "ImportDeclaration", + ); + await testSnapshot( + t, + 'import foo from "foo" with { type: "json" };', + "ImportDeclaration", + ); }); -Deno.test("Plugin - BreakStatement", () => { - let node = testLintNode("break;", "BreakStatement"); - assertEquals(node[0], { - type: "BreakStatement", - range: [1, 7], - label: null, - }); - - node = testLintNode("break foo;", "BreakStatement"); - assertEquals(node[0], { - type: "BreakStatement", - range: [1, 11], - label: { - type: "Identifier", - range: [7, 10], - name: "foo", - }, - }); +Deno.test("Plugin - ExportNamedDeclaration", async (t) => { + await testSnapshot(t, 'export { foo } from "foo";', "ExportNamedDeclaration"); + await testSnapshot( + t, + 'export { bar as baz } from "foo";', + "ExportNamedDeclaration", + ); + await testSnapshot( + t, + 'export { foo } from "foo" with { type: "json" };', + "ExportNamedDeclaration", + ); }); -Deno.test("Plugin - ContinueStatement", () => { - let node = testLintNode("continue;", "ContinueStatement"); - assertEquals(node[0], { - type: "ContinueStatement", - range: [1, 10], - label: null, - }); - - node = testLintNode("continue foo;", "ContinueStatement"); - assertEquals(node[0], { - type: "ContinueStatement", - range: [1, 14], - label: { - type: "Identifier", - range: [10, 13], - name: "foo", - }, - }); +Deno.test("Plugin - ExportDefaultDeclaration", async (t) => { + await testSnapshot( + t, + "export default function foo() {}", + "ExportDefaultDeclaration", + ); + await testSnapshot( + t, + "export default function () {}", + "ExportDefaultDeclaration", + ); + await testSnapshot( + t, + "export default class Foo {}", + "ExportDefaultDeclaration", + ); + await testSnapshot( + t, + "export default class {}", + "ExportDefaultDeclaration", + ); + await testSnapshot(t, "export default bar;", "ExportDefaultDeclaration"); + await testSnapshot( + t, + "export default interface Foo {};", + "ExportDefaultDeclaration", + ); }); -Deno.test("Plugin - DebuggerStatement", () => { - const node = testLintNode("debugger;", "DebuggerStatement"); - assertEquals(node[0], { - type: "DebuggerStatement", - range: [1, 10], - }); +Deno.test("Plugin - ExportAllDeclaration", async (t) => { + await testSnapshot(t, 'export * from "foo";', "ExportAllDeclaration"); + await testSnapshot(t, 'export * as foo from "foo";', "ExportAllDeclaration"); + await testSnapshot( + t, + 'export * from "foo" with { type: "json" };', + "ExportAllDeclaration", + ); }); -Deno.test("Plugin - DoWhileStatement", () => { - const node = testLintNode("do {} while (foo);", "DoWhileStatement"); - assertEquals(node[0], { - type: "DoWhileStatement", - range: [1, 19], - test: { - type: "Identifier", - range: [14, 17], - name: "foo", - }, - body: { - type: "BlockStatement", - range: [4, 6], - body: [], - }, - }); +Deno.test("Plugin - TSExportAssignment", async (t) => { + await testSnapshot(t, "export = foo;", "TSExportAssignment"); }); -Deno.test("Plugin - ExpressionStatement", () => { - const node = testLintNode("foo;", "ExpressionStatement"); - assertEquals(node[0], { - type: "ExpressionStatement", - range: [1, 5], - expression: { - type: "Identifier", - range: [1, 4], - name: "foo", - }, - }); +Deno.test("Plugin - TSNamespaceExportDeclaration", async (t) => { + await testSnapshot( + t, + "export as namespace A;", + "TSNamespaceExportDeclaration", + ); }); -Deno.test("Plugin - ForInStatement", () => { - const node = testLintNode("for (a in b) {}", "ForInStatement"); - assertEquals(node[0], { - type: "ForInStatement", - range: [1, 16], - left: { - type: "Identifier", - range: [6, 7], - name: "a", - }, - right: { - type: "Identifier", - range: [11, 12], - name: "b", - }, - body: { - type: "BlockStatement", - range: [14, 16], - body: [], - }, - }); +Deno.test("Plugin - TSImportEqualsDeclaration", async (t) => { + await testSnapshot(t, "import a = b", "TSImportEqualsDeclaration"); + await testSnapshot( + t, + 'import a = require("foo")', + "TSImportEqualsDeclaration", + ); }); -Deno.test("Plugin - ForOfStatement", () => { - let node = testLintNode("for (a of b) {}", "ForOfStatement"); - assertEquals(node[0], { - type: "ForOfStatement", - range: [1, 16], - await: false, - left: { - type: "Identifier", - range: [6, 7], - name: "a", - }, - right: { - type: "Identifier", - range: [11, 12], - name: "b", - }, - body: { - type: "BlockStatement", - range: [14, 16], - body: [], - }, - }); - - node = testLintNode("for await (a of b) {}", "ForOfStatement"); - assertEquals(node[0], { - type: "ForOfStatement", - range: [1, 22], - await: true, - left: { - type: "Identifier", - range: [12, 13], - name: "a", - }, - right: { - type: "Identifier", - range: [17, 18], - name: "b", - }, - body: { - type: "BlockStatement", - range: [20, 22], - body: [], - }, - }); +Deno.test("Plugin - BlockStatement", async (t) => { + await testSnapshot(t, "{ foo; }", "BlockStatement"); }); -Deno.test("Plugin - ForStatement", () => { - let node = testLintNode("for (;;) {}", "ForStatement"); - assertEquals(node[0], { - type: "ForStatement", - range: [1, 12], - init: null, - test: null, - update: null, - body: { - type: "BlockStatement", - range: [10, 12], - body: [], - }, - }); - - node = testLintNode("for (a; b; c) {}", "ForStatement"); - assertEquals(node[0], { - type: "ForStatement", - range: [1, 17], - init: { - type: "Identifier", - range: [6, 7], - name: "a", - }, - test: { - type: "Identifier", - range: [9, 10], - name: "b", - }, - update: { - type: "Identifier", - range: [12, 13], - name: "c", - }, - body: { - type: "BlockStatement", - range: [15, 17], - body: [], - }, - }); +Deno.test("Plugin - BreakStatement", async (t) => { + await testSnapshot(t, "while (false) break;", "BreakStatement"); + await testSnapshot(t, "foo: while (false) break foo;", "BreakStatement"); }); -Deno.test("Plugin - IfStatement", () => { - let node = testLintNode("if (foo) {}", "IfStatement"); - assertEquals(node[0], { - type: "IfStatement", - range: [1, 12], - test: { - type: "Identifier", - name: "foo", - range: [5, 8], - }, - consequent: { - type: "BlockStatement", - range: [10, 12], - body: [], - }, - alternate: null, - }); - - node = testLintNode("if (foo) {} else {}", "IfStatement"); - assertEquals(node[0], { - type: "IfStatement", - range: [1, 20], - test: { - type: "Identifier", - name: "foo", - range: [5, 8], - }, - consequent: { - type: "BlockStatement", - range: [10, 12], - body: [], - }, - alternate: { - type: "BlockStatement", - range: [18, 20], - body: [], - }, - }); +Deno.test("Plugin - ContinueStatement", async (t) => { + await testSnapshot(t, "continue;", "ContinueStatement"); + await testSnapshot(t, "continue foo;", "ContinueStatement"); }); -Deno.test("Plugin - LabeledStatement", () => { - const node = testLintNode("foo: {};", "LabeledStatement"); - assertEquals(node[0], { - type: "LabeledStatement", - range: [1, 8], - label: { - type: "Identifier", - name: "foo", - range: [1, 4], - }, - body: { - type: "BlockStatement", - range: [6, 8], - body: [], - }, - }); +Deno.test("Plugin - DebuggerStatement", async (t) => { + await testSnapshot(t, "debugger;", "DebuggerStatement"); }); -Deno.test("Plugin - ReturnStatement", () => { - let node = testLintNode("return", "ReturnStatement"); - assertEquals(node[0], { - type: "ReturnStatement", - range: [1, 7], - argument: null, - }); - - node = testLintNode("return foo;", "ReturnStatement"); - assertEquals(node[0], { - type: "ReturnStatement", - range: [1, 12], - argument: { - type: "Identifier", - name: "foo", - range: [8, 11], - }, - }); +Deno.test("Plugin - DoWhileStatement", async (t) => { + await testSnapshot(t, "do {} while (foo);", "DoWhileStatement"); }); -Deno.test("Plugin - SwitchStatement", () => { - const node = testLintNode( +Deno.test("Plugin - ExpressionStatement", async (t) => { + await testSnapshot(t, "foo;", "ExpressionStatement"); +}); + +Deno.test("Plugin - ForInStatement", async (t) => { + await testSnapshot(t, "for (a in b) {}", "ForInStatement"); +}); + +Deno.test("Plugin - ForOfStatement", async (t) => { + await testSnapshot(t, "for (a of b) {}", "ForOfStatement"); + await testSnapshot(t, "for await (a of b) {}", "ForOfStatement"); +}); + +Deno.test("Plugin - ForStatement", async (t) => { + await testSnapshot(t, "for (;;) {}", "ForStatement"); + await testSnapshot(t, "for (a; b; c) {}", "ForStatement"); +}); + +Deno.test("Plugin - IfStatement", async (t) => { + await testSnapshot(t, "if (foo) {}", "IfStatement"); + await testSnapshot(t, "if (foo) {} else {}", "IfStatement"); +}); + +Deno.test("Plugin - LabeledStatement", async (t) => { + await testSnapshot(t, "foo: {};", "LabeledStatement"); +}); + +Deno.test("Plugin - ReturnStatement", async (t) => { + await testSnapshot(t, "return", "ReturnStatement"); + await testSnapshot(t, "return foo;", "ReturnStatement"); +}); + +Deno.test("Plugin - SwitchStatement", async (t) => { + await testSnapshot( + t, `switch (foo) { case foo: case bar: @@ -619,151 +478,449 @@ Deno.test("Plugin - SwitchStatement", () => { }`, "SwitchStatement", ); - assertEquals(node[0], { - type: "SwitchStatement", - range: [1, 94], - discriminant: { - type: "Identifier", - range: [9, 12], - name: "foo", - }, - cases: [ - { - type: "SwitchCase", - range: [22, 31], - test: { - type: "Identifier", - range: [27, 30], - name: "foo", - }, - consequent: [], - }, - { - type: "SwitchCase", - range: [38, 62], - test: { - type: "Identifier", - range: [43, 46], - name: "bar", - }, - consequent: [ - { - type: "BreakStatement", - label: null, - range: [56, 62], - }, - ], - }, - { - type: "SwitchCase", - range: [69, 88], - test: null, - consequent: [ - { - type: "BlockStatement", - range: [86, 88], - body: [], - }, - ], - }, - ], - }); }); -Deno.test("Plugin - ThrowStatement", () => { - const node = testLintNode("throw foo;", "ThrowStatement"); - assertEquals(node[0], { - type: "ThrowStatement", - range: [1, 11], - argument: { - type: "Identifier", - range: [7, 10], - name: "foo", - }, - }); +Deno.test("Plugin - ThrowStatement", async (t) => { + await testSnapshot(t, "throw foo;", "ThrowStatement"); }); -Deno.test("Plugin - TryStatement", () => { - let node = testLintNode("try {} catch {};", "TryStatement"); - assertEquals(node[0], { - type: "TryStatement", - range: [1, 16], - block: { - type: "BlockStatement", - range: [5, 7], - body: [], - }, - handler: { - type: "CatchClause", - range: [8, 16], - param: null, - body: { - type: "BlockStatement", - range: [14, 16], - body: [], - }, - }, - finalizer: null, - }); - - node = testLintNode("try {} catch (e) {};", "TryStatement"); - assertEquals(node[0], { - type: "TryStatement", - range: [1, 20], - block: { - type: "BlockStatement", - range: [5, 7], - body: [], - }, - handler: { - type: "CatchClause", - range: [8, 20], - param: { - type: "Identifier", - range: [15, 16], - name: "e", - }, - body: { - type: "BlockStatement", - range: [18, 20], - body: [], - }, - }, - finalizer: null, - }); - - node = testLintNode("try {} finally {};", "TryStatement"); - assertEquals(node[0], { - type: "TryStatement", - range: [1, 18], - block: { - type: "BlockStatement", - range: [5, 7], - body: [], - }, - handler: null, - finalizer: { - type: "BlockStatement", - range: [16, 18], - body: [], - }, - }); +Deno.test("Plugin - TryStatement", async (t) => { + await testSnapshot(t, "try {} catch {};", "TryStatement"); + await testSnapshot(t, "try {} catch (e) {};", "TryStatement"); + await testSnapshot(t, "try {} finally {};", "TryStatement"); }); -Deno.test("Plugin - WhileStatement", () => { - const node = testLintNode("while (foo) {}", "WhileStatement"); - assertEquals(node[0], { - type: "WhileStatement", - range: [1, 15], - test: { - type: "Identifier", - range: [8, 11], - name: "foo", - }, - body: { - type: "BlockStatement", - range: [13, 15], - body: [], - }, - }); +Deno.test("Plugin - WhileStatement", async (t) => { + await testSnapshot(t, "while (foo) {}", "WhileStatement"); +}); + +Deno.test("Plugin - WithStatement", async (t) => { + await testSnapshot(t, "with ([]) {}", "WithStatement"); +}); + +Deno.test("Plugin - ArrayExpression", async (t) => { + await testSnapshot(t, "[[],,[]]", "ArrayExpression"); +}); + +Deno.test("Plugin - ArrowFunctionExpression", async (t) => { + await testSnapshot(t, "() => {}", "ArrowFunctionExpression"); + await testSnapshot(t, "async () => {}", "ArrowFunctionExpression"); + await testSnapshot( + t, + "(a: number, ...b: any[]): any => {}", + "ArrowFunctionExpression", + ); +}); + +Deno.test("Plugin - AssignmentExpression", async (t) => { + await testSnapshot(t, "a = b", "AssignmentExpression"); + await testSnapshot(t, "a = a ??= b", "AssignmentExpression"); +}); + +Deno.test("Plugin - AwaitExpression", async (t) => { + await testSnapshot(t, "await foo;", "AwaitExpression"); +}); + +Deno.test("Plugin - BinaryExpression", async (t) => { + await testSnapshot(t, "a > b", "BinaryExpression"); + await testSnapshot(t, "a >= b", "BinaryExpression"); + await testSnapshot(t, "a < b", "BinaryExpression"); + await testSnapshot(t, "a <= b", "BinaryExpression"); + await testSnapshot(t, "a == b", "BinaryExpression"); + await testSnapshot(t, "a === b", "BinaryExpression"); + await testSnapshot(t, "a != b", "BinaryExpression"); + await testSnapshot(t, "a !== b", "BinaryExpression"); + await testSnapshot(t, "a << b", "BinaryExpression"); + await testSnapshot(t, "a >> b", "BinaryExpression"); + await testSnapshot(t, "a >>> b", "BinaryExpression"); + await testSnapshot(t, "a + b", "BinaryExpression"); + await testSnapshot(t, "a - b", "BinaryExpression"); + await testSnapshot(t, "a * b", "BinaryExpression"); + await testSnapshot(t, "a / b", "BinaryExpression"); + await testSnapshot(t, "a % b", "BinaryExpression"); + await testSnapshot(t, "a | b", "BinaryExpression"); + await testSnapshot(t, "a ^ b", "BinaryExpression"); + await testSnapshot(t, "a & b", "BinaryExpression"); + await testSnapshot(t, "a in b", "BinaryExpression"); + await testSnapshot(t, "a ** b", "BinaryExpression"); +}); + +Deno.test("Plugin - CallExpression", async (t) => { + await testSnapshot(t, "foo();", "CallExpression"); + await testSnapshot(t, "foo(a, ...b);", "CallExpression"); + await testSnapshot(t, "foo?.();", "CallExpression"); + await testSnapshot(t, "foo();", "CallExpression"); +}); + +Deno.test("Plugin - ChainExpression", async (t) => { + await testSnapshot(t, "a?.b", "ChainExpression"); +}); + +Deno.test("Plugin - ClassExpression", async (t) => { + await testSnapshot(t, "a = class {}", "ClassExpression"); + await testSnapshot(t, "a = class Foo {}", "ClassExpression"); + await testSnapshot(t, "a = class Foo extends Bar {}", "ClassExpression"); + await testSnapshot( + t, + "a = class Foo extends Bar implements Baz, Baz2 {}", + "ClassExpression", + ); + await testSnapshot(t, "a = class Foo {}", "ClassExpression"); + await testSnapshot(t, "a = class { foo() {} }", "ClassExpression"); + await testSnapshot(t, "a = class { #foo() {} }", "ClassExpression"); + await testSnapshot(t, "a = class { foo: number }", "ClassExpression"); + await testSnapshot(t, "a = class { foo = bar }", "ClassExpression"); + await testSnapshot( + t, + "a = class { constructor(public foo: string) {} }", + "ClassExpression", + ); + await testSnapshot(t, "a = class { #foo: number = bar }", "ClassExpression"); + await testSnapshot(t, "a = class { static foo = bar }", "ClassExpression"); + await testSnapshot( + t, + "a = class { static foo; static { foo = bar } }", + "ClassExpression", + ); +}); + +Deno.test("Plugin - ConditionalExpression", async (t) => { + await testSnapshot(t, "a ? b : c", "ConditionalExpression"); +}); + +Deno.test("Plugin - FunctionExpression", async (t) => { + await testSnapshot(t, "a = function () {}", "FunctionExpression"); + await testSnapshot(t, "a = function foo() {}", "FunctionExpression"); + await testSnapshot( + t, + "a = function (a?: number, ...b: any[]): any {}", + "FunctionExpression", + ); + await testSnapshot(t, "a = async function* () {}", "FunctionExpression"); +}); + +Deno.test("Plugin - Identifier", async (t) => { + await testSnapshot(t, "a", "Identifier"); +}); + +Deno.test("Plugin - ImportExpression", async (t) => { + await testSnapshot( + t, + "import('foo', { with: { type: 'json' } })", + "ImportExpression", + ); +}); + +Deno.test("Plugin - LogicalExpression", async (t) => { + await testSnapshot(t, "a && b", "LogicalExpression"); + await testSnapshot(t, "a || b", "LogicalExpression"); + await testSnapshot(t, "a ?? b", "LogicalExpression"); +}); + +Deno.test("Plugin - MemberExpression", async (t) => { + await testSnapshot(t, "a.b", "MemberExpression"); + await testSnapshot(t, "a['b']", "MemberExpression"); +}); + +Deno.test("Plugin - MetaProperty", async (t) => { + await testSnapshot(t, "import.meta", "MetaProperty"); +}); + +Deno.test("Plugin - NewExpression", async (t) => { + await testSnapshot(t, "new Foo()", "NewExpression"); + await testSnapshot(t, "new Foo(a, ...b)", "NewExpression"); +}); + +Deno.test("Plugin - ObjectExpression", async (t) => { + await testSnapshot(t, "a = {}", "ObjectExpression"); + await testSnapshot(t, "a = { a }", "ObjectExpression"); + await testSnapshot(t, "a = { b: c, [c]: d }", "ObjectExpression"); +}); + +Deno.test("Plugin - PrivateIdentifier", async (t) => { + await testSnapshot(t, "class Foo { #foo = foo }", "PrivateIdentifier"); +}); + +Deno.test("Plugin - SequenceExpression", async (t) => { + await testSnapshot(t, "(a, b)", "SequenceExpression"); +}); + +Deno.test("Plugin - Super", async (t) => { + await testSnapshot( + t, + "class Foo extends Bar { constructor() { super(); } }", + "Super", + ); +}); + +Deno.test("Plugin - TaggedTemplateExpression", async (t) => { + await testSnapshot(t, "foo`foo ${bar} baz`", "TaggedTemplateExpression"); +}); + +Deno.test("Plugin - TemplateLiteral", async (t) => { + await testSnapshot(t, "`foo ${bar} baz`", "TemplateLiteral"); +}); + +Deno.test("Plugin - ThisExpression", async (t) => { + await testSnapshot(t, "this", "ThisExpression"); +}); + +Deno.test("Plugin - TSAsExpression", async (t) => { + await testSnapshot(t, "a as b", "TSAsExpression"); + await testSnapshot(t, "a as const", "TSAsExpression"); +}); + +Deno.test("Plugin - TSNonNullExpression", async (t) => { + await testSnapshot(t, "a!", "TSNonNullExpression"); +}); + +Deno.test("Plugin - TSSatisfiesExpression", async (t) => { + await testSnapshot(t, "a satisfies b", "TSSatisfiesExpression"); +}); + +Deno.test("Plugin - UnaryExpression", async (t) => { + await testSnapshot(t, "typeof a", "UnaryExpression"); + await testSnapshot(t, "void 0", "UnaryExpression"); + await testSnapshot(t, "-a", "UnaryExpression"); + await testSnapshot(t, "+a", "UnaryExpression"); +}); + +Deno.test("Plugin - UpdateExpression", async (t) => { + await testSnapshot(t, "a++", "UpdateExpression"); + await testSnapshot(t, "++a", "UpdateExpression"); + await testSnapshot(t, "a--", "UpdateExpression"); + await testSnapshot(t, "--a", "UpdateExpression"); +}); + +Deno.test("Plugin - YieldExpression", async (t) => { + await testSnapshot(t, "function* foo() { yield bar; }", "YieldExpression"); +}); + +Deno.test("Plugin - Literal", async (t) => { + await testSnapshot(t, "1", "Literal"); + await testSnapshot(t, "'foo'", "Literal"); + await testSnapshot(t, '"foo"', "Literal"); + await testSnapshot(t, "true", "Literal"); + await testSnapshot(t, "false", "Literal"); + await testSnapshot(t, "null", "Literal"); + await testSnapshot(t, "1n", "Literal"); + await testSnapshot(t, "/foo/g", "Literal"); +}); + +Deno.test("Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr", async (t) => { + await testSnapshot(t, "

", "JSXElement"); + await testSnapshot(t, "
", "JSXElement"); + await testSnapshot(t, "
", "JSXElement"); + await testSnapshot(t, '
', "JSXElement"); + await testSnapshot(t, "
", "JSXElement"); + await testSnapshot(t, "
foo{2}
", "JSXElement"); + await testSnapshot(t, "", "JSXElement"); + await testSnapshot(t, "
", "JSXElement"); + await testSnapshot(t, "", "JSXElement"); + await testSnapshot(t, " />", "JSXElement"); +}); + +Deno.test("Plugin - JSXFragment + JSXOpeningFragment + JSXClosingFragment", async (t) => { + await testSnapshot(t, "<>", "JSXFragment"); + await testSnapshot(t, "<>foo{2}", "JSXFragment"); +}); + +Deno.test("Plugin - TSAsExpression", async (t) => { + await testSnapshot(t, "a as any", "TSAsExpression"); + await testSnapshot(t, '"foo" as const', "TSAsExpression"); +}); + +Deno.test("Plugin - TSEnumDeclaration", async (t) => { + await testSnapshot(t, "enum Foo {}", "TSEnumDeclaration"); + await testSnapshot(t, "const enum Foo {}", "TSEnumDeclaration"); + await testSnapshot(t, "enum Foo { A, B }", "TSEnumDeclaration"); + await testSnapshot(t, 'enum Foo { "a-b" }', "TSEnumDeclaration"); + await testSnapshot( + t, + "enum Foo { A = 1, B = 2, C = A | B }", + "TSEnumDeclaration", + ); +}); + +Deno.test("Plugin - TSInterface", async (t) => { + await testSnapshot(t, "interface A {}", "TSInterface"); + await testSnapshot(t, "interface A {}", "TSInterface"); + await testSnapshot(t, "interface A extends Foo, Bar {}", "TSInterface"); + await testSnapshot(t, "interface A { foo: any, bar?: any }", "TSInterface"); + await testSnapshot( + t, + "interface A { readonly [key: string]: any }", + "TSInterface", + ); + + await testSnapshot(t, "interface A { readonly a: any }", "TSInterface"); + await testSnapshot(t, "interface A { (a: T): T }", "TSInterface"); + await testSnapshot(t, "interface A { new (a: T): T }", "TSInterface"); + await testSnapshot(t, "interface A { a: new (a: T) => T }", "TSInterface"); + await testSnapshot(t, "interface A { get a(): string }", "TSInterface"); + await testSnapshot(t, "interface A { set a(v: string) }", "TSInterface"); + + await testSnapshot( + t, + "interface A { a(arg?: any, ...args: any[]): any }", + "TSInterface", + ); +}); + +Deno.test("Plugin - TSSatisfiesExpression", async (t) => { + await testSnapshot(t, "const a = {} satisfies A", "TSSatisfiesExpression"); +}); + +Deno.test("Plugin - TSTypeAliasDeclaration", async (t) => { + await testSnapshot(t, "type A = any", "TSTypeAliasDeclaration"); + await testSnapshot(t, "type A = any", "TSTypeAliasDeclaration"); + await testSnapshot(t, "declare type A = any", "TSTypeAliasDeclaration"); +}); + +Deno.test("Plugin - TSNonNullExpression", async (t) => { + await testSnapshot(t, "a!", "TSNonNullExpression"); +}); + +Deno.test("Plugin - TSUnionType", async (t) => { + await testSnapshot(t, "type A = B | C", "TSUnionType"); +}); + +Deno.test("Plugin - TSIntersectionType", async (t) => { + await testSnapshot(t, "type A = B & C", "TSIntersectionType"); +}); + +Deno.test("Plugin - TSModuleDeclaration", async (t) => { + await testSnapshot(t, "module A {}", "TSModuleDeclaration"); + await testSnapshot( + t, + "declare module A { export function A(): void }", + "TSModuleDeclaration", + ); +}); + +Deno.test("Plugin - TSModuleDeclaration + TSModuleBlock", async (t) => { + await testSnapshot(t, "module A {}", "TSModuleDeclaration"); + await testSnapshot( + t, + "namespace A { namespace B {} }", + "TSModuleDeclaration", + ); +}); + +Deno.test("Plugin - TSQualifiedName", async (t) => { + await testSnapshot(t, "type A = a.b;", "TSQualifiedName"); +}); + +Deno.test("Plugin - TSTypeLiteral", async (t) => { + await testSnapshot(t, "type A = { a: 1 };", "TSTypeLiteral"); +}); + +Deno.test("Plugin - TSOptionalType", async (t) => { + await testSnapshot(t, "type A = [number?]", "TSOptionalType"); +}); + +Deno.test("Plugin - TSRestType", async (t) => { + await testSnapshot(t, "type A = [...number[]]", "TSRestType"); +}); + +Deno.test("Plugin - TSConditionalType", async (t) => { + await testSnapshot( + t, + "type A = B extends C ? number : string;", + "TSConditionalType", + ); +}); + +Deno.test("Plugin - TSInferType", async (t) => { + await testSnapshot( + t, + "type A = T extends Array ? Item : T;", + "TSInferType", + ); +}); + +Deno.test("Plugin - TSTypeOperator", async (t) => { + await testSnapshot(t, "type A = keyof B", "TSTypeOperator"); + await testSnapshot(t, "declare const sym1: unique symbol;", "TSTypeOperator"); + await testSnapshot(t, "type A = readonly []", "TSTypeOperator"); +}); + +Deno.test("Plugin - TSMappedType", async (t) => { + await testSnapshot( + t, + "type A = { [P in keyof T]: boolean; };", + "TSMappedType", + ); + await testSnapshot( + t, + "type A = { readonly [P in keyof T]: []; };", + "TSMappedType", + ); + await testSnapshot( + t, + "type A = { -readonly [P in keyof T]: []; };", + "TSMappedType", + ); + await testSnapshot( + t, + "type A = { +readonly [P in keyof T]: []; };", + "TSMappedType", + ); + await testSnapshot( + t, + "type A = { [P in keyof T]?: boolean; };", + "TSMappedType", + ); + await testSnapshot( + t, + "type A = { [P in keyof T]-?: boolean; };", + "TSMappedType", + ); + await testSnapshot( + t, + "type A = { [P in keyof T]+?: boolean; };", + "TSMappedType", + ); +}); + +Deno.test("Plugin - TSLiteralType", async (t) => { + await testSnapshot(t, "type A = true", "TSLiteralType"); + await testSnapshot(t, "type A = false", "TSLiteralType"); + await testSnapshot(t, "type A = 1", "TSLiteralType"); + await testSnapshot(t, 'type A = "foo"', "TSLiteralType"); +}); + +Deno.test("Plugin - TSTemplateLiteralType", async (t) => { + await testSnapshot(t, "type A = `a ${string}`", "TSTemplateLiteralType"); +}); + +Deno.test("Plugin - TSTupleType + TSArrayType", async (t) => { + await testSnapshot(t, "type A = [number]", "TSTupleType"); + await testSnapshot(t, "type A = [x: number]", "TSTupleType"); + await testSnapshot(t, "type A = [x: number]", "TSTupleType"); + await testSnapshot(t, "type A = [...x: number[]]", "TSTupleType"); +}); + +Deno.test("Plugin - TSArrayType", async (t) => { + await testSnapshot(t, "type A = number[]", "TSArrayType"); +}); + +Deno.test("Plugin - TSTypeQuery", async (t) => { + await testSnapshot(t, "type A = typeof B", "TSTypeQuery"); +}); + +Deno.test("Plugin - TS keywords", async (t) => { + await testSnapshot(t, "type A = any", "TSAnyKeyword"); + await testSnapshot(t, "type A = bigint", "TSBigIntKeyword"); + await testSnapshot(t, "type A = boolean", "TSBooleanKeyword"); + await testSnapshot(t, "type A = intrinsic", "TSIntrinsicKeyword"); + await testSnapshot(t, "type A = never", "TSNeverKeyword"); + await testSnapshot(t, "type A = null", "TSNullKeyword"); + await testSnapshot(t, "type A = number", "TSNumberKeyword"); + await testSnapshot(t, "type A = object", "TSObjectKeyword"); + await testSnapshot(t, "type A = string", "TSStringKeyword"); + await testSnapshot(t, "type A = symbol", "TSSymbolKeyword"); + await testSnapshot(t, "type A = undefined", "TSUndefinedKeyword"); + await testSnapshot(t, "type A = unknown", "TSUnknownKeyword"); + await testSnapshot(t, "type A = void", "TSVoidKeyword"); }); diff --git a/tests/unit/lint_selectors_test.ts b/tests/unit/lint_selectors_test.ts index 0909a4907a..e9e4dacb4e 100644 --- a/tests/unit/lint_selectors_test.ts +++ b/tests/unit/lint_selectors_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals } from "@std/assert/equals"; import { @@ -20,6 +20,9 @@ import { import { assertThrows } from "@std/assert"; Deno.test("splitSelectors", () => { + assertEquals(splitSelectors("*"), ["*"]); + assertEquals(splitSelectors("*,*"), ["*", "*"]); + assertEquals(splitSelectors("*,* "), ["*", "*"]); assertEquals(splitSelectors("foo"), ["foo"]); assertEquals(splitSelectors("foo, bar"), ["foo", "bar"]); assertEquals(splitSelectors("foo:f(bar, baz)"), ["foo:f(bar, baz)"]); diff --git a/tests/unit/make_temp_test.ts b/tests/unit/make_temp_test.ts index 32383387b5..d22b633091 100644 --- a/tests/unit/make_temp_test.ts +++ b/tests/unit/make_temp_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, diff --git a/tests/unit/message_channel_test.ts b/tests/unit/message_channel_test.ts index 0fcbc5e95d..bf7bb6443a 100644 --- a/tests/unit/message_channel_test.ts +++ b/tests/unit/message_channel_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // NOTE: these are just sometests to test the TypeScript types. Real coverage is // provided by WPT. import { assert, assertEquals } from "@std/assert"; diff --git a/tests/unit/mkdir_test.ts b/tests/unit/mkdir_test.ts index def77cd3e4..7b71e4a799 100644 --- a/tests/unit/mkdir_test.ts +++ b/tests/unit/mkdir_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, diff --git a/tests/unit/navigator_test.ts b/tests/unit/navigator_test.ts index 5dcc423fa5..955c34dcc4 100644 --- a/tests/unit/navigator_test.ts +++ b/tests/unit/navigator_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert } from "./test_util.ts"; Deno.test(function navigatorNumCpus() { diff --git a/tests/unit/net_test.ts b/tests/unit/net_test.ts index cfa42b3d36..9c2819c30a 100644 --- a/tests/unit/net_test.ts +++ b/tests/unit/net_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, diff --git a/tests/unit/network_interfaces_test.ts b/tests/unit/network_interfaces_test.ts index 160efbfe60..675400365f 100644 --- a/tests/unit/network_interfaces_test.ts +++ b/tests/unit/network_interfaces_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert } from "./test_util.ts"; diff --git a/tests/unit/ops_test.ts b/tests/unit/ops_test.ts index 631e5c5736..60f67cdca6 100644 --- a/tests/unit/ops_test.ts +++ b/tests/unit/ops_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. const EXPECTED_OP_COUNT = 13; diff --git a/tests/unit/os_test.ts b/tests/unit/os_test.ts index a70796505f..36b6daad2f 100644 --- a/tests/unit/os_test.ts +++ b/tests/unit/os_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, diff --git a/tests/unit/path_from_url_test.ts b/tests/unit/path_from_url_test.ts index b3a6406bcb..3785f2bbb5 100644 --- a/tests/unit/path_from_url_test.ts +++ b/tests/unit/path_from_url_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertThrows } from "./test_util.ts"; diff --git a/tests/unit/performance_test.ts b/tests/unit/performance_test.ts index fa056c7f54..22f51a4ce6 100644 --- a/tests/unit/performance_test.ts +++ b/tests/unit/performance_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, diff --git a/tests/unit/permissions_test.ts b/tests/unit/permissions_test.ts index f981b10fd6..8bb1633423 100644 --- a/tests/unit/permissions_test.ts +++ b/tests/unit/permissions_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, diff --git a/tests/unit/process_test.ts b/tests/unit/process_test.ts index 5cbab3b4c5..17589d8581 100644 --- a/tests/unit/process_test.ts +++ b/tests/unit/process_test.ts @@ -1,5 +1,5 @@ // deno-lint-ignore-file no-deprecated-deno-api -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, diff --git a/tests/unit/progressevent_test.ts b/tests/unit/progressevent_test.ts index 809c2ad391..3e7aa9ec15 100644 --- a/tests/unit/progressevent_test.ts +++ b/tests/unit/progressevent_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals } from "./test_util.ts"; Deno.test(function progressEventConstruct() { diff --git a/tests/unit/promise_hooks_test.ts b/tests/unit/promise_hooks_test.ts index f7c44155d1..7fd7a8f51d 100644 --- a/tests/unit/promise_hooks_test.ts +++ b/tests/unit/promise_hooks_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals } from "./test_util.ts"; diff --git a/tests/unit/quic_test.ts b/tests/unit/quic_test.ts index f5423327de..f87a38cecc 100644 --- a/tests/unit/quic_test.ts +++ b/tests/unit/quic_test.ts @@ -1,28 +1,32 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -import { assertEquals } from "./test_util.ts"; +import { assert, assertEquals } from "./test_util.ts"; const cert = Deno.readTextFileSync("tests/testdata/tls/localhost.crt"); const key = Deno.readTextFileSync("tests/testdata/tls/localhost.key"); const caCerts = [Deno.readTextFileSync("tests/testdata/tls/RootCA.pem")]; -async function pair(opt?: Deno.QuicTransportOptions): Promise< - [Deno.QuicConn, Deno.QuicConn, Deno.QuicListener] -> { - const listener = await Deno.listenQuic({ - hostname: "localhost", - port: 0, +interface Pair { + server: Deno.QuicConn; + client: Deno.QuicConn; + endpoint: Deno.QuicEndpoint; +} + +async function pair(opt?: Deno.QuicTransportOptions): Promise { + const endpoint = new Deno.QuicEndpoint({ hostname: "localhost" }); + const listener = endpoint.listen({ cert, key, alpnProtocols: ["deno-test"], ...opt, }); + assertEquals(endpoint, listener.endpoint); const [server, client] = await Promise.all([ listener.accept(), Deno.connectQuic({ hostname: "localhost", - port: listener.addr.port, + port: endpoint.addr.port, caCerts, alpnProtocols: ["deno-test"], ...opt, @@ -31,13 +35,14 @@ async function pair(opt?: Deno.QuicTransportOptions): Promise< assertEquals(server.protocol, "deno-test"); assertEquals(client.protocol, "deno-test"); - assertEquals(client.remoteAddr, listener.addr); + assertEquals(client.remoteAddr, endpoint.addr); + assertEquals(server.serverName, "localhost"); - return [server, client, listener]; + return { server, client, endpoint }; } Deno.test("bidirectional stream", async () => { - const [server, client, listener] = await pair(); + const { server, client, endpoint } = await pair(); const encoded = (new TextEncoder()).encode("hi!"); @@ -57,12 +62,12 @@ Deno.test("bidirectional stream", async () => { assertEquals(data, encoded); } - listener.close({ closeCode: 0, reason: "" }); - client.close({ closeCode: 0, reason: "" }); + client.close(); + endpoint.close(); }); Deno.test("unidirectional stream", async () => { - const [server, client, listener] = await pair(); + const { server, client, endpoint } = await pair(); const encoded = (new TextEncoder()).encode("hi!"); @@ -82,12 +87,12 @@ Deno.test("unidirectional stream", async () => { assertEquals(data, encoded); } - listener.close({ closeCode: 0, reason: "" }); - client.close({ closeCode: 0, reason: "" }); + endpoint.close(); + client.close(); }); Deno.test("datagrams", async () => { - const [server, client, listener] = await pair(); + const { server, client, endpoint } = await pair(); const encoded = (new TextEncoder()).encode("hi!"); @@ -96,22 +101,20 @@ Deno.test("datagrams", async () => { const data = await client.readDatagram(); assertEquals(data, encoded); - listener.close({ closeCode: 0, reason: "" }); - client.close({ closeCode: 0, reason: "" }); + endpoint.close(); + client.close(); }); Deno.test("closing", async () => { - const [server, client, listener] = await pair(); + const { server, client } = await pair(); server.close({ closeCode: 42, reason: "hi!" }); assertEquals(await client.closed, { closeCode: 42, reason: "hi!" }); - - listener.close({ closeCode: 0, reason: "" }); }); Deno.test("max concurrent streams", async () => { - const [server, client, listener] = await pair({ + const { server, client, endpoint } = await pair({ maxConcurrentBidirectionalStreams: 1, maxConcurrentUnidirectionalStreams: 1, }); @@ -136,15 +139,13 @@ Deno.test("max concurrent streams", async () => { }); } - listener.close({ closeCode: 0, reason: "" }); - server.close({ closeCode: 0, reason: "" }); - client.close({ closeCode: 0, reason: "" }); + endpoint.close(); + client.close(); }); Deno.test("incoming", async () => { - const listener = await Deno.listenQuic({ - hostname: "localhost", - port: 0, + const endpoint = new Deno.QuicEndpoint({ hostname: "localhost" }); + const listener = endpoint.listen({ cert, key, alpnProtocols: ["deno-test"], @@ -153,7 +154,7 @@ Deno.test("incoming", async () => { const connect = () => Deno.connectQuic({ hostname: "localhost", - port: listener.addr.port, + port: endpoint.addr.port, caCerts, alpnProtocols: ["deno-test"], }); @@ -165,8 +166,63 @@ Deno.test("incoming", async () => { assertEquals(server.protocol, "deno-test"); assertEquals(client.protocol, "deno-test"); - assertEquals(client.remoteAddr, listener.addr); + assertEquals(client.remoteAddr, endpoint.addr); - listener.close({ closeCode: 0, reason: "" }); - client.close({ closeCode: 0, reason: "" }); + endpoint.close(); + client.close(); +}); + +Deno.test("0rtt", async () => { + const sEndpoint = new Deno.QuicEndpoint({ hostname: "localhost" }); + const listener = sEndpoint.listen({ + cert, + key, + alpnProtocols: ["deno-test"], + }); + + (async () => { + while (true) { + let incoming; + try { + incoming = await listener.incoming(); + } catch (e) { + if (e instanceof Deno.errors.BadResource) { + break; + } + throw e; + } + const conn = incoming.accept({ zeroRtt: true }); + conn.handshake.then(() => { + conn.close(); + }); + } + })(); + + const endpoint = new Deno.QuicEndpoint(); + + const c1 = await Deno.connectQuic({ + hostname: "localhost", + port: sEndpoint.addr.port, + caCerts, + alpnProtocols: ["deno-test"], + endpoint, + }); + + await c1.closed; + + const c2 = Deno.connectQuic({ + hostname: "localhost", + port: sEndpoint.addr.port, + caCerts, + alpnProtocols: ["deno-test"], + zeroRtt: true, + endpoint, + }); + + assert(!(c2 instanceof Promise), "0rtt should be accepted"); + + await c2.closed; + + sEndpoint.close(); + endpoint.close(); }); diff --git a/tests/unit/read_dir_test.ts b/tests/unit/read_dir_test.ts index b00495eb45..9c5e6da79f 100644 --- a/tests/unit/read_dir_test.ts +++ b/tests/unit/read_dir_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, diff --git a/tests/unit/read_file_test.ts b/tests/unit/read_file_test.ts index 7123833e9c..5716816b37 100644 --- a/tests/unit/read_file_test.ts +++ b/tests/unit/read_file_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, diff --git a/tests/unit/read_link_test.ts b/tests/unit/read_link_test.ts index c89ffe4927..7ecee2d567 100644 --- a/tests/unit/read_link_test.ts +++ b/tests/unit/read_link_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertRejects, diff --git a/tests/unit/read_text_file_test.ts b/tests/unit/read_text_file_test.ts index 1ec57bde35..39cd3e798c 100644 --- a/tests/unit/read_text_file_test.ts +++ b/tests/unit/read_text_file_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, diff --git a/tests/unit/real_path_test.ts b/tests/unit/real_path_test.ts index 7832846308..79dd0c084f 100644 --- a/tests/unit/real_path_test.ts +++ b/tests/unit/real_path_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, diff --git a/tests/unit/ref_unref_test.ts b/tests/unit/ref_unref_test.ts index 6f5bcf0a77..751f2af387 100644 --- a/tests/unit/ref_unref_test.ts +++ b/tests/unit/ref_unref_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertNotEquals, execCode } from "./test_util.ts"; diff --git a/tests/unit/remove_test.ts b/tests/unit/remove_test.ts index 261ff6bd05..38421f8610 100644 --- a/tests/unit/remove_test.ts +++ b/tests/unit/remove_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertRejects, assertThrows } from "./test_util.ts"; const REMOVE_METHODS = ["remove", "removeSync"] as const; diff --git a/tests/unit/rename_test.ts b/tests/unit/rename_test.ts index 3162c699c6..bacd54c675 100644 --- a/tests/unit/rename_test.ts +++ b/tests/unit/rename_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, diff --git a/tests/unit/request_test.ts b/tests/unit/request_test.ts index fe34c20a50..fa7619cd93 100644 --- a/tests/unit/request_test.ts +++ b/tests/unit/request_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertStringIncludes } from "./test_util.ts"; Deno.test(async function fromInit() { diff --git a/tests/unit/response_test.ts b/tests/unit/response_test.ts index bbdd5f481d..383790af3a 100644 --- a/tests/unit/response_test.ts +++ b/tests/unit/response_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, diff --git a/tests/unit/serve_test.ts b/tests/unit/serve_test.ts index f5896bc64b..09616b0151 100644 --- a/tests/unit/serve_test.ts +++ b/tests/unit/serve_test.ts @@ -1,8 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console -import { assertMatch, assertRejects } from "@std/assert"; +import { assertIsError, assertMatch, assertRejects } from "@std/assert"; import { Buffer, BufReader, BufWriter, type Reader } from "@std/io"; import { TextProtoReader } from "../testdata/run/textproto.ts"; import { @@ -387,7 +387,7 @@ Deno.test(async function httpServerCanResolveHostnames() { const ac = new AbortController(); const { promise, resolve } = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: (_req) => new Response("ok"), hostname: "localhost", port: servePort, @@ -410,7 +410,7 @@ Deno.test(async function httpServerRejectsOnAddrInUse() { const ac = new AbortController(); const { promise, resolve } = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: (_req) => new Response("ok"), hostname: "localhost", port: servePort, @@ -441,7 +441,7 @@ Deno.test({ permissions: { net: true } }, async function httpServerBasic() { const deferred = Promise.withResolvers(); const listeningDeferred = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (request, { remoteAddr }) => { // FIXME(bartlomieju): // make sure that request can be inspected @@ -483,7 +483,7 @@ Deno.test( const deferred = Promise.withResolvers(); const listeningDeferred = Promise.withResolvers(); const listener = Deno.listen({ port: servePort }); - const server = serveHttpOnListener( + await using server = serveHttpOnListener( listener, ac.signal, async ( @@ -532,7 +532,7 @@ Deno.test( headers: { "connection": "close" }, }); - const server = serveHttpOnConnection( + await using server = serveHttpOnConnection( await acceptPromise, ac.signal, async ( @@ -572,7 +572,7 @@ Deno.test({ permissions: { net: true } }, async function httpServerOnError() { const { promise, resolve } = Promise.withResolvers(); let requestStash: Request | null; - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (request: Request) => { requestStash = request; await new Promise((r) => setTimeout(r, 100)); @@ -607,7 +607,7 @@ Deno.test( // deno-lint-ignore no-unused-vars let requestStash: Request | null; - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (request: Request) => { requestStash = request; await new Promise((r) => setTimeout(r, 100)); @@ -640,7 +640,7 @@ Deno.test( const { promise, resolve } = Promise.withResolvers(); const response = new Response("Hello World"); let hadError = false; - const server = Deno.serve({ + await using server = Deno.serve({ handler: () => { return response; }, @@ -684,7 +684,7 @@ Deno.test( const ac = new AbortController(); const { promise, resolve } = Promise.withResolvers(); let hadError = false; - const server = Deno.serve({ + await using server = Deno.serve({ handler: () => { return Response.error(); }, @@ -717,7 +717,7 @@ Deno.test({ permissions: { net: true } }, async function httpServerOverload1() { const deferred = Promise.withResolvers(); const listeningDeferred = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ port: servePort, signal: ac.signal, onListen: onListen(listeningDeferred.resolve), @@ -752,7 +752,7 @@ Deno.test({ permissions: { net: true } }, async function httpServerOverload2() { const deferred = Promise.withResolvers(); const listeningDeferred = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ port: servePort, signal: ac.signal, onListen: onListen(listeningDeferred.resolve), @@ -807,7 +807,7 @@ Deno.test( Deno.test({ permissions: { net: true } }, async function httpServerPort0() { const ac = new AbortController(); - const server = Deno.serve({ + await using server = Deno.serve({ handler() { return new Response("Hello World"); }, @@ -841,7 +841,7 @@ Deno.test( }; try { - const server = Deno.serve({ + await using server = Deno.serve({ handler() { return new Response("Hello World"); }, @@ -866,7 +866,7 @@ Deno.test( const ac = new AbortController(); let headers: Headers; - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (request) => { await request.text(); headers = request.headers; @@ -896,7 +896,7 @@ Deno.test( ); Deno.test({ permissions: { net: true } }, async function validPortString() { - const server = Deno.serve({ + await using server = Deno.serve({ handler: (_request) => new Response(), port: "4501" as unknown as number, }); @@ -921,7 +921,7 @@ Deno.test({ permissions: { net: true } }, async function ipv6Hostname() { }; try { - const server = Deno.serve({ + await using server = Deno.serve({ handler: () => new Response(), hostname: "::1", port: 0, @@ -1017,7 +1017,7 @@ function createUrlTest( const listeningDeferred = Promise.withResolvers(); const urlDeferred = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: (request: Request) => { urlDeferred.resolve(request.url); return new Response(""); @@ -1117,7 +1117,7 @@ Deno.test( const ac = new AbortController(); const listeningDeferred = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: (request) => { assertEquals(request.body, null); deferred.resolve(); @@ -1157,7 +1157,7 @@ Deno.test( const ac = new AbortController(); const listeningDeferred = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (request) => { await assertRejects(async () => { await request.text(); @@ -1221,7 +1221,7 @@ function createStreamTest(count: number, delay: number, action: string) { Deno.test(`httpServerStreamCount${count}Delay${delay}${action}`, async () => { const ac = new AbortController(); const { promise, resolve } = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: (_request) => { return new Response(makeStream(count, delay)); }, @@ -1275,7 +1275,7 @@ Deno.test( writer.close(); const { promise, resolve } = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (request) => { const reqBody = await request.text(); assertEquals("hello world", reqBody); @@ -1303,7 +1303,7 @@ Deno.test( Deno.test({ permissions: { net: true } }, async function httpServerClose() { const ac = new AbortController(); const { promise, resolve } = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: () => new Response("ok"), port: servePort, signal: ac.signal, @@ -1323,7 +1323,7 @@ Deno.test({ permissions: { net: true } }, async function httpServerCloseGet() { const listeningDeferred = Promise.withResolvers(); const requestDeferred = Promise.withResolvers(); const responseDeferred = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: async () => { requestDeferred.resolve(); await new Promise((r) => setTimeout(r, 500)); @@ -1349,13 +1349,12 @@ Deno.test({ permissions: { net: true } }, async function httpServerCloseGet() { await server.finished; }); -// FIXME: Deno.test( { permissions: { net: true } }, async function httpServerEmptyBlobResponse() { const ac = new AbortController(); const { promise, resolve } = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: () => new Response(new Blob([])), port: servePort, signal: ac.signal, @@ -1380,7 +1379,7 @@ Deno.test( const ac = new AbortController(); const listeningDeferred = Promise.withResolvers(); const errorDeferred = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: () => { const body = new ReadableStream({ start(controller) { @@ -1421,7 +1420,7 @@ Deno.test( const ac = new AbortController(); const { promise, resolve } = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: () => new Response("韓國".repeat(10)), port: servePort, signal: ac.signal, @@ -1456,7 +1455,7 @@ Deno.test({ permissions: { net: true } }, async function httpServerWebSocket() { const ac = new AbortController(); const listeningDeferred = Promise.withResolvers(); const doneDeferred = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: (request) => { const { response, @@ -1501,7 +1500,7 @@ Deno.test( async function httpServerWebSocketRaw() { const ac = new AbortController(); const { promise, resolve } = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (request) => { const { conn, response } = upgradeHttpRaw(request); const buf = new Uint8Array(1024); @@ -1581,7 +1580,7 @@ Deno.test( const ac = new AbortController(); const done = Promise.withResolvers(); const listeningDeferred = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: (request) => { const { response, @@ -1635,7 +1634,7 @@ Deno.test( const ac = new AbortController(); const done = Promise.withResolvers(); const listeningDeferred = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: (request) => { const { response, @@ -1673,7 +1672,7 @@ Deno.test( const ac = new AbortController(); const done = Promise.withResolvers(); const listeningDeferred = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: (request) => { const { response, @@ -1723,7 +1722,7 @@ Deno.test( const ac = new AbortController(); let headers: Headers; - const server = Deno.serve({ + await using server = Deno.serve({ handler: (request) => { headers = request.headers; deferred.resolve(); @@ -1762,7 +1761,7 @@ Deno.test( let headers: Headers; let text: string; - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (request) => { headers = request.headers; text = await request.text(); @@ -1807,7 +1806,7 @@ Deno.test( const ac = new AbortController(); const listeningDeferred = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: () => { deferred.resolve(); return new Response(""); @@ -1858,7 +1857,7 @@ Deno.test( const { promise, resolve } = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve( + await using server = Deno.serve( { port: servePort, signal: ac.signal }, (request: Request) => { assert(request.body); @@ -1889,7 +1888,7 @@ Deno.test( const { promise, resolve } = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve( + await using server = Deno.serve( { port: servePort, signal: ac.signal }, (request: Request) => { assert(request.body); @@ -2005,7 +2004,7 @@ Deno.test( }).pipeThrough(new TextEncoderStream()); } - const server = Deno.serve({ + await using server = Deno.serve({ handler: () => { deferred.resolve(); return new Response(periodicStream()); @@ -2037,7 +2036,7 @@ Deno.test( { permissions: { net: true } }, async function httpLargeReadableStreamChunk() { const ac = new AbortController(); - const server = Deno.serve({ + await using server = Deno.serve({ handler() { return new Response( new ReadableStream({ @@ -2077,7 +2076,7 @@ Deno.test( const listeningDeferred = Promise.withResolvers(); const deferred = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: (request) => { assertEquals(request.headers.get("X-Header-Test"), "á"); deferred.resolve(); @@ -2123,7 +2122,7 @@ Deno.test( const listeningDeferred = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (request) => { // FIXME: // assertEquals(new URL(request.url).href, `http://127.0.0.1:${servePort}/`); @@ -2177,7 +2176,7 @@ Deno.test( const listeningDeferred = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (request) => { assertEquals(await request.text(), ""); assertEquals(request.headers.get("cookie"), "foo=bar; bar=foo"); @@ -2221,7 +2220,7 @@ Deno.test( const hostname = "localhost"; - const server = Deno.serve({ + await using server = Deno.serve({ handler: () => { deferred.resolve(); return new Response("ok"); @@ -2256,7 +2255,7 @@ Deno.test( const listeningDeferred = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: (request) => { assertEquals(request.body, null); deferred.resolve(); @@ -2292,7 +2291,7 @@ Deno.test( const listeningDeferred = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: (request) => { assertEquals(request.method, "GET"); assertEquals(request.headers.get("host"), "deno.land"); @@ -2326,7 +2325,7 @@ Deno.test( const listeningDeferred = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: (request) => { assertEquals(request.method, "GET"); assertEquals(request.headers.get("server"), "hello\tworld"); @@ -2360,7 +2359,7 @@ Deno.test( const listeningDeferred = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (request) => { assertEquals(request.method, "GET"); assertEquals(await request.text(), ""); @@ -2396,7 +2395,7 @@ Deno.test( const listeningDeferred = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (request) => { assertEquals(request.method, "POST"); assertEquals(await request.text(), "I'm a good request."); @@ -2443,7 +2442,7 @@ function createServerLengthTest(name: string, testCase: TestCase) { const listeningDeferred = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: (request) => { assertEquals(request.method, "GET"); deferred.resolve(); @@ -2575,7 +2574,7 @@ Deno.test( const listeningDeferred = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (request) => { assertEquals(request.method, "POST"); assertEquals(request.headers.get("content-length"), "5"); @@ -2611,7 +2610,7 @@ Deno.test( async function httpServerPostWithInvalidPrefixContentLength() { const ac = new AbortController(); const { promise, resolve } = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: () => { throw new Error("unreachable"); }, @@ -2651,7 +2650,7 @@ Deno.test( const listeningDeferred = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (request) => { assertEquals(request.method, "POST"); assertEquals(await request.text(), "qwert"); @@ -2688,7 +2687,7 @@ Deno.test( const listeningDeferred = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (r) => { deferred.resolve(); assertEquals(await r.text(), "12345"); @@ -2724,7 +2723,7 @@ Deno.test( const listeningDeferred = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: () => { deferred.resolve(); return new Response("NaN".repeat(100)); @@ -2867,7 +2866,7 @@ for (const testCase of compressionTestCases) { const deferred = Promise.withResolvers(); const listeningDeferred = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (_request) => { const f = await makeTempFile(testCase.length); deferred.resolve(); @@ -2923,7 +2922,7 @@ Deno.test( const listeningDeferred = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (request) => { assertEquals( await request.bytes(), @@ -2971,7 +2970,7 @@ for (const delay of ["delay", "nodelay"]) { const listeningDeferred = Promise.withResolvers(); const waitForAbort = Promise.withResolvers(); const waitForRequest = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ port: servePort, signal: ac.signal, onListen: onListen(listeningDeferred.resolve), @@ -3121,7 +3120,7 @@ Deno.test( const { promise, resolve } = Promise.withResolvers(); const hostname = "127.0.0.1"; - const server = Deno.serve({ + await using server = Deno.serve({ handler: () => new Response("Hello World"), hostname, port: servePort, @@ -3151,7 +3150,7 @@ Deno.test( const { promise, resolve } = Promise.withResolvers(); const hostname = "127.0.0.1"; - const server = Deno.serve({ + await using server = Deno.serve({ handler: () => new Response("Hello World"), hostname, port: servePort, @@ -3186,7 +3185,7 @@ Deno.test( const listeningDeferred = Promise.withResolvers(); const deferred = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (req) => { assertEquals(await req.text(), ""); deferred.resolve(); @@ -3221,7 +3220,7 @@ Deno.test( const ac = new AbortController(); const { promise, resolve } = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: () => { throw new Error("oops"); }, @@ -3268,7 +3267,7 @@ Deno.test( async function httpServer204ResponseDoesntSendContentLength() { const { promise, resolve } = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: (_request) => new Response(null, { status: 204 }), port: servePort, signal: ac.signal, @@ -3298,7 +3297,7 @@ Deno.test( const ac = new AbortController(); const listeningDeferred = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: () => { deferred.resolve(); return new Response(null, { status: 304 }); @@ -3343,7 +3342,7 @@ Deno.test( const ac = new AbortController(); const listeningDeferred = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (req) => { deferred.resolve(); assertEquals(await req.text(), "hello"); @@ -3404,7 +3403,7 @@ Deno.test( const listeningDeferred = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (req) => { deferred.resolve(); assertEquals(await req.text(), ""); @@ -3458,7 +3457,7 @@ for (const [name, req] of badRequests) { const ac = new AbortController(); const { promise, resolve } = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: () => { throw new Error("oops"); }, @@ -3505,7 +3504,7 @@ Deno.test( let reqCount = -1; let timerId: number | undefined; - const server = Deno.serve({ + await using server = Deno.serve({ handler: (_req) => { reqCount++; if (reqCount === 0) { @@ -3600,7 +3599,7 @@ Deno.test( const ac = new AbortController(); const { promise, resolve } = Promise.withResolvers(); let count = 0; - const server = Deno.serve({ + await using server = Deno.serve({ async onListen({ port }: { port: number }) { const res1 = await fetch(`http://localhost:${port}/`); assertEquals(await res1.text(), "hello world 1"); @@ -3630,7 +3629,7 @@ Deno.test( const ac = new AbortController(); const { promise, resolve } = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (req) => { const cloned = req.clone(); assertEquals(req.headers, cloned.headers); @@ -3684,7 +3683,7 @@ Deno.test( const ac = new AbortController(); const { promise, resolve } = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (req) => { await req.text(); @@ -3733,7 +3732,7 @@ Deno.test({ const ac = new AbortController(); const { promise, resolve } = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: async (req) => { const _reader = req.body?.getReader(); @@ -3780,7 +3779,7 @@ Deno.test( async function testIssue16567() { const ac = new AbortController(); const { promise, resolve } = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ async onListen({ port }) { const res1 = await fetch(`http://localhost:${port}/`); assertEquals((await res1.text()).length, 40 * 50_000); @@ -3947,7 +3946,7 @@ Deno.test( }, async function httpServeCurlH2C() { const ac = new AbortController(); - const server = Deno.serve( + await using server = Deno.serve( { port: servePort, signal: ac.signal }, () => new Response("hello world!"), ); @@ -3982,7 +3981,7 @@ Deno.test( const ac = new AbortController(); const { resolve } = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: () => { const response = new Response("Hello World", { headers: { @@ -4025,7 +4024,7 @@ Deno.test( }, async function httpsServeCurlH2C() { const ac = new AbortController(); - const server = Deno.serve( + await using server = Deno.serve( { signal: ac.signal, port: servePort, @@ -4082,7 +4081,7 @@ Deno.test( const { promise, resolve } = Promise.withResolvers(); const ac = new AbortController(); const filePath = tmpUnixSocketPath(); - const server = Deno.serve( + await using server = Deno.serve( { signal: ac.signal, path: filePath, @@ -4115,7 +4114,7 @@ Deno.test( const listeningDeferred = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve( + await using server = Deno.serve( { port: servePort, onListen: onListen(listeningDeferred.resolve), @@ -4151,7 +4150,7 @@ Deno.test( const { promise, resolve } = Promise.withResolvers(); const ac = new AbortController(); - const server = Deno.serve( + await using server = Deno.serve( { port: servePort, onListen: onListen(resolve), @@ -4187,7 +4186,7 @@ Deno.test( let timer: number | undefined = undefined; let _controller; - const server = Deno.serve( + await using server = Deno.serve( { port: servePort, onListen: onListen(resolve), @@ -4237,7 +4236,7 @@ Deno.test({ await assertRejects( async () => { const ac = new AbortController(); - const server = Deno.serve({ + await using server = Deno.serve({ path: "path/to/socket", handler: (_req) => new Response("Hello, world"), signal: ac.signal, @@ -4260,7 +4259,7 @@ Deno.test({ }, async () => { const { promise, resolve } = Promise.withResolvers<{ hostname: string }>(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: (_) => new Response("ok"), hostname: "0.0.0.0", port: 0, @@ -4278,7 +4277,7 @@ Deno.test({ let cancelled = false; - const server = Deno.serve({ + await using server = Deno.serve({ hostname: "0.0.0.0", port: servePort, onListen: () => resolve(), @@ -4305,7 +4304,7 @@ Deno.test({ }, async () => { const { promise, resolve } = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ hostname: "0.0.0.0", port: servePort, onListen: () => resolve(), @@ -4335,7 +4334,7 @@ Deno.test( const ac = new AbortController(); const listeningDeferred = Promise.withResolvers(); const doneDeferred = Promise.withResolvers(); - const server = Deno.serve({ + await using server = Deno.serve({ handler: (request) => { const { response, @@ -4379,3 +4378,46 @@ Deno.test( await server.finished; }, ); + +Deno.test({ + name: + "req.body.getReader().read() throws the error with reasonable error message", +}, async () => { + const { promise, resolve, reject } = Promise.withResolvers(); + const server = Deno.serve({ onListen, port: 0 }, async (req) => { + const reader = req.body!.getReader(); + + try { + while (true) { + const { done } = await reader.read(); + if (done) break; + } + } catch (e) { + // deno-lint-ignore no-explicit-any + resolve(e as any); + } + + reject(new Error("Should not reach here")); + server.shutdown(); + return new Response(); + }); + + async function onListen({ port }: { port: number }) { + const body = "a".repeat(1000); + const request = `POST / HTTP/1.1\r\n` + + `Host: 127.0.0.1:${port}\r\n` + + `Content-Length: 1000\r\n` + + "\r\n" + body; + + const connection = await Deno.connect({ hostname: "127.0.0.1", port }); + await connection.write(new TextEncoder().encode(request)); + connection.close(); + } + await server.finished; + const e = await promise; + assertIsError( + e, + Deno.errors.BadResource, + "Cannot read request body as underlying resource unavailable", + ); +}); diff --git a/tests/unit/signal_test.ts b/tests/unit/signal_test.ts index 8923aa75bf..bfaa9aac90 100644 --- a/tests/unit/signal_test.ts +++ b/tests/unit/signal_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertThrows, delay } from "./test_util.ts"; Deno.test( diff --git a/tests/unit/stat_test.ts b/tests/unit/stat_test.ts index 0609035b41..0f10f6e2d6 100644 --- a/tests/unit/stat_test.ts +++ b/tests/unit/stat_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, diff --git a/tests/unit/stdio_test.ts b/tests/unit/stdio_test.ts index d24fdc8efa..c605ccb9ad 100644 --- a/tests/unit/stdio_test.ts +++ b/tests/unit/stdio_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals } from "./test_util.ts"; Deno.test(async function stdioStdinRead() { diff --git a/tests/unit/streams_test.ts b/tests/unit/streams_test.ts index 53225a1553..84a87d166d 100644 --- a/tests/unit/streams_test.ts +++ b/tests/unit/streams_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertRejects, diff --git a/tests/unit/structured_clone_test.ts b/tests/unit/structured_clone_test.ts index 6e0473f9a9..fc5d68e9da 100644 --- a/tests/unit/structured_clone_test.ts +++ b/tests/unit/structured_clone_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, assertThrows } from "./test_util.ts"; diff --git a/tests/unit/symbol_test.ts b/tests/unit/symbol_test.ts index 54db7f5bae..2dca022b14 100644 --- a/tests/unit/symbol_test.ts +++ b/tests/unit/symbol_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert } from "./test_util.ts"; // Test that `Symbol.metadata` is defined. This file can be removed when V8 diff --git a/tests/unit/symlink_test.ts b/tests/unit/symlink_test.ts index 47a685ec61..cdf0ea5bbd 100644 --- a/tests/unit/symlink_test.ts +++ b/tests/unit/symlink_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertRejects, diff --git a/tests/unit/test_util.ts b/tests/unit/test_util.ts index a987cb5427..6e7865ea7a 100644 --- a/tests/unit/test_util.ts +++ b/tests/unit/test_util.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import * as colors from "@std/fmt/colors"; import { assert } from "@std/assert"; diff --git a/tests/unit/testing_test.ts b/tests/unit/testing_test.ts index 51372c42b0..96104df9c4 100644 --- a/tests/unit/testing_test.ts +++ b/tests/unit/testing_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertRejects, assertThrows } from "./test_util.ts"; Deno.test(function testWrongOverloads() { diff --git a/tests/unit/text_encoding_test.ts b/tests/unit/text_encoding_test.ts index 719e5907e4..1f378b2125 100644 --- a/tests/unit/text_encoding_test.ts +++ b/tests/unit/text_encoding_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, diff --git a/tests/unit/timers_test.ts b/tests/unit/timers_test.ts index 580d8c524e..29d338c761 100644 --- a/tests/unit/timers_test.ts +++ b/tests/unit/timers_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console diff --git a/tests/unit/tls_sni_test.ts b/tests/unit/tls_sni_test.ts index a8d51108e7..3874753ded 100644 --- a/tests/unit/tls_sni_test.ts +++ b/tests/unit/tls_sni_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertRejects } from "./test_util.ts"; // @ts-expect-error TypeScript (as of 3.7) does not support indexing namespaces by symbol const { resolverSymbol, serverNameSymbol } = Deno[Deno.internal]; diff --git a/tests/unit/tls_test.ts b/tests/unit/tls_test.ts index 219f4a4508..53db347a13 100644 --- a/tests/unit/tls_test.ts +++ b/tests/unit/tls_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, diff --git a/tests/unit/truncate_test.ts b/tests/unit/truncate_test.ts index cebd6e8ee1..ae41b82271 100644 --- a/tests/unit/truncate_test.ts +++ b/tests/unit/truncate_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertRejects, assertThrows } from "./test_util.ts"; Deno.test( diff --git a/tests/unit/tty_color_test.ts b/tests/unit/tty_color_test.ts index 6f26891e37..a1ca43951c 100644 --- a/tests/unit/tty_color_test.ts +++ b/tests/unit/tty_color_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals } from "./test_util.ts"; // Note tests for Deno.stdin.setRaw is in integration tests. diff --git a/tests/unit/tty_test.ts b/tests/unit/tty_test.ts index 1d29a0b706..352c313b43 100644 --- a/tests/unit/tty_test.ts +++ b/tests/unit/tty_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-deprecated-deno-api diff --git a/tests/unit/umask_test.ts b/tests/unit/umask_test.ts index 0e97f0d353..c7cdd68e4c 100644 --- a/tests/unit/umask_test.ts +++ b/tests/unit/umask_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals } from "./test_util.ts"; Deno.test( diff --git a/tests/unit/url_search_params_test.ts b/tests/unit/url_search_params_test.ts index d682c291a9..9846c7a91c 100644 --- a/tests/unit/url_search_params_test.ts +++ b/tests/unit/url_search_params_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals } from "./test_util.ts"; Deno.test(function urlSearchParamsWithMultipleSpaces() { diff --git a/tests/unit/url_test.ts b/tests/unit/url_test.ts index b0dc86232b..5643fbd258 100644 --- a/tests/unit/url_test.ts +++ b/tests/unit/url_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, diff --git a/tests/unit/urlpattern_test.ts b/tests/unit/urlpattern_test.ts index 3c1fb0cf19..4d815cd042 100644 --- a/tests/unit/urlpattern_test.ts +++ b/tests/unit/urlpattern_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals } from "./test_util.ts"; import { assertType, IsExact } from "@std/testing/types"; diff --git a/tests/unit/utime_test.ts b/tests/unit/utime_test.ts index 7a1fee74eb..5669499aaf 100644 --- a/tests/unit/utime_test.ts +++ b/tests/unit/utime_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, diff --git a/tests/unit/version_test.ts b/tests/unit/version_test.ts index 307295ad87..fd570fb16d 100644 --- a/tests/unit/version_test.ts +++ b/tests/unit/version_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals } from "./test_util.ts"; diff --git a/tests/unit/wasm_test.ts b/tests/unit/wasm_test.ts index 8ee9392f93..80bc468f7d 100644 --- a/tests/unit/wasm_test.ts +++ b/tests/unit/wasm_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, assertRejects } from "./test_util.ts"; diff --git a/tests/unit/webcrypto_test.ts b/tests/unit/webcrypto_test.ts index 09552a0587..bc5b307de5 100644 --- a/tests/unit/webcrypto_test.ts +++ b/tests/unit/webcrypto_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, diff --git a/tests/unit/webgpu_test.ts b/tests/unit/webgpu_test.ts index aac75d3420..f7bfc0bbc2 100644 --- a/tests/unit/webgpu_test.ts +++ b/tests/unit/webgpu_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, assertThrows } from "./test_util.ts"; diff --git a/tests/unit/websocket_test.ts b/tests/unit/websocket_test.ts index d9878828db..e5e4b1a7a7 100644 --- a/tests/unit/websocket_test.ts +++ b/tests/unit/websocket_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, assertThrows, fail } from "./test_util.ts"; const servePort = 4248; @@ -262,7 +262,7 @@ Deno.test({ socket.onopen = () => socket.send("Hello"); socket.onmessage = () => { socket.send("Bye"); - socket.close(); + socket.close(1000); }; socket.onclose = () => ac.abort(); socket.onerror = () => fail(); @@ -288,7 +288,8 @@ Deno.test({ seenBye = true; } }; - ws.onclose = () => { + ws.onclose = (e) => { + assertEquals(e.code, 1000); deferred.resolve(); }; await Promise.all([deferred.promise, server.finished]); diff --git a/tests/unit/websocketstream_test.ts.disabled b/tests/unit/websocketstream_test.ts.disabled index 4f8c321c92..7a64318d47 100644 --- a/tests/unit/websocketstream_test.ts.disabled +++ b/tests/unit/websocketstream_test.ts.disabled @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, diff --git a/tests/unit/webstorage_test.ts b/tests/unit/webstorage_test.ts index aa832b1c4b..1c2f9cfa34 100644 --- a/tests/unit/webstorage_test.ts +++ b/tests/unit/webstorage_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-explicit-any import { assert, assertEquals, assertThrows } from "./test_util.ts"; diff --git a/tests/unit/worker_permissions_test.ts b/tests/unit/worker_permissions_test.ts index 28bf9f92af..20736357f5 100644 --- a/tests/unit/worker_permissions_test.ts +++ b/tests/unit/worker_permissions_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals } from "./test_util.ts"; Deno.test( diff --git a/tests/unit/worker_test.ts b/tests/unit/worker_test.ts index 42c257282c..c0777bb78b 100644 --- a/tests/unit/worker_test.ts +++ b/tests/unit/worker_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console diff --git a/tests/unit/write_file_test.ts b/tests/unit/write_file_test.ts index 15e462cca9..53a5434e04 100644 --- a/tests/unit/write_file_test.ts +++ b/tests/unit/write_file_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, diff --git a/tests/unit/write_text_file_test.ts b/tests/unit/write_text_file_test.ts index 9e1b75326b..f8209250a1 100644 --- a/tests/unit/write_text_file_test.ts +++ b/tests/unit/write_text_file_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, diff --git a/tests/unit_node/_fs/_fs_access_test.ts b/tests/unit_node/_fs/_fs_access_test.ts index 0881769f2c..1333d9b7c8 100644 --- a/tests/unit_node/_fs/_fs_access_test.ts +++ b/tests/unit_node/_fs/_fs_access_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import * as fs from "node:fs"; import { assertRejects, assertThrows } from "@std/assert"; diff --git a/tests/unit_node/_fs/_fs_appendFile_test.ts b/tests/unit_node/_fs/_fs_appendFile_test.ts index 5ee8eabed4..d6f45786cb 100644 --- a/tests/unit_node/_fs/_fs_appendFile_test.ts +++ b/tests/unit_node/_fs/_fs_appendFile_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertThrows, fail } from "@std/assert"; import { appendFile, appendFileSync } from "node:fs"; import { fromFileUrl } from "@std/path"; diff --git a/tests/unit_node/_fs/_fs_chmod_test.ts b/tests/unit_node/_fs/_fs_chmod_test.ts index 97dc9ecdda..db097397e2 100644 --- a/tests/unit_node/_fs/_fs_chmod_test.ts +++ b/tests/unit_node/_fs/_fs_chmod_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertRejects, assertThrows, fail } from "@std/assert"; import { assertCallbackErrorUncaught } from "../_test_utils.ts"; import { chmod, chmodSync } from "node:fs"; diff --git a/tests/unit_node/_fs/_fs_chown_test.ts b/tests/unit_node/_fs/_fs_chown_test.ts index 6cb2f576ad..d9e6870ac6 100644 --- a/tests/unit_node/_fs/_fs_chown_test.ts +++ b/tests/unit_node/_fs/_fs_chown_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, fail } from "@std/assert"; import { assertCallbackErrorUncaught } from "../_test_utils.ts"; import { chown, chownSync } from "node:fs"; diff --git a/tests/unit_node/_fs/_fs_close_test.ts b/tests/unit_node/_fs/_fs_close_test.ts index 8880bc0461..62f2d4f05e 100644 --- a/tests/unit_node/_fs/_fs_close_test.ts +++ b/tests/unit_node/_fs/_fs_close_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertThrows, fail } from "@std/assert"; import { assertCallbackErrorUncaught } from "../_test_utils.ts"; import { close, closeSync } from "node:fs"; diff --git a/tests/unit_node/_fs/_fs_copy_test.ts b/tests/unit_node/_fs/_fs_copy_test.ts index 22f30ea373..b52f1951c6 100644 --- a/tests/unit_node/_fs/_fs_copy_test.ts +++ b/tests/unit_node/_fs/_fs_copy_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import * as path from "@std/path"; import { assert } from "@std/assert"; import { assertCallbackErrorUncaught } from "../_test_utils.ts"; diff --git a/tests/unit_node/_fs/_fs_dir_test.ts b/tests/unit_node/_fs/_fs_dir_test.ts index 0f41543e92..7da76e50fb 100644 --- a/tests/unit_node/_fs/_fs_dir_test.ts +++ b/tests/unit_node/_fs/_fs_dir_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, fail } from "@std/assert"; import { assertCallbackErrorUncaught } from "../_test_utils.ts"; import { Dir as DirOrig, type Dirent } from "node:fs"; diff --git a/tests/unit_node/_fs/_fs_dirent_test.ts b/tests/unit_node/_fs/_fs_dirent_test.ts index 093617fafd..a709163f4a 100644 --- a/tests/unit_node/_fs/_fs_dirent_test.ts +++ b/tests/unit_node/_fs/_fs_dirent_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, assertThrows } from "@std/assert"; import { Dirent as Dirent_ } from "node:fs"; diff --git a/tests/unit_node/_fs/_fs_exists_test.ts b/tests/unit_node/_fs/_fs_exists_test.ts index 7ed7584ae6..3de7afdc18 100644 --- a/tests/unit_node/_fs/_fs_exists_test.ts +++ b/tests/unit_node/_fs/_fs_exists_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, assertStringIncludes } from "@std/assert"; import { exists, existsSync } from "node:fs"; import { promisify } from "node:util"; diff --git a/tests/unit_node/_fs/_fs_fdatasync_test.ts b/tests/unit_node/_fs/_fs_fdatasync_test.ts index 40ca2969f9..59c2b5657f 100644 --- a/tests/unit_node/_fs/_fs_fdatasync_test.ts +++ b/tests/unit_node/_fs/_fs_fdatasync_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, fail } from "@std/assert"; import { fdatasync, fdatasyncSync } from "node:fs"; diff --git a/tests/unit_node/_fs/_fs_fstat_test.ts b/tests/unit_node/_fs/_fs_fstat_test.ts index afcac836f6..79e5106525 100644 --- a/tests/unit_node/_fs/_fs_fstat_test.ts +++ b/tests/unit_node/_fs/_fs_fstat_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { fstat, fstatSync } from "node:fs"; import { fail } from "@std/assert"; diff --git a/tests/unit_node/_fs/_fs_fsync_test.ts b/tests/unit_node/_fs/_fs_fsync_test.ts index 3c1509410e..cd01786a2f 100644 --- a/tests/unit_node/_fs/_fs_fsync_test.ts +++ b/tests/unit_node/_fs/_fs_fsync_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, fail } from "@std/assert"; import { fsync, fsyncSync } from "node:fs"; diff --git a/tests/unit_node/_fs/_fs_ftruncate_test.ts b/tests/unit_node/_fs/_fs_ftruncate_test.ts index 974f8f168e..b51ac6c2ca 100644 --- a/tests/unit_node/_fs/_fs_ftruncate_test.ts +++ b/tests/unit_node/_fs/_fs_ftruncate_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertThrows, fail } from "@std/assert"; import { ftruncate, ftruncateSync } from "node:fs"; diff --git a/tests/unit_node/_fs/_fs_futimes_test.ts b/tests/unit_node/_fs/_fs_futimes_test.ts index 9b0c64efd6..207610abed 100644 --- a/tests/unit_node/_fs/_fs_futimes_test.ts +++ b/tests/unit_node/_fs/_fs_futimes_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertThrows, fail } from "@std/assert"; import { futimes, futimesSync } from "node:fs"; diff --git a/tests/unit_node/_fs/_fs_handle_test.ts b/tests/unit_node/_fs/_fs_handle_test.ts index 84d72c0745..d7ae32b5ea 100644 --- a/tests/unit_node/_fs/_fs_handle_test.ts +++ b/tests/unit_node/_fs/_fs_handle_test.ts @@ -1,8 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import * as path from "@std/path"; import { Buffer } from "node:buffer"; import * as fs from "node:fs/promises"; -import { assert, assertEquals } from "@std/assert"; +import { assert, assertEquals, assertRejects } from "@std/assert"; const moduleDir = path.dirname(path.fromFileUrl(import.meta.url)); const testData = path.resolve(moduleDir, "testdata", "hello.txt"); @@ -118,6 +118,45 @@ Deno.test("[node/fs filehandle.writeFile] Write to file", async function () { assertEquals(decoder.decode(data), "hello world"); }); +Deno.test( + "[node/fs filehandle.writev] Write array of buffers to file", + async function () { + const tempFile: string = await Deno.makeTempFile(); + const fileHandle = await fs.open(tempFile, "w"); + + const buffer1 = Buffer.from("hello "); + const buffer2 = Buffer.from("world"); + const res = await fileHandle.writev([buffer1, buffer2]); + + const data = Deno.readFileSync(tempFile); + await Deno.remove(tempFile); + await fileHandle.close(); + + assertEquals(res.bytesWritten, 11); + assertEquals(decoder.decode(data), "hello world"); + }, +); + +Deno.test( + "[node/fs filehandle.writev] Write array of buffers to file with position", + async function () { + const tempFile: string = await Deno.makeTempFile(); + const fileHandle = await fs.open(tempFile, "w"); + + const buffer1 = Buffer.from("hello "); + const buffer2 = Buffer.from("world"); + await fileHandle.writev([buffer1, buffer2], 0); + const buffer3 = Buffer.from("lorem ipsum"); + await fileHandle.writev([buffer3], 6); + + const data = Deno.readFileSync(tempFile); + await Deno.remove(tempFile); + await fileHandle.close(); + + assertEquals(decoder.decode(data), "hello lorem ipsum"); + }, +); + Deno.test( "[node/fs filehandle.truncate] Truncate file with length", async function () { @@ -199,3 +238,65 @@ Deno.test( assertEquals(data.length, 0); }, ); + +Deno.test({ + name: "[node/fs filehandle.chmod] Change the permissions of the file", + ignore: Deno.build.os === "windows", + async fn() { + const fileHandle = await fs.open(testData); + + const readOnly = 0o444; + await fileHandle.chmod(readOnly.toString(8)); + assertEquals(Deno.statSync(testData).mode! & 0o777, readOnly); + + const readWrite = 0o666; + await fileHandle.chmod(readWrite.toString(8)); + assertEquals(Deno.statSync(testData).mode! & 0o777, readWrite); + + await fileHandle.close(); + }, +}); + +Deno.test({ + name: + "[node/fs filehandle.utimes] Change the file system timestamps of the file", + async fn() { + const fileHandle = await fs.open(testData); + + const atime = new Date(); + const mtime = new Date(0); + + await fileHandle.utimes(atime, mtime); + assertEquals(Deno.statSync(testData).atime!, atime); + assertEquals(Deno.statSync(testData).mtime!, mtime); + + await fileHandle.close(); + }, +}); + +Deno.test({ + name: "[node/fs filehandle.chown] Change owner of the file", + ignore: Deno.build.os === "windows", + async fn() { + const fileHandle = await fs.open(testData); + + const nobodyUid = 65534; + const nobodyGid = 65534; + + await assertRejects( + async () => await fileHandle.chown(nobodyUid, nobodyGid), + Deno.errors.PermissionDenied, + "Operation not permitted", + ); + + const realUid = Deno.uid() || 1000; + const realGid = Deno.gid() || 1000; + + await fileHandle.chown(realUid, realGid); + + assertEquals(Deno.statSync(testData).uid, realUid); + assertEquals(Deno.statSync(testData).gid, realGid); + + await fileHandle.close(); + }, +}); diff --git a/tests/unit_node/_fs/_fs_link_test.ts b/tests/unit_node/_fs/_fs_link_test.ts index 3062db7a67..fca1dfe869 100644 --- a/tests/unit_node/_fs/_fs_link_test.ts +++ b/tests/unit_node/_fs/_fs_link_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import * as path from "@std/path"; import { assert, assertEquals, fail } from "@std/assert"; import { assertCallbackErrorUncaught } from "../_test_utils.ts"; diff --git a/tests/unit_node/_fs/_fs_lstat_test.ts b/tests/unit_node/_fs/_fs_lstat_test.ts index 6a42443452..196d5f23b7 100644 --- a/tests/unit_node/_fs/_fs_lstat_test.ts +++ b/tests/unit_node/_fs/_fs_lstat_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { lstat, lstatSync } from "node:fs"; import { fail } from "@std/assert"; import { assertCallbackErrorUncaught } from "../_test_utils.ts"; diff --git a/tests/unit_node/_fs/_fs_mkdir_test.ts b/tests/unit_node/_fs/_fs_mkdir_test.ts index b9f6adf44c..d3476a23a7 100644 --- a/tests/unit_node/_fs/_fs_mkdir_test.ts +++ b/tests/unit_node/_fs/_fs_mkdir_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import * as path from "@std/path"; import { assert } from "@std/assert"; import { assertCallbackErrorUncaught } from "../_test_utils.ts"; diff --git a/tests/unit_node/_fs/_fs_mkdtemp_test.ts b/tests/unit_node/_fs/_fs_mkdtemp_test.ts index 47530b495a..4e130d4b9d 100644 --- a/tests/unit_node/_fs/_fs_mkdtemp_test.ts +++ b/tests/unit_node/_fs/_fs_mkdtemp_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertRejects, assertThrows } from "@std/assert"; import { EncodingOption, existsSync, mkdtemp, mkdtempSync } from "node:fs"; import { env } from "node:process"; diff --git a/tests/unit_node/_fs/_fs_open_test.ts b/tests/unit_node/_fs/_fs_open_test.ts index b4679cbab6..cd8cdf791b 100644 --- a/tests/unit_node/_fs/_fs_open_test.ts +++ b/tests/unit_node/_fs/_fs_open_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { O_APPEND, O_CREAT, diff --git a/tests/unit_node/_fs/_fs_opendir_test.ts b/tests/unit_node/_fs/_fs_opendir_test.ts index e22a47a702..37200d364f 100644 --- a/tests/unit_node/_fs/_fs_opendir_test.ts +++ b/tests/unit_node/_fs/_fs_opendir_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, diff --git a/tests/unit_node/_fs/_fs_readFile_test.ts b/tests/unit_node/_fs/_fs_readFile_test.ts index a75f12d1f6..0903777bca 100644 --- a/tests/unit_node/_fs/_fs_readFile_test.ts +++ b/tests/unit_node/_fs/_fs_readFile_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertCallbackErrorUncaught } from "../_test_utils.ts"; import { promises, readFile, readFileSync } from "node:fs"; import * as path from "@std/path"; diff --git a/tests/unit_node/_fs/_fs_read_test.ts b/tests/unit_node/_fs/_fs_read_test.ts index 867ec01c5c..6def1ff71d 100644 --- a/tests/unit_node/_fs/_fs_read_test.ts +++ b/tests/unit_node/_fs/_fs_read_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// import { assert, diff --git a/tests/unit_node/_fs/_fs_readdir_test.ts b/tests/unit_node/_fs/_fs_readdir_test.ts index 3e36b1dc2d..b5071b5777 100644 --- a/tests/unit_node/_fs/_fs_readdir_test.ts +++ b/tests/unit_node/_fs/_fs_readdir_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertNotEquals, fail } from "@std/assert"; import { assertCallbackErrorUncaught } from "../_test_utils.ts"; import { readdir, readdirSync } from "node:fs"; diff --git a/tests/unit_node/_fs/_fs_readlink_test.ts b/tests/unit_node/_fs/_fs_readlink_test.ts index 23c5e3896e..9443f2903f 100644 --- a/tests/unit_node/_fs/_fs_readlink_test.ts +++ b/tests/unit_node/_fs/_fs_readlink_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertCallbackErrorUncaught } from "../_test_utils.ts"; import { readlink, readlinkSync } from "node:fs"; import { assert, assertEquals } from "@std/assert"; diff --git a/tests/unit_node/_fs/_fs_realpath_test.ts b/tests/unit_node/_fs/_fs_realpath_test.ts index b0285cf545..25d266c4bf 100644 --- a/tests/unit_node/_fs/_fs_realpath_test.ts +++ b/tests/unit_node/_fs/_fs_realpath_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import * as path from "@std/path"; import { assertEquals } from "@std/assert"; import { assertCallbackErrorUncaught } from "../_test_utils.ts"; diff --git a/tests/unit_node/_fs/_fs_rename_test.ts b/tests/unit_node/_fs/_fs_rename_test.ts index 76d2e13141..91185e02a2 100644 --- a/tests/unit_node/_fs/_fs_rename_test.ts +++ b/tests/unit_node/_fs/_fs_rename_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, fail } from "@std/assert"; import { assertCallbackErrorUncaught } from "../_test_utils.ts"; import { rename, renameSync } from "node:fs"; diff --git a/tests/unit_node/_fs/_fs_rm_test.ts b/tests/unit_node/_fs/_fs_rm_test.ts index 6ded2e5645..da02b60f30 100644 --- a/tests/unit_node/_fs/_fs_rm_test.ts +++ b/tests/unit_node/_fs/_fs_rm_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertRejects, assertThrows, fail } from "@std/assert"; import { rm, rmSync } from "node:fs"; import { existsSync } from "node:fs"; diff --git a/tests/unit_node/_fs/_fs_rmdir_test.ts b/tests/unit_node/_fs/_fs_rmdir_test.ts index db0c692a40..90d2c7c8a8 100644 --- a/tests/unit_node/_fs/_fs_rmdir_test.ts +++ b/tests/unit_node/_fs/_fs_rmdir_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, fail } from "@std/assert"; import { rmdir, rmdirSync } from "node:fs"; import { existsSync } from "node:fs"; diff --git a/tests/unit_node/_fs/_fs_stat_test.ts b/tests/unit_node/_fs/_fs_stat_test.ts index 3cbbe940b0..d10521d0cd 100644 --- a/tests/unit_node/_fs/_fs_stat_test.ts +++ b/tests/unit_node/_fs/_fs_stat_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertCallbackErrorUncaught } from "../_test_utils.ts"; import { BigIntStats, stat, Stats, statSync } from "node:fs"; import { assert, assertEquals, fail } from "@std/assert"; diff --git a/tests/unit_node/_fs/_fs_statfs_test.ts b/tests/unit_node/_fs/_fs_statfs_test.ts index fc85bcf174..51cbb0e552 100644 --- a/tests/unit_node/_fs/_fs_statfs_test.ts +++ b/tests/unit_node/_fs/_fs_statfs_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import * as fs from "node:fs"; import { assertEquals, assertRejects } from "@std/assert"; diff --git a/tests/unit_node/_fs/_fs_symlink_test.ts b/tests/unit_node/_fs/_fs_symlink_test.ts index dfd6adb51a..d4a86bfc0f 100644 --- a/tests/unit_node/_fs/_fs_symlink_test.ts +++ b/tests/unit_node/_fs/_fs_symlink_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertThrows, fail } from "@std/assert"; import { symlink, symlinkSync } from "node:fs"; diff --git a/tests/unit_node/_fs/_fs_truncate_test.ts b/tests/unit_node/_fs/_fs_truncate_test.ts index 67bd021e45..ebb33a0c29 100644 --- a/tests/unit_node/_fs/_fs_truncate_test.ts +++ b/tests/unit_node/_fs/_fs_truncate_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertThrows, fail } from "@std/assert"; import { truncate, truncateSync } from "node:fs"; diff --git a/tests/unit_node/_fs/_fs_unlink_test.ts b/tests/unit_node/_fs/_fs_unlink_test.ts index f96217f8ef..a48ef58bc7 100644 --- a/tests/unit_node/_fs/_fs_unlink_test.ts +++ b/tests/unit_node/_fs/_fs_unlink_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, fail } from "@std/assert"; import { existsSync } from "node:fs"; import { assertCallbackErrorUncaught } from "../_test_utils.ts"; diff --git a/tests/unit_node/_fs/_fs_utimes_test.ts b/tests/unit_node/_fs/_fs_utimes_test.ts index 717d511c06..56233973ac 100644 --- a/tests/unit_node/_fs/_fs_utimes_test.ts +++ b/tests/unit_node/_fs/_fs_utimes_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertThrows, fail } from "@std/assert"; import { utimes, utimesSync } from "node:fs"; diff --git a/tests/unit_node/_fs/_fs_watch_test.ts b/tests/unit_node/_fs/_fs_watch_test.ts index 963e0889f1..d611202066 100644 --- a/tests/unit_node/_fs/_fs_watch_test.ts +++ b/tests/unit_node/_fs/_fs_watch_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { unwatchFile, watch, watchFile } from "node:fs"; import { watch as watchPromise } from "node:fs/promises"; import { assert, assertEquals } from "@std/assert"; diff --git a/tests/unit_node/_fs/_fs_writeFile_test.ts b/tests/unit_node/_fs/_fs_writeFile_test.ts index 2733a2df0b..503faf8f4c 100644 --- a/tests/unit_node/_fs/_fs_writeFile_test.ts +++ b/tests/unit_node/_fs/_fs_writeFile_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, diff --git a/tests/unit_node/_fs/_fs_write_test.ts b/tests/unit_node/_fs/_fs_write_test.ts index 400fce73aa..6a5d4c9c26 100644 --- a/tests/unit_node/_fs/_fs_write_test.ts +++ b/tests/unit_node/_fs/_fs_write_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console diff --git a/tests/unit_node/_test_utils.ts b/tests/unit_node/_test_utils.ts index c451ccd84b..a78444fd4a 100644 --- a/tests/unit_node/_test_utils.ts +++ b/tests/unit_node/_test_utils.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertStringIncludes } from "@std/assert"; diff --git a/tests/unit_node/assert_test.ts b/tests/unit_node/assert_test.ts index dc565458f6..f6dc18836d 100644 --- a/tests/unit_node/assert_test.ts +++ b/tests/unit_node/assert_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import * as assert from "node:assert"; Deno.test("[node/assert] .throws() compares Error instance", () => { diff --git a/tests/unit_node/assertion_error_test.ts b/tests/unit_node/assertion_error_test.ts index 4f8fe70ba5..60b0020d90 100644 --- a/tests/unit_node/assertion_error_test.ts +++ b/tests/unit_node/assertion_error_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { stripAnsiCode } from "@std/fmt/colors"; import { assert, assertStrictEquals } from "@std/assert"; import { AssertionError } from "node:assert"; diff --git a/tests/unit_node/async_hooks_test.ts b/tests/unit_node/async_hooks_test.ts index edad57bf76..d76898bcf5 100644 --- a/tests/unit_node/async_hooks_test.ts +++ b/tests/unit_node/async_hooks_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { AsyncLocalStorage, AsyncResource } from "node:async_hooks"; import process from "node:process"; import { setImmediate } from "node:timers"; diff --git a/tests/unit_node/buffer_test.ts b/tests/unit_node/buffer_test.ts index bd7f6edb17..3929769ffa 100644 --- a/tests/unit_node/buffer_test.ts +++ b/tests/unit_node/buffer_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { Buffer } from "node:buffer"; import { assertEquals, assertThrows } from "@std/assert"; diff --git a/tests/unit_node/child_process_test.ts b/tests/unit_node/child_process_test.ts index 0ea3c46cf0..1732b9d2bf 100644 --- a/tests/unit_node/child_process_test.ts +++ b/tests/unit_node/child_process_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import CP from "node:child_process"; import { Buffer } from "node:buffer"; @@ -656,6 +656,73 @@ Deno.test({ }, }); +Deno.test({ + name: + "[node/child_process spawn] child inherits Deno.env when options.env is not provided", + async fn() { + const deferred = withTimeout(); + Deno.env.set("BAR", "BAR"); + const env = spawn( + `"${Deno.execPath()}" eval -p "Deno.env.toObject().BAR"`, + { + shell: true, + }, + ); + try { + let envOutput = ""; + + assert(env.stdout); + env.on("error", (err: Error) => deferred.reject(err)); + env.stdout.on("data", (data) => { + envOutput += data; + }); + env.on("close", () => { + deferred.resolve(envOutput.trim()); + }); + await deferred.promise; + } finally { + env.kill(); + Deno.env.delete("BAR"); + } + const value = await deferred.promise; + assertEquals(value, "BAR"); + }, +}); + +Deno.test({ + name: + "[node/child_process spawn] child doesn't inherit Deno.env when options.env is provided", + async fn() { + const deferred = withTimeout(); + Deno.env.set("BAZ", "BAZ"); + const env = spawn( + `"${Deno.execPath()}" eval -p "Deno.env.toObject().BAZ"`, + { + env: {}, + shell: true, + }, + ); + try { + let envOutput = ""; + + assert(env.stdout); + env.on("error", (err: Error) => deferred.reject(err)); + env.stdout.on("data", (data) => { + envOutput += data; + }); + env.on("close", () => { + deferred.resolve(envOutput.trim()); + }); + await deferred.promise; + } finally { + env.kill(); + Deno.env.delete("BAZ"); + } + const value = await deferred.promise; + assertEquals(value, "undefined"); + }, +}); + // Regression test for https://github.com/denoland/deno/issues/20373 Deno.test(async function undefinedValueInEnvVar() { const deferred = withTimeout(); diff --git a/tests/unit_node/cluster_test.ts b/tests/unit_node/cluster_test.ts index d9a59ae63a..e0335c4824 100644 --- a/tests/unit_node/cluster_test.ts +++ b/tests/unit_node/cluster_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals } from "@std/assert"; import cluster from "node:cluster"; import * as clusterNamed from "node:cluster"; diff --git a/tests/unit_node/console_test.ts b/tests/unit_node/console_test.ts index 25d4a78e57..a9e3551074 100644 --- a/tests/unit_node/console_test.ts +++ b/tests/unit_node/console_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import vm from "node:vm"; import { stripAnsiCode } from "@std/fmt/colors"; diff --git a/tests/unit_node/crypto/crypto_cipher_gcm_test.ts b/tests/unit_node/crypto/crypto_cipher_gcm_test.ts index 16f6f56a9c..dd02ee5e32 100644 --- a/tests/unit_node/crypto/crypto_cipher_gcm_test.ts +++ b/tests/unit_node/crypto/crypto_cipher_gcm_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import crypto from "node:crypto"; import { Buffer } from "node:buffer"; diff --git a/tests/unit_node/crypto/crypto_cipher_test.ts b/tests/unit_node/crypto/crypto_cipher_test.ts index e40625c5a4..bc001c8d0f 100644 --- a/tests/unit_node/crypto/crypto_cipher_test.ts +++ b/tests/unit_node/crypto/crypto_cipher_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import crypto from "node:crypto"; import { Buffer } from "node:buffer"; import { Readable } from "node:stream"; diff --git a/tests/unit_node/crypto/crypto_hash_test.ts b/tests/unit_node/crypto/crypto_hash_test.ts index 0d4e307096..0a3fd2245e 100644 --- a/tests/unit_node/crypto/crypto_hash_test.ts +++ b/tests/unit_node/crypto/crypto_hash_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { createHash, createHmac, getHashes } from "node:crypto"; import { Buffer } from "node:buffer"; import { Readable } from "node:stream"; diff --git a/tests/unit_node/crypto/crypto_hkdf_test.ts b/tests/unit_node/crypto/crypto_hkdf_test.ts index 34102fd03d..dc128db584 100644 --- a/tests/unit_node/crypto/crypto_hkdf_test.ts +++ b/tests/unit_node/crypto/crypto_hkdf_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { hkdfSync } from "node:crypto"; import { assertEquals } from "@std/assert"; import { Buffer } from "node:buffer"; diff --git a/tests/unit_node/crypto/crypto_import_export.ts b/tests/unit_node/crypto/crypto_import_export.ts index fc41cbacc2..458178d578 100644 --- a/tests/unit_node/crypto/crypto_import_export.ts +++ b/tests/unit_node/crypto/crypto_import_export.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import crypto, { KeyFormat } from "node:crypto"; import path from "node:path"; import { Buffer } from "node:buffer"; diff --git a/tests/unit_node/crypto/crypto_key_test.ts b/tests/unit_node/crypto/crypto_key_test.ts index 82306d02fe..ac54a35419 100644 --- a/tests/unit_node/crypto/crypto_key_test.ts +++ b/tests/unit_node/crypto/crypto_key_test.ts @@ -1,6 +1,6 @@ // deno-lint-ignore-file no-explicit-any -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { createECDH, createHmac, diff --git a/tests/unit_node/crypto/crypto_misc_test.ts b/tests/unit_node/crypto/crypto_misc_test.ts index 9f72683398..3c49edd388 100644 --- a/tests/unit_node/crypto/crypto_misc_test.ts +++ b/tests/unit_node/crypto/crypto_misc_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { randomFillSync, randomUUID, timingSafeEqual } from "node:crypto"; import { Buffer } from "node:buffer"; import { assert, assertEquals, assertThrows } from "../../unit/test_util.ts"; diff --git a/tests/unit_node/crypto/crypto_pbkdf2_test.ts b/tests/unit_node/crypto/crypto_pbkdf2_test.ts index c937eb0c47..5eb4b82210 100644 --- a/tests/unit_node/crypto/crypto_pbkdf2_test.ts +++ b/tests/unit_node/crypto/crypto_pbkdf2_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { pbkdf2, pbkdf2Sync } from "node:crypto"; import { assert, assertEquals } from "@std/assert"; import nodeFixtures from "../testdata/crypto_digest_fixtures.json" with { diff --git a/tests/unit_node/crypto/crypto_scrypt_test.ts b/tests/unit_node/crypto/crypto_scrypt_test.ts index 03c08909ea..3f4d1437f0 100644 --- a/tests/unit_node/crypto/crypto_scrypt_test.ts +++ b/tests/unit_node/crypto/crypto_scrypt_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { scrypt, scryptSync } from "node:crypto"; import { Buffer } from "node:buffer"; import { assertEquals } from "@std/assert"; diff --git a/tests/unit_node/crypto/crypto_sign_test.ts b/tests/unit_node/crypto/crypto_sign_test.ts index 97c80b28af..24b049ca36 100644 --- a/tests/unit_node/crypto/crypto_sign_test.ts +++ b/tests/unit_node/crypto/crypto_sign_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals } from "@std/assert"; import { diff --git a/tests/unit_node/crypto/generate_fixture.mjs b/tests/unit_node/crypto/generate_fixture.mjs index 3724fe4aff..3fb78e82c4 100644 --- a/tests/unit_node/crypto/generate_fixture.mjs +++ b/tests/unit_node/crypto/generate_fixture.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Run this file with `node` to regenerate the testdata/crypto_digest_fixtures.json file. import { readFileSync, writeFileSync } from "node:fs"; diff --git a/tests/unit_node/crypto/generate_keys.mjs b/tests/unit_node/crypto/generate_keys.mjs index 29d9f570f3..d422729a29 100644 --- a/tests/unit_node/crypto/generate_keys.mjs +++ b/tests/unit_node/crypto/generate_keys.mjs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { writeFileSync } from "node:fs"; import { join } from "node:path"; diff --git a/tests/unit_node/dgram_test.ts b/tests/unit_node/dgram_test.ts index 2ccdfbfb7a..521b2448ad 100644 --- a/tests/unit_node/dgram_test.ts +++ b/tests/unit_node/dgram_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals } from "@std/assert"; import { execCode } from "../unit/test_util.ts"; diff --git a/tests/unit_node/domain_test.ts b/tests/unit_node/domain_test.ts index ddc56efae3..59b2c57b77 100644 --- a/tests/unit_node/domain_test.ts +++ b/tests/unit_node/domain_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Copyright © Benjamin Lupton // This code has been forked by https://github.com/bevry/domain-browser/commit/8bce7f4a093966ca850da75b024239ad5d0b33c6 diff --git a/tests/unit_node/events_test.ts b/tests/unit_node/events_test.ts index 8cfef6319a..152ace787b 100644 --- a/tests/unit_node/events_test.ts +++ b/tests/unit_node/events_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import events, { addAbortListener, EventEmitter } from "node:events"; diff --git a/tests/unit_node/fetch_test.ts b/tests/unit_node/fetch_test.ts index 399d6052a5..d005fd1d6e 100644 --- a/tests/unit_node/fetch_test.ts +++ b/tests/unit_node/fetch_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals } from "@std/assert"; import { createReadStream } from "node:fs"; diff --git a/tests/unit_node/fs_test.ts b/tests/unit_node/fs_test.ts index 32bea40e75..2dcd45529f 100644 --- a/tests/unit_node/fs_test.ts +++ b/tests/unit_node/fs_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// import { assert, assertEquals, assertRejects, assertThrows } from "@std/assert"; diff --git a/tests/unit_node/http2_test.ts b/tests/unit_node/http2_test.ts index 90f2388124..698e6b4ebe 100644 --- a/tests/unit_node/http2_test.ts +++ b/tests/unit_node/http2_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console diff --git a/tests/unit_node/http_test.ts b/tests/unit_node/http_test.ts index f30a4a20a3..b4f0d260aa 100644 --- a/tests/unit_node/http_test.ts +++ b/tests/unit_node/http_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console @@ -1881,3 +1881,14 @@ Deno.test("[node/http] decompress brotli response", { "localhost:3000", ], ["user-agent", "Deno/2.1.1"]]); }); + +Deno.test("[node/http] an error with DNS propagates to request object", async () => { + const { resolve, promise } = Promise.withResolvers(); + const req = http.request("http://invalid-hostname.test", () => {}); + req.on("error", (err) => { + assertEquals(err.name, "Error"); + assertEquals(err.message, "getaddrinfo ENOTFOUND invalid-hostname.test"); + resolve(); + }); + await promise; +}); diff --git a/tests/unit_node/inspector_test.ts b/tests/unit_node/inspector_test.ts index 0eb3f5a07b..ed94332108 100644 --- a/tests/unit_node/inspector_test.ts +++ b/tests/unit_node/inspector_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import inspector, { Session } from "node:inspector"; import inspectorPromises, { Session as SessionPromise, diff --git a/tests/unit_node/internal/_randomBytes_test.ts b/tests/unit_node/internal/_randomBytes_test.ts index ff3acf5e38..d479f44e76 100644 --- a/tests/unit_node/internal/_randomBytes_test.ts +++ b/tests/unit_node/internal/_randomBytes_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals, assertRejects, assertThrows } from "@std/assert"; import { assertCallbackErrorUncaught } from "../_test_utils.ts"; import { pseudoRandomBytes, randomBytes } from "node:crypto"; diff --git a/tests/unit_node/internal/_randomFill_test.ts b/tests/unit_node/internal/_randomFill_test.ts index 7b590666cd..d865b75f39 100644 --- a/tests/unit_node/internal/_randomFill_test.ts +++ b/tests/unit_node/internal/_randomFill_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { Buffer } from "node:buffer"; import { randomFill, randomFillSync } from "node:crypto"; import { assertEquals, assertNotEquals, assertThrows } from "@std/assert"; diff --git a/tests/unit_node/internal/_randomInt_test.ts b/tests/unit_node/internal/_randomInt_test.ts index b0d9d771ee..ec2f869551 100644 --- a/tests/unit_node/internal/_randomInt_test.ts +++ b/tests/unit_node/internal/_randomInt_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { randomInt } from "node:crypto"; import { assert, assertThrows } from "@std/assert"; diff --git a/tests/unit_node/module_test.ts b/tests/unit_node/module_test.ts index 96c3504bd2..728a339fb6 100644 --- a/tests/unit_node/module_test.ts +++ b/tests/unit_node/module_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { builtinModules, diff --git a/tests/unit_node/net_test.ts b/tests/unit_node/net_test.ts index 83d751866f..1142e6201d 100644 --- a/tests/unit_node/net_test.ts +++ b/tests/unit_node/net_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console diff --git a/tests/unit_node/os_test.ts b/tests/unit_node/os_test.ts index 78636e755d..99ad82c031 100644 --- a/tests/unit_node/os_test.ts +++ b/tests/unit_node/os_test.ts @@ -1,5 +1,5 @@ // deno-lint-ignore-file no-undef -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import os from "node:os"; import { diff --git a/tests/unit_node/path_test.ts b/tests/unit_node/path_test.ts index bd0711334d..63aa5ee2c1 100644 --- a/tests/unit_node/path_test.ts +++ b/tests/unit_node/path_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import path from "node:path"; import posix from "node:path/posix"; diff --git a/tests/unit_node/perf_hooks_test.ts b/tests/unit_node/perf_hooks_test.ts index 83d0062228..a77dd08538 100644 --- a/tests/unit_node/perf_hooks_test.ts +++ b/tests/unit_node/perf_hooks_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import * as perfHooks from "node:perf_hooks"; import { monitorEventLoopDelay, diff --git a/tests/unit_node/process_test.ts b/tests/unit_node/process_test.ts index 49de2dce1d..592bd6497f 100644 --- a/tests/unit_node/process_test.ts +++ b/tests/unit_node/process_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-undef no-console diff --git a/tests/unit_node/punycode_test.ts b/tests/unit_node/punycode_test.ts index fffa26164f..d4fa5b50a0 100644 --- a/tests/unit_node/punycode_test.ts +++ b/tests/unit_node/punycode_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import * as punycode from "node:punycode"; import { assertEquals } from "@std/assert"; diff --git a/tests/unit_node/querystring_test.ts b/tests/unit_node/querystring_test.ts index 09672df370..d57941264c 100644 --- a/tests/unit_node/querystring_test.ts +++ b/tests/unit_node/querystring_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals } from "@std/assert"; import { parse, stringify } from "node:querystring"; diff --git a/tests/unit_node/readline_test.ts b/tests/unit_node/readline_test.ts index 68f0cd7c92..02fd6958bf 100644 --- a/tests/unit_node/readline_test.ts +++ b/tests/unit_node/readline_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { createInterface, Interface } from "node:readline"; import { assertInstanceOf } from "@std/assert"; import { Readable, Writable } from "node:stream"; diff --git a/tests/unit_node/repl_test.ts b/tests/unit_node/repl_test.ts index 693fdcc9eb..d0759f442f 100644 --- a/tests/unit_node/repl_test.ts +++ b/tests/unit_node/repl_test.ts @@ -1,5 +1,5 @@ // deno-lint-ignore-file no-undef -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import repl from "node:repl"; import { assert } from "@std/assert"; diff --git a/tests/unit_node/stream_test.ts b/tests/unit_node/stream_test.ts index b8542f6cfd..9c58ae03d6 100644 --- a/tests/unit_node/stream_test.ts +++ b/tests/unit_node/stream_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals } from "@std/assert"; import { fromFileUrl, relative } from "@std/path"; diff --git a/tests/unit_node/string_decoder_test.ts b/tests/unit_node/string_decoder_test.ts index 34fbdd8810..1062373422 100644 --- a/tests/unit_node/string_decoder_test.ts +++ b/tests/unit_node/string_decoder_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals } from "@std/assert"; import { Buffer } from "node:buffer"; import { StringDecoder } from "node:string_decoder"; diff --git a/tests/unit_node/timers_test.ts b/tests/unit_node/timers_test.ts index ecff32e763..43a3338096 100644 --- a/tests/unit_node/timers_test.ts +++ b/tests/unit_node/timers_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, fail } from "@std/assert"; import * as timers from "node:timers"; diff --git a/tests/unit_node/tls_test.ts b/tests/unit_node/tls_test.ts index 627b948cd1..f34d9efb5b 100644 --- a/tests/unit_node/tls_test.ts +++ b/tests/unit_node/tls_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, diff --git a/tests/unit_node/tty_test.ts b/tests/unit_node/tty_test.ts index df2888ddd0..9acf9be614 100644 --- a/tests/unit_node/tty_test.ts +++ b/tests/unit_node/tty_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-explicit-any import { assert } from "@std/assert"; diff --git a/tests/unit_node/util_test.ts b/tests/unit_node/util_test.ts index af174b0f4d..0f83bb1b9a 100644 --- a/tests/unit_node/util_test.ts +++ b/tests/unit_node/util_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, diff --git a/tests/unit_node/v8_test.ts b/tests/unit_node/v8_test.ts index f7208fb0ef..7262ccd1fb 100644 --- a/tests/unit_node/v8_test.ts +++ b/tests/unit_node/v8_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { cachedDataVersionTag, deserialize, diff --git a/tests/unit_node/vm_test.ts b/tests/unit_node/vm_test.ts index 85b9556637..2876208e2f 100644 --- a/tests/unit_node/vm_test.ts +++ b/tests/unit_node/vm_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assertEquals, assertThrows } from "@std/assert"; import { createContext, diff --git a/tests/unit_node/wasi_test.ts b/tests/unit_node/wasi_test.ts index 6af2d4b1db..ae174e961b 100644 --- a/tests/unit_node/wasi_test.ts +++ b/tests/unit_node/wasi_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import wasi from "node:wasi"; import { assertThrows } from "@std/assert"; diff --git a/tests/unit_node/worker_threads_test.ts b/tests/unit_node/worker_threads_test.ts index 5f38d51d4d..c994b91eb1 100644 --- a/tests/unit_node/worker_threads_test.ts +++ b/tests/unit_node/worker_threads_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, diff --git a/tests/unit_node/zlib_test.ts b/tests/unit_node/zlib_test.ts index de2d2450d1..fb066a30d1 100644 --- a/tests/unit_node/zlib_test.ts +++ b/tests/unit_node/zlib_test.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { assert, assertEquals } from "@std/assert"; import { fromFileUrl, relative } from "@std/path"; diff --git a/tests/util/server/Cargo.toml b/tests/util/server/Cargo.toml index efc81da17c..aec9f6e91c 100644 --- a/tests/util/server/Cargo.toml +++ b/tests/util/server/Cargo.toml @@ -1,4 +1,4 @@ -# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +# Copyright 2018-2025 the Deno authors. MIT license. [package] name = "test_server" diff --git a/tests/util/server/src/assertions.rs b/tests/util/server/src/assertions.rs index c8b8845f4c..9eb39fb4a8 100644 --- a/tests/util/server/src/assertions.rs +++ b/tests/util/server/src/assertions.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::io::Write; diff --git a/tests/util/server/src/builders.rs b/tests/util/server/src/builders.rs index 1cc1af2812..d5df8d09c8 100644 --- a/tests/util/server/src/builders.rs +++ b/tests/util/server/src/builders.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::cell::RefCell; use std::collections::HashMap; diff --git a/tests/util/server/src/factory.rs b/tests/util/server/src/factory.rs index 5b796fbc1d..a13d673971 100644 --- a/tests/util/server/src/factory.rs +++ b/tests/util/server/src/factory.rs @@ -1,8 +1,9 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use glob::glob; +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashSet; use std::path::PathBuf; +use glob::glob; + /// Generate a unit test factory verified and backed by a glob. #[macro_export] macro_rules! unit_test_factory { diff --git a/tests/util/server/src/fs.rs b/tests/util/server/src/fs.rs index 7feb0799ae..19b94731eb 100644 --- a/tests/util/server/src/fs.rs +++ b/tests/util/server/src/fs.rs @@ -1,7 +1,5 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use lsp_types::Uri; -use pretty_assertions::assert_eq; use std::borrow::Cow; use std::collections::HashSet; use std::ffi::OsStr; @@ -15,6 +13,8 @@ use std::str::FromStr; use std::sync::Arc; use anyhow::Context; +use lsp_types::Uri; +use pretty_assertions::assert_eq; use serde::de::DeserializeOwned; use serde::Serialize; use url::Url; diff --git a/tests/util/server/src/https.rs b/tests/util/server/src/https.rs index 617fd5cae2..f3fc1291fe 100644 --- a/tests/util/server/src/https.rs +++ b/tests/util/server/src/https.rs @@ -1,4 +1,9 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. +use std::io; +use std::num::NonZeroUsize; +use std::result::Result; +use std::sync::Arc; + use anyhow::anyhow; use futures::Stream; use futures::StreamExt; @@ -6,10 +11,6 @@ use rustls_tokio_stream::rustls; use rustls_tokio_stream::rustls::pki_types::CertificateDer; use rustls_tokio_stream::rustls::pki_types::PrivateKeyDer; use rustls_tokio_stream::TlsStream; -use std::io; -use std::num::NonZeroUsize; -use std::result::Result; -use std::sync::Arc; use tokio::net::TcpStream; use crate::get_tcp_listener_stream; diff --git a/tests/util/server/src/lib.rs b/tests/util/server/src/lib.rs index 531944bf6a..477568ab1b 100644 --- a/tests/util/server/src/lib.rs +++ b/tests/util/server/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashMap; use std::env; @@ -1296,9 +1296,10 @@ pub(crate) mod colors { #[cfg(test)] mod tests { - use super::*; use pretty_assertions::assert_eq; + use super::*; + #[test] fn parse_wrk_output_1() { const TEXT: &str = include_str!("./testdata/wrk1.txt"); diff --git a/tests/util/server/src/lsp.rs b/tests/util/server/src/lsp.rs index 92169ee644..3a7321db62 100644 --- a/tests/util/server/src/lsp.rs +++ b/tests/util/server/src/lsp.rs @@ -1,11 +1,24 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::deno_exe_path; -use crate::jsr_registry_url; -use crate::npm_registry_url; -use crate::PathRef; - -use super::TempDir; +use std::collections::HashMap; +use std::collections::HashSet; +use std::ffi::OsStr; +use std::ffi::OsString; +use std::io; +use std::io::BufRead; +use std::io::BufReader; +use std::io::Write; +use std::path::Path; +use std::process::Child; +use std::process::ChildStdin; +use std::process::ChildStdout; +use std::process::Command; +use std::process::Stdio; +use std::str::FromStr; +use std::sync::mpsc; +use std::sync::Arc; +use std::time::Duration; +use std::time::Instant; use anyhow::Result; use lsp_types as lsp; @@ -32,27 +45,14 @@ use serde::Serialize; use serde_json::json; use serde_json::to_value; use serde_json::Value; -use std::collections::HashMap; -use std::collections::HashSet; -use std::ffi::OsStr; -use std::ffi::OsString; -use std::io; -use std::io::BufRead; -use std::io::BufReader; -use std::io::Write; -use std::path::Path; -use std::process::Child; -use std::process::ChildStdin; -use std::process::ChildStdout; -use std::process::Command; -use std::process::Stdio; -use std::str::FromStr; -use std::sync::mpsc; -use std::sync::Arc; -use std::time::Duration; -use std::time::Instant; use url::Url; +use super::TempDir; +use crate::deno_exe_path; +use crate::jsr_registry_url; +use crate::npm_registry_url; +use crate::PathRef; + static CONTENT_TYPE_REG: Lazy = lazy_regex::lazy_regex!(r"(?i)^content-length:\s+(\d+)"); @@ -900,6 +900,20 @@ impl LspClient { self.read_diagnostics() } + pub fn did_close_file(&mut self, file: &SourceFile) { + self.did_close(json!({ + "textDocument": file.identifier(), + })) + } + + pub fn did_close(&mut self, params: Value) { + self.did_close_raw(params); + } + + pub fn did_close_raw(&mut self, params: Value) { + self.write_notification("textDocument/didClose", params); + } + pub fn did_open_raw(&mut self, params: Value) { self.write_notification("textDocument/didOpen", params); } @@ -1289,6 +1303,9 @@ impl SourceFile { "md" => "markdown", "html" => "html", "css" => "css", + "scss" => "scss", + "sass" => "sass", + "less" => "less", "yaml" => "yaml", "sql" => "sql", "svelte" => "svelte", diff --git a/tests/util/server/src/macros.rs b/tests/util/server/src/macros.rs index e076583f19..52c84acf00 100644 --- a/tests/util/server/src/macros.rs +++ b/tests/util/server/src/macros.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. #[macro_export] // https://stackoverflow.com/questions/38088067/equivalent-of-func-or-function-in-rust diff --git a/tests/util/server/src/npm.rs b/tests/util/server/src/npm.rs index 0261b2532c..da9a59cf2f 100644 --- a/tests/util/server/src/npm.rs +++ b/tests/util/server/src/npm.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::collections::HashMap; use std::fs; diff --git a/tests/util/server/src/pty.rs b/tests/util/server/src/pty.rs index 07659262cf..d72617cd5e 100644 --- a/tests/util/server/src/pty.rs +++ b/tests/util/server/src/pty.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use std::borrow::Cow; use std::collections::HashMap; @@ -323,9 +323,10 @@ fn create_pty( cwd: &Path, env_vars: Option>, ) -> Box { - use crate::pty::unix::UnixPty; use std::os::unix::process::CommandExt; + use crate::pty::unix::UnixPty; + // Manually open pty main/secondary sides in the test process. Since we're not actually // changing uid/gid here, this is the easiest way to do it. diff --git a/tests/util/server/src/servers/grpc.rs b/tests/util/server/src/servers/grpc.rs index 144afc06a3..f097fbd595 100644 --- a/tests/util/server/src/servers/grpc.rs +++ b/tests/util/server/src/servers/grpc.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. use futures::StreamExt; use h2; diff --git a/tests/util/server/src/servers/hyper_utils.rs b/tests/util/server/src/servers/hyper_utils.rs index 8e01151ed4..a8b30ac24e 100644 --- a/tests/util/server/src/servers/hyper_utils.rs +++ b/tests/util/server/src/servers/hyper_utils.rs @@ -1,4 +1,10 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::convert::Infallible; +use std::io; +use std::net::SocketAddr; +use std::pin::Pin; +use std::result::Result; use bytes::Bytes; use futures::Future; @@ -10,11 +16,6 @@ use http::Request; use http::Response; use http_body_util::combinators::UnsyncBoxBody; use hyper_util::rt::TokioIo; -use std::convert::Infallible; -use std::io; -use std::net::SocketAddr; -use std::pin::Pin; -use std::result::Result; use tokio::net::TcpListener; #[derive(Debug, Clone, Copy)] diff --git a/tests/util/server/src/servers/jsr_registry.rs b/tests/util/server/src/servers/jsr_registry.rs index 8970750a28..b4b045087c 100644 --- a/tests/util/server/src/servers/jsr_registry.rs +++ b/tests/util/server/src/servers/jsr_registry.rs @@ -1,10 +1,12 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::tests_path; +use std::collections::BTreeMap; +use std::collections::HashMap; +use std::convert::Infallible; +use std::net::SocketAddr; +use std::path::Path; +use std::sync::Mutex; -use super::run_server; -use super::ServerKind; -use super::ServerOptions; use base64::engine::general_purpose::STANDARD_NO_PAD; use base64::Engine as _; use bytes::Bytes; @@ -17,12 +19,11 @@ use hyper::Response; use hyper::StatusCode; use once_cell::sync::Lazy; use serde_json::json; -use std::collections::BTreeMap; -use std::collections::HashMap; -use std::convert::Infallible; -use std::net::SocketAddr; -use std::path::Path; -use std::sync::Mutex; + +use super::run_server; +use super::ServerKind; +use super::ServerOptions; +use crate::tests_path; pub async fn registry_server(port: u16) { let registry_server_addr = SocketAddr::from(([127, 0, 0, 1], port)); diff --git a/tests/util/server/src/servers/mod.rs b/tests/util/server/src/servers/mod.rs index 4345c27cde..03f327319c 100644 --- a/tests/util/server/src/servers/mod.rs +++ b/tests/util/server/src/servers/mod.rs @@ -1,7 +1,14 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // Usage: provide a port as argument to run hyper_hello benchmark server // otherwise this starts multiple servers on many ports for test endpoints. +use std::collections::HashMap; +use std::convert::Infallible; +use std::env; +use std::net::SocketAddr; +use std::result::Result; +use std::time::Duration; + use base64::prelude::BASE64_STANDARD; use base64::Engine; use bytes::Bytes; @@ -27,12 +34,6 @@ use http_body_util::Empty; use http_body_util::Full; use pretty_assertions::assert_eq; use prost::Message; -use std::collections::HashMap; -use std::convert::Infallible; -use std::env; -use std::net::SocketAddr; -use std::result::Result; -use std::time::Duration; use tokio::io::AsyncWriteExt; use tokio::net::TcpStream; @@ -48,12 +49,11 @@ use hyper_utils::run_server_with_acceptor; use hyper_utils::ServerKind; use hyper_utils::ServerOptions; -use crate::TEST_SERVERS_COUNT; - use super::https::get_tls_listener_stream; use super::https::SupportedHttpVersions; use super::std_path; use super::testdata_path; +use crate::TEST_SERVERS_COUNT; pub(crate) const PORT: u16 = 4545; const TEST_AUTH_TOKEN: &str = "abcdef123456789"; diff --git a/tests/util/server/src/servers/nodejs_org_mirror.rs b/tests/util/server/src/servers/nodejs_org_mirror.rs index 521e79d3c4..e3e94757c0 100644 --- a/tests/util/server/src/servers/nodejs_org_mirror.rs +++ b/tests/util/server/src/servers/nodejs_org_mirror.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. //! Server for NodeJS header tarballs, used by `node-gyp` in tests to download headers //! diff --git a/tests/util/server/src/servers/npm_registry.rs b/tests/util/server/src/servers/npm_registry.rs index 4ada468fac..c814b83340 100644 --- a/tests/util/server/src/servers/npm_registry.rs +++ b/tests/util/server/src/servers/npm_registry.rs @@ -1,14 +1,11 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. -use crate::npm; +use std::convert::Infallible; +use std::net::Ipv6Addr; +use std::net::SocketAddr; +use std::net::SocketAddrV6; +use std::path::PathBuf; -use super::custom_headers; -use super::empty_body; -use super::hyper_utils::HandlerOutput; -use super::run_server; -use super::string_body; -use super::ServerKind; -use super::ServerOptions; use bytes::Bytes; use futures::future::LocalBoxFuture; use futures::Future; @@ -18,11 +15,15 @@ use hyper::body::Incoming; use hyper::Request; use hyper::Response; use hyper::StatusCode; -use std::convert::Infallible; -use std::net::Ipv6Addr; -use std::net::SocketAddr; -use std::net::SocketAddrV6; -use std::path::PathBuf; + +use super::custom_headers; +use super::empty_body; +use super::hyper_utils::HandlerOutput; +use super::run_server; +use super::string_body; +use super::ServerKind; +use super::ServerOptions; +use crate::npm; pub fn public_npm_registry(port: u16) -> Vec> { run_npm_server(port, "npm registry server error", { diff --git a/tests/util/server/src/servers/ws.rs b/tests/util/server/src/servers/ws.rs index dd4efbf659..2b9189f3e1 100644 --- a/tests/util/server/src/servers/ws.rs +++ b/tests/util/server/src/servers/ws.rs @@ -1,4 +1,7 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::pin::Pin; +use std::result::Result; use anyhow::anyhow; use bytes::Bytes; @@ -22,8 +25,6 @@ use hyper::Response; use hyper::StatusCode; use hyper_util::rt::TokioIo; use pretty_assertions::assert_eq; -use std::pin::Pin; -use std::result::Result; use tokio::io::AsyncReadExt; use tokio::io::AsyncWriteExt; diff --git a/tests/util/server/src/spawn.rs b/tests/util/server/src/spawn.rs index bfd83e9b26..936da7c785 100644 --- a/tests/util/server/src/spawn.rs +++ b/tests/util/server/src/spawn.rs @@ -1,7 +1,8 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use anyhow::Error; +// Copyright 2018-2025 the Deno authors. MIT license. use std::convert::Infallible; +use anyhow::Error; + /// For unix targets, we just replace our current process with the desired cargo process. #[cfg(unix)] pub fn exec_replace_inner( @@ -30,6 +31,7 @@ pub fn exec_replace_inner( ) -> Result { use std::os::windows::io::AsRawHandle; use std::process::Command; + use win32job::ExtendedLimitInfo; use win32job::Job; diff --git a/tests/util/server/src/test_server.rs b/tests/util/server/src/test_server.rs index 3ae3eaa7d9..a118318e6f 100644 --- a/tests/util/server/src/test_server.rs +++ b/tests/util/server/src/test_server.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. #![allow(clippy::print_stdout)] #![allow(clippy::print_stderr)] diff --git a/tests/wpt/runner/runner.ts b/tests/wpt/runner/runner.ts index 6e654fd334..e124d28c7a 100644 --- a/tests/wpt/runner/runner.ts +++ b/tests/wpt/runner/runner.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { delay, join, diff --git a/tests/wpt/runner/testharnessreport.js b/tests/wpt/runner/testharnessreport.js index 7cc6a9e2dd..f5fce1efe3 100644 --- a/tests/wpt/runner/testharnessreport.js +++ b/tests/wpt/runner/testharnessreport.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. window.add_result_callback(({ message, name, stack, status }) => { const data = new TextEncoder().encode( diff --git a/tests/wpt/runner/utils.ts b/tests/wpt/runner/utils.ts index 140c388ec2..1d9426aed9 100644 --- a/tests/wpt/runner/utils.ts +++ b/tests/wpt/runner/utils.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. /// FLAGS import { parseArgs } from "@std/cli/parse-args"; diff --git a/tests/wpt/wpt.ts b/tests/wpt/wpt.ts index b13a10cf4c..ec4a77fba1 100755 --- a/tests/wpt/wpt.ts +++ b/tests/wpt/wpt.ts @@ -1,5 +1,5 @@ #!/usr/bin/env -S deno run --allow-write --allow-read --allow-net --allow-env --allow-run --config=tests/config/deno.json -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console diff --git a/tools/build_bench.ts b/tools/build_bench.ts index 400737561b..ccc72410ba 100755 --- a/tools/build_bench.ts +++ b/tools/build_bench.ts @@ -1,5 +1,5 @@ #!/usr/bin/env -S deno run --allow-env --allow-read --allow-write --allow-run=git,cargo -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import $ from "https://deno.land/x/dax@0.32.0/mod.ts"; diff --git a/tools/build_benchmark_jsons.js b/tools/build_benchmark_jsons.js index 64310f75a7..6ed7cb0d83 100755 --- a/tools/build_benchmark_jsons.js +++ b/tools/build_benchmark_jsons.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { buildPath, existsSync, join } from "./util.js"; const currentDataFile = join(buildPath(), "bench.json"); diff --git a/tools/copyright_checker.js b/tools/copyright_checker.js index d7d196bc44..9ac84e3ec5 100755 --- a/tools/copyright_checker.js +++ b/tools/copyright_checker.js @@ -1,11 +1,11 @@ #!/usr/bin/env -S deno run --allow-read=. --allow-run=git --config=tests/config/deno.json -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console import { getSources, ROOT_PATH } from "./util.js"; -const copyrightYear = 2024; +const copyrightYear = 2025; const buffer = new Uint8Array(1024); const textDecoder = new TextDecoder(); @@ -63,7 +63,7 @@ export async function checkCopyright() { const ACCEPTABLE_LINES = /^(\/\/ deno-lint-.*|\/\/ Copyright.*|\/\/ Ported.*|\s*|#!\/.*)\n/; const COPYRIGHT_LINE = - `Copyright 2018-${copyrightYear} the Deno authors. All rights reserved. MIT license.`; + `Copyright 2018-${copyrightYear} the Deno authors. MIT license.`; const TOML_COPYRIGHT_LINE = "# " + COPYRIGHT_LINE; const C_STYLE_COPYRIGHT_LINE = "// " + COPYRIGHT_LINE; diff --git a/tools/core_import_map.json b/tools/core_import_map.json index d38221eb4c..935c7179a1 100644 --- a/tools/core_import_map.json +++ b/tools/core_import_map.json @@ -38,7 +38,7 @@ "ext:deno_node/_fs/_fs_stat.ts": "../ext/node/polyfills/_fs/_fs_stat.ts", "ext:deno_node/_fs/_fs_watch.ts": "../ext/node/polyfills/_fs/_fs_watch.ts", "ext:deno_node/_fs/_fs_write.mjs": "../ext/node/polyfills/_fs/_fs_write.mjs", - "ext:deno_node/_fs/_fs_writev.mjs": "../ext/node/polyfills/_fs/_fs_writev.mjs", + "ext:deno_node/_fs/_fs_writev.ts": "../ext/node/polyfills/_fs/_fs_writev.ts", "ext:deno_node/_global.d.ts": "../ext/node/polyfills/_global.d.ts", "node:_http_agent": "../ext/node/polyfills/_http_agent.mjs", "node:_http_common": "../ext/node/polyfills/_http_common.ts", @@ -81,6 +81,7 @@ "node:https": "../ext/node/polyfills/https.ts", "node:inspector": "../ext/node/polyfills/inspector.ts", "ext:deno_node/inspector.ts": "../ext/node/polyfills/inspector.ts", + "ext:deno_node/internal/idna.ts": "../ext/node/polyfills/internal/idna.ts", "ext:deno_node/internal_binding/_libuv_winerror.ts": "../ext/node/polyfills/internal_binding/_libuv_winerror.ts", "ext:deno_node/internal_binding/_listen.ts": "../ext/node/polyfills/internal_binding/_listen.ts", "ext:deno_node/internal_binding/_node.ts": "../ext/node/polyfills/internal_binding/_node.ts", @@ -95,6 +96,8 @@ "ext:deno_node/internal_binding/crypto.ts": "../ext/node/polyfills/internal_binding/crypto.ts", "ext:deno_node/internal_binding/handle_wrap.ts": "../ext/node/polyfills/internal_binding/handle_wrap.ts", "ext:deno_node/internal_binding/mod.ts": "../ext/node/polyfills/internal_binding/mod.ts", + "ext:deno_node/internal_binding/node_file.ts": "../ext/node/polyfills/internal_binding/node_file.ts", + "ext:deno_node/internal_binding/node_options.ts": "../ext/node/polyfills/internal_binding/node_options.ts", "ext:deno_node/internal_binding/pipe_wrap.ts": "../ext/node/polyfills/internal_binding/pipe_wrap.ts", "ext:deno_node/internal_binding/stream_wrap.ts": "../ext/node/polyfills/internal_binding/stream_wrap.ts", "ext:deno_node/internal_binding/string_decoder.ts": "../ext/node/polyfills/internal_binding/string_decoder.ts", @@ -239,10 +242,10 @@ "ext:runtime/06_util.js": "../runtime/js/06_util.js", "ext:runtime/10_permissions.js": "../runtime/js/10_permissions.js", "ext:runtime/11_workers.js": "../runtime/js/11_workers.js", - "ext:runtime/30_os.js": "../runtime/js/30_os.js", + "ext:deno_os/30_os.js": "../ext/os/30_os.js", "ext:runtime/40_fs_events.js": "../runtime/js/40_fs_events.js", - "ext:runtime/40_process.js": "../runtime/js/40_process.js", - "ext:runtime/40_signals.js": "../runtime/js/40_signals.js", + "ext:deno_process/40_process.js": "../ext/process/40_process.js", + "ext:deno_os/40_signals.js": "../ext/os/40_signals.js", "ext:runtime/40_tty.js": "../runtime/js/40_tty.js", "ext:runtime/41_prompt.js": "../runtime/js/41_prompt.js", "ext:runtime/90_deno_ns.js": "../runtime/js/90_deno_ns.js", diff --git a/tools/format.js b/tools/format.js index b29667ca77..02211cdaf8 100755 --- a/tools/format.js +++ b/tools/format.js @@ -1,5 +1,5 @@ #!/usr/bin/env -S deno run --allow-all --config=tests/config/deno.json -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { join, ROOT_PATH } from "./util.js"; const subcommand = Deno.args.includes("--check") ? "check" : "fmt"; diff --git a/tools/generate_types_deno.ts b/tools/generate_types_deno.ts index 265b6f5371..fa60f51a4b 100755 --- a/tools/generate_types_deno.ts +++ b/tools/generate_types_deno.ts @@ -1,5 +1,5 @@ #!/usr/bin/env -S deno run -A -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // This script is used to generate the @types/deno package on DefinitelyTyped. @@ -76,7 +76,7 @@ async function createDenoDtsFile() { file.insertStatements( 0, - "// Copyright 2018-2024 the Deno authors. MIT license.\n\n", + "// Copyright 2018-2025 the Deno authors. MIT license.\n\n", ); file.saveSync(); diff --git a/tools/install_prebuilt.js b/tools/install_prebuilt.js index 0c983d405d..c7a58c4691 100755 --- a/tools/install_prebuilt.js +++ b/tools/install_prebuilt.js @@ -1,5 +1,5 @@ #!/usr/bin/env -S deno run --unstable --allow-write --allow-read --allow-net --config=tests/config/deno.json -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { getPrebuilt } from "./util.js"; const args = Deno.args.slice(); diff --git a/tools/jsdoc_checker.js b/tools/jsdoc_checker.js index 241d04273b..034782136c 100755 --- a/tools/jsdoc_checker.js +++ b/tools/jsdoc_checker.js @@ -1,5 +1,5 @@ #!/usr/bin/env -S deno run --allow-read --allow-env --allow-sys --config=tests/config/deno.json -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { Node, Project, ts } from "npm:ts-morph@22.0.0"; import { join, ROOT_PATH } from "./util.js"; diff --git a/tools/lint.js b/tools/lint.js index 5bc3f2654f..3f548d5c3a 100755 --- a/tools/lint.js +++ b/tools/lint.js @@ -1,5 +1,5 @@ #!/usr/bin/env -S deno run --allow-all --config=tests/config/deno.json -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console diff --git a/tools/napi/generate_symbols_lists.js b/tools/napi/generate_symbols_lists.js index efb0edc043..42942777f6 100755 --- a/tools/napi/generate_symbols_lists.js +++ b/tools/napi/generate_symbols_lists.js @@ -1,5 +1,5 @@ #!/usr/bin/env -S deno run --allow-read --allow-write -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import exports from "../../ext/napi/sym/symbol_exports.json" with { type: "json", diff --git a/tools/ops.d.ts b/tools/ops.d.ts index 8acb1e5883..1d6dc8304a 100644 --- a/tools/ops.d.ts +++ b/tools/ops.d.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // This file is intentionally empty - that puts this file into script mode, // which then allows all symbols to be imported from the file. diff --git a/tools/release/00_start_release.ts b/tools/release/00_start_release.ts index 125a76af66..a7a5d22a40 100755 --- a/tools/release/00_start_release.ts +++ b/tools/release/00_start_release.ts @@ -1,5 +1,5 @@ #!/usr/bin/env -S deno run -A --quiet --lock=tools/deno.lock.json -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console diff --git a/tools/release/01_bump_crate_versions.ts b/tools/release/01_bump_crate_versions.ts index bef8011ba1..ddbc785c75 100755 --- a/tools/release/01_bump_crate_versions.ts +++ b/tools/release/01_bump_crate_versions.ts @@ -1,5 +1,5 @@ #!/usr/bin/env -S deno run -A --lock=tools/deno.lock.json -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { DenoWorkspace } from "./deno_workspace.ts"; import { $, GitLogOutput, semver } from "./deps.ts"; diff --git a/tools/release/02_create_pr.ts b/tools/release/02_create_pr.ts index 5ef64cd144..97f50f0d44 100755 --- a/tools/release/02_create_pr.ts +++ b/tools/release/02_create_pr.ts @@ -1,5 +1,5 @@ #!/usr/bin/env -S deno run -A --lock=tools/deno.lock.json -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { DenoWorkspace } from "./deno_workspace.ts"; import { $, createOctoKit, getGitHubRepository } from "./deps.ts"; diff --git a/tools/release/03_publish_crates.ts b/tools/release/03_publish_crates.ts index ecfb75e796..17ab2f71f7 100755 --- a/tools/release/03_publish_crates.ts +++ b/tools/release/03_publish_crates.ts @@ -1,5 +1,5 @@ #!/usr/bin/env -S deno run -A --lock=tools/deno.lock.json -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console diff --git a/tools/release/04_post_publish.ts b/tools/release/04_post_publish.ts index 2fa9e73561..42bf2dbafd 100755 --- a/tools/release/04_post_publish.ts +++ b/tools/release/04_post_publish.ts @@ -1,5 +1,5 @@ #!/usr/bin/env -S deno run -A --lock=tools/deno.lock.json -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { DenoWorkspace } from "./deno_workspace.ts"; import { $, createOctoKit, getGitHubRepository } from "./deps.ts"; diff --git a/tools/release/05_create_release_notes.ts b/tools/release/05_create_release_notes.ts index 9ea9ade31f..383f5ba089 100755 --- a/tools/release/05_create_release_notes.ts +++ b/tools/release/05_create_release_notes.ts @@ -1,5 +1,5 @@ #!/usr/bin/env -S deno run -A --lock=tools/deno.lock.json -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { $ } from "./deps.ts"; import { DenoWorkspace } from "./deno_workspace.ts"; diff --git a/tools/release/deno_workspace.ts b/tools/release/deno_workspace.ts index e55a02b73f..e5d9f1b928 100644 --- a/tools/release/deno_workspace.ts +++ b/tools/release/deno_workspace.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { $, ReleasesMdFile, Repo } from "./deps.ts"; diff --git a/tools/release/deps.ts b/tools/release/deps.ts index 568830a74b..17177870d7 100644 --- a/tools/release/deps.ts +++ b/tools/release/deps.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. export * from "https://raw.githubusercontent.com/denoland/automation/0.19.0/mod.ts"; export * from "https://raw.githubusercontent.com/denoland/automation/0.19.0/github_actions.ts"; diff --git a/tools/release/npm/bin.cjs b/tools/release/npm/bin.cjs index 984aa350f1..aaa9dd343c 100644 --- a/tools/release/npm/bin.cjs +++ b/tools/release/npm/bin.cjs @@ -1,5 +1,5 @@ #!/usr/bin/env node -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // @ts-check const path = require("path"); diff --git a/tools/release/npm/build.ts b/tools/release/npm/build.ts index b1f1c45cbf..606ff6dbe8 100755 --- a/tools/release/npm/build.ts +++ b/tools/release/npm/build.ts @@ -1,5 +1,5 @@ #!/usr/bin/env -S deno run -A --lock=tools/deno.lock.json -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // NOTICE: This deployment/npm folder was lifted from https://github.com/dprint/dprint/blob/0ba79811cc96d2dee8e0cf766a8c8c0fc44879c2/deployment/npm/ // with permission (Copyright 2019-2023 David Sherret) import $ from "jsr:@david/dax@^0.42.0"; diff --git a/tools/release/npm/install.cjs b/tools/release/npm/install.cjs index 8bf9aabe47..5546818941 100644 --- a/tools/release/npm/install.cjs +++ b/tools/release/npm/install.cjs @@ -1,5 +1,5 @@ // @ts-check -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. "use strict"; require("./install_api.cjs").runInstall(); diff --git a/tools/release/npm/install_api.cjs b/tools/release/npm/install_api.cjs index 026d8ccc45..d2571839bc 100644 --- a/tools/release/npm/install_api.cjs +++ b/tools/release/npm/install_api.cjs @@ -1,5 +1,5 @@ // @ts-check -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. "use strict"; const fs = require("fs"); diff --git a/tools/release/promote_to_release.ts b/tools/release/promote_to_release.ts index 046f4d33a8..bca798d22c 100755 --- a/tools/release/promote_to_release.ts +++ b/tools/release/promote_to_release.ts @@ -1,5 +1,5 @@ #!/usr/bin/env -S deno run -A --lock=tools/deno.lock.json -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console diff --git a/tools/upload_wptfyi.js b/tools/upload_wptfyi.js index 23dd4c6602..b08f352329 100644 --- a/tools/upload_wptfyi.js +++ b/tools/upload_wptfyi.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // This script pushes new WPT results to wpt.fyi. When the `--ghstatus` flag is // passed, will automatically add a status check to the commit with a link to diff --git a/tools/util.js b/tools/util.js index 8669337bff..07f405098c 100644 --- a/tools/util.js +++ b/tools/util.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console diff --git a/tools/verify_pr_title.js b/tools/verify_pr_title.js index 90a045d3f4..dd623bb630 100644 --- a/tools/verify_pr_title.js +++ b/tools/verify_pr_title.js @@ -1,4 +1,4 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. // deno-lint-ignore-file no-console diff --git a/tools/wgpu_sync.js b/tools/wgpu_sync.js index 1d9e180d52..995a4b5975 100755 --- a/tools/wgpu_sync.js +++ b/tools/wgpu_sync.js @@ -1,5 +1,5 @@ #!/usr/bin/env -S deno run --unstable --allow-read --allow-write --allow-run --config=tests/config/deno.json -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2025 the Deno authors. MIT license. import { join, ROOT_PATH } from "./util.js";