mirror of
https://github.com/denoland/deno.git
synced 2025-01-05 13:59:01 -05:00
Merge branch 'main' into support_create_connection
This commit is contained in:
commit
9ec31c6714
350 changed files with 3595 additions and 1477 deletions
|
@ -1,9 +1,8 @@
|
|||
FROM mcr.microsoft.com/vscode/devcontainers/rust:1-bullseye
|
||||
|
||||
# Install cmake and protobuf-compiler
|
||||
# Install cmake
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y cmake \
|
||||
&& apt-get install -y protobuf-compiler \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Deno
|
||||
|
|
6
.github/workflows/cargo_publish.yml
vendored
6
.github/workflows/cargo_publish.yml
vendored
|
@ -32,12 +32,6 @@ jobs:
|
|||
with:
|
||||
deno-version: v1.x
|
||||
|
||||
- name: Install protoc
|
||||
uses: arduino/setup-protoc@v3
|
||||
with:
|
||||
version: '21.12'
|
||||
repo-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
|
||||
- name: Publish
|
||||
env:
|
||||
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
||||
|
|
8
.github/workflows/ci.generate.ts
vendored
8
.github/workflows/ci.generate.ts
vendored
|
@ -5,7 +5,7 @@ import { stringify } from "jsr:@std/yaml@^0.221/stringify";
|
|||
// Bump this number when you want to purge the cache.
|
||||
// Note: the tools/release/01_bump_crate_versions.ts script will update this version
|
||||
// automatically via regex, so ensure that this line maintains this format.
|
||||
const cacheVersion = 15;
|
||||
const cacheVersion = 17;
|
||||
|
||||
const ubuntuX86Runner = "ubuntu-22.04";
|
||||
const ubuntuX86XlRunner = "ubuntu-22.04-xl";
|
||||
|
@ -191,11 +191,6 @@ const installNodeStep = {
|
|||
uses: "actions/setup-node@v4",
|
||||
with: { "node-version": 18 },
|
||||
};
|
||||
const installProtocStep = {
|
||||
name: "Install protoc",
|
||||
uses: "arduino/setup-protoc@v3",
|
||||
with: { "version": "21.12", "repo-token": "${{ secrets.GITHUB_TOKEN }}" },
|
||||
};
|
||||
const installDenoStep = {
|
||||
name: "Install Deno",
|
||||
uses: "denoland/setup-deno@v1",
|
||||
|
@ -494,7 +489,6 @@ const ci = {
|
|||
if: "matrix.job == 'bench' || matrix.job == 'test'",
|
||||
...installNodeStep,
|
||||
},
|
||||
installProtocStep,
|
||||
{
|
||||
if: [
|
||||
"matrix.profile == 'release' &&",
|
||||
|
|
14
.github/workflows/ci.yml
vendored
14
.github/workflows/ci.yml
vendored
|
@ -199,12 +199,6 @@ jobs:
|
|||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Install protoc
|
||||
uses: arduino/setup-protoc@v3
|
||||
with:
|
||||
version: '21.12'
|
||||
repo-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
if: '!(matrix.skip)'
|
||||
- if: |-
|
||||
!(matrix.skip) && (matrix.profile == 'release' &&
|
||||
matrix.job == 'test' &&
|
||||
|
@ -367,8 +361,8 @@ jobs:
|
|||
path: |-
|
||||
~/.cargo/registry/index
|
||||
~/.cargo/registry/cache
|
||||
key: '15-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}'
|
||||
restore-keys: '15-cargo-home-${{ matrix.os }}-${{ matrix.arch }}'
|
||||
key: '17-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}'
|
||||
restore-keys: '17-cargo-home-${{ matrix.os }}-${{ matrix.arch }}'
|
||||
if: '!(matrix.skip)'
|
||||
- name: Restore cache build output (PR)
|
||||
uses: actions/cache/restore@v4
|
||||
|
@ -381,7 +375,7 @@ jobs:
|
|||
!./target/*/*.zip
|
||||
!./target/*/*.tar.gz
|
||||
key: never_saved
|
||||
restore-keys: '15-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-'
|
||||
restore-keys: '17-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
|
||||
|
@ -691,7 +685,7 @@ jobs:
|
|||
!./target/*/*.zip
|
||||
!./target/*/*.sha256sum
|
||||
!./target/*/*.tar.gz
|
||||
key: '15-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}'
|
||||
key: '17-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}'
|
||||
publish-canary:
|
||||
name: publish canary
|
||||
runs-on: ubuntu-22.04
|
||||
|
|
161
Cargo.lock
generated
161
Cargo.lock
generated
|
@ -471,6 +471,26 @@ dependencies = [
|
|||
"which 4.4.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools 0.13.0",
|
||||
"log",
|
||||
"prettyplease 0.2.17",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash 1.1.0",
|
||||
"shlex",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.5.3"
|
||||
|
@ -688,7 +708,7 @@ checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
|
|||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading 0.8.3",
|
||||
"libloading 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1040,7 +1060,7 @@ dependencies = [
|
|||
"cpufeatures",
|
||||
"curve25519-dalek-derive",
|
||||
"digest",
|
||||
"fiat-crypto",
|
||||
"fiat-crypto 0.2.7",
|
||||
"rustc_version 0.4.0",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
|
@ -1064,7 +1084,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "b28bfe653d79bd16c77f659305b195b82bb5ce0c0eb2a4846b82ddbd77586813"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"libloading 0.8.3",
|
||||
"libloading 0.8.5",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
|
@ -1146,7 +1166,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno"
|
||||
version = "2.0.0-rc.8"
|
||||
version = "2.0.0-rc.10"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"async-trait",
|
||||
|
@ -1205,6 +1225,7 @@ dependencies = [
|
|||
"lazy-regex",
|
||||
"libc",
|
||||
"libsui",
|
||||
"libuv-sys-lite",
|
||||
"libz-sys",
|
||||
"log",
|
||||
"lsp-types",
|
||||
|
@ -1253,6 +1274,7 @@ dependencies = [
|
|||
"walkdir",
|
||||
"which 4.4.2",
|
||||
"winapi",
|
||||
"windows-sys 0.52.0",
|
||||
"winres",
|
||||
"yoke",
|
||||
"zeromq",
|
||||
|
@ -1317,7 +1339,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_bench_util"
|
||||
version = "0.162.0"
|
||||
version = "0.164.0"
|
||||
dependencies = [
|
||||
"bencher",
|
||||
"deno_core",
|
||||
|
@ -1326,7 +1348,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_broadcast_channel"
|
||||
version = "0.162.0"
|
||||
version = "0.164.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"deno_core",
|
||||
|
@ -1336,7 +1358,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_cache"
|
||||
version = "0.100.0"
|
||||
version = "0.102.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"deno_core",
|
||||
|
@ -1348,12 +1370,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_cache_dir"
|
||||
version = "0.12.0"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87900cfcd07bdbf3597bc36b77da0c0e7b6c2e65213faa2ed43d9a1ec12bd31d"
|
||||
checksum = "186a102b13b4512841f5f40784cd25822042d22954afe3b5b070d406d15eb4f2"
|
||||
dependencies = [
|
||||
"base32",
|
||||
"deno_media_type",
|
||||
"deno_path_util",
|
||||
"indexmap",
|
||||
"log",
|
||||
"once_cell",
|
||||
|
@ -1367,7 +1390,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_canvas"
|
||||
version = "0.37.0"
|
||||
version = "0.39.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_webgpu",
|
||||
|
@ -1377,12 +1400,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_config"
|
||||
version = "0.35.0"
|
||||
version = "0.37.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "105864a9e0a7fbc22f1106784b2d263f402f157be1c3e1a9905f53d182700c9f"
|
||||
checksum = "3cb7a1723676fba5964f8d7441d8b53748f9e74d6d4241be7de9730da021859a"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"deno_package_json",
|
||||
"deno_path_util",
|
||||
"deno_semver",
|
||||
"glob",
|
||||
"ignore",
|
||||
|
@ -1400,7 +1424,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_console"
|
||||
version = "0.168.0"
|
||||
version = "0.170.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
]
|
||||
|
@ -1445,7 +1469,7 @@ checksum = "a13951ea98c0a4c372f162d669193b4c9d991512de9f2381dd161027f34b26b1"
|
|||
|
||||
[[package]]
|
||||
name = "deno_cron"
|
||||
version = "0.48.0"
|
||||
version = "0.50.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -1457,7 +1481,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_crypto"
|
||||
version = "0.182.0"
|
||||
version = "0.184.0"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"aes-gcm",
|
||||
|
@ -1469,6 +1493,7 @@ dependencies = [
|
|||
"curve25519-dalek",
|
||||
"deno_core",
|
||||
"deno_web",
|
||||
"ed448-goldilocks",
|
||||
"elliptic-curve",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
|
@ -1491,9 +1516,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_doc"
|
||||
version = "0.150.0"
|
||||
version = "0.150.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c762829006b555837691b7016828eb1f93acf0a4ff344357b946898ea5b5610d"
|
||||
checksum = "0841188bc852535b76e53be6c3d13c61cfc6751a731969b8959fe31fa696c73f"
|
||||
dependencies = [
|
||||
"ammonia",
|
||||
"anyhow",
|
||||
|
@ -1517,7 +1542,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_fetch"
|
||||
version = "0.192.0"
|
||||
version = "0.194.0"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
|
@ -1549,7 +1574,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_ffi"
|
||||
version = "0.155.0"
|
||||
version = "0.157.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_permissions",
|
||||
|
@ -1566,7 +1591,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_fs"
|
||||
version = "0.78.0"
|
||||
version = "0.80.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"base32",
|
||||
|
@ -1587,9 +1612,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_graph"
|
||||
version = "0.82.3"
|
||||
version = "0.83.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "938ed2efa1dd9fdcceeebc169b2b7910506b8dacc992cfdcffd84aa6a3eb8db0"
|
||||
checksum = "8c62ce152f24a4c0580e7a91431f75de48281157cf645459de8e9d7268dd95b2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -1616,7 +1641,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_http"
|
||||
version = "0.166.0"
|
||||
version = "0.168.0"
|
||||
dependencies = [
|
||||
"async-compression",
|
||||
"async-trait",
|
||||
|
@ -1655,7 +1680,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_io"
|
||||
version = "0.78.0"
|
||||
version = "0.80.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"deno_core",
|
||||
|
@ -1676,7 +1701,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_kv"
|
||||
version = "0.76.0"
|
||||
version = "0.78.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -1747,7 +1772,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_napi"
|
||||
version = "0.99.0"
|
||||
version = "0.101.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_permissions",
|
||||
|
@ -1769,7 +1794,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_net"
|
||||
version = "0.160.0"
|
||||
version = "0.162.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_permissions",
|
||||
|
@ -1785,7 +1810,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_node"
|
||||
version = "0.105.0"
|
||||
version = "0.107.0"
|
||||
dependencies = [
|
||||
"aead-gcm-stream",
|
||||
"aes",
|
||||
|
@ -1875,9 +1900,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_npm"
|
||||
version = "0.25.2"
|
||||
version = "0.25.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1809e2d77d8a06bc2800dc10c1d4acb664197e518e289a86e336411c1feba785"
|
||||
checksum = "8050bcc2513046cbc0134ae1bc0f3b251a58b95012f3b81e0ea09a7f069c301b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -1909,9 +1934,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_package_json"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38cf6ea5cc98ea7ad58b0e84593773bea03fc0431071a296017bed4151e3dc1d"
|
||||
checksum = "6cbc4c4d3eb0960b58e8f43f9fc2d3f620fcac9a03cd85203e08db5b04e83c1f"
|
||||
dependencies = [
|
||||
"deno_semver",
|
||||
"indexmap",
|
||||
|
@ -1934,7 +1959,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_permissions"
|
||||
version = "0.28.0"
|
||||
version = "0.30.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_path_util",
|
||||
|
@ -1951,7 +1976,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_resolver"
|
||||
version = "0.0.1"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base32",
|
||||
|
@ -1961,12 +1986,13 @@ dependencies = [
|
|||
"deno_semver",
|
||||
"node_resolver",
|
||||
"test_server",
|
||||
"thiserror",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deno_runtime"
|
||||
version = "0.177.0"
|
||||
version = "0.179.0"
|
||||
dependencies = [
|
||||
"deno_ast",
|
||||
"deno_broadcast_channel",
|
||||
|
@ -2044,9 +2070,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_task_shell"
|
||||
version = "0.17.0"
|
||||
version = "0.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd6413ffc1654cad015edb5c4ab574069acdc929a6efafed23bc947901bcff1a"
|
||||
checksum = "4f444918f7102c1a5a143e9d57809e499fb4d365070519bf2e8bdb16d586af2a"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures",
|
||||
|
@ -2081,7 +2107,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_tls"
|
||||
version = "0.155.0"
|
||||
version = "0.157.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_native_certs",
|
||||
|
@ -2129,7 +2155,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_url"
|
||||
version = "0.168.0"
|
||||
version = "0.170.0"
|
||||
dependencies = [
|
||||
"deno_bench_util",
|
||||
"deno_console",
|
||||
|
@ -2140,7 +2166,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_web"
|
||||
version = "0.199.0"
|
||||
version = "0.201.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"base64-simd 0.8.0",
|
||||
|
@ -2161,7 +2187,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_webgpu"
|
||||
version = "0.135.0"
|
||||
version = "0.137.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"raw-window-handle",
|
||||
|
@ -2173,7 +2199,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_webidl"
|
||||
version = "0.168.0"
|
||||
version = "0.170.0"
|
||||
dependencies = [
|
||||
"deno_bench_util",
|
||||
"deno_core",
|
||||
|
@ -2181,7 +2207,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_websocket"
|
||||
version = "0.173.0"
|
||||
version = "0.175.0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"deno_core",
|
||||
|
@ -2202,7 +2228,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_webstorage"
|
||||
version = "0.163.0"
|
||||
version = "0.165.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_web",
|
||||
|
@ -2691,6 +2717,18 @@ dependencies = [
|
|||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ed448-goldilocks"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06924531e9e90130842b012e447f85bdaf9161bc8a0f8092be8cb70b01ebe092"
|
||||
dependencies = [
|
||||
"fiat-crypto 0.1.20",
|
||||
"hex",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "editpe"
|
||||
version = "0.1.0"
|
||||
|
@ -2831,9 +2869,9 @@ checksum = "31ae425815400e5ed474178a7a22e275a9687086a12ca63ec793ff292d8fdae8"
|
|||
|
||||
[[package]]
|
||||
name = "eszip"
|
||||
version = "0.78.0"
|
||||
version = "0.79.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0546f00d41dbc6e90b50e922759c02559a897e59b683369c3a13519cd5108b6"
|
||||
checksum = "8eb55c89bdde75a3826a79d49c9d847623ae7fbdb2695b542982982da990d33e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -2953,6 +2991,12 @@ dependencies = [
|
|||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fiat-crypto"
|
||||
version = "0.1.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77"
|
||||
|
||||
[[package]]
|
||||
name = "fiat-crypto"
|
||||
version = "0.2.7"
|
||||
|
@ -4037,7 +4081,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"libloading 0.8.3",
|
||||
"libloading 0.8.5",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
|
@ -4142,9 +4186,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.3"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
|
||||
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets 0.52.4",
|
||||
|
@ -4190,6 +4234,16 @@ dependencies = [
|
|||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libuv-sys-lite"
|
||||
version = "1.48.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca8dfd1a173826d193e3b955e07c22765829890f62c677a59c4a410cb4f47c01"
|
||||
dependencies = [
|
||||
"bindgen 0.70.1",
|
||||
"libloading 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libz-sys"
|
||||
version = "1.1.16"
|
||||
|
@ -4487,7 +4541,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "napi_sym"
|
||||
version = "0.98.0"
|
||||
version = "0.100.0"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"serde",
|
||||
|
@ -4556,7 +4610,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "node_resolver"
|
||||
version = "0.7.0"
|
||||
version = "0.9.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -7203,6 +7257,7 @@ dependencies = [
|
|||
name = "test_napi"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"libuv-sys-lite",
|
||||
"napi-build",
|
||||
"napi-sys",
|
||||
"test_server",
|
||||
|
@ -7889,7 +7944,7 @@ version = "0.106.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a381badc47c6f15acb5fe0b5b40234162349ed9d4e4fd7c83a7f5547c0fc69c5"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"bindgen 0.69.4",
|
||||
"bitflags 2.6.0",
|
||||
"fslock",
|
||||
"gzip-header",
|
||||
|
@ -8156,7 +8211,7 @@ dependencies = [
|
|||
"js-sys",
|
||||
"khronos-egl",
|
||||
"libc",
|
||||
"libloading 0.8.3",
|
||||
"libloading 0.8.5",
|
||||
"log",
|
||||
"metal",
|
||||
"naga",
|
||||
|
|
148
Cargo.toml
148
Cargo.toml
|
@ -48,16 +48,16 @@ repository = "https://github.com/denoland/deno"
|
|||
deno_ast = { version = "=0.42.1", features = ["transpiling"] }
|
||||
deno_core = { version = "0.311.0" }
|
||||
|
||||
deno_bench_util = { version = "0.162.0", path = "./bench_util" }
|
||||
deno_bench_util = { version = "0.164.0", path = "./bench_util" }
|
||||
deno_lockfile = "=0.23.1"
|
||||
deno_media_type = { version = "0.1.4", features = ["module_specifier"] }
|
||||
deno_npm = "=0.25.2"
|
||||
deno_npm = "=0.25.3"
|
||||
deno_path_util = "=0.2.0"
|
||||
deno_permissions = { version = "0.28.0", path = "./runtime/permissions" }
|
||||
deno_runtime = { version = "0.177.0", path = "./runtime" }
|
||||
deno_permissions = { version = "0.30.0", path = "./runtime/permissions" }
|
||||
deno_runtime = { version = "0.179.0", path = "./runtime" }
|
||||
deno_semver = "=0.5.14"
|
||||
deno_terminal = "0.2.0"
|
||||
napi_sym = { version = "0.98.0", path = "./cli/napi/sym" }
|
||||
napi_sym = { version = "0.100.0", path = "./cli/napi/sym" }
|
||||
test_util = { package = "test_server", path = "./tests/util/server" }
|
||||
|
||||
denokv_proto = "0.8.1"
|
||||
|
@ -66,32 +66,32 @@ denokv_remote = "0.8.1"
|
|||
denokv_sqlite = { default-features = false, version = "0.8.2" }
|
||||
|
||||
# exts
|
||||
deno_broadcast_channel = { version = "0.162.0", path = "./ext/broadcast_channel" }
|
||||
deno_cache = { version = "0.100.0", path = "./ext/cache" }
|
||||
deno_canvas = { version = "0.37.0", path = "./ext/canvas" }
|
||||
deno_console = { version = "0.168.0", path = "./ext/console" }
|
||||
deno_cron = { version = "0.48.0", path = "./ext/cron" }
|
||||
deno_crypto = { version = "0.182.0", path = "./ext/crypto" }
|
||||
deno_fetch = { version = "0.192.0", path = "./ext/fetch" }
|
||||
deno_ffi = { version = "0.155.0", path = "./ext/ffi" }
|
||||
deno_fs = { version = "0.78.0", path = "./ext/fs" }
|
||||
deno_http = { version = "0.166.0", path = "./ext/http" }
|
||||
deno_io = { version = "0.78.0", path = "./ext/io" }
|
||||
deno_kv = { version = "0.76.0", path = "./ext/kv" }
|
||||
deno_napi = { version = "0.99.0", path = "./ext/napi" }
|
||||
deno_net = { version = "0.160.0", path = "./ext/net" }
|
||||
deno_node = { version = "0.105.0", path = "./ext/node" }
|
||||
deno_tls = { version = "0.155.0", path = "./ext/tls" }
|
||||
deno_url = { version = "0.168.0", path = "./ext/url" }
|
||||
deno_web = { version = "0.199.0", path = "./ext/web" }
|
||||
deno_webgpu = { version = "0.135.0", path = "./ext/webgpu" }
|
||||
deno_webidl = { version = "0.168.0", path = "./ext/webidl" }
|
||||
deno_websocket = { version = "0.173.0", path = "./ext/websocket" }
|
||||
deno_webstorage = { version = "0.163.0", path = "./ext/webstorage" }
|
||||
deno_broadcast_channel = { version = "0.164.0", path = "./ext/broadcast_channel" }
|
||||
deno_cache = { version = "0.102.0", path = "./ext/cache" }
|
||||
deno_canvas = { version = "0.39.0", path = "./ext/canvas" }
|
||||
deno_console = { version = "0.170.0", path = "./ext/console" }
|
||||
deno_cron = { version = "0.50.0", path = "./ext/cron" }
|
||||
deno_crypto = { version = "0.184.0", path = "./ext/crypto" }
|
||||
deno_fetch = { version = "0.194.0", path = "./ext/fetch" }
|
||||
deno_ffi = { version = "0.157.0", path = "./ext/ffi" }
|
||||
deno_fs = { version = "0.80.0", path = "./ext/fs" }
|
||||
deno_http = { version = "0.168.0", path = "./ext/http" }
|
||||
deno_io = { version = "0.80.0", path = "./ext/io" }
|
||||
deno_kv = { version = "0.78.0", path = "./ext/kv" }
|
||||
deno_napi = { version = "0.101.0", path = "./ext/napi" }
|
||||
deno_net = { version = "0.162.0", path = "./ext/net" }
|
||||
deno_node = { version = "0.107.0", path = "./ext/node" }
|
||||
deno_tls = { version = "0.157.0", path = "./ext/tls" }
|
||||
deno_url = { version = "0.170.0", path = "./ext/url" }
|
||||
deno_web = { version = "0.201.0", path = "./ext/web" }
|
||||
deno_webgpu = { version = "0.137.0", path = "./ext/webgpu" }
|
||||
deno_webidl = { version = "0.170.0", path = "./ext/webidl" }
|
||||
deno_websocket = { version = "0.175.0", path = "./ext/websocket" }
|
||||
deno_webstorage = { version = "0.165.0", path = "./ext/webstorage" }
|
||||
|
||||
# resolvers
|
||||
deno_resolver = { version = "0.0.1", path = "./resolvers/deno" }
|
||||
node_resolver = { version = "0.7.0", path = "./resolvers/node" }
|
||||
deno_resolver = { version = "0.2.0", path = "./resolvers/deno" }
|
||||
node_resolver = { version = "0.9.0", path = "./resolvers/node" }
|
||||
|
||||
aes = "=0.8.3"
|
||||
anyhow = "1.0.57"
|
||||
|
@ -110,8 +110,8 @@ console_static_text = "=0.8.1"
|
|||
dashmap = "5.5.3"
|
||||
data-encoding = "2.3.3"
|
||||
data-url = "=0.3.0"
|
||||
deno_cache_dir = "=0.12.0"
|
||||
deno_package_json = { version = "=0.1.1", default-features = false }
|
||||
deno_cache_dir = "=0.13.0"
|
||||
deno_package_json = { version = "0.1.2", default-features = false }
|
||||
dlopen2 = "0.6.1"
|
||||
ecb = "=0.1.2"
|
||||
elliptic-curve = { version = "0.13.4", features = ["alloc", "arithmetic", "ecdh", "std", "pem", "jwk"] }
|
||||
|
@ -225,10 +225,9 @@ nix = "=0.26.2"
|
|||
# windows deps
|
||||
junction = "=0.2.0"
|
||||
winapi = "=0.3.9"
|
||||
windows-sys = { version = "0.52.0", features = ["Win32_Foundation", "Win32_Media", "Win32_Storage_FileSystem", "Win32_System_IO", "Win32_System_WindowsProgramming", "Wdk", "Wdk_System", "Wdk_System_SystemInformation", "Win32_System_Pipes", "Wdk_Storage_FileSystem", "Win32_System_Registry"] }
|
||||
windows-sys = { version = "0.52.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"] }
|
||||
winres = "=0.1.12"
|
||||
|
||||
# NB: the `bench` and `release` profiles must remain EXACTLY the same.
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
incremental = true
|
||||
|
@ -246,13 +245,6 @@ inherits = "release"
|
|||
codegen-units = 128
|
||||
lto = "thin"
|
||||
|
||||
# NB: the `bench` and `release` profiles must remain EXACTLY the same.
|
||||
[profile.bench]
|
||||
codegen-units = 1
|
||||
incremental = true
|
||||
lto = true
|
||||
opt-level = 'z' # Optimize for size
|
||||
|
||||
# Key generation is too slow on `debug`
|
||||
[profile.dev.package.num-bigint-dig]
|
||||
opt-level = 3
|
||||
|
@ -261,80 +253,6 @@ opt-level = 3
|
|||
[profile.dev.package.v8]
|
||||
opt-level = 1
|
||||
|
||||
# Optimize these packages for performance.
|
||||
# NB: the `bench` and `release` profiles must remain EXACTLY the same.
|
||||
[profile.bench.package.async-compression]
|
||||
opt-level = 3
|
||||
[profile.bench.package.base64-simd]
|
||||
opt-level = 3
|
||||
[profile.bench.package.brotli]
|
||||
opt-level = 3
|
||||
[profile.bench.package.brotli-decompressor]
|
||||
opt-level = 3
|
||||
[profile.bench.package.bytes]
|
||||
opt-level = 3
|
||||
[profile.bench.package.deno_bench_util]
|
||||
opt-level = 3
|
||||
[profile.bench.package.deno_broadcast_channel]
|
||||
opt-level = 3
|
||||
[profile.bench.package.deno_core]
|
||||
opt-level = 3
|
||||
[profile.bench.package.deno_crypto]
|
||||
opt-level = 3
|
||||
[profile.bench.package.deno_fetch]
|
||||
opt-level = 3
|
||||
[profile.bench.package.deno_ffi]
|
||||
opt-level = 3
|
||||
[profile.bench.package.deno_http]
|
||||
opt-level = 3
|
||||
[profile.bench.package.deno_napi]
|
||||
opt-level = 3
|
||||
[profile.bench.package.deno_net]
|
||||
opt-level = 3
|
||||
[profile.bench.package.deno_node]
|
||||
opt-level = 3
|
||||
[profile.bench.package.deno_runtime]
|
||||
opt-level = 3
|
||||
[profile.bench.package.deno_tls]
|
||||
opt-level = 3
|
||||
[profile.bench.package.deno_url]
|
||||
opt-level = 3
|
||||
[profile.bench.package.deno_web]
|
||||
opt-level = 3
|
||||
[profile.bench.package.deno_websocket]
|
||||
opt-level = 3
|
||||
[profile.bench.package.fastwebsockets]
|
||||
opt-level = 3
|
||||
[profile.bench.package.flate2]
|
||||
opt-level = 3
|
||||
[profile.bench.package.futures-util]
|
||||
opt-level = 3
|
||||
[profile.bench.package.hyper]
|
||||
opt-level = 3
|
||||
[profile.bench.package.miniz_oxide]
|
||||
opt-level = 3
|
||||
[profile.bench.package.num-bigint-dig]
|
||||
opt-level = 3
|
||||
[profile.bench.package.rand]
|
||||
opt-level = 3
|
||||
[profile.bench.package.serde]
|
||||
opt-level = 3
|
||||
[profile.bench.package.serde_v8]
|
||||
opt-level = 3
|
||||
[profile.bench.package.test_napi]
|
||||
opt-level = 3
|
||||
[profile.bench.package.tokio]
|
||||
opt-level = 3
|
||||
[profile.bench.package.url]
|
||||
opt-level = 3
|
||||
[profile.bench.package.v8]
|
||||
opt-level = 3
|
||||
[profile.bench.package.zstd]
|
||||
opt-level = 3
|
||||
[profile.bench.package.zstd-sys]
|
||||
opt-level = 3
|
||||
|
||||
# NB: the `bench` and `release` profiles must remain EXACTLY the same.
|
||||
[profile.release.package.async-compression]
|
||||
opt-level = 3
|
||||
[profile.release.package.base64-simd]
|
||||
|
@ -393,6 +311,8 @@ opt-level = 3
|
|||
opt-level = 3
|
||||
[profile.release.package.serde_v8]
|
||||
opt-level = 3
|
||||
[profile.release.package.libsui]
|
||||
opt-level = 3
|
||||
[profile.release.package.test_napi]
|
||||
opt-level = 3
|
||||
[profile.release.package.tokio]
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_bench_util"
|
||||
version = "0.162.0"
|
||||
version = "0.164.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno"
|
||||
version = "2.0.0-rc.8"
|
||||
version = "2.0.0-rc.10"
|
||||
authors.workspace = true
|
||||
default-run = "deno"
|
||||
edition.workspace = true
|
||||
|
@ -65,10 +65,10 @@ winres.workspace = true
|
|||
[dependencies]
|
||||
deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "proposal", "react", "sourcemap", "transforms", "typescript", "view", "visit"] }
|
||||
deno_cache_dir = { workspace = true }
|
||||
deno_config = { version = "=0.35.0", features = ["workspace", "sync"] }
|
||||
deno_config = { version = "=0.37.1", features = ["workspace", "sync"] }
|
||||
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] }
|
||||
deno_doc = { version = "0.150.0", features = ["html", "syntect"] }
|
||||
deno_graph = { version = "=0.82.3" }
|
||||
deno_doc = { version = "0.150.1", features = ["html", "syntect"] }
|
||||
deno_graph = { version = "=0.83.1" }
|
||||
deno_lint = { version = "=0.67.0", features = ["docs"] }
|
||||
deno_lockfile.workspace = true
|
||||
deno_npm.workspace = true
|
||||
|
@ -77,9 +77,9 @@ deno_path_util.workspace = true
|
|||
deno_resolver.workspace = true
|
||||
deno_runtime = { workspace = true, features = ["include_js_files_for_snapshotting"] }
|
||||
deno_semver.workspace = true
|
||||
deno_task_shell = "=0.17.0"
|
||||
deno_task_shell = "=0.18.1"
|
||||
deno_terminal.workspace = true
|
||||
eszip = "=0.78.0"
|
||||
eszip = "=0.79.1"
|
||||
libsui = "0.4.0"
|
||||
napi_sym.workspace = true
|
||||
node_resolver.workspace = true
|
||||
|
@ -170,12 +170,14 @@ zstd.workspace = true
|
|||
[target.'cfg(windows)'.dependencies]
|
||||
junction.workspace = true
|
||||
winapi = { workspace = true, features = ["knownfolders", "mswsock", "objbase", "shlobj", "tlhelp32", "winbase", "winerror", "winsock2"] }
|
||||
windows-sys.workspace = true
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
nix.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
deno_bench_util.workspace = true
|
||||
libuv-sys-lite = "=1.48.2"
|
||||
pretty_assertions.workspace = true
|
||||
test_util.workspace = true
|
||||
|
||||
|
|
|
@ -580,6 +580,15 @@ pub struct UnstableConfig {
|
|||
pub features: Vec<String>, // --unstabe-kv --unstable-cron
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Default)]
|
||||
pub struct InternalFlags {
|
||||
/// Used when the language server is configured with an
|
||||
/// explicit cache option.
|
||||
pub cache_path: Option<PathBuf>,
|
||||
/// Only reads to the lockfile instead of writing to it.
|
||||
pub lockfile_skip_write: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Default)]
|
||||
pub struct Flags {
|
||||
/// Vector of CLI arguments - these are user script arguments, all Deno
|
||||
|
@ -591,9 +600,6 @@ pub struct Flags {
|
|||
pub ca_stores: Option<Vec<String>>,
|
||||
pub ca_data: Option<CaData>,
|
||||
pub cache_blocklist: Vec<String>,
|
||||
/// This is not exposed as an option in the CLI, it is used internally when
|
||||
/// the language server is configured with an explicit cache option.
|
||||
pub cache_path: Option<PathBuf>,
|
||||
pub cached_only: bool,
|
||||
pub type_check_mode: TypeCheckMode,
|
||||
pub config_flag: ConfigFlag,
|
||||
|
@ -602,6 +608,8 @@ pub struct Flags {
|
|||
pub enable_op_summary_metrics: bool,
|
||||
pub enable_testing_features: bool,
|
||||
pub ext: Option<String>,
|
||||
/// Flags that aren't exposed in the CLI, but are used internally.
|
||||
pub internal: InternalFlags,
|
||||
pub ignore: Vec<String>,
|
||||
pub import_map_path: Option<String>,
|
||||
pub env_file: Option<String>,
|
||||
|
@ -688,9 +696,10 @@ impl PermissionFlags {
|
|||
}
|
||||
|
||||
let builtin_allowed_import_hosts = [
|
||||
"jsr.io:443",
|
||||
"deno.land:443",
|
||||
"esm.sh:443",
|
||||
"jsr.io:443",
|
||||
"cdn.jsdelivr.net:443",
|
||||
"raw.githubusercontent.com:443",
|
||||
"gist.githubusercontent.com:443",
|
||||
];
|
||||
|
@ -1176,7 +1185,6 @@ static DENO_HELP: &str = cstr!(
|
|||
<y>Tooling:</>
|
||||
<g>bench</> Run benchmarks
|
||||
<p(245)>deno bench bench.ts</>
|
||||
<g>cache</> Cache the dependencies
|
||||
<g>check</> Type-check the dependencies
|
||||
<g>clean</> Remove the cache directory
|
||||
<g>compile</> Compile the script into a self contained executable
|
||||
|
@ -2902,6 +2910,7 @@ List all available tasks:
|
|||
.help("Specify the directory to run the task in")
|
||||
.value_hint(ValueHint::DirPath),
|
||||
)
|
||||
.arg(node_modules_dir_arg())
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -3254,7 +3263,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
|
|||
<g>-W, --allow-write[=<<PATH>...]</> Allow file system write access. Optionally specify allowed paths.
|
||||
<p(245)>--allow-write | --allow-write="/etc,/var/log.txt"</>
|
||||
<g>-I, --allow-import[=<<IP_OR_HOSTNAME>...]</> Allow importing from remote hosts. Optionally specify allowed IP addresses and host names, with ports as necessary.
|
||||
Default value: <p(245)>deno.land:443,jsr.io:443,esm.sh:443,raw.githubusercontent.com:443,user.githubusercontent.com:443</>
|
||||
Default value: <p(245)>deno.land:443,jsr.io:443,esm.sh:443,cdn.jsdelivr.net:443,raw.githubusercontent.com:443,user.githubusercontent.com:443</>
|
||||
<p(245)>--allow-import | --allow-import="example.com,github.com"</>
|
||||
<g>-N, --allow-net[=<<IP_OR_HOSTNAME>...]</> Allow network access. Optionally specify allowed IP addresses and host names, with ports as necessary.
|
||||
<p(245)>--allow-net | --allow-net="localhost:8080,deno.land"</>
|
||||
|
@ -3274,7 +3283,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
|
|||
<p(245)>--deny-net | --deny-net="localhost:8080,deno.land"</>
|
||||
<g> --deny-env[=<<VARIABLE_NAME>...]</> Deny access to environment variables. Optionally specify inacessible environment variables.
|
||||
<p(245)>--deny-env | --deny-env="PORT,HOME,PATH"</>
|
||||
<g>-S, --deny-sys[=<<API_NAME>...]</> Deny access to OS information. Optionally deny specific APIs by function name.
|
||||
<g> --deny-sys[=<<API_NAME>...]</> Deny access to OS information. Optionally deny specific APIs by function name.
|
||||
<p(245)>--deny-sys | --deny-sys="systemMemoryInfo,osRelease"</>
|
||||
<g>--deny-run[=<<PROGRAM_NAME>...]</> Deny running subprocesses. Optionally specify denied runnable program names.
|
||||
<p(245)>--deny-run | --deny-run="whoami,ps"</>
|
||||
|
@ -3664,7 +3673,7 @@ fn allow_import_arg() -> Arg {
|
|||
.require_equals(true)
|
||||
.value_name("IP_OR_HOSTNAME")
|
||||
.help(cstr!(
|
||||
"Allow importing from remote hosts. Optionally specify allowed IP addresses and host names, with ports as necessary. Default value: <p(245)>deno.land:443,jsr.io:443,esm.sh:443,raw.githubusercontent.com:443,user.githubusercontent.com:443</>"
|
||||
"Allow importing from remote hosts. Optionally specify allowed IP addresses and host names, with ports as necessary. Default value: <p(245)>deno.land:443,jsr.io:443,esm.sh:443,cdn.jsdelivr.net:443,raw.githubusercontent.com:443,user.githubusercontent.com:443</>"
|
||||
))
|
||||
.value_parser(flags_net::validator)
|
||||
}
|
||||
|
@ -4966,6 +4975,7 @@ fn task_parse(flags: &mut Flags, matches: &mut ArgMatches) {
|
|||
.unwrap_or(ConfigFlag::Discover);
|
||||
|
||||
unstable_args_parse(flags, matches, UnstableArgsConfig::ResolutionAndRuntime);
|
||||
node_modules_arg_parse(flags, matches);
|
||||
|
||||
let mut task_flags = TaskFlags {
|
||||
cwd: matches.remove_one::<String>("cwd"),
|
||||
|
|
|
@ -24,11 +24,20 @@ use crate::args::InstallKind;
|
|||
|
||||
use deno_lockfile::Lockfile;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CliLockfileReadFromPathOptions {
|
||||
pub file_path: PathBuf,
|
||||
pub frozen: bool,
|
||||
/// Causes the lockfile to only be read from, but not written to.
|
||||
pub skip_write: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CliLockfile {
|
||||
lockfile: Mutex<Lockfile>,
|
||||
pub filename: PathBuf,
|
||||
pub frozen: bool,
|
||||
frozen: bool,
|
||||
skip_write: bool,
|
||||
}
|
||||
|
||||
pub struct Guard<'a, T> {
|
||||
|
@ -50,15 +59,6 @@ impl<'a, T> std::ops::DerefMut for Guard<'a, T> {
|
|||
}
|
||||
|
||||
impl CliLockfile {
|
||||
pub fn new(lockfile: Lockfile, frozen: bool) -> Self {
|
||||
let filename = lockfile.filename.clone();
|
||||
Self {
|
||||
lockfile: Mutex::new(lockfile),
|
||||
filename,
|
||||
frozen,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the inner deno_lockfile::Lockfile.
|
||||
pub fn lock(&self) -> Guard<Lockfile> {
|
||||
Guard {
|
||||
|
@ -78,6 +78,10 @@ impl CliLockfile {
|
|||
}
|
||||
|
||||
pub fn write_if_changed(&self) -> Result<(), AnyError> {
|
||||
if self.skip_write {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.error_if_changed()?;
|
||||
let mut lockfile = self.lockfile.lock();
|
||||
let Some(bytes) = lockfile.resolve_write_bytes() else {
|
||||
|
@ -142,7 +146,7 @@ impl CliLockfile {
|
|||
return Ok(None);
|
||||
}
|
||||
|
||||
let filename = match flags.lock {
|
||||
let file_path = match flags.lock {
|
||||
Some(ref lock) => PathBuf::from(lock),
|
||||
None => match workspace.resolve_lockfile_path()? {
|
||||
Some(path) => path,
|
||||
|
@ -160,7 +164,11 @@ impl CliLockfile {
|
|||
.unwrap_or(false)
|
||||
});
|
||||
|
||||
let lockfile = Self::read_from_path(filename, frozen)?;
|
||||
let lockfile = Self::read_from_path(CliLockfileReadFromPathOptions {
|
||||
file_path,
|
||||
frozen,
|
||||
skip_write: flags.internal.lockfile_skip_write,
|
||||
})?;
|
||||
|
||||
// initialize the lockfile with the workspace's configuration
|
||||
let root_url = workspace.root_dir();
|
||||
|
@ -212,25 +220,29 @@ impl CliLockfile {
|
|||
}
|
||||
|
||||
pub fn read_from_path(
|
||||
file_path: PathBuf,
|
||||
frozen: bool,
|
||||
opts: CliLockfileReadFromPathOptions,
|
||||
) -> Result<CliLockfile, AnyError> {
|
||||
match std::fs::read_to_string(&file_path) {
|
||||
Ok(text) => Ok(CliLockfile::new(
|
||||
Lockfile::new(deno_lockfile::NewLockfileOptions {
|
||||
file_path,
|
||||
content: &text,
|
||||
overwrite: false,
|
||||
})?,
|
||||
frozen,
|
||||
)),
|
||||
Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(
|
||||
CliLockfile::new(Lockfile::new_empty(file_path, false), frozen),
|
||||
),
|
||||
Err(err) => Err(err).with_context(|| {
|
||||
format!("Failed reading lockfile '{}'", file_path.display())
|
||||
}),
|
||||
}
|
||||
let lockfile = match std::fs::read_to_string(&opts.file_path) {
|
||||
Ok(text) => Lockfile::new(deno_lockfile::NewLockfileOptions {
|
||||
file_path: opts.file_path,
|
||||
content: &text,
|
||||
overwrite: false,
|
||||
})?,
|
||||
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
|
||||
Lockfile::new_empty(opts.file_path, false)
|
||||
}
|
||||
Err(err) => {
|
||||
return Err(err).with_context(|| {
|
||||
format!("Failed reading lockfile '{}'", opts.file_path.display())
|
||||
});
|
||||
}
|
||||
};
|
||||
Ok(CliLockfile {
|
||||
filename: lockfile.filename.clone(),
|
||||
lockfile: Mutex::new(lockfile),
|
||||
frozen: opts.frozen,
|
||||
skip_write: opts.skip_write,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn error_if_changed(&self) -> Result<(), AnyError> {
|
||||
|
|
|
@ -44,6 +44,7 @@ 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;
|
||||
|
||||
use deno_ast::ModuleSpecifier;
|
||||
|
@ -824,11 +825,9 @@ impl CliOptions {
|
|||
}
|
||||
}
|
||||
|
||||
warn_insecure_allow_run_flags(&flags);
|
||||
|
||||
let maybe_lockfile = maybe_lockfile.filter(|_| !force_global_cache);
|
||||
let deno_dir_provider =
|
||||
Arc::new(DenoDirProvider::new(flags.cache_path.clone()));
|
||||
Arc::new(DenoDirProvider::new(flags.internal.cache_path.clone()));
|
||||
let maybe_node_modules_folder = resolve_node_modules_folder(
|
||||
&initial_cwd,
|
||||
&flags,
|
||||
|
@ -1710,27 +1709,6 @@ impl CliOptions {
|
|||
}
|
||||
}
|
||||
|
||||
/// Warns for specific uses of `--allow-run`. This function is not
|
||||
/// intended to catch every single possible insecure use of `--allow-run`,
|
||||
/// but is just an attempt to discourage some common pitfalls.
|
||||
fn warn_insecure_allow_run_flags(flags: &Flags) {
|
||||
let permissions = &flags.permissions;
|
||||
if permissions.allow_all {
|
||||
return;
|
||||
}
|
||||
let Some(allow_run_list) = permissions.allow_run.as_ref() else {
|
||||
return;
|
||||
};
|
||||
|
||||
// discourage using --allow-run without an allow list
|
||||
if allow_run_list.is_empty() {
|
||||
log::warn!(
|
||||
"{} --allow-run without an allow list is susceptible to exploits. Prefer specifying an allow list (https://docs.deno.com/runtime/fundamentals/security/#running-subprocesses)",
|
||||
colors::yellow("Warning")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves the path to use for a local node_modules folder.
|
||||
fn resolve_node_modules_folder(
|
||||
cwd: &Path,
|
||||
|
|
|
@ -6,6 +6,7 @@ use std::sync::Arc;
|
|||
use deno_config::workspace::Workspace;
|
||||
use deno_core::serde_json;
|
||||
use deno_package_json::PackageJsonDepValue;
|
||||
use deno_package_json::PackageJsonDepValueParseError;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use deno_semver::package::PackageReq;
|
||||
|
||||
|
@ -26,6 +27,7 @@ pub struct InstallNpmWorkspacePkg {
|
|||
pub struct NpmInstallDepsProvider {
|
||||
remote_pkgs: Vec<InstallNpmRemotePkg>,
|
||||
workspace_pkgs: Vec<InstallNpmWorkspacePkg>,
|
||||
pkg_json_dep_errors: Vec<PackageJsonDepValueParseError>,
|
||||
}
|
||||
|
||||
impl NpmInstallDepsProvider {
|
||||
|
@ -37,6 +39,7 @@ impl NpmInstallDepsProvider {
|
|||
// todo(dsherret): estimate capacity?
|
||||
let mut workspace_pkgs = Vec::new();
|
||||
let mut remote_pkgs = Vec::new();
|
||||
let mut pkg_json_dep_errors = Vec::new();
|
||||
let workspace_npm_pkgs = workspace.npm_packages();
|
||||
|
||||
for (_, folder) in workspace.config_folders() {
|
||||
|
@ -83,8 +86,12 @@ impl NpmInstallDepsProvider {
|
|||
let deps = pkg_json.resolve_local_package_json_deps();
|
||||
let mut pkg_pkgs = Vec::with_capacity(deps.len());
|
||||
for (alias, dep) in deps {
|
||||
let Ok(dep) = dep else {
|
||||
continue;
|
||||
let dep = match dep {
|
||||
Ok(dep) => dep,
|
||||
Err(err) => {
|
||||
pkg_json_dep_errors.push(err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
match dep {
|
||||
PackageJsonDepValue::Req(pkg_req) => {
|
||||
|
@ -131,14 +138,19 @@ impl NpmInstallDepsProvider {
|
|||
Self {
|
||||
remote_pkgs,
|
||||
workspace_pkgs,
|
||||
pkg_json_dep_errors,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remote_pkgs(&self) -> &Vec<InstallNpmRemotePkg> {
|
||||
pub fn remote_pkgs(&self) -> &[InstallNpmRemotePkg] {
|
||||
&self.remote_pkgs
|
||||
}
|
||||
|
||||
pub fn workspace_pkgs(&self) -> &Vec<InstallNpmWorkspacePkg> {
|
||||
pub fn workspace_pkgs(&self) -> &[InstallNpmWorkspacePkg] {
|
||||
&self.workspace_pkgs
|
||||
}
|
||||
|
||||
pub fn pkg_json_dep_errors(&self) -> &[PackageJsonDepValueParseError] {
|
||||
&self.pkg_json_dep_errors
|
||||
}
|
||||
}
|
||||
|
|
|
@ -387,6 +387,8 @@ fn main() {
|
|||
"Missing symbols list! Generate using tools/napi/generate_symbols_lists.js",
|
||||
);
|
||||
|
||||
println!("cargo:rustc-rerun-if-changed={}", symbols_path.display());
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
println!(
|
||||
"cargo:rustc-link-arg-bin=deno=/DEF:{}",
|
||||
|
|
6
cli/cache/deno_dir.rs
vendored
6
cli/cache/deno_dir.rs
vendored
|
@ -126,9 +126,9 @@ impl DenoDir {
|
|||
self.root.join("registries")
|
||||
}
|
||||
|
||||
/// Path to the dependencies cache folder.
|
||||
pub fn deps_folder_path(&self) -> PathBuf {
|
||||
self.root.join("deps")
|
||||
/// Path to the remote cache folder.
|
||||
pub fn remote_folder_path(&self) -> PathBuf {
|
||||
self.root.join("remote")
|
||||
}
|
||||
|
||||
/// Path to the origin data cache folder.
|
||||
|
|
11
cli/cache/mod.rs
vendored
11
cli/cache/mod.rs
vendored
|
@ -87,10 +87,6 @@ impl deno_cache_dir::DenoCacheEnv for RealDenoCacheEnv {
|
|||
std::fs::create_dir_all(path)
|
||||
}
|
||||
|
||||
fn remove_file(&self, path: &Path) -> std::io::Result<()> {
|
||||
std::fs::remove_file(path)
|
||||
}
|
||||
|
||||
fn modified(&self, path: &Path) -> std::io::Result<Option<SystemTime>> {
|
||||
match std::fs::metadata(path) {
|
||||
Ok(metadata) => Ok(Some(
|
||||
|
@ -149,13 +145,6 @@ impl<'a> deno_cache_dir::DenoCacheEnv for DenoCacheEnvFsAdapter<'a> {
|
|||
.map_err(|e| e.into_io_error())
|
||||
}
|
||||
|
||||
fn remove_file(&self, path: &Path) -> std::io::Result<()> {
|
||||
self
|
||||
.0
|
||||
.remove_sync(path, false)
|
||||
.map_err(|e| e.into_io_error())
|
||||
}
|
||||
|
||||
fn modified(&self, path: &Path) -> std::io::Result<Option<SystemTime>> {
|
||||
self
|
||||
.0
|
||||
|
|
|
@ -301,7 +301,7 @@ impl CliFactory {
|
|||
pub fn global_http_cache(&self) -> Result<&Arc<GlobalHttpCache>, AnyError> {
|
||||
self.services.global_http_cache.get_or_try_init(|| {
|
||||
Ok(Arc::new(GlobalHttpCache::new(
|
||||
self.deno_dir()?.deps_folder_path(),
|
||||
self.deno_dir()?.remote_folder_path(),
|
||||
crate::cache::RealDenoCacheEnv,
|
||||
)))
|
||||
})
|
||||
|
|
|
@ -726,7 +726,7 @@ mod tests {
|
|||
maybe_temp_dir: Option<TempDir>,
|
||||
) -> (FileFetcher, TempDir, Arc<BlobStore>) {
|
||||
let temp_dir = maybe_temp_dir.unwrap_or_default();
|
||||
let location = temp_dir.path().join("deps").to_path_buf();
|
||||
let location = temp_dir.path().join("remote").to_path_buf();
|
||||
let blob_store: Arc<BlobStore> = Default::default();
|
||||
let file_fetcher = FileFetcher::new(
|
||||
Arc::new(GlobalHttpCache::new(location, RealDenoCacheEnv)),
|
||||
|
@ -964,7 +964,7 @@ mod tests {
|
|||
|
||||
// This creates a totally new instance, simulating another Deno process
|
||||
// invocation and indicates to "cache bust".
|
||||
let location = temp_dir.path().join("deps").to_path_buf();
|
||||
let location = temp_dir.path().join("remote").to_path_buf();
|
||||
let file_fetcher = FileFetcher::new(
|
||||
Arc::new(GlobalHttpCache::new(
|
||||
location,
|
||||
|
@ -990,7 +990,7 @@ mod tests {
|
|||
async fn test_fetch_uses_cache() {
|
||||
let _http_server_guard = test_util::http_server();
|
||||
let temp_dir = TempDir::new();
|
||||
let location = temp_dir.path().join("deps").to_path_buf();
|
||||
let location = temp_dir.path().join("remote").to_path_buf();
|
||||
let specifier =
|
||||
resolve_url("http://localhost:4545/subdir/mismatch_ext.ts").unwrap();
|
||||
|
||||
|
@ -1156,7 +1156,7 @@ mod tests {
|
|||
async fn test_fetch_uses_cache_with_redirects() {
|
||||
let _http_server_guard = test_util::http_server();
|
||||
let temp_dir = TempDir::new();
|
||||
let location = temp_dir.path().join("deps").to_path_buf();
|
||||
let location = temp_dir.path().join("remote").to_path_buf();
|
||||
let specifier =
|
||||
resolve_url("http://localhost:4548/subdir/mismatch_ext.ts").unwrap();
|
||||
let redirected_specifier =
|
||||
|
@ -1324,7 +1324,7 @@ mod tests {
|
|||
async fn test_fetch_no_remote() {
|
||||
let _http_server_guard = test_util::http_server();
|
||||
let temp_dir = TempDir::new();
|
||||
let location = temp_dir.path().join("deps").to_path_buf();
|
||||
let location = temp_dir.path().join("remote").to_path_buf();
|
||||
let file_fetcher = FileFetcher::new(
|
||||
Arc::new(GlobalHttpCache::new(
|
||||
location,
|
||||
|
@ -1350,7 +1350,7 @@ mod tests {
|
|||
async fn test_fetch_cache_only() {
|
||||
let _http_server_guard = test_util::http_server();
|
||||
let temp_dir = TempDir::new();
|
||||
let location = temp_dir.path().join("deps").to_path_buf();
|
||||
let location = temp_dir.path().join("remote").to_path_buf();
|
||||
let file_fetcher_01 = FileFetcher::new(
|
||||
Arc::new(GlobalHttpCache::new(location.clone(), RealDenoCacheEnv)),
|
||||
CacheSetting::Only,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use super::diagnostics::DenoDiagnostic;
|
||||
use super::diagnostics::DiagnosticSource;
|
||||
use super::documents::Document;
|
||||
use super::documents::Documents;
|
||||
use super::language_server;
|
||||
use super::resolver::LspResolver;
|
||||
|
@ -9,7 +10,9 @@ use super::tsc;
|
|||
use super::urls::url_to_uri;
|
||||
|
||||
use crate::args::jsr_url;
|
||||
use crate::lsp::search::PackageSearchApi;
|
||||
use crate::tools::lint::CliLinter;
|
||||
use deno_config::workspace::MappedResolution;
|
||||
use deno_lint::diagnostic::LintDiagnosticRange;
|
||||
|
||||
use deno_ast::SourceRange;
|
||||
|
@ -225,6 +228,7 @@ pub struct TsResponseImportMapper<'a> {
|
|||
documents: &'a Documents,
|
||||
maybe_import_map: Option<&'a ImportMap>,
|
||||
resolver: &'a LspResolver,
|
||||
file_referrer: ModuleSpecifier,
|
||||
}
|
||||
|
||||
impl<'a> TsResponseImportMapper<'a> {
|
||||
|
@ -232,11 +236,13 @@ impl<'a> TsResponseImportMapper<'a> {
|
|||
documents: &'a Documents,
|
||||
maybe_import_map: Option<&'a ImportMap>,
|
||||
resolver: &'a LspResolver,
|
||||
file_referrer: &ModuleSpecifier,
|
||||
) -> Self {
|
||||
Self {
|
||||
documents,
|
||||
maybe_import_map,
|
||||
resolver,
|
||||
file_referrer: file_referrer.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -257,8 +263,6 @@ impl<'a> TsResponseImportMapper<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
let file_referrer = self.documents.get_file_referrer(referrer);
|
||||
|
||||
if let Some(jsr_path) = specifier.as_str().strip_prefix(jsr_url().as_str())
|
||||
{
|
||||
let mut segments = jsr_path.split('/');
|
||||
|
@ -273,7 +277,7 @@ impl<'a> TsResponseImportMapper<'a> {
|
|||
let export = self.resolver.jsr_lookup_export_for_path(
|
||||
&nv,
|
||||
&path,
|
||||
file_referrer.as_deref(),
|
||||
Some(&self.file_referrer),
|
||||
)?;
|
||||
let sub_path = (export != ".").then_some(export);
|
||||
let mut req = None;
|
||||
|
@ -299,7 +303,7 @@ impl<'a> TsResponseImportMapper<'a> {
|
|||
req = req.or_else(|| {
|
||||
self
|
||||
.resolver
|
||||
.jsr_lookup_req_for_nv(&nv, file_referrer.as_deref())
|
||||
.jsr_lookup_req_for_nv(&nv, Some(&self.file_referrer))
|
||||
});
|
||||
let spec_str = if let Some(req) = req {
|
||||
let req_ref = PackageReqReference { req, sub_path };
|
||||
|
@ -329,7 +333,7 @@ impl<'a> TsResponseImportMapper<'a> {
|
|||
|
||||
if let Some(npm_resolver) = self
|
||||
.resolver
|
||||
.maybe_managed_npm_resolver(file_referrer.as_deref())
|
||||
.maybe_managed_npm_resolver(Some(&self.file_referrer))
|
||||
{
|
||||
if npm_resolver.in_npm_package(specifier) {
|
||||
if let Ok(Some(pkg_id)) =
|
||||
|
@ -465,6 +469,26 @@ impl<'a> TsResponseImportMapper<'a> {
|
|||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn is_valid_import(
|
||||
&self,
|
||||
specifier_text: &str,
|
||||
referrer: &ModuleSpecifier,
|
||||
) -> bool {
|
||||
self
|
||||
.resolver
|
||||
.as_graph_resolver(Some(&self.file_referrer))
|
||||
.resolve(
|
||||
specifier_text,
|
||||
&deno_graph::Range {
|
||||
specifier: referrer.clone(),
|
||||
start: deno_graph::Position::zeroed(),
|
||||
end: deno_graph::Position::zeroed(),
|
||||
},
|
||||
deno_graph::source::ResolutionMode::Types,
|
||||
)
|
||||
.is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
fn try_reverse_map_package_json_exports(
|
||||
|
@ -577,7 +601,7 @@ fn fix_ts_import_action(
|
|||
referrer: &ModuleSpecifier,
|
||||
action: &tsc::CodeFixAction,
|
||||
import_mapper: &TsResponseImportMapper,
|
||||
) -> Result<tsc::CodeFixAction, AnyError> {
|
||||
) -> Result<Option<tsc::CodeFixAction>, AnyError> {
|
||||
if matches!(
|
||||
action.fix_name.as_str(),
|
||||
"import" | "fixMissingFunctionDeclaration"
|
||||
|
@ -620,19 +644,21 @@ fn fix_ts_import_action(
|
|||
})
|
||||
.collect();
|
||||
|
||||
return Ok(tsc::CodeFixAction {
|
||||
return Ok(Some(tsc::CodeFixAction {
|
||||
description,
|
||||
changes,
|
||||
commands: None,
|
||||
fix_name: action.fix_name.clone(),
|
||||
fix_id: None,
|
||||
fix_all_description: None,
|
||||
});
|
||||
}));
|
||||
} else if !import_mapper.is_valid_import(specifier, referrer) {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(action.clone())
|
||||
Ok(Some(action.clone()))
|
||||
}
|
||||
|
||||
/// Determines if two TypeScript diagnostic codes are effectively equivalent.
|
||||
|
@ -973,11 +999,14 @@ impl CodeActionCollection {
|
|||
"The action returned from TypeScript is unsupported.",
|
||||
));
|
||||
}
|
||||
let action = fix_ts_import_action(
|
||||
let Some(action) = fix_ts_import_action(
|
||||
specifier,
|
||||
action,
|
||||
&language_server.get_ts_response_import_mapper(specifier),
|
||||
)?;
|
||||
)?
|
||||
else {
|
||||
return Ok(());
|
||||
};
|
||||
let edit = ts_changes_to_edit(&action.changes, language_server)?;
|
||||
let code_action = lsp::CodeAction {
|
||||
title: action.description.clone(),
|
||||
|
@ -1151,6 +1180,162 @@ impl CodeActionCollection {
|
|||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
pub async fn add_source_actions(
|
||||
&mut self,
|
||||
document: &Document,
|
||||
range: &lsp::Range,
|
||||
language_server: &language_server::Inner,
|
||||
) {
|
||||
async fn deno_types_for_npm_action(
|
||||
document: &Document,
|
||||
range: &lsp::Range,
|
||||
language_server: &language_server::Inner,
|
||||
) -> Option<lsp::CodeAction> {
|
||||
let (dep_key, dependency, _) =
|
||||
document.get_maybe_dependency(&range.end)?;
|
||||
if dependency.maybe_deno_types_specifier.is_some() {
|
||||
return None;
|
||||
}
|
||||
if dependency.maybe_code.maybe_specifier().is_none()
|
||||
&& dependency.maybe_type.maybe_specifier().is_none()
|
||||
{
|
||||
// We're using byonm and the package is not cached.
|
||||
return None;
|
||||
}
|
||||
let position = deno_graph::Position::new(
|
||||
range.end.line as usize,
|
||||
range.end.character as usize,
|
||||
);
|
||||
let import_range = dependency.imports.iter().find_map(|i| {
|
||||
if json!(i.kind) != json!("es") && json!(i.kind) != json!("tsType") {
|
||||
return None;
|
||||
}
|
||||
if !i.specifier_range.includes(&position) {
|
||||
return None;
|
||||
}
|
||||
i.full_range.as_ref()
|
||||
})?;
|
||||
let referrer = document.specifier();
|
||||
let file_referrer = document.file_referrer();
|
||||
let config_data = language_server
|
||||
.config
|
||||
.tree
|
||||
.data_for_specifier(file_referrer?)?;
|
||||
let workspace_resolver = config_data.resolver.clone();
|
||||
let npm_ref = if let Ok(resolution) =
|
||||
workspace_resolver.resolve(&dep_key, document.specifier())
|
||||
{
|
||||
let specifier = match resolution {
|
||||
MappedResolution::Normal { specifier, .. }
|
||||
| MappedResolution::ImportMap { specifier, .. } => specifier,
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
NpmPackageReqReference::from_specifier(&specifier).ok()?
|
||||
} else {
|
||||
// Only resolve bare package.json deps for byonm.
|
||||
if !config_data.byonm {
|
||||
return None;
|
||||
}
|
||||
if !language_server
|
||||
.resolver
|
||||
.is_bare_package_json_dep(&dep_key, referrer)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
NpmPackageReqReference::from_str(&format!("npm:{}", &dep_key)).ok()?
|
||||
};
|
||||
let package_name = &npm_ref.req().name;
|
||||
if package_name.starts_with("@types/") {
|
||||
return None;
|
||||
}
|
||||
let managed_npm_resolver = language_server
|
||||
.resolver
|
||||
.maybe_managed_npm_resolver(file_referrer);
|
||||
if let Some(npm_resolver) = managed_npm_resolver {
|
||||
if !npm_resolver.is_pkg_req_folder_cached(npm_ref.req()) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
if language_server
|
||||
.resolver
|
||||
.npm_to_file_url(&npm_ref, document.specifier(), file_referrer)
|
||||
.is_some()
|
||||
{
|
||||
// The package import has types.
|
||||
return None;
|
||||
}
|
||||
let types_package_name = format!("@types/{package_name}");
|
||||
let types_package_version = language_server
|
||||
.npm_search_api
|
||||
.versions(&types_package_name)
|
||||
.await
|
||||
.ok()
|
||||
.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)
|
||||
{
|
||||
format!("npm:{req}")
|
||||
} else {
|
||||
format!("npm:{}@^{}", &types_package_name, types_package_version)
|
||||
};
|
||||
let specifier = ModuleSpecifier::parse(&specifier_text).ok()?;
|
||||
if let Some(file_referrer) = file_referrer {
|
||||
if let Some(text) = language_server
|
||||
.get_ts_response_import_mapper(file_referrer)
|
||||
.check_specifier(&specifier, referrer)
|
||||
{
|
||||
specifier_text = text;
|
||||
}
|
||||
}
|
||||
specifier_text
|
||||
} else {
|
||||
types_package_name.clone()
|
||||
};
|
||||
let uri = language_server
|
||||
.url_map
|
||||
.specifier_to_uri(referrer, file_referrer)
|
||||
.ok()?;
|
||||
let position = lsp::Position {
|
||||
line: import_range.start.line as u32,
|
||||
character: import_range.start.character as u32,
|
||||
};
|
||||
let new_text = format!(
|
||||
"{}// @deno-types=\"{}\"\n",
|
||||
if position.character == 0 { "" } else { "\n" },
|
||||
&types_specifier_text
|
||||
);
|
||||
let text_edit = lsp::TextEdit {
|
||||
range: lsp::Range {
|
||||
start: position,
|
||||
end: position,
|
||||
},
|
||||
new_text,
|
||||
};
|
||||
Some(lsp::CodeAction {
|
||||
title: format!(
|
||||
"Add @deno-types directive for \"{}\"",
|
||||
&types_specifier_text
|
||||
),
|
||||
kind: Some(lsp::CodeActionKind::QUICKFIX),
|
||||
diagnostics: None,
|
||||
edit: Some(lsp::WorkspaceEdit {
|
||||
changes: Some([(uri, vec![text_edit])].into_iter().collect()),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
if let Some(action) =
|
||||
deno_types_for_npm_action(document, range, language_server).await
|
||||
{
|
||||
self.actions.push(CodeActionKind::Deno(action));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepend the whitespace characters found at the start of line_content to content.
|
||||
|
|
|
@ -94,7 +94,7 @@ impl LspCache {
|
|||
let deno_dir = DenoDir::new(global_cache_path)
|
||||
.expect("should be infallible with absolute custom root");
|
||||
let global = Arc::new(GlobalHttpCache::new(
|
||||
deno_dir.deps_folder_path(),
|
||||
deno_dir.remote_folder_path(),
|
||||
crate::cache::RealDenoCacheEnv,
|
||||
));
|
||||
Self {
|
||||
|
|
|
@ -53,6 +53,7 @@ use super::logging::lsp_log;
|
|||
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;
|
||||
use crate::args::LintFlags;
|
||||
use crate::args::LintOptions;
|
||||
|
@ -1931,7 +1932,11 @@ fn resolve_lockfile_from_path(
|
|||
lockfile_path: PathBuf,
|
||||
frozen: bool,
|
||||
) -> Option<CliLockfile> {
|
||||
match CliLockfile::read_from_path(lockfile_path, frozen) {
|
||||
match CliLockfile::read_from_path(CliLockfileReadFromPathOptions {
|
||||
file_path: lockfile_path,
|
||||
frozen,
|
||||
skip_write: false,
|
||||
}) {
|
||||
Ok(value) => {
|
||||
if value.filename.exists() {
|
||||
if let Ok(specifier) = ModuleSpecifier::from_file_path(&value.filename)
|
||||
|
|
|
@ -1517,17 +1517,19 @@ fn diagnose_dependency(
|
|||
let import_ranges: Vec<_> = dependency
|
||||
.imports
|
||||
.iter()
|
||||
.map(|i| documents::to_lsp_range(&i.range))
|
||||
.map(|i| documents::to_lsp_range(&i.specifier_range))
|
||||
.collect();
|
||||
// TODO(nayeemrmn): This is a crude way of detecting `@deno-types` which has
|
||||
// a different specifier and therefore needs a separate call to
|
||||
// `diagnose_resolution()`. It would be much cleaner if that were modelled as
|
||||
// a separate dependency: https://github.com/denoland/deno_graph/issues/247.
|
||||
let is_types_deno_types = !dependency.maybe_type.is_none()
|
||||
&& !dependency
|
||||
.imports
|
||||
.iter()
|
||||
.any(|i| dependency.maybe_type.includes(&i.range.start).is_some());
|
||||
&& !dependency.imports.iter().any(|i| {
|
||||
dependency
|
||||
.maybe_type
|
||||
.includes(&i.specifier_range.start)
|
||||
.is_some()
|
||||
});
|
||||
|
||||
diagnostics.extend(
|
||||
diagnose_resolution(
|
||||
|
|
|
@ -96,6 +96,7 @@ use crate::args::CaData;
|
|||
use crate::args::CacheSetting;
|
||||
use crate::args::CliOptions;
|
||||
use crate::args::Flags;
|
||||
use crate::args::InternalFlags;
|
||||
use crate::args::UnstableFmtOptions;
|
||||
use crate::factory::CliFactory;
|
||||
use crate::file_fetcher::FileFetcher;
|
||||
|
@ -207,11 +208,11 @@ pub struct Inner {
|
|||
module_registry: ModuleRegistry,
|
||||
/// A lazily create "server" for handling test run requests.
|
||||
maybe_testing_server: Option<testing::TestServer>,
|
||||
npm_search_api: CliNpmSearchApi,
|
||||
pub npm_search_api: CliNpmSearchApi,
|
||||
project_version: usize,
|
||||
/// A collection of measurements which instrument that performance of the LSP.
|
||||
performance: Arc<Performance>,
|
||||
resolver: Arc<LspResolver>,
|
||||
pub resolver: Arc<LspResolver>,
|
||||
task_queue: LanguageServerTaskQueue,
|
||||
/// A memoized version of fixable diagnostic codes retrieved from TypeScript.
|
||||
ts_fixable_diagnostics: Vec<String>,
|
||||
|
@ -1612,8 +1613,8 @@ impl Inner {
|
|||
None => false,
|
||||
})
|
||||
.collect();
|
||||
let mut code_actions = CodeActionCollection::default();
|
||||
if !fixable_diagnostics.is_empty() {
|
||||
let mut code_actions = CodeActionCollection::default();
|
||||
let file_diagnostics = self
|
||||
.diagnostics_server
|
||||
.get_ts_diagnostics(&specifier, asset_or_doc.document_lsp_version());
|
||||
|
@ -1721,9 +1722,14 @@ impl Inner {
|
|||
.add_cache_all_action(&specifier, no_cache_diagnostics.to_owned());
|
||||
}
|
||||
}
|
||||
code_actions.set_preferred_fixes();
|
||||
all_actions.extend(code_actions.get_response());
|
||||
}
|
||||
if let Some(document) = asset_or_doc.document() {
|
||||
code_actions
|
||||
.add_source_actions(document, ¶ms.range, self)
|
||||
.await;
|
||||
}
|
||||
code_actions.set_preferred_fixes();
|
||||
all_actions.extend(code_actions.get_response());
|
||||
|
||||
// Refactor
|
||||
let only = params
|
||||
|
@ -1912,6 +1918,7 @@ impl Inner {
|
|||
// as the import map is an implementation detail
|
||||
.and_then(|d| d.resolver.maybe_import_map()),
|
||||
self.resolver.as_ref(),
|
||||
file_referrer,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -3600,7 +3607,10 @@ impl Inner {
|
|||
};
|
||||
let cli_options = CliOptions::new(
|
||||
Arc::new(Flags {
|
||||
cache_path: Some(self.cache.deno_dir().root.clone()),
|
||||
internal: InternalFlags {
|
||||
cache_path: Some(self.cache.deno_dir().root.clone()),
|
||||
..Default::default()
|
||||
},
|
||||
ca_stores: workspace_settings.certificate_stores.clone(),
|
||||
ca_data: workspace_settings.tls_certificate.clone().map(CaData::File),
|
||||
unsafely_ignore_certificate_errors: workspace_settings
|
||||
|
|
|
@ -328,11 +328,11 @@ impl LspResolver {
|
|||
) -> Option<(ModuleSpecifier, MediaType)> {
|
||||
let resolver = self.get_scope_resolver(file_referrer);
|
||||
let node_resolver = resolver.node_resolver.as_ref()?;
|
||||
Some(NodeResolution::into_specifier_and_media_type(
|
||||
Some(NodeResolution::into_specifier_and_media_type(Some(
|
||||
node_resolver
|
||||
.resolve_req_reference(req_ref, referrer, NodeResolutionMode::Types)
|
||||
.ok(),
|
||||
))
|
||||
.ok()?,
|
||||
)))
|
||||
}
|
||||
|
||||
pub fn in_node_modules(&self, specifier: &ModuleSpecifier) -> bool {
|
||||
|
@ -373,6 +373,26 @@ impl LspResolver {
|
|||
Some(NodeResolution::into_specifier_and_media_type(Some(resolution)).1)
|
||||
}
|
||||
|
||||
pub fn is_bare_package_json_dep(
|
||||
&self,
|
||||
specifier_text: &str,
|
||||
referrer: &ModuleSpecifier,
|
||||
) -> bool {
|
||||
let resolver = self.get_scope_resolver(Some(referrer));
|
||||
let Some(node_resolver) = resolver.node_resolver.as_ref() else {
|
||||
return false;
|
||||
};
|
||||
node_resolver
|
||||
.resolve_if_for_npm_pkg(
|
||||
specifier_text,
|
||||
referrer,
|
||||
NodeResolutionMode::Types,
|
||||
)
|
||||
.ok()
|
||||
.flatten()
|
||||
.is_some()
|
||||
}
|
||||
|
||||
pub fn get_closest_package_json(
|
||||
&self,
|
||||
referrer: &ModuleSpecifier,
|
||||
|
|
57
cli/main.rs
57
cli/main.rs
|
@ -37,6 +37,7 @@ 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_runtime::WorkerExecutionMode;
|
||||
pub use deno_runtime::UNSTABLE_GRANULAR_FLAGS;
|
||||
|
||||
|
@ -51,10 +52,12 @@ use deno_runtime::fmt_errors::FixSuggestion;
|
|||
use deno_runtime::tokio_util::create_and_run_current_thread_with_maybe_metrics;
|
||||
use deno_terminal::colors;
|
||||
use factory::CliFactory;
|
||||
use npm::ResolvePkgFolderFromDenoReqError;
|
||||
use standalone::MODULE_NOT_FOUND;
|
||||
use standalone::UNSUPPORTED_SCHEME;
|
||||
use std::env;
|
||||
use std::future::Future;
|
||||
use std::io::IsTerminal;
|
||||
use std::ops::Deref;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
@ -159,7 +162,19 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
|||
DenoSubcommand::Uninstall(uninstall_flags) => spawn_subcommand(async {
|
||||
tools::installer::uninstall(flags, uninstall_flags).await
|
||||
}),
|
||||
DenoSubcommand::Lsp => spawn_subcommand(async { lsp::start().await }),
|
||||
DenoSubcommand::Lsp => spawn_subcommand(async {
|
||||
if std::io::stderr().is_terminal() {
|
||||
log::warn!(
|
||||
"{} command is intended to be run by text editors and IDEs and shouldn't be run manually.
|
||||
|
||||
Visit https://docs.deno.com/runtime/getting_started/setup_your_environment/ for instruction
|
||||
how to setup your favorite text editor.
|
||||
|
||||
Press Ctrl+C to exit.
|
||||
", colors::cyan("deno lsp"));
|
||||
}
|
||||
lsp::start().await
|
||||
}),
|
||||
DenoSubcommand::Lint(lint_flags) => spawn_subcommand(async {
|
||||
if lint_flags.rules {
|
||||
tools::lint::print_rules_list(
|
||||
|
@ -182,6 +197,21 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
|||
match result {
|
||||
Ok(v) => Ok(v),
|
||||
Err(script_err) => {
|
||||
if let Some(ResolvePkgFolderFromDenoReqError::Byonm(ByonmResolvePkgFolderFromDenoReqError::UnmatchedReq(_))) = script_err.downcast_ref::<ResolvePkgFolderFromDenoReqError>() {
|
||||
if flags.node_modules_dir.is_none() {
|
||||
let mut flags = flags.deref().clone();
|
||||
let watch = match &flags.subcommand {
|
||||
DenoSubcommand::Run(run_flags) => run_flags.watch.clone(),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
flags.node_modules_dir = Some(deno_config::deno_json::NodeModulesDirMode::None);
|
||||
// use the current lockfile, but don't write it out
|
||||
if flags.frozen_lockfile.is_none() {
|
||||
flags.internal.lockfile_skip_write = true;
|
||||
}
|
||||
return tools::run::run_script(WorkerExecutionMode::Run, Arc::new(flags), watch).await;
|
||||
}
|
||||
}
|
||||
let script_err_msg = script_err.to_string();
|
||||
if script_err_msg.starts_with(MODULE_NOT_FOUND) || script_err_msg.starts_with(UNSUPPORTED_SCHEME) {
|
||||
if run_flags.bare {
|
||||
|
@ -392,6 +422,31 @@ fn get_suggestions_for_terminal_errors(e: &JsError) -> Vec<FixSuggestion> {
|
|||
"Run again with `--unstable-webgpu` flag to enable this API.",
|
||||
),
|
||||
];
|
||||
// Try to capture errors like:
|
||||
// ```
|
||||
// Uncaught Error: Cannot find module '../build/Release/canvas.node'
|
||||
// Require stack:
|
||||
// - /.../deno/npm/registry.npmjs.org/canvas/2.11.2/lib/bindings.js
|
||||
// - /.../.cache/deno/npm/registry.npmjs.org/canvas/2.11.2/lib/canvas.js
|
||||
// ```
|
||||
} else if msg.contains("Cannot find module")
|
||||
&& msg.contains("Require stack")
|
||||
&& msg.contains(".node'")
|
||||
{
|
||||
return vec![
|
||||
FixSuggestion::info_multiline(
|
||||
&[
|
||||
"Trying to execute an npm package using Node-API addons,",
|
||||
"these packages require local `node_modules` directory to be present."
|
||||
]
|
||||
),
|
||||
FixSuggestion::hint_multiline(
|
||||
&[
|
||||
"Add `\"nodeModulesDir\": \"auto\" option to `deno.json`, and then run",
|
||||
"`deno install --allow-scripts=npm:<package> --entrypoint <script>` to setup `node_modules` directory."
|
||||
]
|
||||
)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
{ "node_api_create_syntax_error"; "napi_make_callback"; "napi_has_named_property"; "napi_async_destroy"; "napi_coerce_to_object"; "napi_get_arraybuffer_info"; "napi_detach_arraybuffer"; "napi_get_undefined"; "napi_reference_unref"; "napi_fatal_error"; "napi_open_callback_scope"; "napi_close_callback_scope"; "napi_get_value_uint32"; "napi_create_function"; "napi_create_arraybuffer"; "napi_get_value_int64"; "napi_get_all_property_names"; "napi_resolve_deferred"; "napi_is_detached_arraybuffer"; "napi_create_string_utf8"; "napi_create_threadsafe_function"; "node_api_throw_syntax_error"; "napi_create_bigint_int64"; "napi_wrap"; "napi_set_property"; "napi_get_value_bigint_int64"; "napi_open_handle_scope"; "napi_create_error"; "napi_create_buffer"; "napi_cancel_async_work"; "napi_is_exception_pending"; "napi_acquire_threadsafe_function"; "napi_create_external"; "napi_get_threadsafe_function_context"; "napi_get_null"; "napi_create_string_utf16"; "node_api_create_external_string_utf16"; "napi_get_value_bigint_uint64"; "napi_module_register"; "napi_is_typedarray"; "napi_create_external_buffer"; "napi_get_new_target"; "napi_get_instance_data"; "napi_close_handle_scope"; "napi_get_value_string_utf16"; "napi_get_property_names"; "napi_is_arraybuffer"; "napi_get_cb_info"; "napi_define_properties"; "napi_add_env_cleanup_hook"; "node_api_get_module_file_name"; "napi_get_node_version"; "napi_create_int64"; "napi_create_double"; "napi_get_and_clear_last_exception"; "napi_create_reference"; "napi_get_typedarray_info"; "napi_call_threadsafe_function"; "napi_get_last_error_info"; "napi_create_array_with_length"; "napi_coerce_to_number"; "napi_get_global"; "napi_is_error"; "napi_set_instance_data"; "napi_create_typedarray"; "napi_throw_type_error"; "napi_has_property"; "napi_get_value_external"; "napi_create_range_error"; "napi_typeof"; "napi_ref_threadsafe_function"; "napi_create_bigint_uint64"; "napi_get_prototype"; "napi_adjust_external_memory"; "napi_release_threadsafe_function"; "napi_delete_async_work"; "napi_create_string_latin1"; "node_api_create_external_string_latin1"; "napi_is_array"; "napi_unref_threadsafe_function"; "napi_throw_error"; "napi_has_own_property"; "napi_get_reference_value"; "napi_remove_env_cleanup_hook"; "napi_get_value_string_utf8"; "napi_is_promise"; "napi_get_boolean"; "napi_run_script"; "napi_get_element"; "napi_get_named_property"; "napi_get_buffer_info"; "napi_get_value_bool"; "napi_reference_ref"; "napi_create_object"; "napi_create_promise"; "napi_create_int32"; "napi_escape_handle"; "napi_open_escapable_handle_scope"; "napi_throw"; "napi_get_value_double"; "napi_set_named_property"; "napi_call_function"; "napi_create_date"; "napi_object_freeze"; "napi_get_uv_event_loop"; "napi_get_value_string_latin1"; "napi_reject_deferred"; "napi_add_finalizer"; "napi_create_array"; "napi_delete_reference"; "napi_get_date_value"; "napi_create_dataview"; "napi_get_version"; "napi_define_class"; "napi_is_date"; "napi_remove_wrap"; "napi_delete_property"; "napi_instanceof"; "napi_create_buffer_copy"; "napi_delete_element"; "napi_object_seal"; "napi_queue_async_work"; "napi_get_value_bigint_words"; "napi_is_buffer"; "napi_get_array_length"; "napi_get_property"; "napi_new_instance"; "napi_set_element"; "napi_create_bigint_words"; "napi_strict_equals"; "napi_is_dataview"; "napi_close_escapable_handle_scope"; "napi_get_dataview_info"; "napi_get_value_int32"; "napi_unwrap"; "napi_throw_range_error"; "napi_coerce_to_bool"; "napi_create_uint32"; "napi_has_element"; "napi_create_external_arraybuffer"; "napi_create_symbol"; "node_api_symbol_for"; "napi_coerce_to_string"; "napi_create_type_error"; "napi_fatal_exception"; "napi_create_async_work"; "napi_async_init"; "node_api_create_property_key_utf16"; "napi_type_tag_object"; "napi_check_object_type_tag"; "node_api_post_finalizer"; "napi_add_async_cleanup_hook"; "napi_remove_async_cleanup_hook"; };
|
||||
{ "node_api_create_syntax_error"; "napi_make_callback"; "napi_has_named_property"; "napi_async_destroy"; "napi_coerce_to_object"; "napi_get_arraybuffer_info"; "napi_detach_arraybuffer"; "napi_get_undefined"; "napi_reference_unref"; "napi_fatal_error"; "napi_open_callback_scope"; "napi_close_callback_scope"; "napi_get_value_uint32"; "napi_create_function"; "napi_create_arraybuffer"; "napi_get_value_int64"; "napi_get_all_property_names"; "napi_resolve_deferred"; "napi_is_detached_arraybuffer"; "napi_create_string_utf8"; "napi_create_threadsafe_function"; "node_api_throw_syntax_error"; "napi_create_bigint_int64"; "napi_wrap"; "napi_set_property"; "napi_get_value_bigint_int64"; "napi_open_handle_scope"; "napi_create_error"; "napi_create_buffer"; "napi_cancel_async_work"; "napi_is_exception_pending"; "napi_acquire_threadsafe_function"; "napi_create_external"; "napi_get_threadsafe_function_context"; "napi_get_null"; "napi_create_string_utf16"; "node_api_create_external_string_utf16"; "napi_get_value_bigint_uint64"; "napi_module_register"; "napi_is_typedarray"; "napi_create_external_buffer"; "napi_get_new_target"; "napi_get_instance_data"; "napi_close_handle_scope"; "napi_get_value_string_utf16"; "napi_get_property_names"; "napi_is_arraybuffer"; "napi_get_cb_info"; "napi_define_properties"; "napi_add_env_cleanup_hook"; "node_api_get_module_file_name"; "napi_get_node_version"; "napi_create_int64"; "napi_create_double"; "napi_get_and_clear_last_exception"; "napi_create_reference"; "napi_get_typedarray_info"; "napi_call_threadsafe_function"; "napi_get_last_error_info"; "napi_create_array_with_length"; "napi_coerce_to_number"; "napi_get_global"; "napi_is_error"; "napi_set_instance_data"; "napi_create_typedarray"; "napi_throw_type_error"; "napi_has_property"; "napi_get_value_external"; "napi_create_range_error"; "napi_typeof"; "napi_ref_threadsafe_function"; "napi_create_bigint_uint64"; "napi_get_prototype"; "napi_adjust_external_memory"; "napi_release_threadsafe_function"; "napi_delete_async_work"; "napi_create_string_latin1"; "node_api_create_external_string_latin1"; "napi_is_array"; "napi_unref_threadsafe_function"; "napi_throw_error"; "napi_has_own_property"; "napi_get_reference_value"; "napi_remove_env_cleanup_hook"; "napi_get_value_string_utf8"; "napi_is_promise"; "napi_get_boolean"; "napi_run_script"; "napi_get_element"; "napi_get_named_property"; "napi_get_buffer_info"; "napi_get_value_bool"; "napi_reference_ref"; "napi_create_object"; "napi_create_promise"; "napi_create_int32"; "napi_escape_handle"; "napi_open_escapable_handle_scope"; "napi_throw"; "napi_get_value_double"; "napi_set_named_property"; "napi_call_function"; "napi_create_date"; "napi_object_freeze"; "napi_get_uv_event_loop"; "napi_get_value_string_latin1"; "napi_reject_deferred"; "napi_add_finalizer"; "napi_create_array"; "napi_delete_reference"; "napi_get_date_value"; "napi_create_dataview"; "napi_get_version"; "napi_define_class"; "napi_is_date"; "napi_remove_wrap"; "napi_delete_property"; "napi_instanceof"; "napi_create_buffer_copy"; "napi_delete_element"; "napi_object_seal"; "napi_queue_async_work"; "napi_get_value_bigint_words"; "napi_is_buffer"; "napi_get_array_length"; "napi_get_property"; "napi_new_instance"; "napi_set_element"; "napi_create_bigint_words"; "napi_strict_equals"; "napi_is_dataview"; "napi_close_escapable_handle_scope"; "napi_get_dataview_info"; "napi_get_value_int32"; "napi_unwrap"; "napi_throw_range_error"; "napi_coerce_to_bool"; "napi_create_uint32"; "napi_has_element"; "napi_create_external_arraybuffer"; "napi_create_symbol"; "node_api_symbol_for"; "napi_coerce_to_string"; "napi_create_type_error"; "napi_fatal_exception"; "napi_create_async_work"; "napi_async_init"; "node_api_create_property_key_utf16"; "napi_type_tag_object"; "napi_check_object_type_tag"; "node_api_post_finalizer"; "napi_add_async_cleanup_hook"; "napi_remove_async_cleanup_hook"; "uv_mutex_init"; "uv_mutex_lock"; "uv_mutex_unlock"; "uv_mutex_destroy"; "uv_async_init"; "uv_async_send"; "uv_close"; };
|
|
@ -150,4 +150,11 @@ _napi_type_tag_object
|
|||
_napi_check_object_type_tag
|
||||
_node_api_post_finalizer
|
||||
_napi_add_async_cleanup_hook
|
||||
_napi_remove_async_cleanup_hook
|
||||
_napi_remove_async_cleanup_hook
|
||||
_uv_mutex_init
|
||||
_uv_mutex_lock
|
||||
_uv_mutex_unlock
|
||||
_uv_mutex_destroy
|
||||
_uv_async_init
|
||||
_uv_async_send
|
||||
_uv_close
|
|
@ -152,4 +152,11 @@ EXPORTS
|
|||
napi_check_object_type_tag
|
||||
node_api_post_finalizer
|
||||
napi_add_async_cleanup_hook
|
||||
napi_remove_async_cleanup_hook
|
||||
napi_remove_async_cleanup_hook
|
||||
uv_mutex_init
|
||||
uv_mutex_lock
|
||||
uv_mutex_unlock
|
||||
uv_mutex_destroy
|
||||
uv_async_init
|
||||
uv_async_send
|
||||
uv_close
|
|
@ -18,3 +18,4 @@
|
|||
pub mod js_native_api;
|
||||
pub mod node_api;
|
||||
pub mod util;
|
||||
pub mod uv;
|
||||
|
|
|
@ -547,11 +547,16 @@ fn napi_delete_async_work(env: *mut Env, work: napi_async_work) -> napi_status {
|
|||
}
|
||||
|
||||
#[napi_sym]
|
||||
fn napi_get_uv_event_loop(env: *mut Env, uv_loop: *mut *mut ()) -> napi_status {
|
||||
let env = check_env!(env);
|
||||
fn napi_get_uv_event_loop(
|
||||
env_ptr: *mut Env,
|
||||
uv_loop: *mut *mut (),
|
||||
) -> napi_status {
|
||||
let env = check_env!(env_ptr);
|
||||
check_arg!(env, uv_loop);
|
||||
// There is no uv_loop in Deno
|
||||
napi_set_last_error(env, napi_generic_failure)
|
||||
unsafe {
|
||||
*uv_loop = env_ptr.cast();
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[napi_sym]
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "napi_sym"
|
||||
version = "0.98.0"
|
||||
version = "0.100.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -152,6 +152,13 @@
|
|||
"napi_check_object_type_tag",
|
||||
"node_api_post_finalizer",
|
||||
"napi_add_async_cleanup_hook",
|
||||
"napi_remove_async_cleanup_hook"
|
||||
"napi_remove_async_cleanup_hook",
|
||||
"uv_mutex_init",
|
||||
"uv_mutex_lock",
|
||||
"uv_mutex_unlock",
|
||||
"uv_mutex_destroy",
|
||||
"uv_async_init",
|
||||
"uv_async_send",
|
||||
"uv_close"
|
||||
]
|
||||
}
|
||||
|
|
231
cli/napi/uv.rs
Normal file
231
cli/napi/uv.rs
Normal file
|
@ -0,0 +1,231 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use deno_core::parking_lot::Mutex;
|
||||
use deno_runtime::deno_napi::*;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::ptr::addr_of_mut;
|
||||
|
||||
#[allow(clippy::print_stderr)]
|
||||
fn assert_ok(res: c_int) -> c_int {
|
||||
if res != 0 {
|
||||
eprintln!("bad result in uv polyfill: {res}");
|
||||
// don't panic because that might unwind into
|
||||
// c/c++
|
||||
std::process::abort();
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
use crate::napi::js_native_api::napi_create_string_utf8;
|
||||
use crate::napi::node_api::napi_create_async_work;
|
||||
use crate::napi::node_api::napi_delete_async_work;
|
||||
use crate::napi::node_api::napi_queue_async_work;
|
||||
use std::ffi::c_int;
|
||||
|
||||
const UV_MUTEX_SIZE: usize = {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
std::mem::size_of::<libc::pthread_mutex_t>()
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
std::mem::size_of::<windows_sys::Win32::System::Threading::CRITICAL_SECTION>(
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
struct uv_mutex_t {
|
||||
mutex: Mutex<()>,
|
||||
_padding: [MaybeUninit<usize>; const {
|
||||
(UV_MUTEX_SIZE - size_of::<Mutex<()>>()) / size_of::<usize>()
|
||||
}],
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn uv_mutex_init(lock: *mut uv_mutex_t) -> c_int {
|
||||
unsafe {
|
||||
addr_of_mut!((*lock).mutex).write(Mutex::new(()));
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn uv_mutex_lock(lock: *mut uv_mutex_t) {
|
||||
unsafe {
|
||||
let guard = (*lock).mutex.lock();
|
||||
// forget the guard so it doesn't unlock when it goes out of scope.
|
||||
// we're going to unlock it manually
|
||||
std::mem::forget(guard);
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn uv_mutex_unlock(lock: *mut uv_mutex_t) {
|
||||
unsafe {
|
||||
(*lock).mutex.force_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn uv_mutex_destroy(_lock: *mut uv_mutex_t) {
|
||||
// no cleanup required
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[allow(dead_code)]
|
||||
enum uv_handle_type {
|
||||
UV_UNKNOWN_HANDLE = 0,
|
||||
UV_ASYNC,
|
||||
UV_CHECK,
|
||||
UV_FS_EVENT,
|
||||
UV_FS_POLL,
|
||||
UV_HANDLE,
|
||||
UV_IDLE,
|
||||
UV_NAMED_PIPE,
|
||||
UV_POLL,
|
||||
UV_PREPARE,
|
||||
UV_PROCESS,
|
||||
UV_STREAM,
|
||||
UV_TCP,
|
||||
UV_TIMER,
|
||||
UV_TTY,
|
||||
UV_UDP,
|
||||
UV_SIGNAL,
|
||||
UV_FILE,
|
||||
UV_HANDLE_TYPE_MAX,
|
||||
}
|
||||
|
||||
const UV_HANDLE_SIZE: usize = 96;
|
||||
|
||||
#[repr(C)]
|
||||
struct uv_handle_t {
|
||||
// public members
|
||||
pub data: *mut c_void,
|
||||
pub r#loop: *mut uv_loop_t,
|
||||
pub r#type: uv_handle_type,
|
||||
|
||||
_padding: [MaybeUninit<usize>; const {
|
||||
(UV_HANDLE_SIZE
|
||||
- size_of::<*mut c_void>()
|
||||
- size_of::<*mut uv_loop_t>()
|
||||
- size_of::<uv_handle_type>())
|
||||
/ size_of::<usize>()
|
||||
}],
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
const UV_ASYNC_SIZE: usize = 128;
|
||||
|
||||
#[cfg(windows)]
|
||||
const UV_ASYNC_SIZE: usize = 224;
|
||||
|
||||
#[repr(C)]
|
||||
struct uv_async_t {
|
||||
// public members
|
||||
pub data: *mut c_void,
|
||||
pub r#loop: *mut uv_loop_t,
|
||||
pub r#type: uv_handle_type,
|
||||
// private
|
||||
async_cb: uv_async_cb,
|
||||
work: napi_async_work,
|
||||
_padding: [MaybeUninit<usize>; const {
|
||||
(UV_ASYNC_SIZE
|
||||
- size_of::<*mut c_void>()
|
||||
- size_of::<*mut uv_loop_t>()
|
||||
- size_of::<uv_handle_type>()
|
||||
- size_of::<uv_async_cb>()
|
||||
- size_of::<napi_async_work>())
|
||||
/ size_of::<usize>()
|
||||
}],
|
||||
}
|
||||
|
||||
type uv_loop_t = Env;
|
||||
type uv_async_cb = extern "C" fn(handle: *mut uv_async_t);
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn uv_async_init(
|
||||
r#loop: *mut uv_loop_t,
|
||||
// probably uninitialized
|
||||
r#async: *mut uv_async_t,
|
||||
async_cb: uv_async_cb,
|
||||
) -> c_int {
|
||||
unsafe {
|
||||
addr_of_mut!((*r#async).r#loop).write(r#loop);
|
||||
addr_of_mut!((*r#async).r#type).write(uv_handle_type::UV_ASYNC);
|
||||
addr_of_mut!((*r#async).async_cb).write(async_cb);
|
||||
|
||||
let mut resource_name: MaybeUninit<napi_value> = MaybeUninit::uninit();
|
||||
assert_ok(napi_create_string_utf8(
|
||||
r#loop,
|
||||
c"uv_async".as_ptr(),
|
||||
usize::MAX,
|
||||
resource_name.as_mut_ptr(),
|
||||
));
|
||||
let resource_name = resource_name.assume_init();
|
||||
|
||||
let res = napi_create_async_work(
|
||||
r#loop,
|
||||
None::<v8::Local<'static, v8::Value>>.into(),
|
||||
resource_name,
|
||||
Some(async_exec_wrap),
|
||||
None,
|
||||
r#async.cast(),
|
||||
addr_of_mut!((*r#async).work),
|
||||
);
|
||||
-res
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn uv_async_send(handle: *mut uv_async_t) -> c_int {
|
||||
unsafe { -napi_queue_async_work((*handle).r#loop, (*handle).work) }
|
||||
}
|
||||
|
||||
type uv_close_cb = unsafe extern "C" fn(*mut uv_handle_t);
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn uv_close(handle: *mut uv_handle_t, close: uv_close_cb) {
|
||||
unsafe {
|
||||
if handle.is_null() {
|
||||
close(handle);
|
||||
return;
|
||||
}
|
||||
if let uv_handle_type::UV_ASYNC = (*handle).r#type {
|
||||
let handle: *mut uv_async_t = handle.cast();
|
||||
napi_delete_async_work((*handle).r#loop, (*handle).work);
|
||||
}
|
||||
close(handle);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn async_exec_wrap(_env: napi_env, data: *mut c_void) {
|
||||
let data: *mut uv_async_t = data.cast();
|
||||
unsafe {
|
||||
((*data).async_cb)(data);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn sizes() {
|
||||
assert_eq!(
|
||||
std::mem::size_of::<libuv_sys_lite::uv_mutex_t>(),
|
||||
UV_MUTEX_SIZE
|
||||
);
|
||||
assert_eq!(
|
||||
std::mem::size_of::<libuv_sys_lite::uv_handle_t>(),
|
||||
UV_HANDLE_SIZE
|
||||
);
|
||||
assert_eq!(
|
||||
std::mem::size_of::<libuv_sys_lite::uv_async_t>(),
|
||||
UV_ASYNC_SIZE
|
||||
);
|
||||
assert_eq!(std::mem::size_of::<uv_mutex_t>(), UV_MUTEX_SIZE);
|
||||
assert_eq!(std::mem::size_of::<uv_handle_t>(), UV_HANDLE_SIZE);
|
||||
assert_eq!(std::mem::size_of::<uv_async_t>(), UV_ASYNC_SIZE);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
// 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;
|
||||
|
@ -21,6 +22,7 @@ use crate::resolver::CliDenoResolverFs;
|
|||
|
||||
use super::CliNpmResolver;
|
||||
use super::InnerCliNpmResolverRef;
|
||||
use super::ResolvePkgFolderFromDenoReqError;
|
||||
|
||||
pub type CliByonmNpmResolverCreateOptions =
|
||||
ByonmNpmResolverCreateOptions<CliDenoResolverFs>;
|
||||
|
@ -31,18 +33,19 @@ pub type CliByonmNpmResolver = ByonmNpmResolver<CliDenoResolverFs>;
|
|||
struct CliByonmWrapper(Arc<CliByonmNpmResolver>);
|
||||
|
||||
impl NodeRequireResolver for CliByonmWrapper {
|
||||
fn ensure_read_permission(
|
||||
fn ensure_read_permission<'a>(
|
||||
&self,
|
||||
permissions: &mut dyn NodePermissions,
|
||||
path: &Path,
|
||||
) -> Result<(), AnyError> {
|
||||
path: &'a Path,
|
||||
) -> Result<Cow<'a, Path>, AnyError> {
|
||||
if !path
|
||||
.components()
|
||||
.any(|c| c.as_os_str().to_ascii_lowercase() == "node_modules")
|
||||
{
|
||||
_ = permissions.check_read_path(path)?;
|
||||
permissions.check_read_path(path)
|
||||
} else {
|
||||
Ok(Cow::Borrowed(path))
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,10 +93,11 @@ impl CliNpmResolver for CliByonmNpmResolver {
|
|||
&self,
|
||||
req: &PackageReq,
|
||||
referrer: &Url,
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
) -> Result<PathBuf, ResolvePkgFolderFromDenoReqError> {
|
||||
ByonmNpmResolver::resolve_pkg_folder_from_deno_module_req(
|
||||
self, req, referrer,
|
||||
)
|
||||
.map_err(ResolvePkgFolderFromDenoReqError::Byonm)
|
||||
}
|
||||
|
||||
fn check_state_hash(&self) -> Option<u64> {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// 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;
|
||||
|
@ -20,6 +21,7 @@ use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
|
|||
use deno_npm::NpmPackageId;
|
||||
use deno_npm::NpmResolutionPackage;
|
||||
use deno_npm::NpmSystemInfo;
|
||||
use deno_runtime::colors;
|
||||
use deno_runtime::deno_fs::FileSystem;
|
||||
use deno_runtime::deno_node::NodePermissions;
|
||||
use deno_runtime::deno_node::NodeRequireResolver;
|
||||
|
@ -51,6 +53,7 @@ use self::resolvers::NpmPackageFsResolver;
|
|||
|
||||
use super::CliNpmResolver;
|
||||
use super::InnerCliNpmResolverRef;
|
||||
use super::ResolvePkgFolderFromDenoReqError;
|
||||
|
||||
mod cache;
|
||||
mod registry;
|
||||
|
@ -428,6 +431,16 @@ impl ManagedCliNpmResolver {
|
|||
self.resolution.snapshot()
|
||||
}
|
||||
|
||||
pub fn top_package_req_for_name(&self, name: &str) -> Option<PackageReq> {
|
||||
let package_reqs = self.resolution.package_reqs();
|
||||
let mut entries = package_reqs
|
||||
.iter()
|
||||
.filter(|(_, nv)| nv.name == name)
|
||||
.collect::<Vec<_>>();
|
||||
entries.sort_by_key(|(_, nv)| &nv.version);
|
||||
Some(entries.last()?.0.clone())
|
||||
}
|
||||
|
||||
pub fn serialized_valid_snapshot_for_system(
|
||||
&self,
|
||||
system_info: &NpmSystemInfo,
|
||||
|
@ -467,6 +480,25 @@ impl ManagedCliNpmResolver {
|
|||
self.resolution.resolve_pkg_id_from_pkg_req(req)
|
||||
}
|
||||
|
||||
pub fn ensure_no_pkg_json_dep_errors(&self) -> Result<(), AnyError> {
|
||||
for err in self.npm_install_deps_provider.pkg_json_dep_errors() {
|
||||
match err {
|
||||
deno_package_json::PackageJsonDepValueParseError::VersionReq(_) => {
|
||||
return Err(
|
||||
AnyError::from(err.clone())
|
||||
.context("Failed to install from package.json"),
|
||||
);
|
||||
}
|
||||
deno_package_json::PackageJsonDepValueParseError::Unsupported {
|
||||
..
|
||||
} => {
|
||||
log::warn!("{} {} in package.json", colors::yellow("Warning"), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Ensures that the top level `package.json` dependencies are installed.
|
||||
/// This may set up the `node_modules` directory.
|
||||
///
|
||||
|
@ -478,6 +510,7 @@ impl ManagedCliNpmResolver {
|
|||
if !self.top_level_install_flag.raise() {
|
||||
return Ok(false); // already did this
|
||||
}
|
||||
|
||||
let pkg_json_remote_pkgs = self.npm_install_deps_provider.remote_pkgs();
|
||||
if pkg_json_remote_pkgs.is_empty() {
|
||||
return Ok(false);
|
||||
|
@ -561,11 +594,11 @@ impl NpmResolver for ManagedCliNpmResolver {
|
|||
}
|
||||
|
||||
impl NodeRequireResolver for ManagedCliNpmResolver {
|
||||
fn ensure_read_permission(
|
||||
fn ensure_read_permission<'a>(
|
||||
&self,
|
||||
permissions: &mut dyn NodePermissions,
|
||||
path: &Path,
|
||||
) -> Result<(), AnyError> {
|
||||
path: &'a Path,
|
||||
) -> Result<Cow<'a, Path>, AnyError> {
|
||||
self.fs_resolver.ensure_read_permission(permissions, path)
|
||||
}
|
||||
}
|
||||
|
@ -639,9 +672,13 @@ impl CliNpmResolver for ManagedCliNpmResolver {
|
|||
&self,
|
||||
req: &PackageReq,
|
||||
_referrer: &ModuleSpecifier,
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
let pkg_id = self.resolve_pkg_id_from_pkg_req(req)?;
|
||||
self.resolve_pkg_folder_from_pkg_id(&pkg_id)
|
||||
) -> Result<PathBuf, ResolvePkgFolderFromDenoReqError> {
|
||||
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)
|
||||
}
|
||||
|
||||
fn check_state_hash(&self) -> Option<u64> {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
pub mod bin_entries;
|
||||
pub mod lifecycle_scripts;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::io::ErrorKind;
|
||||
use std::path::Path;
|
||||
|
@ -62,11 +63,12 @@ pub trait NpmPackageFsResolver: Send + Sync {
|
|||
|
||||
async fn cache_packages(&self) -> Result<(), AnyError>;
|
||||
|
||||
fn ensure_read_permission(
|
||||
#[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: &Path,
|
||||
) -> Result<(), AnyError>;
|
||||
path: &'a Path,
|
||||
) -> Result<Cow<'a, Path>, AnyError>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -85,11 +87,15 @@ impl RegistryReadPermissionChecker {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn ensure_registry_read_permission(
|
||||
pub fn ensure_registry_read_permission<'a>(
|
||||
&self,
|
||||
permissions: &mut dyn NodePermissions,
|
||||
path: &Path,
|
||||
) -> Result<(), AnyError> {
|
||||
path: &'a Path,
|
||||
) -> Result<Cow<'a, Path>, 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
|
||||
|
@ -118,20 +124,20 @@ impl RegistryReadPermissionChecker {
|
|||
},
|
||||
}
|
||||
};
|
||||
let Some(registry_path_canon) = canonicalize(&self.registry_path)? else {
|
||||
return Ok(()); // not exists, allow reading
|
||||
};
|
||||
let Some(path_canon) = canonicalize(path)? else {
|
||||
return Ok(()); // not exists, allow reading
|
||||
};
|
||||
|
||||
if path_canon.starts_with(registry_path_canon) {
|
||||
return Ok(());
|
||||
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)?;
|
||||
Ok(())
|
||||
permissions.check_read_path(path)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -183,11 +183,11 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn ensure_read_permission(
|
||||
fn ensure_read_permission<'a>(
|
||||
&self,
|
||||
permissions: &mut dyn NodePermissions,
|
||||
path: &Path,
|
||||
) -> Result<(), AnyError> {
|
||||
path: &'a Path,
|
||||
) -> Result<Cow<'a, Path>, AnyError> {
|
||||
self
|
||||
.registry_read_permission_checker
|
||||
.ensure_registry_read_permission(permissions, path)
|
||||
|
|
|
@ -257,11 +257,11 @@ impl NpmPackageFsResolver for LocalNpmPackageResolver {
|
|||
.await
|
||||
}
|
||||
|
||||
fn ensure_read_permission(
|
||||
fn ensure_read_permission<'a>(
|
||||
&self,
|
||||
permissions: &mut dyn NodePermissions,
|
||||
path: &Path,
|
||||
) -> Result<(), AnyError> {
|
||||
path: &'a Path,
|
||||
) -> Result<Cow<'a, Path>, AnyError> {
|
||||
self
|
||||
.registry_read_permission_checker
|
||||
.ensure_registry_read_permission(permissions, path)
|
||||
|
@ -343,6 +343,14 @@ 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();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
for package in &package_partitions.packages {
|
||||
if let Some(current_pkg) =
|
||||
newest_packages_by_name.get_mut(&package.id.nv.name)
|
||||
|
@ -357,11 +365,29 @@ async fn sync_resolution_with_fs(
|
|||
let package_folder_name =
|
||||
get_package_folder_id_folder_name(&package.get_package_cache_folder_id());
|
||||
let folder_path = deno_local_registry_dir.join(&package_folder_name);
|
||||
let tags = package_tags
|
||||
.get(&package.id.nv)
|
||||
.map(|tags| tags.join(","))
|
||||
.unwrap_or_default();
|
||||
enum PackageFolderState {
|
||||
UpToDate,
|
||||
Uninitialized,
|
||||
TagsOutdated,
|
||||
}
|
||||
let initialized_file = folder_path.join(".initialized");
|
||||
let package_state = std::fs::read_to_string(&initialized_file)
|
||||
.map(|s| {
|
||||
if s != tags {
|
||||
PackageFolderState::TagsOutdated
|
||||
} else {
|
||||
PackageFolderState::UpToDate
|
||||
}
|
||||
})
|
||||
.unwrap_or(PackageFolderState::Uninitialized);
|
||||
if !cache
|
||||
.cache_setting()
|
||||
.should_use_for_npm_package(&package.id.nv.name)
|
||||
|| !initialized_file.exists()
|
||||
|| matches!(package_state, PackageFolderState::Uninitialized)
|
||||
{
|
||||
// cache bust the dep from the dep setup cache so the symlinks
|
||||
// are forced to be recreated
|
||||
|
@ -371,6 +397,7 @@ async fn sync_resolution_with_fs(
|
|||
let bin_entries_to_setup = bin_entries.clone();
|
||||
let packages_with_deprecation_warnings =
|
||||
packages_with_deprecation_warnings.clone();
|
||||
|
||||
cache_futures.push(async move {
|
||||
tarball_cache
|
||||
.ensure_package(&package.id.nv, &package.dist)
|
||||
|
@ -389,7 +416,7 @@ async fn sync_resolution_with_fs(
|
|||
move || {
|
||||
clone_dir_recursive(&cache_folder, &package_path)?;
|
||||
// write out a file that indicates this folder has been initialized
|
||||
fs::write(initialized_file, "")?;
|
||||
fs::write(initialized_file, tags)?;
|
||||
|
||||
Ok::<_, AnyError>(())
|
||||
}
|
||||
|
@ -410,6 +437,8 @@ async fn sync_resolution_with_fs(
|
|||
drop(pb_guard); // explicit for clarity
|
||||
Ok::<_, AnyError>(())
|
||||
});
|
||||
} else if matches!(package_state, PackageFolderState::TagsOutdated) {
|
||||
fs::write(initialized_file, tags)?;
|
||||
}
|
||||
|
||||
let sub_node_modules = folder_path.join("node_modules");
|
||||
|
@ -518,9 +547,9 @@ async fn sync_resolution_with_fs(
|
|||
// linked into the root
|
||||
match found_names.entry(remote_alias) {
|
||||
Entry::Occupied(nv) => {
|
||||
alias_clashes
|
||||
|| remote.req.name != nv.get().name // alias to a different package (in case of duplicate aliases)
|
||||
|| !remote.req.version_req.matches(&nv.get().version) // incompatible version
|
||||
// alias to a different package (in case of duplicate aliases)
|
||||
// or the version doesn't match the version in the root node_modules
|
||||
alias_clashes || &remote_pkg.id.nv != *nv.get()
|
||||
}
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(&remote_pkg.id.nv);
|
||||
|
|
|
@ -14,11 +14,13 @@ use deno_core::error::AnyError;
|
|||
use deno_core::serde_json;
|
||||
use deno_npm::registry::NpmPackageInfo;
|
||||
use deno_resolver::npm::ByonmNpmResolver;
|
||||
use deno_resolver::npm::ByonmResolvePkgFolderFromDenoReqError;
|
||||
use deno_runtime::deno_node::NodeRequireResolver;
|
||||
use deno_runtime::ops::process::NpmProcessStateProvider;
|
||||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::package::PackageReq;
|
||||
use node_resolver::NpmResolver;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::args::npm_registry_url;
|
||||
use crate::file_fetcher::FileFetcher;
|
||||
|
@ -29,6 +31,14 @@ pub use self::managed::CliNpmResolverManagedCreateOptions;
|
|||
pub use self::managed::CliNpmResolverManagedSnapshotOption;
|
||||
pub use self::managed::ManagedCliNpmResolver;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ResolvePkgFolderFromDenoReqError {
|
||||
#[error(transparent)]
|
||||
Managed(deno_core::error::AnyError),
|
||||
#[error(transparent)]
|
||||
Byonm(#[from] ByonmResolvePkgFolderFromDenoReqError),
|
||||
}
|
||||
|
||||
pub enum CliNpmResolverCreateOptions {
|
||||
Managed(CliNpmResolverManagedCreateOptions),
|
||||
Byonm(CliByonmNpmResolverCreateOptions),
|
||||
|
@ -93,7 +103,7 @@ pub trait CliNpmResolver: NpmResolver {
|
|||
&self,
|
||||
req: &PackageReq,
|
||||
referrer: &ModuleSpecifier,
|
||||
) -> Result<PathBuf, AnyError>;
|
||||
) -> Result<PathBuf, ResolvePkgFolderFromDenoReqError>;
|
||||
|
||||
/// Returns a hash returning the state of the npm resolver
|
||||
/// or `None` if the state currently can't be determined.
|
||||
|
|
|
@ -298,6 +298,10 @@ 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()?;
|
||||
}
|
||||
crate::tools::registry::cache_top_level_deps(&factory, None).await?;
|
||||
|
||||
if let Some(lockfile) = factory.cli_options()?.maybe_lockfile() {
|
||||
|
|
|
@ -558,12 +558,7 @@ pub async fn add(
|
|||
result.context("Failed to update configuration file")?;
|
||||
}
|
||||
|
||||
// clear the previously cached package.json from memory before reloading it
|
||||
node_resolver::PackageJsonThreadLocalCache::clear();
|
||||
// make a new CliFactory to pick up the updated config file
|
||||
let cli_factory = CliFactory::from_flags(flags);
|
||||
// cache deps
|
||||
cache_deps::cache_top_level_deps(&cli_factory, Some(jsr_resolver)).await?;
|
||||
npm_install_after_modification(flags, Some(jsr_resolver)).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -786,15 +781,33 @@ pub async fn remove(
|
|||
config.commit().await?;
|
||||
}
|
||||
|
||||
// Update deno.lock
|
||||
node_resolver::PackageJsonThreadLocalCache::clear();
|
||||
let cli_factory = CliFactory::from_flags(flags);
|
||||
cache_deps::cache_top_level_deps(&cli_factory, None).await?;
|
||||
npm_install_after_modification(flags, None).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn npm_install_after_modification(
|
||||
flags: Arc<Flags>,
|
||||
// explicitly provided to prevent redownloading
|
||||
jsr_resolver: Option<Arc<crate::jsr::JsrFetchResolver>>,
|
||||
) -> Result<(), AnyError> {
|
||||
// clear the previously cached package.json from memory before reloading it
|
||||
node_resolver::PackageJsonThreadLocalCache::clear();
|
||||
|
||||
// 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()?;
|
||||
}
|
||||
// npm install
|
||||
cache_deps::cache_top_level_deps(&cli_factory, jsr_resolver).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_config_file_content<
|
||||
I: IntoIterator<Item = (&'static str, Option<String>)>,
|
||||
>(
|
||||
|
|
|
@ -11,6 +11,7 @@ use deno_core::futures::StreamExt;
|
|||
use deno_semver::package::PackageReq;
|
||||
|
||||
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<Arc<crate::jsr::JsrFetchResolver>>,
|
||||
) -> Result<(), AnyError> {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_broadcast_channel"
|
||||
version = "0.162.0"
|
||||
version = "0.164.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
2
ext/cache/Cargo.toml
vendored
2
ext/cache/Cargo.toml
vendored
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_cache"
|
||||
version = "0.100.0"
|
||||
version = "0.102.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_canvas"
|
||||
version = "0.37.0"
|
||||
version = "0.39.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_console"
|
||||
version = "0.168.0"
|
||||
version = "0.170.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_cron"
|
||||
version = "0.48.0"
|
||||
version = "0.50.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -18,21 +18,27 @@ import {
|
|||
op_crypto_decrypt,
|
||||
op_crypto_derive_bits,
|
||||
op_crypto_derive_bits_x25519,
|
||||
op_crypto_derive_bits_x448,
|
||||
op_crypto_encrypt,
|
||||
op_crypto_export_key,
|
||||
op_crypto_export_pkcs8_ed25519,
|
||||
op_crypto_export_pkcs8_x25519,
|
||||
op_crypto_export_pkcs8_x448,
|
||||
op_crypto_export_spki_ed25519,
|
||||
op_crypto_export_spki_x25519,
|
||||
op_crypto_export_spki_x448,
|
||||
op_crypto_generate_ed25519_keypair,
|
||||
op_crypto_generate_key,
|
||||
op_crypto_generate_x25519_keypair,
|
||||
op_crypto_generate_x448_keypair,
|
||||
op_crypto_get_random_values,
|
||||
op_crypto_import_key,
|
||||
op_crypto_import_pkcs8_ed25519,
|
||||
op_crypto_import_pkcs8_x25519,
|
||||
op_crypto_import_pkcs8_x448,
|
||||
op_crypto_import_spki_ed25519,
|
||||
op_crypto_import_spki_x25519,
|
||||
op_crypto_import_spki_x448,
|
||||
op_crypto_jwk_x_ed25519,
|
||||
op_crypto_random_uuid,
|
||||
op_crypto_sign_ed25519,
|
||||
|
@ -134,6 +140,7 @@ const supportedAlgorithms = {
|
|||
"AES-KW": "AesKeyGenParams",
|
||||
"HMAC": "HmacKeyGenParams",
|
||||
"X25519": null,
|
||||
"X448": null,
|
||||
"Ed25519": null,
|
||||
},
|
||||
"sign": {
|
||||
|
@ -165,12 +172,14 @@ const supportedAlgorithms = {
|
|||
"AES-KW": null,
|
||||
"Ed25519": null,
|
||||
"X25519": null,
|
||||
"X448": null,
|
||||
},
|
||||
"deriveBits": {
|
||||
"HKDF": "HkdfParams",
|
||||
"PBKDF2": "Pbkdf2Params",
|
||||
"ECDH": "EcdhKeyDeriveParams",
|
||||
"X25519": "EcdhKeyDeriveParams",
|
||||
"X448": "EcdhKeyDeriveParams",
|
||||
},
|
||||
"encrypt": {
|
||||
"RSA-OAEP": "RsaOaepParams",
|
||||
|
@ -1037,6 +1046,10 @@ class SubtleCrypto {
|
|||
result = exportKeyEd25519(format, key, innerKey);
|
||||
break;
|
||||
}
|
||||
case "X448": {
|
||||
result = exportKeyX448(format, key, innerKey);
|
||||
break;
|
||||
}
|
||||
case "X25519": {
|
||||
result = exportKeyX25519(format, key, innerKey);
|
||||
break;
|
||||
|
@ -1954,6 +1967,48 @@ async function generateKey(normalizedAlgorithm, extractable, usages) {
|
|||
|
||||
return generateKeyAES(normalizedAlgorithm, extractable, usages);
|
||||
}
|
||||
case "X448": {
|
||||
if (
|
||||
ArrayPrototypeFind(
|
||||
usages,
|
||||
(u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u),
|
||||
) !== undefined
|
||||
) {
|
||||
throw new DOMException("Invalid key usage", "SyntaxError");
|
||||
}
|
||||
const privateKeyData = new Uint8Array(56);
|
||||
const publicKeyData = new Uint8Array(56);
|
||||
|
||||
op_crypto_generate_x448_keypair(privateKeyData, publicKeyData);
|
||||
|
||||
const handle = {};
|
||||
WeakMapPrototypeSet(KEY_STORE, handle, privateKeyData);
|
||||
|
||||
const publicHandle = {};
|
||||
WeakMapPrototypeSet(KEY_STORE, publicHandle, publicKeyData);
|
||||
|
||||
const algorithm = {
|
||||
name: algorithmName,
|
||||
};
|
||||
|
||||
const publicKey = constructKey(
|
||||
"public",
|
||||
true,
|
||||
usageIntersection(usages, []),
|
||||
algorithm,
|
||||
publicHandle,
|
||||
);
|
||||
|
||||
const privateKey = constructKey(
|
||||
"private",
|
||||
extractable,
|
||||
usageIntersection(usages, ["deriveKey", "deriveBits"]),
|
||||
algorithm,
|
||||
handle,
|
||||
);
|
||||
|
||||
return { publicKey, privateKey };
|
||||
}
|
||||
case "X25519": {
|
||||
if (
|
||||
ArrayPrototypeFind(
|
||||
|
@ -2100,6 +2155,211 @@ async function generateKey(normalizedAlgorithm, extractable, usages) {
|
|||
}
|
||||
}
|
||||
|
||||
function importKeyX448(
|
||||
format,
|
||||
keyData,
|
||||
extractable,
|
||||
keyUsages,
|
||||
) {
|
||||
switch (format) {
|
||||
case "raw": {
|
||||
// 1.
|
||||
if (keyUsages.length > 0) {
|
||||
throw new DOMException("Invalid key usage", "SyntaxError");
|
||||
}
|
||||
|
||||
const handle = {};
|
||||
WeakMapPrototypeSet(KEY_STORE, handle, keyData);
|
||||
|
||||
// 2-3.
|
||||
const algorithm = {
|
||||
name: "X448",
|
||||
};
|
||||
|
||||
// 4-6.
|
||||
return constructKey(
|
||||
"public",
|
||||
extractable,
|
||||
[],
|
||||
algorithm,
|
||||
handle,
|
||||
);
|
||||
}
|
||||
case "spki": {
|
||||
// 1.
|
||||
if (keyUsages.length > 0) {
|
||||
throw new DOMException("Invalid key usage", "SyntaxError");
|
||||
}
|
||||
|
||||
const publicKeyData = new Uint8Array(56);
|
||||
if (!op_crypto_import_spki_x448(keyData, publicKeyData)) {
|
||||
throw new DOMException("Invalid key data", "DataError");
|
||||
}
|
||||
|
||||
const handle = {};
|
||||
WeakMapPrototypeSet(KEY_STORE, handle, publicKeyData);
|
||||
|
||||
const algorithm = {
|
||||
name: "X448",
|
||||
};
|
||||
|
||||
return constructKey(
|
||||
"public",
|
||||
extractable,
|
||||
[],
|
||||
algorithm,
|
||||
handle,
|
||||
);
|
||||
}
|
||||
case "pkcs8": {
|
||||
// 1.
|
||||
if (
|
||||
ArrayPrototypeFind(
|
||||
keyUsages,
|
||||
(u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u),
|
||||
) !== undefined
|
||||
) {
|
||||
throw new DOMException("Invalid key usage", "SyntaxError");
|
||||
}
|
||||
|
||||
const privateKeyData = new Uint8Array(32);
|
||||
if (!op_crypto_import_pkcs8_x448(keyData, privateKeyData)) {
|
||||
throw new DOMException("Invalid key data", "DataError");
|
||||
}
|
||||
|
||||
const handle = {};
|
||||
WeakMapPrototypeSet(KEY_STORE, handle, privateKeyData);
|
||||
|
||||
const algorithm = {
|
||||
name: "X448",
|
||||
};
|
||||
|
||||
return constructKey(
|
||||
"private",
|
||||
extractable,
|
||||
usageIntersection(keyUsages, recognisedUsages),
|
||||
algorithm,
|
||||
handle,
|
||||
);
|
||||
}
|
||||
case "jwk": {
|
||||
// 1.
|
||||
const jwk = keyData;
|
||||
|
||||
// 2.
|
||||
if (jwk.d !== undefined) {
|
||||
if (
|
||||
ArrayPrototypeFind(
|
||||
keyUsages,
|
||||
(u) =>
|
||||
!ArrayPrototypeIncludes(
|
||||
["deriveKey", "deriveBits"],
|
||||
u,
|
||||
),
|
||||
) !== undefined
|
||||
) {
|
||||
throw new DOMException("Invalid key usage", "SyntaxError");
|
||||
}
|
||||
}
|
||||
|
||||
// 3.
|
||||
if (jwk.d === undefined && keyUsages.length > 0) {
|
||||
throw new DOMException("Invalid key usage", "SyntaxError");
|
||||
}
|
||||
|
||||
// 4.
|
||||
if (jwk.kty !== "OKP") {
|
||||
throw new DOMException("Invalid key type", "DataError");
|
||||
}
|
||||
|
||||
// 5.
|
||||
if (jwk.crv !== "X448") {
|
||||
throw new DOMException("Invalid curve", "DataError");
|
||||
}
|
||||
|
||||
// 6.
|
||||
if (keyUsages.length > 0 && jwk.use !== undefined) {
|
||||
if (jwk.use !== "enc") {
|
||||
throw new DOMException("Invalid key use", "DataError");
|
||||
}
|
||||
}
|
||||
|
||||
// 7.
|
||||
if (jwk.key_ops !== undefined) {
|
||||
if (
|
||||
ArrayPrototypeFind(
|
||||
jwk.key_ops,
|
||||
(u) => !ArrayPrototypeIncludes(recognisedUsages, u),
|
||||
) !== undefined
|
||||
) {
|
||||
throw new DOMException(
|
||||
"'key_ops' property of JsonWebKey is invalid",
|
||||
"DataError",
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
!ArrayPrototypeEvery(
|
||||
jwk.key_ops,
|
||||
(u) => ArrayPrototypeIncludes(keyUsages, u),
|
||||
)
|
||||
) {
|
||||
throw new DOMException(
|
||||
"'key_ops' property of JsonWebKey is invalid",
|
||||
"DataError",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 8.
|
||||
if (jwk.ext !== undefined && jwk.ext === false && extractable) {
|
||||
throw new DOMException("Invalid key extractability", "DataError");
|
||||
}
|
||||
|
||||
// 9.
|
||||
if (jwk.d !== undefined) {
|
||||
// https://www.rfc-editor.org/rfc/rfc8037#section-2
|
||||
const privateKeyData = op_crypto_base64url_decode(jwk.d);
|
||||
|
||||
const handle = {};
|
||||
WeakMapPrototypeSet(KEY_STORE, handle, privateKeyData);
|
||||
|
||||
const algorithm = {
|
||||
name: "X448",
|
||||
};
|
||||
|
||||
return constructKey(
|
||||
"private",
|
||||
extractable,
|
||||
usageIntersection(keyUsages, ["deriveKey", "deriveBits"]),
|
||||
algorithm,
|
||||
handle,
|
||||
);
|
||||
} else {
|
||||
// https://www.rfc-editor.org/rfc/rfc8037#section-2
|
||||
const publicKeyData = op_crypto_base64url_decode(jwk.x);
|
||||
|
||||
const handle = {};
|
||||
WeakMapPrototypeSet(KEY_STORE, handle, publicKeyData);
|
||||
|
||||
const algorithm = {
|
||||
name: "X448",
|
||||
};
|
||||
|
||||
return constructKey(
|
||||
"public",
|
||||
extractable,
|
||||
[],
|
||||
algorithm,
|
||||
handle,
|
||||
);
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new DOMException("Not implemented", "NotSupportedError");
|
||||
}
|
||||
}
|
||||
|
||||
function importKeyEd25519(
|
||||
format,
|
||||
keyData,
|
||||
|
@ -3358,6 +3618,14 @@ async function importKeyInner(
|
|||
["wrapKey", "unwrapKey"],
|
||||
);
|
||||
}
|
||||
case "X448": {
|
||||
return importKeyX448(
|
||||
format,
|
||||
keyData,
|
||||
extractable,
|
||||
keyUsages,
|
||||
);
|
||||
}
|
||||
case "X25519": {
|
||||
return importKeyX25519(
|
||||
format,
|
||||
|
@ -4162,6 +4430,66 @@ function exportKeyEd25519(format, key, innerKey) {
|
|||
}
|
||||
}
|
||||
|
||||
function exportKeyX448(format, key, innerKey) {
|
||||
switch (format) {
|
||||
case "raw": {
|
||||
// 1.
|
||||
if (key[_type] !== "public") {
|
||||
throw new DOMException(
|
||||
"Key is not a public key",
|
||||
"InvalidAccessError",
|
||||
);
|
||||
}
|
||||
|
||||
// 2-3.
|
||||
return TypedArrayPrototypeGetBuffer(innerKey);
|
||||
}
|
||||
case "spki": {
|
||||
// 1.
|
||||
if (key[_type] !== "public") {
|
||||
throw new DOMException(
|
||||
"Key is not a public key",
|
||||
"InvalidAccessError",
|
||||
);
|
||||
}
|
||||
|
||||
const spkiDer = op_crypto_export_spki_x448(innerKey);
|
||||
return TypedArrayPrototypeGetBuffer(spkiDer);
|
||||
}
|
||||
case "pkcs8": {
|
||||
// 1.
|
||||
if (key[_type] !== "private") {
|
||||
throw new DOMException(
|
||||
"Key is not a private key",
|
||||
"InvalidAccessError",
|
||||
);
|
||||
}
|
||||
|
||||
const pkcs8Der = op_crypto_export_pkcs8_x448(
|
||||
new Uint8Array([0x04, 0x22, ...new SafeArrayIterator(innerKey)]),
|
||||
);
|
||||
pkcs8Der[15] = 0x20;
|
||||
return TypedArrayPrototypeGetBuffer(pkcs8Der);
|
||||
}
|
||||
case "jwk": {
|
||||
if (key[_type] === "private") {
|
||||
throw new DOMException("Not implemented", "NotSupportedError");
|
||||
}
|
||||
const x = op_crypto_base64url_encode(innerKey);
|
||||
const jwk = {
|
||||
kty: "OKP",
|
||||
crv: "X448",
|
||||
x,
|
||||
"key_ops": key.usages,
|
||||
ext: key[_extractable],
|
||||
};
|
||||
return jwk;
|
||||
}
|
||||
default:
|
||||
throw new DOMException("Not implemented", "NotSupportedError");
|
||||
}
|
||||
}
|
||||
|
||||
function exportKeyX25519(format, key, innerKey) {
|
||||
switch (format) {
|
||||
case "raw": {
|
||||
|
@ -4519,6 +4847,55 @@ async function deriveBits(normalizedAlgorithm, baseKey, length) {
|
|||
|
||||
return TypedArrayPrototypeGetBuffer(buf);
|
||||
}
|
||||
case "X448": {
|
||||
// 1.
|
||||
if (baseKey[_type] !== "private") {
|
||||
throw new DOMException("Invalid key type", "InvalidAccessError");
|
||||
}
|
||||
// 2.
|
||||
const publicKey = normalizedAlgorithm.public;
|
||||
// 3.
|
||||
if (publicKey[_type] !== "public") {
|
||||
throw new DOMException("Invalid key type", "InvalidAccessError");
|
||||
}
|
||||
// 4.
|
||||
if (publicKey[_algorithm].name !== baseKey[_algorithm].name) {
|
||||
throw new DOMException(
|
||||
"Algorithm mismatch",
|
||||
"InvalidAccessError",
|
||||
);
|
||||
}
|
||||
|
||||
// 5.
|
||||
const kHandle = baseKey[_handle];
|
||||
const k = WeakMapPrototypeGet(KEY_STORE, kHandle);
|
||||
|
||||
const uHandle = publicKey[_handle];
|
||||
const u = WeakMapPrototypeGet(KEY_STORE, uHandle);
|
||||
|
||||
const secret = new Uint8Array(56);
|
||||
const isIdentity = op_crypto_derive_bits_x448(k, u, secret);
|
||||
|
||||
// 6.
|
||||
if (isIdentity) {
|
||||
throw new DOMException("Invalid key", "OperationError");
|
||||
}
|
||||
|
||||
// 7.
|
||||
if (length === null) {
|
||||
return TypedArrayPrototypeGetBuffer(secret);
|
||||
} else if (
|
||||
TypedArrayPrototypeGetByteLength(secret) * 8 < length
|
||||
) {
|
||||
throw new DOMException("Invalid length", "OperationError");
|
||||
} else {
|
||||
return ArrayBufferPrototypeSlice(
|
||||
TypedArrayPrototypeGetBuffer(secret),
|
||||
0,
|
||||
MathCeil(length / 8),
|
||||
);
|
||||
}
|
||||
}
|
||||
case "X25519": {
|
||||
// 1.
|
||||
if (baseKey[_type] !== "private") {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_crypto"
|
||||
version = "0.182.0"
|
||||
version = "0.184.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
@ -24,6 +24,7 @@ ctr = "0.9.1"
|
|||
curve25519-dalek = "4.1.3"
|
||||
deno_core.workspace = true
|
||||
deno_web.workspace = true
|
||||
ed448-goldilocks = { version = "0.8.3", features = ["zeroize"] }
|
||||
elliptic-curve = { version = "0.13.1", features = ["std", "pem"] }
|
||||
num-traits = "0.2.14"
|
||||
once_cell.workspace = true
|
||||
|
|
|
@ -64,6 +64,7 @@ mod import_key;
|
|||
mod key;
|
||||
mod shared;
|
||||
mod x25519;
|
||||
mod x448;
|
||||
|
||||
pub use crate::decrypt::op_crypto_decrypt;
|
||||
pub use crate::encrypt::op_crypto_encrypt;
|
||||
|
@ -98,6 +99,14 @@ deno_core::extension!(deno_crypto,
|
|||
x25519::op_crypto_derive_bits_x25519,
|
||||
x25519::op_crypto_import_spki_x25519,
|
||||
x25519::op_crypto_import_pkcs8_x25519,
|
||||
x25519::op_crypto_export_spki_x25519,
|
||||
x25519::op_crypto_export_pkcs8_x25519,
|
||||
x448::op_crypto_generate_x448_keypair,
|
||||
x448::op_crypto_derive_bits_x448,
|
||||
x448::op_crypto_import_spki_x448,
|
||||
x448::op_crypto_import_pkcs8_x448,
|
||||
x448::op_crypto_export_spki_x448,
|
||||
x448::op_crypto_export_pkcs8_x448,
|
||||
ed25519::op_crypto_generate_ed25519_keypair,
|
||||
ed25519::op_crypto_import_spki_ed25519,
|
||||
ed25519::op_crypto_import_pkcs8_ed25519,
|
||||
|
@ -106,8 +115,6 @@ deno_core::extension!(deno_crypto,
|
|||
ed25519::op_crypto_export_spki_ed25519,
|
||||
ed25519::op_crypto_export_pkcs8_ed25519,
|
||||
ed25519::op_crypto_jwk_x_ed25519,
|
||||
x25519::op_crypto_export_spki_x25519,
|
||||
x25519::op_crypto_export_pkcs8_x25519,
|
||||
],
|
||||
esm = [ "00_crypto.js" ],
|
||||
options = {
|
||||
|
|
|
@ -47,10 +47,10 @@ pub fn op_crypto_derive_bits_x25519(
|
|||
let sh_sec = x25519_dalek::x25519(k, u);
|
||||
let point = MontgomeryPoint(sh_sec);
|
||||
if point.ct_eq(&MONTGOMERY_IDENTITY).unwrap_u8() == 1 {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
secret.copy_from_slice(&sh_sec);
|
||||
true
|
||||
false
|
||||
}
|
||||
|
||||
// id-X25519 OBJECT IDENTIFIER ::= { 1 3 101 110 }
|
||||
|
|
147
ext/crypto/x448.rs
Normal file
147
ext/crypto/x448.rs
Normal file
|
@ -0,0 +1,147 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
use deno_core::error::custom_error;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::op2;
|
||||
use deno_core::ToJsBuffer;
|
||||
use ed448_goldilocks::curve::MontgomeryPoint;
|
||||
use ed448_goldilocks::Scalar;
|
||||
use elliptic_curve::pkcs8::PrivateKeyInfo;
|
||||
use elliptic_curve::subtle::ConstantTimeEq;
|
||||
use rand::rngs::OsRng;
|
||||
use rand::RngCore;
|
||||
use spki::der::asn1::BitString;
|
||||
use spki::der::Decode;
|
||||
use spki::der::Encode;
|
||||
|
||||
#[op2(fast)]
|
||||
pub fn op_crypto_generate_x448_keypair(
|
||||
#[buffer] pkey: &mut [u8],
|
||||
#[buffer] pubkey: &mut [u8],
|
||||
) {
|
||||
let mut rng = OsRng;
|
||||
rng.fill_bytes(pkey);
|
||||
|
||||
// x448(pkey, 5)
|
||||
let point = &MontgomeryPoint::generator()
|
||||
* &Scalar::from_bytes(pkey.try_into().unwrap());
|
||||
pubkey.copy_from_slice(&point.0);
|
||||
}
|
||||
|
||||
const MONTGOMERY_IDENTITY: MontgomeryPoint = MontgomeryPoint([0; 56]);
|
||||
|
||||
#[op2(fast)]
|
||||
pub fn op_crypto_derive_bits_x448(
|
||||
#[buffer] k: &[u8],
|
||||
#[buffer] u: &[u8],
|
||||
#[buffer] secret: &mut [u8],
|
||||
) -> bool {
|
||||
let k: [u8; 56] = k.try_into().expect("Expected byteLength 56");
|
||||
let u: [u8; 56] = u.try_into().expect("Expected byteLength 56");
|
||||
|
||||
// x448(k, u)
|
||||
let point = &MontgomeryPoint(u) * &Scalar::from_bytes(k);
|
||||
if point.ct_eq(&MONTGOMERY_IDENTITY).unwrap_u8() == 1 {
|
||||
return true;
|
||||
}
|
||||
|
||||
secret.copy_from_slice(&point.0);
|
||||
false
|
||||
}
|
||||
|
||||
// id-X448 OBJECT IDENTIFIER ::= { 1 3 101 111 }
|
||||
const X448_OID: const_oid::ObjectIdentifier =
|
||||
const_oid::ObjectIdentifier::new_unwrap("1.3.101.111");
|
||||
|
||||
#[op2]
|
||||
#[serde]
|
||||
pub fn op_crypto_export_spki_x448(
|
||||
#[buffer] pubkey: &[u8],
|
||||
) -> Result<ToJsBuffer, AnyError> {
|
||||
let key_info = spki::SubjectPublicKeyInfo {
|
||||
algorithm: spki::AlgorithmIdentifierRef {
|
||||
oid: X448_OID,
|
||||
parameters: None,
|
||||
},
|
||||
subject_public_key: BitString::from_bytes(pubkey)?,
|
||||
};
|
||||
Ok(
|
||||
key_info
|
||||
.to_der()
|
||||
.map_err(|_| {
|
||||
custom_error("DOMExceptionOperationError", "Failed to export key")
|
||||
})?
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[serde]
|
||||
pub fn op_crypto_export_pkcs8_x448(
|
||||
#[buffer] pkey: &[u8],
|
||||
) -> Result<ToJsBuffer, AnyError> {
|
||||
use rsa::pkcs1::der::Encode;
|
||||
|
||||
let pk_info = rsa::pkcs8::PrivateKeyInfo {
|
||||
public_key: None,
|
||||
algorithm: rsa::pkcs8::AlgorithmIdentifierRef {
|
||||
oid: X448_OID,
|
||||
parameters: None,
|
||||
},
|
||||
private_key: pkey, // OCTET STRING
|
||||
};
|
||||
|
||||
let mut buf = Vec::new();
|
||||
pk_info.encode_to_vec(&mut buf)?;
|
||||
Ok(buf.into())
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
pub fn op_crypto_import_spki_x448(
|
||||
#[buffer] key_data: &[u8],
|
||||
#[buffer] out: &mut [u8],
|
||||
) -> bool {
|
||||
// 2-3.
|
||||
let pk_info = match spki::SubjectPublicKeyInfoRef::try_from(key_data) {
|
||||
Ok(pk_info) => pk_info,
|
||||
Err(_) => return false,
|
||||
};
|
||||
// 4.
|
||||
let alg = pk_info.algorithm.oid;
|
||||
if alg != X448_OID {
|
||||
return false;
|
||||
}
|
||||
// 5.
|
||||
if pk_info.algorithm.parameters.is_some() {
|
||||
return false;
|
||||
}
|
||||
out.copy_from_slice(pk_info.subject_public_key.raw_bytes());
|
||||
true
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
pub fn op_crypto_import_pkcs8_x448(
|
||||
#[buffer] key_data: &[u8],
|
||||
#[buffer] out: &mut [u8],
|
||||
) -> bool {
|
||||
// 2-3.
|
||||
let pk_info = match PrivateKeyInfo::from_der(key_data) {
|
||||
Ok(pk_info) => pk_info,
|
||||
Err(_) => return false,
|
||||
};
|
||||
// 4.
|
||||
let alg = pk_info.algorithm.oid;
|
||||
if alg != X448_OID {
|
||||
return false;
|
||||
}
|
||||
// 5.
|
||||
if pk_info.algorithm.parameters.is_some() {
|
||||
return false;
|
||||
}
|
||||
// 6.
|
||||
// CurvePrivateKey ::= OCTET STRING
|
||||
if pk_info.private_key.len() != 56 {
|
||||
return false;
|
||||
}
|
||||
out.copy_from_slice(&pk_info.private_key[2..]);
|
||||
true
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_fetch"
|
||||
version = "0.192.0"
|
||||
version = "0.194.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_ffi"
|
||||
version = "0.155.0"
|
||||
version = "0.157.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_fs"
|
||||
version = "0.78.0"
|
||||
version = "0.80.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_http"
|
||||
version = "0.166.0"
|
||||
version = "0.168.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_io"
|
||||
version = "0.78.0"
|
||||
version = "0.80.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_kv"
|
||||
version = "0.76.0"
|
||||
version = "0.78.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_napi"
|
||||
version = "0.99.0"
|
||||
version = "0.101.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -124,17 +124,19 @@ function loadTlsKeyPair(api, {
|
|||
|
||||
// Check for "pem" format
|
||||
if (keyFormat !== undefined && keyFormat !== "pem") {
|
||||
throw new TypeError('If `keyFormat` is specified, it must be "pem"');
|
||||
throw new TypeError(
|
||||
`If "keyFormat" is specified, it must be "pem": received "${keyFormat}"`,
|
||||
);
|
||||
}
|
||||
|
||||
if (cert !== undefined && key === undefined) {
|
||||
throw new TypeError(
|
||||
`If \`cert\` is specified, \`key\` must be specified as well for \`${api}\`.`,
|
||||
`If \`cert\` is specified, \`key\` must be specified as well for \`${api}\``,
|
||||
);
|
||||
}
|
||||
if (cert === undefined && key !== undefined) {
|
||||
throw new TypeError(
|
||||
`If \`key\` is specified, \`cert\` must be specified as well for \`${api}\`.`,
|
||||
`If \`key\` is specified, \`cert\` must be specified as well for \`${api}\``,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_net"
|
||||
version = "0.160.0"
|
||||
version = "0.162.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_node"
|
||||
version = "0.105.0"
|
||||
version = "0.107.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -66,6 +66,7 @@ pub trait NodePermissions {
|
|||
&mut self,
|
||||
path: &'a Path,
|
||||
) -> Result<Cow<'a, Path>, AnyError>;
|
||||
fn query_read_all(&mut self) -> bool;
|
||||
fn check_sys(&mut self, kind: &str, api_name: &str) -> Result<(), AnyError>;
|
||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||
fn check_write_with_api_name(
|
||||
|
@ -103,6 +104,10 @@ impl NodePermissions for deno_permissions::PermissionsContainer {
|
|||
deno_permissions::PermissionsContainer::check_read_path(self, path, None)
|
||||
}
|
||||
|
||||
fn query_read_all(&mut self) -> bool {
|
||||
deno_permissions::PermissionsContainer::query_read_all(self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn check_write_with_api_name(
|
||||
&mut self,
|
||||
|
@ -124,11 +129,12 @@ pub type NodeRequireResolverRc =
|
|||
deno_fs::sync::MaybeArc<dyn NodeRequireResolver>;
|
||||
|
||||
pub trait NodeRequireResolver: std::fmt::Debug + MaybeSend + MaybeSync {
|
||||
fn ensure_read_permission(
|
||||
#[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: &Path,
|
||||
) -> Result<(), AnyError>;
|
||||
path: &'a Path,
|
||||
) -> Result<Cow<'a, Path>, AnyError>;
|
||||
}
|
||||
|
||||
pub static NODE_ENV_VAR_ALLOWLIST: Lazy<HashSet<String>> = Lazy::new(|| {
|
||||
|
@ -167,6 +173,7 @@ deno_core::extension!(deno_node,
|
|||
|
||||
ops::buffer::op_is_ascii,
|
||||
ops::buffer::op_is_utf8,
|
||||
ops::buffer::op_transcode,
|
||||
ops::crypto::op_node_check_prime_async,
|
||||
ops::crypto::op_node_check_prime_bytes_async,
|
||||
ops::crypto::op_node_check_prime_bytes,
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use deno_core::anyhow::anyhow;
|
||||
use deno_core::anyhow::Result;
|
||||
use deno_core::op2;
|
||||
|
||||
#[op2(fast)]
|
||||
|
@ -11,3 +13,107 @@ pub fn op_is_ascii(#[buffer] buf: &[u8]) -> bool {
|
|||
pub fn op_is_utf8(#[buffer] buf: &[u8]) -> bool {
|
||||
std::str::from_utf8(buf).is_ok()
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[buffer]
|
||||
pub fn op_transcode(
|
||||
#[buffer] source: &[u8],
|
||||
#[string] from_encoding: &str,
|
||||
#[string] to_encoding: &str,
|
||||
) -> Result<Vec<u8>> {
|
||||
match (from_encoding, to_encoding) {
|
||||
("utf8", "ascii") => Ok(utf8_to_ascii(source)),
|
||||
("utf8", "latin1") => Ok(utf8_to_latin1(source)),
|
||||
("utf8", "utf16le") => utf8_to_utf16le(source),
|
||||
("utf16le", "utf8") => utf16le_to_utf8(source),
|
||||
("latin1", "utf16le") | ("ascii", "utf16le") => {
|
||||
Ok(latin1_ascii_to_utf16le(source))
|
||||
}
|
||||
(from, to) => Err(anyhow!("Unable to transcode Buffer {from}->{to}")),
|
||||
}
|
||||
}
|
||||
|
||||
fn latin1_ascii_to_utf16le(source: &[u8]) -> Vec<u8> {
|
||||
let mut result = Vec::with_capacity(source.len() * 2);
|
||||
for &byte in source {
|
||||
result.push(byte);
|
||||
result.push(0);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn utf16le_to_utf8(source: &[u8]) -> Result<Vec<u8>> {
|
||||
let ucs2_vec: Vec<u16> = 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))
|
||||
}
|
||||
|
||||
fn utf8_to_utf16le(source: &[u8]) -> Result<Vec<u8>> {
|
||||
let utf8_string = std::str::from_utf8(source)?;
|
||||
let ucs2_vec: Vec<u16> = utf8_string.encode_utf16().collect();
|
||||
let bytes: Vec<u8> = ucs2_vec.iter().flat_map(|&x| x.to_le_bytes()).collect();
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
fn utf8_to_latin1(source: &[u8]) -> Vec<u8> {
|
||||
let mut latin1_bytes = Vec::with_capacity(source.len());
|
||||
let mut i = 0;
|
||||
while i < source.len() {
|
||||
match source[i] {
|
||||
byte if byte <= 0x7F => {
|
||||
// ASCII character
|
||||
latin1_bytes.push(byte);
|
||||
i += 1;
|
||||
}
|
||||
byte if (0xC2..=0xDF).contains(&byte) && i + 1 < source.len() => {
|
||||
// 2-byte UTF-8 sequence
|
||||
let codepoint =
|
||||
((byte as u16 & 0x1F) << 6) | (source[i + 1] as u16 & 0x3F);
|
||||
latin1_bytes.push(if codepoint <= 0xFF {
|
||||
codepoint as u8
|
||||
} else {
|
||||
b'?'
|
||||
});
|
||||
i += 2;
|
||||
}
|
||||
_ => {
|
||||
// 3-byte or 4-byte UTF-8 sequence, or invalid UTF-8
|
||||
latin1_bytes.push(b'?');
|
||||
// Skip to the next valid UTF-8 start byte
|
||||
i += 1;
|
||||
while i < source.len() && (source[i] & 0xC0) == 0x80 {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
latin1_bytes
|
||||
}
|
||||
|
||||
fn utf8_to_ascii(source: &[u8]) -> Vec<u8> {
|
||||
let mut ascii_bytes = Vec::with_capacity(source.len());
|
||||
let mut i = 0;
|
||||
while i < source.len() {
|
||||
match source[i] {
|
||||
byte if byte <= 0x7F => {
|
||||
// ASCII character
|
||||
ascii_bytes.push(byte);
|
||||
i += 1;
|
||||
}
|
||||
_ => {
|
||||
// Non-ASCII character
|
||||
ascii_bytes.push(b'?');
|
||||
// Skip to the next valid UTF-8 start byte
|
||||
i += 1;
|
||||
while i < source.len() && (source[i] & 0xC0) == 0x80 {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ascii_bytes
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ use deno_path_util::normalize_path;
|
|||
use node_resolver::NodeModuleKind;
|
||||
use node_resolver::NodeResolutionMode;
|
||||
use node_resolver::REQUIRE_CONDITIONS;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
@ -25,10 +26,11 @@ use crate::NodeRequireResolverRc;
|
|||
use crate::NodeResolverRc;
|
||||
use crate::NpmResolverRc;
|
||||
|
||||
fn ensure_read_permission<P>(
|
||||
#[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: &Path,
|
||||
) -> Result<(), AnyError>
|
||||
file_path: &'a Path,
|
||||
) -> Result<Cow<'a, Path>, AnyError>
|
||||
where
|
||||
P: NodePermissions + 'static,
|
||||
{
|
||||
|
@ -107,7 +109,7 @@ where
|
|||
deno_path_util::normalize_path(current_dir.join(from))
|
||||
};
|
||||
|
||||
ensure_read_permission::<P>(state, &from)?;
|
||||
let from = ensure_read_permission::<P>(state, &from)?;
|
||||
|
||||
if cfg!(windows) {
|
||||
// return root node_modules when path is 'D:\\'.
|
||||
|
@ -129,7 +131,7 @@ where
|
|||
}
|
||||
|
||||
let mut paths = Vec::with_capacity(from.components().count());
|
||||
let mut current_path = from.as_path();
|
||||
let mut current_path = from.as_ref();
|
||||
let mut maybe_parent = Some(current_path);
|
||||
while let Some(parent) = maybe_parent {
|
||||
if !parent.ends_with("node_modules") {
|
||||
|
@ -267,7 +269,7 @@ where
|
|||
P: NodePermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
ensure_read_permission::<P>(state, &path)?;
|
||||
let path = ensure_read_permission::<P>(state, &path)?;
|
||||
let fs = state.borrow::<FileSystemRc>();
|
||||
if let Ok(metadata) = fs.stat_sync(&path) {
|
||||
if metadata.is_file {
|
||||
|
@ -290,7 +292,7 @@ where
|
|||
P: NodePermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(request);
|
||||
ensure_read_permission::<P>(state, &path)?;
|
||||
let path = ensure_read_permission::<P>(state, &path)?;
|
||||
let fs = state.borrow::<FileSystemRc>();
|
||||
let canonicalized_path =
|
||||
deno_core::strip_unc_prefix(fs.realpath_sync(&path)?);
|
||||
|
@ -362,7 +364,7 @@ where
|
|||
if parent_id == "<repl>" || parent_id == "internal/preload" {
|
||||
let fs = state.borrow::<FileSystemRc>();
|
||||
if let Ok(cwd) = fs.cwd() {
|
||||
ensure_read_permission::<P>(state, &cwd)?;
|
||||
let cwd = ensure_read_permission::<P>(state, &cwd)?;
|
||||
return Ok(Some(cwd.to_string_lossy().into_owned()));
|
||||
}
|
||||
}
|
||||
|
@ -443,7 +445,7 @@ where
|
|||
P: NodePermissions + 'static,
|
||||
{
|
||||
let file_path = PathBuf::from(file_path);
|
||||
ensure_read_permission::<P>(state, &file_path)?;
|
||||
let file_path = ensure_read_permission::<P>(state, &file_path)?;
|
||||
let fs = state.borrow::<FileSystemRc>();
|
||||
Ok(fs.read_text_file_lossy_sync(&file_path, None)?)
|
||||
}
|
||||
|
@ -528,7 +530,7 @@ where
|
|||
P: NodePermissions + 'static,
|
||||
{
|
||||
let filename = PathBuf::from(filename);
|
||||
ensure_read_permission::<P>(state, filename.parent().unwrap())?;
|
||||
// permissions: allow reading the closest package.json files
|
||||
let node_resolver = state.borrow::<NodeResolverRc>().clone();
|
||||
node_resolver
|
||||
.get_closest_package_json_from_path(&filename)
|
||||
|
@ -567,7 +569,7 @@ where
|
|||
P: NodePermissions + 'static,
|
||||
{
|
||||
let referrer_path = PathBuf::from(&referrer_filename);
|
||||
ensure_read_permission::<P>(state, &referrer_path)?;
|
||||
let referrer_path = ensure_read_permission::<P>(state, &referrer_path)?;
|
||||
let node_resolver = state.borrow::<NodeResolverRc>();
|
||||
let Some(pkg) =
|
||||
node_resolver.get_closest_package_json_from_path(&referrer_path)?
|
||||
|
|
|
@ -7,6 +7,7 @@ use deno_core::url::Url;
|
|||
use deno_core::OpState;
|
||||
use deno_fs::FileSystemRc;
|
||||
use node_resolver::NodeResolution;
|
||||
use std::borrow::Cow;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
@ -14,10 +15,11 @@ use crate::NodePermissions;
|
|||
use crate::NodeRequireResolverRc;
|
||||
use crate::NodeResolverRc;
|
||||
|
||||
fn ensure_read_permission<P>(
|
||||
#[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: &Path,
|
||||
) -> Result<(), AnyError>
|
||||
file_path: &'a Path,
|
||||
) -> Result<Cow<'a, Path>, AnyError>
|
||||
where
|
||||
P: NodePermissions + 'static,
|
||||
{
|
||||
|
@ -47,7 +49,7 @@ where
|
|||
"Relative path entries must start with '.' or '..'",
|
||||
));
|
||||
}
|
||||
ensure_read_permission::<P>(state, &path)?;
|
||||
let path = ensure_read_permission::<P>(state, &path)?;
|
||||
let fs = state.borrow::<FileSystemRc>();
|
||||
let canonicalized_path =
|
||||
deno_core::strip_unc_prefix(fs.realpath_sync(&path)?);
|
||||
|
@ -57,7 +59,7 @@ where
|
|||
let url_path = url
|
||||
.to_file_path()
|
||||
.map_err(|e| generic_error(format!("URL to Path-String: {:#?}", e)))?;
|
||||
ensure_read_permission::<P>(state, &url_path)?;
|
||||
let url_path = ensure_read_permission::<P>(state, &url_path)?;
|
||||
let fs = state.borrow::<FileSystemRc>();
|
||||
if !fs.exists_sync(&url_path) {
|
||||
return Err(generic_error(format!("File not found [{:?}]", url_path)));
|
||||
|
|
|
@ -13,4 +13,5 @@ export {
|
|||
kMaxLength,
|
||||
kStringMaxLength,
|
||||
SlowBuffer,
|
||||
transcode,
|
||||
} from "ext:deno_node/internal/buffer.mjs";
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// deno-lint-ignore-file prefer-primordials
|
||||
|
||||
import { core } from "ext:core/mod.js";
|
||||
import { op_is_ascii, op_is_utf8 } from "ext:core/ops";
|
||||
import { op_is_ascii, op_is_utf8, op_transcode } from "ext:core/ops";
|
||||
|
||||
import { TextDecoder, TextEncoder } from "ext:deno_web/08_text_encoding.js";
|
||||
import { codes } from "ext:deno_node/internal/error_codes.ts";
|
||||
|
@ -32,7 +32,11 @@ import {
|
|||
import { normalizeEncoding } from "ext:deno_node/internal/util.mjs";
|
||||
import { validateBuffer } from "ext:deno_node/internal/validators.mjs";
|
||||
import { isUint8Array } from "ext:deno_node/internal/util/types.ts";
|
||||
import { ERR_INVALID_STATE, NodeError } from "ext:deno_node/internal/errors.ts";
|
||||
import {
|
||||
ERR_INVALID_STATE,
|
||||
genericNodeError,
|
||||
NodeError,
|
||||
} from "ext:deno_node/internal/errors.ts";
|
||||
import {
|
||||
forgivingBase64Encode,
|
||||
forgivingBase64UrlEncode,
|
||||
|
@ -2598,6 +2602,48 @@ export function isAscii(input) {
|
|||
], input);
|
||||
}
|
||||
|
||||
export function transcode(source, fromEnco, toEnco) {
|
||||
if (!isUint8Array(source)) {
|
||||
throw new codes.ERR_INVALID_ARG_TYPE(
|
||||
"source",
|
||||
["Buffer", "Uint8Array"],
|
||||
source,
|
||||
);
|
||||
}
|
||||
if (source.length === 0) {
|
||||
return Buffer.alloc(0);
|
||||
}
|
||||
const code = "U_ILLEGAL_ARGUMENT_ERROR";
|
||||
const illegalArgumentError = genericNodeError(
|
||||
`Unable to transcode Buffer [${code}]`,
|
||||
{ code: code, errno: 1 },
|
||||
);
|
||||
fromEnco = normalizeEncoding(fromEnco);
|
||||
toEnco = normalizeEncoding(toEnco);
|
||||
if (!fromEnco || !toEnco) {
|
||||
throw illegalArgumentError;
|
||||
}
|
||||
// Return the provided source when transcode is not required
|
||||
// for the from/to encoding pair.
|
||||
const returnSource = fromEnco === toEnco ||
|
||||
fromEnco === "ascii" && toEnco === "utf8" ||
|
||||
fromEnco === "ascii" && toEnco === "latin1";
|
||||
if (returnSource) {
|
||||
return Buffer.from(source);
|
||||
}
|
||||
|
||||
try {
|
||||
const result = op_transcode(new Uint8Array(source), fromEnco, toEnco);
|
||||
return Buffer.from(result, toEnco);
|
||||
} catch (err) {
|
||||
if (err.message.includes("Unable to transcode Buffer")) {
|
||||
throw illegalArgumentError;
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
atob,
|
||||
btoa,
|
||||
|
@ -2610,4 +2656,5 @@ export default {
|
|||
kMaxLength,
|
||||
kStringMaxLength,
|
||||
SlowBuffer,
|
||||
transcode,
|
||||
};
|
||||
|
|
|
@ -313,20 +313,6 @@ export class DefaultDeserializer extends Deserializer {
|
|||
);
|
||||
}
|
||||
}
|
||||
export const promiseHooks = {
|
||||
onInit() {
|
||||
notImplemented("v8.promiseHooks.onInit");
|
||||
},
|
||||
onSettled() {
|
||||
notImplemented("v8.promiseHooks.onSetttled");
|
||||
},
|
||||
onBefore() {
|
||||
notImplemented("v8.promiseHooks.onBefore");
|
||||
},
|
||||
createHook() {
|
||||
notImplemented("v8.promiseHooks.createHook");
|
||||
},
|
||||
};
|
||||
export default {
|
||||
cachedDataVersionTag,
|
||||
getHeapCodeStatistics,
|
||||
|
@ -343,5 +329,4 @@ export default {
|
|||
Deserializer,
|
||||
DefaultSerializer,
|
||||
DefaultDeserializer,
|
||||
promiseHooks,
|
||||
};
|
||||
|
|
|
@ -302,8 +302,8 @@ class NodeWorker extends EventEmitter {
|
|||
if (this.#status !== "TERMINATED") {
|
||||
this.#status = "TERMINATED";
|
||||
op_host_terminate_worker(this.#id);
|
||||
this.emit("exit", 0);
|
||||
}
|
||||
this.emit("exit", 0);
|
||||
return PromiseResolve(0);
|
||||
}
|
||||
|
||||
|
@ -422,7 +422,11 @@ internals.__initWorkerThreads = (
|
|||
|
||||
parentPort.once = function (this: ParentPort, name, listener) {
|
||||
// deno-lint-ignore no-explicit-any
|
||||
const _listener = (ev: any) => listener(ev.data);
|
||||
const _listener = (ev: any) => {
|
||||
const message = ev.data;
|
||||
patchMessagePortIfFound(message);
|
||||
return listener(message);
|
||||
};
|
||||
listeners.set(listener, _listener);
|
||||
this.addEventListener(name, _listener);
|
||||
return this;
|
||||
|
@ -494,7 +498,9 @@ export function receiveMessageOnPort(port: MessagePort): object | undefined {
|
|||
port[MessagePortReceiveMessageOnPortSymbol] = true;
|
||||
const data = op_message_port_recv_message_sync(port[MessagePortIdSymbol]);
|
||||
if (data === null) return undefined;
|
||||
return { message: deserializeJsMessageData(data)[0] };
|
||||
const message = deserializeJsMessageData(data)[0];
|
||||
patchMessagePortIfFound(message);
|
||||
return { message };
|
||||
}
|
||||
|
||||
class NodeMessageChannel {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_tls"
|
||||
version = "0.155.0"
|
||||
version = "0.157.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -139,7 +139,7 @@ class URLSearchParams {
|
|||
throw new TypeError(
|
||||
`${prefix}: Item ${
|
||||
i + 0
|
||||
} in the parameter list does have length 2 exactly.`,
|
||||
} in the parameter list does have length 2 exactly`,
|
||||
);
|
||||
}
|
||||
return [pair[0], pair[1]];
|
||||
|
|
|
@ -31,6 +31,7 @@ import * as webidl from "ext:deno_webidl/00_webidl.js";
|
|||
import { createFilteredInspectProxy } from "ext:deno_console/01_console.js";
|
||||
|
||||
const _components = Symbol("components");
|
||||
const urlPatternSettings = { groupStringFallback: false };
|
||||
|
||||
/**
|
||||
* @typedef Components
|
||||
|
@ -349,7 +350,11 @@ class URLPattern {
|
|||
const groups = res.groups;
|
||||
for (let i = 0; i < groupList.length; ++i) {
|
||||
// TODO(lucacasonato): this is vulnerable to override mistake
|
||||
groups[groupList[i]] = match[i + 1] ?? ""; // TODO(@crowlKats): remove fallback for 2.0
|
||||
if (urlPatternSettings.groupStringFallback) {
|
||||
groups[groupList[i]] = match[i + 1] ?? "";
|
||||
} else {
|
||||
groups[groupList[i]] = match[i + 1];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -422,4 +427,4 @@ webidl.converters.URLPatternOptions = webidl
|
|||
},
|
||||
]);
|
||||
|
||||
export { URLPattern };
|
||||
export { URLPattern, urlPatternSettings };
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_url"
|
||||
version = "0.168.0"
|
||||
version = "0.170.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -22,6 +22,7 @@ const {
|
|||
Symbol,
|
||||
SymbolFor,
|
||||
SymbolIterator,
|
||||
PromiseResolve,
|
||||
SafeArrayIterator,
|
||||
TypeError,
|
||||
} = primordials;
|
||||
|
@ -41,7 +42,10 @@ import {
|
|||
import { isDetachedBuffer } from "./06_streams.js";
|
||||
import { DOMException } from "./01_dom_exception.js";
|
||||
|
||||
let messageEventListenerCount = 0;
|
||||
// counter of how many message ports are actively refed
|
||||
// either due to the existence of "message" event listeners or
|
||||
// explicit calls to ref/unref (in the case of node message ports)
|
||||
let refedMessagePortsCount = 0;
|
||||
|
||||
class MessageChannel {
|
||||
/** @type {MessagePort} */
|
||||
|
@ -93,6 +97,7 @@ const MessagePortReceiveMessageOnPortSymbol = Symbol(
|
|||
);
|
||||
const _enabled = Symbol("enabled");
|
||||
const _refed = Symbol("refed");
|
||||
const _messageEventListenerCount = Symbol("messageEventListenerCount");
|
||||
const nodeWorkerThreadCloseCb = Symbol("nodeWorkerThreadCloseCb");
|
||||
const nodeWorkerThreadCloseCbInvoked = Symbol("nodeWorkerThreadCloseCbInvoked");
|
||||
export const refMessagePort = Symbol("refMessagePort");
|
||||
|
@ -109,6 +114,9 @@ function createMessagePort(id) {
|
|||
port[core.hostObjectBrand] = core.hostObjectBrand;
|
||||
setEventTargetData(port);
|
||||
port[_id] = id;
|
||||
port[_enabled] = false;
|
||||
port[_messageEventListenerCount] = 0;
|
||||
port[_refed] = false;
|
||||
return port;
|
||||
}
|
||||
|
||||
|
@ -122,12 +130,18 @@ function nodeWorkerThreadMaybeInvokeCloseCb(port) {
|
|||
}
|
||||
}
|
||||
|
||||
const _isRefed = Symbol("isRefed");
|
||||
const _dataPromise = Symbol("dataPromise");
|
||||
|
||||
class MessagePort extends EventTarget {
|
||||
/** @type {number | null} */
|
||||
[_id] = null;
|
||||
/** @type {boolean} */
|
||||
[_enabled] = false;
|
||||
[_refed] = false;
|
||||
/** @type {Promise<any> | undefined} */
|
||||
[_dataPromise] = undefined;
|
||||
[_messageEventListenerCount] = 0;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
@ -193,24 +207,21 @@ class MessagePort extends EventTarget {
|
|||
this[_enabled] = true;
|
||||
while (true) {
|
||||
if (this[_id] === null) break;
|
||||
// Exit if no message event listeners are present in Node compat mode.
|
||||
if (
|
||||
typeof this[nodeWorkerThreadCloseCb] == "function" &&
|
||||
messageEventListenerCount === 0
|
||||
) break;
|
||||
let data;
|
||||
try {
|
||||
data = await op_message_port_recv_message(
|
||||
this[_dataPromise] = op_message_port_recv_message(
|
||||
this[_id],
|
||||
);
|
||||
if (
|
||||
typeof this[nodeWorkerThreadCloseCb] === "function" &&
|
||||
!this[_refed]
|
||||
) {
|
||||
core.unrefOpPromise(this[_dataPromise]);
|
||||
}
|
||||
data = await this[_dataPromise];
|
||||
this[_dataPromise] = undefined;
|
||||
} catch (err) {
|
||||
if (ObjectPrototypeIsPrototypeOf(InterruptedPrototype, err)) {
|
||||
// If we were interrupted, check if the interruption is coming
|
||||
// from `receiveMessageOnPort` API from Node compat, if so, continue.
|
||||
if (this[MessagePortReceiveMessageOnPortSymbol]) {
|
||||
this[MessagePortReceiveMessageOnPortSymbol] = false;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
nodeWorkerThreadMaybeInvokeCloseCb(this);
|
||||
|
@ -246,12 +257,26 @@ class MessagePort extends EventTarget {
|
|||
}
|
||||
|
||||
[refMessagePort](ref) {
|
||||
if (ref && !this[_refed]) {
|
||||
this[_refed] = true;
|
||||
messageEventListenerCount++;
|
||||
} else if (!ref && this[_refed]) {
|
||||
this[_refed] = false;
|
||||
messageEventListenerCount = 0;
|
||||
if (ref) {
|
||||
if (!this[_refed]) {
|
||||
refedMessagePortsCount++;
|
||||
if (
|
||||
this[_dataPromise]
|
||||
) {
|
||||
core.refOpPromise(this[_dataPromise]);
|
||||
}
|
||||
this[_refed] = true;
|
||||
}
|
||||
} else if (!ref) {
|
||||
if (this[_refed]) {
|
||||
refedMessagePortsCount--;
|
||||
if (
|
||||
this[_dataPromise]
|
||||
) {
|
||||
core.unrefOpPromise(this[_dataPromise]);
|
||||
}
|
||||
this[_refed] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,15 +291,20 @@ class MessagePort extends EventTarget {
|
|||
|
||||
removeEventListener(...args) {
|
||||
if (args[0] == "message") {
|
||||
messageEventListenerCount--;
|
||||
if (--this[_messageEventListenerCount] === 0 && this[_refed]) {
|
||||
refedMessagePortsCount--;
|
||||
this[_refed] = false;
|
||||
}
|
||||
}
|
||||
super.removeEventListener(...new SafeArrayIterator(args));
|
||||
}
|
||||
|
||||
addEventListener(...args) {
|
||||
if (args[0] == "message") {
|
||||
messageEventListenerCount++;
|
||||
if (!this[_refed]) this[_refed] = true;
|
||||
if (++this[_messageEventListenerCount] === 1 && !this[_refed]) {
|
||||
refedMessagePortsCount++;
|
||||
this[_refed] = true;
|
||||
}
|
||||
}
|
||||
super.addEventListener(...new SafeArrayIterator(args));
|
||||
}
|
||||
|
@ -295,7 +325,17 @@ class MessagePort extends EventTarget {
|
|||
}
|
||||
|
||||
defineEventHandler(MessagePort.prototype, "message", function (self) {
|
||||
self.start();
|
||||
if (self[nodeWorkerThreadCloseCb]) {
|
||||
(async () => {
|
||||
// delay `start()` until he end of this event loop turn, to give `receiveMessageOnPort`
|
||||
// a chance to receive a message first. this is primarily to resolve an issue with
|
||||
// a pattern used in `npm:piscina` that results in an indefinite hang
|
||||
await PromiseResolve();
|
||||
self.start();
|
||||
})();
|
||||
} else {
|
||||
self.start();
|
||||
}
|
||||
});
|
||||
defineEventHandler(MessagePort.prototype, "messageerror");
|
||||
|
||||
|
@ -463,12 +503,12 @@ function structuredClone(value, options) {
|
|||
export {
|
||||
deserializeJsMessageData,
|
||||
MessageChannel,
|
||||
messageEventListenerCount,
|
||||
MessagePort,
|
||||
MessagePortIdSymbol,
|
||||
MessagePortPrototype,
|
||||
MessagePortReceiveMessageOnPortSymbol,
|
||||
nodeWorkerThreadCloseCb,
|
||||
refedMessagePortsCount,
|
||||
serializeJsMessageData,
|
||||
structuredClone,
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_web"
|
||||
version = "0.199.0"
|
||||
version = "0.201.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -239,7 +239,6 @@ pub fn op_message_port_recv_message_sync(
|
|||
#[smi] rid: ResourceId,
|
||||
) -> Result<Option<JsMessageData>, AnyError> {
|
||||
let resource = state.resource_table.get::<MessagePortResource>(rid)?;
|
||||
resource.cancel.cancel();
|
||||
let mut rx = resource.port.rx.borrow_mut();
|
||||
|
||||
match rx.try_recv() {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_webgpu"
|
||||
version = "0.135.0"
|
||||
version = "0.137.0"
|
||||
authors = ["the Deno authors"]
|
||||
edition.workspace = true
|
||||
license = "MIT"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_webidl"
|
||||
version = "0.168.0"
|
||||
version = "0.170.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_websocket"
|
||||
version = "0.173.0"
|
||||
version = "0.175.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -143,6 +143,9 @@ function createStorage(persistent) {
|
|||
if (ReflectHas(target, key)) {
|
||||
return undefined;
|
||||
}
|
||||
if (typeof key === "symbol") {
|
||||
return undefined;
|
||||
}
|
||||
const value = target.getItem(key);
|
||||
if (value === null) {
|
||||
return undefined;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_webstorage"
|
||||
version = "0.163.0"
|
||||
version = "0.165.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_resolver"
|
||||
version = "0.0.1"
|
||||
version = "0.2.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
@ -13,16 +13,16 @@ description = "Deno resolution algorithm"
|
|||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[features]
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
base32.workspace = true
|
||||
deno_media_type.workspace = true
|
||||
deno_package_json.workspace = true
|
||||
deno_package_json.features = ["sync"]
|
||||
deno_path_util.workspace = true
|
||||
deno_semver.workspace = true
|
||||
node_resolver.workspace = true
|
||||
thiserror.workspace = true
|
||||
url.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -5,8 +5,6 @@ use std::path::Path;
|
|||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::bail;
|
||||
use anyhow::Error as AnyError;
|
||||
use deno_package_json::PackageJson;
|
||||
use deno_package_json::PackageJsonDepValue;
|
||||
use deno_path_util::url_to_file_path;
|
||||
|
@ -18,6 +16,7 @@ use node_resolver::errors::PackageJsonLoadError;
|
|||
use node_resolver::errors::PackageNotFoundError;
|
||||
use node_resolver::load_pkg_json;
|
||||
use node_resolver::NpmResolver;
|
||||
use thiserror::Error;
|
||||
use url::Url;
|
||||
|
||||
use crate::fs::DenoPkgJsonFsAdapter;
|
||||
|
@ -25,6 +24,18 @@ use crate::fs::DenoResolverFs;
|
|||
|
||||
use super::local::normalize_pkg_name_for_node_modules_deno_folder;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ByonmResolvePkgFolderFromDenoReqError {
|
||||
#[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(String),
|
||||
#[error(transparent)]
|
||||
PackageJson(#[from] PackageJsonLoadError),
|
||||
#[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),
|
||||
#[error(transparent)]
|
||||
Io(#[from] std::io::Error),
|
||||
}
|
||||
|
||||
pub struct ByonmNpmResolverCreateOptions<Fs: DenoResolverFs> {
|
||||
pub fs: Fs,
|
||||
// todo(dsherret): investigate removing this
|
||||
|
@ -100,12 +111,12 @@ impl<Fs: DenoResolverFs> ByonmNpmResolver<Fs> {
|
|||
&self,
|
||||
req: &PackageReq,
|
||||
referrer: &Url,
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
) -> Result<PathBuf, ByonmResolvePkgFolderFromDenoReqError> {
|
||||
fn node_resolve_dir<Fs: DenoResolverFs>(
|
||||
fs: &Fs,
|
||||
alias: &str,
|
||||
start_dir: &Path,
|
||||
) -> Result<Option<PathBuf>, AnyError> {
|
||||
) -> std::io::Result<Option<PathBuf>> {
|
||||
for ancestor in start_dir.ancestors() {
|
||||
let node_modules_folder = ancestor.join("node_modules");
|
||||
let sub_dir = join_package_name(&node_modules_folder, alias);
|
||||
|
@ -131,14 +142,7 @@ impl<Fs: DenoResolverFs> ByonmNpmResolver<Fs> {
|
|||
return Ok(resolved);
|
||||
}
|
||||
|
||||
bail!(
|
||||
concat!(
|
||||
"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`?"
|
||||
),
|
||||
alias,
|
||||
);
|
||||
Err(ByonmResolvePkgFolderFromDenoReqError::MissingAlias(alias))
|
||||
}
|
||||
None => {
|
||||
// now check if node_modules/.deno/ matches this constraint
|
||||
|
@ -146,16 +150,9 @@ impl<Fs: DenoResolverFs> ByonmNpmResolver<Fs> {
|
|||
return Ok(folder);
|
||||
}
|
||||
|
||||
bail!(
|
||||
concat!(
|
||||
"Could not find a matching package for 'npm:{}' in the node_modules ",
|
||||
"directory. Ensure you have all your JSR and npm dependencies listed ",
|
||||
"in your deno.json or package.json, then run `deno install`. Alternatively, ",
|
||||
r#"turn on auto-install by specifying `"nodeModulesDir": "auto"` in your "#,
|
||||
"deno.json file."
|
||||
),
|
||||
req,
|
||||
);
|
||||
Err(ByonmResolvePkgFolderFromDenoReqError::UnmatchedReq(
|
||||
req.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +161,7 @@ impl<Fs: DenoResolverFs> ByonmNpmResolver<Fs> {
|
|||
&self,
|
||||
req: &PackageReq,
|
||||
referrer: &Url,
|
||||
) -> Result<Option<(Arc<PackageJson>, String)>, AnyError> {
|
||||
) -> Result<Option<(Arc<PackageJson>, String)>, PackageJsonLoadError> {
|
||||
fn resolve_alias_from_pkg_json(
|
||||
req: &PackageReq,
|
||||
pkg_json: &PackageJson,
|
||||
|
@ -256,7 +253,24 @@ impl<Fs: DenoResolverFs> ByonmNpmResolver<Fs> {
|
|||
let Ok(version) = Version::parse_from_npm(version) else {
|
||||
continue;
|
||||
};
|
||||
if req.version_req.matches(&version) {
|
||||
if let Some(tag) = req.version_req.tag() {
|
||||
let initialized_file =
|
||||
node_modules_deno_dir.join(&entry.name).join(".initialized");
|
||||
let Ok(contents) = self.fs.read_to_string_lossy(&initialized_file)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let mut tags = contents.split(',').map(str::trim);
|
||||
if tags.any(|t| t == tag) {
|
||||
if let Some((best_version_version, _)) = &best_version {
|
||||
if version > *best_version_version {
|
||||
best_version = Some((version, entry.name));
|
||||
}
|
||||
} else {
|
||||
best_version = Some((version, entry.name));
|
||||
}
|
||||
}
|
||||
} else if req.version_req.matches(&version) {
|
||||
if let Some((best_version_version, _)) = &best_version {
|
||||
if version > *best_version_version {
|
||||
best_version = Some((version, entry.name));
|
||||
|
|
|
@ -5,4 +5,5 @@ mod local;
|
|||
|
||||
pub use byonm::ByonmNpmResolver;
|
||||
pub use byonm::ByonmNpmResolverCreateOptions;
|
||||
pub use byonm::ByonmResolvePkgFolderFromDenoReqError;
|
||||
pub use local::normalize_pkg_name_for_node_modules_deno_folder;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "node_resolver"
|
||||
version = "0.7.0"
|
||||
version = "0.9.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_runtime"
|
||||
version = "0.177.0"
|
||||
version = "0.179.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -26,24 +26,44 @@ enum FixSuggestionKind {
|
|||
Hint,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum FixSuggestionMessage<'a> {
|
||||
Single(&'a str),
|
||||
Multiline(&'a [&'a str]),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FixSuggestion<'a> {
|
||||
kind: FixSuggestionKind,
|
||||
message: &'a str,
|
||||
message: FixSuggestionMessage<'a>,
|
||||
}
|
||||
|
||||
impl<'a> FixSuggestion<'a> {
|
||||
pub fn info(message: &'a str) -> Self {
|
||||
Self {
|
||||
kind: FixSuggestionKind::Info,
|
||||
message,
|
||||
message: FixSuggestionMessage::Single(message),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn info_multiline(messages: &'a [&'a str]) -> Self {
|
||||
Self {
|
||||
kind: FixSuggestionKind::Info,
|
||||
message: FixSuggestionMessage::Multiline(messages),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hint(message: &'a str) -> Self {
|
||||
Self {
|
||||
kind: FixSuggestionKind::Hint,
|
||||
message,
|
||||
message: FixSuggestionMessage::Single(message),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hint_multiline(messages: &'a [&'a str]) -> Self {
|
||||
Self {
|
||||
kind: FixSuggestionKind::Hint,
|
||||
message: FixSuggestionMessage::Multiline(messages),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -238,7 +258,21 @@ fn format_js_error_inner(
|
|||
FixSuggestionKind::Hint => write!(s, "{} ", cyan("hint:")).unwrap(),
|
||||
FixSuggestionKind::Info => write!(s, "{} ", yellow("info:")).unwrap(),
|
||||
};
|
||||
write!(s, "{}", suggestion.message).unwrap();
|
||||
match suggestion.message {
|
||||
FixSuggestionMessage::Single(msg) => {
|
||||
write!(s, "{}", msg).unwrap();
|
||||
}
|
||||
FixSuggestionMessage::Multiline(messages) => {
|
||||
for (idx, message) in messages.iter().enumerate() {
|
||||
if idx != 0 {
|
||||
writeln!(s).unwrap();
|
||||
write!(s, " ").unwrap();
|
||||
}
|
||||
write!(s, "{}", message).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if index != (suggestions.len() - 1) {
|
||||
writeln!(s).unwrap();
|
||||
}
|
||||
|
|
|
@ -169,8 +169,11 @@ let isClosing = false;
|
|||
let globalDispatchEvent;
|
||||
|
||||
function hasMessageEventListener() {
|
||||
// the function name is kind of a misnomer, but we want to behave
|
||||
// as if we have message event listeners if a node message port is explicitly
|
||||
// refed (and the inverse as well)
|
||||
return event.listenerCount(globalThis, "message") > 0 ||
|
||||
messagePort.messageEventListenerCount > 0;
|
||||
messagePort.refedMessagePortsCount > 0;
|
||||
}
|
||||
|
||||
async function pollForMessages() {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_permissions"
|
||||
version = "0.28.0"
|
||||
version = "0.30.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -476,6 +476,9 @@ impl<TQuery: QueryDescriptor> UnaryPermission<TQuery> {
|
|||
if state != PermissionState::Prompt {
|
||||
return state;
|
||||
}
|
||||
if !self.prompt {
|
||||
return PermissionState::Denied;
|
||||
}
|
||||
let mut message = String::with_capacity(40);
|
||||
message.push_str(&format!("{} access", TQuery::flag_name()));
|
||||
if let Some(desc) = desc {
|
||||
|
@ -2282,6 +2285,11 @@ impl PermissionsContainer {
|
|||
self.inner.lock().read.check_all(Some(api_name))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn query_read_all(&self) -> bool {
|
||||
self.inner.lock().read.query(None) == PermissionState::Granted
|
||||
}
|
||||
|
||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||
#[inline(always)]
|
||||
pub fn check_write(
|
||||
|
@ -2611,8 +2619,13 @@ impl PermissionsContainer {
|
|||
&self,
|
||||
path: Option<&str>,
|
||||
) -> Result<PermissionState, AnyError> {
|
||||
let inner = self.inner.lock();
|
||||
let permission = &inner.read;
|
||||
if permission.is_allow_all() {
|
||||
return Ok(PermissionState::Granted);
|
||||
}
|
||||
Ok(
|
||||
self.inner.lock().read.query(
|
||||
permission.query(
|
||||
path
|
||||
.map(|path| {
|
||||
Result::<_, AnyError>::Ok(
|
||||
|
@ -2630,8 +2643,13 @@ impl PermissionsContainer {
|
|||
&self,
|
||||
path: Option<&str>,
|
||||
) -> Result<PermissionState, AnyError> {
|
||||
let inner = self.inner.lock();
|
||||
let permission = &inner.write;
|
||||
if permission.is_allow_all() {
|
||||
return Ok(PermissionState::Granted);
|
||||
}
|
||||
Ok(
|
||||
self.inner.lock().write.query(
|
||||
permission.query(
|
||||
path
|
||||
.map(|path| {
|
||||
Result::<_, AnyError>::Ok(
|
||||
|
@ -2649,8 +2667,13 @@ impl PermissionsContainer {
|
|||
&self,
|
||||
host: Option<&str>,
|
||||
) -> Result<PermissionState, AnyError> {
|
||||
let inner = self.inner.lock();
|
||||
let permission = &inner.net;
|
||||
if permission.is_allow_all() {
|
||||
return Ok(PermissionState::Granted);
|
||||
}
|
||||
Ok(
|
||||
self.inner.lock().net.query(
|
||||
permission.query(
|
||||
match host {
|
||||
None => None,
|
||||
Some(h) => Some(self.descriptor_parser.parse_net_descriptor(h)?),
|
||||
|
@ -2662,7 +2685,12 @@ impl PermissionsContainer {
|
|||
|
||||
#[inline(always)]
|
||||
pub fn query_env(&self, var: Option<&str>) -> PermissionState {
|
||||
self.inner.lock().env.query(var)
|
||||
let inner = self.inner.lock();
|
||||
let permission = &inner.env;
|
||||
if permission.is_allow_all() {
|
||||
return PermissionState::Granted;
|
||||
}
|
||||
permission.query(var)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -2670,8 +2698,13 @@ impl PermissionsContainer {
|
|||
&self,
|
||||
kind: Option<&str>,
|
||||
) -> Result<PermissionState, AnyError> {
|
||||
let inner = self.inner.lock();
|
||||
let permission = &inner.sys;
|
||||
if permission.is_allow_all() {
|
||||
return Ok(PermissionState::Granted);
|
||||
}
|
||||
Ok(
|
||||
self.inner.lock().sys.query(
|
||||
permission.query(
|
||||
kind
|
||||
.map(|kind| self.descriptor_parser.parse_sys_descriptor(kind))
|
||||
.transpose()?
|
||||
|
@ -2685,8 +2718,13 @@ impl PermissionsContainer {
|
|||
&self,
|
||||
cmd: Option<&str>,
|
||||
) -> Result<PermissionState, AnyError> {
|
||||
let inner = self.inner.lock();
|
||||
let permission = &inner.run;
|
||||
if permission.is_allow_all() {
|
||||
return Ok(PermissionState::Granted);
|
||||
}
|
||||
Ok(
|
||||
self.inner.lock().run.query(
|
||||
permission.query(
|
||||
cmd
|
||||
.map(|request| self.descriptor_parser.parse_run_query(request))
|
||||
.transpose()?
|
||||
|
@ -2700,8 +2738,13 @@ impl PermissionsContainer {
|
|||
&self,
|
||||
path: Option<&str>,
|
||||
) -> Result<PermissionState, AnyError> {
|
||||
let inner = self.inner.lock();
|
||||
let permission = &inner.ffi;
|
||||
if permission.is_allow_all() {
|
||||
return Ok(PermissionState::Granted);
|
||||
}
|
||||
Ok(
|
||||
self.inner.lock().ffi.query(
|
||||
permission.query(
|
||||
path
|
||||
.map(|path| {
|
||||
Result::<_, AnyError>::Ok(
|
||||
|
@ -3906,7 +3949,8 @@ mod tests {
|
|||
fn test_request() {
|
||||
set_prompter(Box::new(TestPrompter));
|
||||
let parser = TestPermissionDescriptorParser;
|
||||
let mut perms: Permissions = Permissions::none_without_prompt();
|
||||
let mut perms: Permissions = Permissions::none_with_prompt();
|
||||
let mut perms_no_prompt: Permissions = Permissions::none_without_prompt();
|
||||
let read_query =
|
||||
|path: &str| parser.parse_path_query(path).unwrap().into_read();
|
||||
let write_query =
|
||||
|
@ -3955,6 +3999,7 @@ mod tests {
|
|||
assert_eq!(perms.run.query(None), PermissionState::Prompt);
|
||||
prompt_value.set(false);
|
||||
assert_eq!(perms.run.request(Some(&run_query)), PermissionState::Granted);
|
||||
assert_eq!(perms_no_prompt.read.request(Some(&read_query("/foo"))), PermissionState::Denied);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -97,6 +97,9 @@ impl deno_node::NodePermissions for Permissions {
|
|||
) -> Result<PathBuf, deno_core::error::AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
fn query_read_all(&mut self) -> bool {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
fn check_write_with_api_name(
|
||||
&mut self,
|
||||
_p: &str,
|
||||
|
|
|
@ -4,7 +4,6 @@ use deno_lockfile::NewLockfileOptions;
|
|||
use deno_semver::jsr::JsrDepPackageReq;
|
||||
use test_util as util;
|
||||
use test_util::itest;
|
||||
use util::env_vars_for_npm_tests;
|
||||
use util::TestContext;
|
||||
use util::TestContextBuilder;
|
||||
|
||||
|
@ -21,104 +20,6 @@ itest!(check_all_local {
|
|||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(module_detection_force {
|
||||
args: "check --quiet check/module_detection_force/main.ts",
|
||||
output_str: Some(""),
|
||||
});
|
||||
|
||||
// Regression test for https://github.com/denoland/deno/issues/14937.
|
||||
itest!(declaration_header_file_with_no_exports {
|
||||
args: "check --quiet check/declaration_header_file_with_no_exports.ts",
|
||||
output_str: Some(""),
|
||||
});
|
||||
|
||||
itest!(check_jsximportsource_importmap_config {
|
||||
args: "check --quiet --config check/jsximportsource_importmap_config/deno.json check/jsximportsource_importmap_config/main.tsx",
|
||||
output_str: Some(""),
|
||||
});
|
||||
|
||||
itest!(jsx_not_checked {
|
||||
args: "check check/jsx_not_checked/main.jsx",
|
||||
output: "check/jsx_not_checked/main.out",
|
||||
envs: env_vars_for_npm_tests(),
|
||||
http_server: true,
|
||||
exit_code: 1,
|
||||
});
|
||||
|
||||
itest!(check_npm_install_diagnostics {
|
||||
args: "check --quiet check/npm_install_diagnostics/main.ts",
|
||||
output: "check/npm_install_diagnostics/main.out",
|
||||
envs: vec![("NO_COLOR".to_string(), "1".to_string())],
|
||||
exit_code: 1,
|
||||
});
|
||||
|
||||
itest!(check_static_response_json {
|
||||
args: "check --quiet check/response_json.ts",
|
||||
exit_code: 0,
|
||||
});
|
||||
|
||||
itest!(check_node_builtin_modules_ts {
|
||||
args: "check --quiet check/node_builtin_modules/mod.ts",
|
||||
output: "check/node_builtin_modules/mod.ts.out",
|
||||
envs: env_vars_for_npm_tests(),
|
||||
exit_code: 1,
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(check_node_builtin_modules_js {
|
||||
args: "check --quiet check/node_builtin_modules/mod.js",
|
||||
output: "check/node_builtin_modules/mod.js.out",
|
||||
envs: env_vars_for_npm_tests(),
|
||||
exit_code: 1,
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(check_no_error_truncation {
|
||||
args: "check --quiet check/no_error_truncation/main.ts --config check/no_error_truncation/deno.json",
|
||||
output: "check/no_error_truncation/main.out",
|
||||
envs: vec![("NO_COLOR".to_string(), "1".to_string())],
|
||||
exit_code: 1,
|
||||
});
|
||||
|
||||
itest!(check_broadcast_channel {
|
||||
args: "check --quiet check/broadcast_channel.ts",
|
||||
exit_code: 0,
|
||||
});
|
||||
|
||||
itest!(check_deno_not_found {
|
||||
args: "check --quiet check/deno_not_found/main.ts",
|
||||
output: "check/deno_not_found/main.out",
|
||||
exit_code: 1,
|
||||
});
|
||||
|
||||
itest!(check_with_exclude_option_by_dir {
|
||||
args:
|
||||
"check --quiet --config check/exclude_option/deno.exclude_dir.json check/exclude_option/ignored/index.ts",
|
||||
output_str: Some(""),
|
||||
exit_code: 0,
|
||||
});
|
||||
|
||||
itest!(check_with_exclude_option_by_glob {
|
||||
args:
|
||||
"check --quiet --config check/exclude_option/deno.exclude_glob.json check/exclude_option/ignored/index.ts",
|
||||
output_str: Some(""),
|
||||
exit_code: 0,
|
||||
});
|
||||
|
||||
itest!(check_without_exclude_option {
|
||||
args:
|
||||
"check --quiet --config check/exclude_option/deno.json check/exclude_option/ignored/index.ts",
|
||||
output: "check/exclude_option/exclude_option.ts.error.out",
|
||||
exit_code: 1,
|
||||
});
|
||||
|
||||
itest!(check_imported_files_listed_in_exclude_option {
|
||||
args:
|
||||
"check --quiet --config check/exclude_option/deno.exclude_dir.json check/exclude_option/index.ts",
|
||||
output: "check/exclude_option/exclude_option.ts.error.out",
|
||||
exit_code: 1,
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn cache_switching_config_then_no_config() {
|
||||
let context = TestContext::default();
|
||||
|
@ -241,12 +142,6 @@ fn ts_no_recheck_on_redirect() {
|
|||
output.assert_matches_text("Hello\n");
|
||||
}
|
||||
|
||||
itest!(check_dts {
|
||||
args: "check --quiet check/dts/check_dts.d.ts",
|
||||
output: "check/dts/check_dts.out",
|
||||
exit_code: 1,
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn check_error_in_dep_then_fix() {
|
||||
let test_context = TestContextBuilder::new().use_temp_cwd().build();
|
||||
|
|
|
@ -21,7 +21,6 @@ fn help_output() {
|
|||
"Install script as an executable",
|
||||
"Uninstall a script previously installed with deno install",
|
||||
"Run benchmarks",
|
||||
"Cache the dependencies",
|
||||
"Type-check the dependencies",
|
||||
"Compile the script into a self contained executable",
|
||||
"Print coverage reports",
|
||||
|
|
|
@ -191,7 +191,7 @@ fn reload_info_not_found_cache_but_exists_remote() {
|
|||
Url::parse(&format!("http://127.0.0.1:4250/{}/meta.json", package))
|
||||
.unwrap();
|
||||
let cache = deno_cache_dir::GlobalHttpCache::new(
|
||||
deno_dir.path().join("deps").to_path_buf(),
|
||||
deno_dir.path().join("remote").to_path_buf(),
|
||||
deno_cache_dir::TestRealDenoCacheEnv,
|
||||
);
|
||||
let entry = cache
|
||||
|
|
|
@ -5906,6 +5906,135 @@ fn lsp_code_actions_deno_cache_all() {
|
|||
client.shutdown();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lsp_code_actions_deno_types_for_npm() {
|
||||
let context = TestContextBuilder::new()
|
||||
.use_http_server()
|
||||
.use_temp_cwd()
|
||||
.add_npm_env_vars()
|
||||
.build();
|
||||
let temp_dir = context.temp_dir();
|
||||
temp_dir.write("deno.json", json!({}).to_string());
|
||||
temp_dir.write(
|
||||
"package.json",
|
||||
json!({
|
||||
"dependencies": {
|
||||
"react": "^18.2.0",
|
||||
"@types/react": "^18.3.10",
|
||||
},
|
||||
})
|
||||
.to_string(),
|
||||
);
|
||||
temp_dir.create_dir_all("managed_node_modules");
|
||||
temp_dir.write(
|
||||
"managed_node_modules/deno.json",
|
||||
json!({
|
||||
"nodeModulesDir": false,
|
||||
})
|
||||
.to_string(),
|
||||
);
|
||||
context.run_npm("install");
|
||||
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": "import \"react\";\n",
|
||||
}
|
||||
}));
|
||||
let res = client.write_request(
|
||||
"textDocument/codeAction",
|
||||
json!({
|
||||
"textDocument": {
|
||||
"uri": temp_dir.url().join("file.ts").unwrap(),
|
||||
},
|
||||
"range": {
|
||||
"start": { "line": 0, "character": 7 },
|
||||
"end": { "line": 0, "character": 7 },
|
||||
},
|
||||
"context": { "diagnostics": [], "only": ["quickfix"] },
|
||||
}),
|
||||
);
|
||||
assert_eq!(
|
||||
res,
|
||||
json!([
|
||||
{
|
||||
"title": "Add @deno-types directive for \"@types/react\"",
|
||||
"kind": "quickfix",
|
||||
"edit": {
|
||||
"changes": {
|
||||
temp_dir.url().join("file.ts").unwrap(): [
|
||||
{
|
||||
"range": {
|
||||
"start": { "line": 0, "character": 0 },
|
||||
"end": { "line": 0, "character": 0 },
|
||||
},
|
||||
"newText": "// @deno-types=\"@types/react\"\n",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
]),
|
||||
);
|
||||
client.did_open(json!({
|
||||
"textDocument": {
|
||||
"uri": temp_dir.url().join("managed_node_modules/file.ts").unwrap(),
|
||||
"languageId": "typescript",
|
||||
"version": 1,
|
||||
"text": "import \"npm:react\";\n",
|
||||
}
|
||||
}));
|
||||
client.write_request(
|
||||
"workspace/executeCommand",
|
||||
json!({
|
||||
"command": "deno.cache",
|
||||
"arguments": [
|
||||
[],
|
||||
temp_dir.url().join("managed_node_modules/file.ts").unwrap(),
|
||||
],
|
||||
}),
|
||||
);
|
||||
let res = client.write_request(
|
||||
"textDocument/codeAction",
|
||||
json!({
|
||||
"textDocument": {
|
||||
"uri": temp_dir.url().join("managed_node_modules/file.ts").unwrap(),
|
||||
},
|
||||
"range": {
|
||||
"start": { "line": 0, "character": 7 },
|
||||
"end": { "line": 0, "character": 7 },
|
||||
},
|
||||
"context": { "diagnostics": [], "only": ["quickfix"] },
|
||||
}),
|
||||
);
|
||||
assert_eq!(
|
||||
res,
|
||||
json!([
|
||||
{
|
||||
"title": "Add @deno-types directive for \"npm:@types/react@^18.3.10\"",
|
||||
"kind": "quickfix",
|
||||
"edit": {
|
||||
"changes": {
|
||||
temp_dir.url().join("managed_node_modules/file.ts").unwrap(): [
|
||||
{
|
||||
"range": {
|
||||
"start": { "line": 0, "character": 0 },
|
||||
"end": { "line": 0, "character": 0 },
|
||||
},
|
||||
"newText": "// @deno-types=\"npm:@types/react@^18.3.10\"\n",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
]),
|
||||
);
|
||||
client.shutdown();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lsp_cache_on_save() {
|
||||
let context = TestContextBuilder::new()
|
||||
|
@ -8375,6 +8504,74 @@ fn lsp_completions_auto_import_and_quick_fix_with_import_map() {
|
|||
client.shutdown();
|
||||
}
|
||||
|
||||
// Regression test for https://github.com/denoland/deno/issues/25775.
|
||||
#[test]
|
||||
fn lsp_quick_fix_missing_import_exclude_bare_node_builtins() {
|
||||
let context = TestContextBuilder::new()
|
||||
.use_http_server()
|
||||
.use_temp_cwd()
|
||||
.add_npm_env_vars()
|
||||
.build();
|
||||
let temp_dir = context.temp_dir();
|
||||
temp_dir.write(
|
||||
"package.json",
|
||||
json!({
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
},
|
||||
})
|
||||
.to_string(),
|
||||
);
|
||||
context.run_npm("install");
|
||||
let mut client = context.new_lsp_command().build();
|
||||
client.initialize_default();
|
||||
let diagnostics = client.did_open(json!({
|
||||
"textDocument": {
|
||||
"uri": temp_dir.url().join("file.ts").unwrap(),
|
||||
"languageId": "typescript",
|
||||
"version": 1,
|
||||
// Include node:buffer import to ensure @types/node is in the dep graph.
|
||||
"text": "import \"node:buffer\";\nassert();\n",
|
||||
},
|
||||
}));
|
||||
let diagnostic = diagnostics
|
||||
.all()
|
||||
.into_iter()
|
||||
.find(|d| d.message == "Cannot find name 'assert'.")
|
||||
.unwrap();
|
||||
let res = client.write_request(
|
||||
"textDocument/codeAction",
|
||||
json!({
|
||||
"textDocument": {
|
||||
"uri": temp_dir.url().join("file.ts").unwrap(),
|
||||
},
|
||||
"range": {
|
||||
"start": { "line": 1, "character": 0 },
|
||||
"end": { "line": 1, "character": 6 },
|
||||
},
|
||||
"context": {
|
||||
"diagnostics": [&diagnostic],
|
||||
"only": ["quickfix"],
|
||||
},
|
||||
}),
|
||||
);
|
||||
let code_actions =
|
||||
serde_json::from_value::<Vec<lsp::CodeAction>>(res).unwrap();
|
||||
let titles = code_actions
|
||||
.iter()
|
||||
.map(|a| a.title.clone())
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(
|
||||
json!(titles),
|
||||
json!([
|
||||
"Add import from \"node:assert\"",
|
||||
"Add import from \"node:console\"",
|
||||
"Add missing function declaration 'assert'",
|
||||
]),
|
||||
);
|
||||
client.shutdown();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lsp_completions_snippet() {
|
||||
let context = TestContextBuilder::new().use_temp_cwd().build();
|
||||
|
|
|
@ -926,9 +926,7 @@ fn lock_redirects() {
|
|||
);
|
||||
}
|
||||
|
||||
// TODO(2.0): this should be rewritten to a spec test and first run `deno install`
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn lock_deno_json_package_json_deps() {
|
||||
let context = TestContextBuilder::new()
|
||||
.use_temp_cwd()
|
||||
|
@ -942,6 +940,7 @@ fn lock_deno_json_package_json_deps() {
|
|||
|
||||
// add a jsr and npm dependency
|
||||
deno_json.write_json(&json!({
|
||||
"nodeModulesDir": "auto",
|
||||
"imports": {
|
||||
"esm-basic": "npm:@denotest/esm-basic",
|
||||
"module_graph": "jsr:@denotest/module-graph@1.4",
|
||||
|
@ -984,6 +983,7 @@ fn lock_deno_json_package_json_deps() {
|
|||
// now remove the npm dependency from the deno.json and move
|
||||
// it to a package.json that uses an alias
|
||||
deno_json.write_json(&json!({
|
||||
"nodeModulesDir": "auto",
|
||||
"imports": {
|
||||
"module_graph": "jsr:@denotest/module-graph@1.4",
|
||||
}
|
||||
|
@ -1060,7 +1060,9 @@ fn lock_deno_json_package_json_deps() {
|
|||
}));
|
||||
|
||||
// now remove the deps from the deno.json
|
||||
deno_json.write("{}");
|
||||
deno_json.write_json(&json!({
|
||||
"nodeModulesDir": "auto"
|
||||
}));
|
||||
main_ts.write("");
|
||||
context
|
||||
.new_command()
|
||||
|
@ -3512,6 +3514,22 @@ itest!(no_prompt_flag {
|
|||
output_str: Some(""),
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn permission_request_with_no_prompt() {
|
||||
TestContext::default()
|
||||
.new_command()
|
||||
.env("NO_COLOR", "1")
|
||||
.args_vec([
|
||||
"run",
|
||||
"--quiet",
|
||||
"--no-prompt",
|
||||
"run/permission_request_no_prompt.ts",
|
||||
])
|
||||
.with_pty(|mut console| {
|
||||
console.expect("PermissionStatus { state: \"denied\", onchange: null }");
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deno_no_prompt_environment_variable() {
|
||||
let output = util::deno_cmd()
|
||||
|
|
|
@ -18,19 +18,6 @@
|
|||
// http_server: true,
|
||||
// });
|
||||
|
||||
// TODO(2.0): decide what to do with this test
|
||||
// should not auto-install the packages in the package.json
|
||||
// when using nodeModulesDir: false
|
||||
// itest!(task_package_json_node_modules_dir_false {
|
||||
// args: "task echo",
|
||||
// cwd: Some("task/package_json_node_modules_dir_false/"),
|
||||
// output: "task/package_json_node_modules_dir_false/bin.out",
|
||||
// copy_temp_dir: Some("task/package_json_node_modules_dir_false/"),
|
||||
// envs: env_vars_for_npm_tests(),
|
||||
// exit_code: 0,
|
||||
// http_server: true,
|
||||
// });
|
||||
|
||||
// TODO(2.0): not entirely clear what's wrong with this test but it hangs for more than 60s
|
||||
// itest!(task_npx_on_own {
|
||||
// args: "task on-own",
|
||||
|
|
|
@ -13,6 +13,7 @@ repository.workspace = true
|
|||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
libuv-sys-lite = "=1.48.2"
|
||||
napi-sys = { version = "=2.2.2", default-features = false, features = ["napi7"] }
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -31,6 +31,7 @@ pub mod strings;
|
|||
pub mod symbol;
|
||||
pub mod tsfn;
|
||||
pub mod typedarray;
|
||||
pub mod uv;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cstr {
|
||||
|
@ -138,6 +139,7 @@ unsafe extern "C" fn napi_register_module_v1(
|
|||
#[cfg(windows)]
|
||||
{
|
||||
napi_sys::setup();
|
||||
libuv_sys_lite::setup();
|
||||
}
|
||||
|
||||
// We create a fresh exports object and leave the passed
|
||||
|
@ -169,6 +171,7 @@ unsafe extern "C" fn napi_register_module_v1(
|
|||
symbol::init(env, exports);
|
||||
make_callback::init(env, exports);
|
||||
object::init(env, exports);
|
||||
uv::init(env, exports);
|
||||
|
||||
init_cleanup_hook(env, exports);
|
||||
|
||||
|
|
206
tests/napi/src/uv.rs
Normal file
206
tests/napi/src/uv.rs
Normal file
|
@ -0,0 +1,206 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
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;
|
||||
use libuv_sys_lite::uv_handle_t;
|
||||
use libuv_sys_lite::uv_mutex_destroy;
|
||||
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;
|
||||
|
||||
struct KeepAlive {
|
||||
tsfn: napi_threadsafe_function,
|
||||
}
|
||||
|
||||
impl KeepAlive {
|
||||
fn new(env: napi_env) -> Self {
|
||||
let mut name = null_mut();
|
||||
assert_napi_ok!(napi_create_string_utf8(
|
||||
env,
|
||||
c"test_uv_async".as_ptr(),
|
||||
13,
|
||||
&mut name
|
||||
));
|
||||
|
||||
unsafe extern "C" fn dummy(
|
||||
_env: napi_env,
|
||||
_cb: napi_callback_info,
|
||||
) -> napi_value {
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
let mut func = null_mut();
|
||||
assert_napi_ok!(napi_create_function(
|
||||
env,
|
||||
c"dummy".as_ptr(),
|
||||
usize::MAX,
|
||||
Some(dummy),
|
||||
null_mut(),
|
||||
&mut func,
|
||||
));
|
||||
|
||||
let mut tsfn = null_mut();
|
||||
assert_napi_ok!(napi_create_threadsafe_function(
|
||||
env,
|
||||
func,
|
||||
null_mut(),
|
||||
name,
|
||||
0,
|
||||
1,
|
||||
null_mut(),
|
||||
None,
|
||||
null_mut(),
|
||||
None,
|
||||
&mut tsfn,
|
||||
));
|
||||
assert_napi_ok!(napi_ref_threadsafe_function(env, tsfn));
|
||||
Self { tsfn }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for KeepAlive {
|
||||
fn drop(&mut self) {
|
||||
assert_napi_ok!(napi_release_threadsafe_function(
|
||||
self.tsfn,
|
||||
ThreadsafeFunctionReleaseMode::release,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
struct Async {
|
||||
mutex: *mut uv_mutex_t,
|
||||
env: napi_env,
|
||||
value: u32,
|
||||
callback: napi_ref,
|
||||
_keep_alive: KeepAlive,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct UvAsyncPtr(*mut uv_async_t);
|
||||
|
||||
unsafe impl Send for UvAsyncPtr {}
|
||||
|
||||
fn new_raw<T>(t: T) -> *mut T {
|
||||
Box::into_raw(Box::new(t))
|
||||
}
|
||||
|
||||
unsafe extern "C" fn close_cb(handle: *mut uv_handle_t) {
|
||||
let handle = handle.cast::<uv_async_t>();
|
||||
let async_ = (*handle).data as *mut Async;
|
||||
let env = (*async_).env;
|
||||
assert_napi_ok!(napi_delete_reference(env, (*async_).callback));
|
||||
|
||||
uv_mutex_destroy((*async_).mutex);
|
||||
let _ = Box::from_raw((*async_).mutex);
|
||||
let _ = Box::from_raw(async_);
|
||||
let _ = Box::from_raw(handle);
|
||||
}
|
||||
|
||||
unsafe extern "C" fn callback(handle: *mut uv_async_t) {
|
||||
eprintln!("callback");
|
||||
let async_ = (*handle).data as *mut Async;
|
||||
uv_mutex_lock((*async_).mutex);
|
||||
let env = (*async_).env;
|
||||
let mut js_cb = null_mut();
|
||||
assert_napi_ok!(napi_get_reference_value(
|
||||
env,
|
||||
(*async_).callback,
|
||||
&mut js_cb
|
||||
));
|
||||
let mut global: napi_value = ptr::null_mut();
|
||||
assert_napi_ok!(napi_get_global(env, &mut global));
|
||||
|
||||
let mut result: napi_value = ptr::null_mut();
|
||||
let value = (*async_).value;
|
||||
eprintln!("value is {value}");
|
||||
let mut value_js = ptr::null_mut();
|
||||
assert_napi_ok!(napi_create_uint32(env, value, &mut value_js));
|
||||
let args = &[value_js];
|
||||
assert_napi_ok!(napi_call_function(
|
||||
env,
|
||||
global,
|
||||
js_cb,
|
||||
1,
|
||||
args.as_ptr(),
|
||||
&mut result,
|
||||
));
|
||||
uv_mutex_unlock((*async_).mutex);
|
||||
if value == 5 {
|
||||
uv_close(handle.cast(), Some(close_cb));
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn uv_async_send(ptr: UvAsyncPtr) {
|
||||
assert_napi_ok!(libuv_sys_lite::uv_async_send(ptr.0));
|
||||
}
|
||||
|
||||
fn make_uv_mutex() -> *mut uv_mutex_t {
|
||||
let mutex = new_raw(MaybeUninit::<uv_mutex_t>::uninit());
|
||||
assert_napi_ok!(libuv_sys_lite::uv_mutex_init(mutex.cast()));
|
||||
mutex.cast()
|
||||
}
|
||||
|
||||
#[allow(unused_unsafe)]
|
||||
extern "C" fn test_uv_async(
|
||||
env: napi_env,
|
||||
info: napi_callback_info,
|
||||
) -> napi_value {
|
||||
let (args, argc, _) = napi_get_callback_info!(env, info, 1);
|
||||
assert_eq!(argc, 1);
|
||||
|
||||
let mut loop_ = null_mut();
|
||||
assert_napi_ok!(napi_get_uv_event_loop(env, &mut loop_));
|
||||
let uv_async = new_raw(MaybeUninit::<uv_async_t>::uninit());
|
||||
let uv_async = uv_async.cast::<uv_async_t>();
|
||||
let mut js_cb = null_mut();
|
||||
assert_napi_ok!(napi_create_reference(env, args[0], 1, &mut js_cb));
|
||||
// let mut tsfn = null_mut();
|
||||
|
||||
let data = new_raw(Async {
|
||||
env,
|
||||
callback: js_cb,
|
||||
mutex: make_uv_mutex(),
|
||||
value: 0,
|
||||
_keep_alive: KeepAlive::new(env),
|
||||
});
|
||||
unsafe {
|
||||
addr_of_mut!((*uv_async).data).write(data.cast());
|
||||
assert_napi_ok!(uv_async_init(loop_.cast(), uv_async, Some(callback)));
|
||||
let uv_async = UvAsyncPtr(uv_async);
|
||||
std::thread::spawn({
|
||||
move || {
|
||||
let data = (*uv_async.0).data as *mut Async;
|
||||
for _ in 0..5 {
|
||||
uv_mutex_lock((*data).mutex);
|
||||
(*data).value += 1;
|
||||
uv_mutex_unlock((*data).mutex);
|
||||
std::thread::sleep(Duration::from_millis(10));
|
||||
uv_async_send(uv_async);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
pub fn init(env: napi_env, exports: napi_value) {
|
||||
let properties = &[napi_new_property!(env, "test_uv_async", test_uv_async)];
|
||||
|
||||
assert_napi_ok!(napi_define_properties(
|
||||
env,
|
||||
exports,
|
||||
properties.len(),
|
||||
properties.as_ptr()
|
||||
));
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue