mirror of
https://github.com/denoland/deno.git
synced 2025-01-21 04:52:26 -05:00
Merge branch 'main' into Add-Dynamic-Device-Path-Handling-for-Windows-File-Access
This commit is contained in:
commit
74c186a8af
791 changed files with 8280 additions and 4346 deletions
|
@ -71,7 +71,7 @@
|
|||
"https://plugins.dprint.dev/typescript-0.93.0.wasm",
|
||||
"https://plugins.dprint.dev/json-0.19.3.wasm",
|
||||
"https://plugins.dprint.dev/markdown-0.17.8.wasm",
|
||||
"https://plugins.dprint.dev/toml-0.6.2.wasm",
|
||||
"https://plugins.dprint.dev/toml-0.6.3.wasm",
|
||||
"https://plugins.dprint.dev/exec-0.5.0.json@8d9972eee71fa1590e04873540421f3eda7674d0f1aae3d7c788615e7b7413d0",
|
||||
"https://plugins.dprint.dev/g-plane/pretty_yaml-v0.5.0.wasm"
|
||||
]
|
||||
|
|
28
.github/workflows/ci.generate.ts
vendored
28
.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 = 16;
|
||||
|
||||
const ubuntuX86Runner = "ubuntu-22.04";
|
||||
const ubuntuX86XlRunner = "ubuntu-22.04-xl";
|
||||
|
@ -757,8 +757,10 @@ const ci = {
|
|||
].join("\n"),
|
||||
run: [
|
||||
"cd target/release",
|
||||
"shasum -a 256 deno > deno-${{ matrix.arch }}-unknown-linux-gnu.sha256sum",
|
||||
"zip -r deno-${{ matrix.arch }}-unknown-linux-gnu.zip deno",
|
||||
"strip denort",
|
||||
"shasum -a 256 denort > denort-${{ matrix.arch }}-unknown-linux-gnu.sha256sum",
|
||||
"zip -r denort-${{ matrix.arch }}-unknown-linux-gnu.zip denort",
|
||||
"./deno types > lib.deno.d.ts",
|
||||
].join("\n"),
|
||||
|
@ -783,8 +785,10 @@ const ci = {
|
|||
"--p12-file=<(echo $APPLE_CODESIGN_KEY | base64 -d) " +
|
||||
"--entitlements-xml-file=cli/entitlements.plist",
|
||||
"cd target/release",
|
||||
"shasum -a 256 deno > deno-${{ matrix.arch }}-apple-darwin.sha256sum",
|
||||
"zip -r deno-${{ matrix.arch }}-apple-darwin.zip deno",
|
||||
"strip denort",
|
||||
"shasum -a 256 denort > denort-${{ matrix.arch }}-apple-darwin.sha256sum",
|
||||
"zip -r denort-${{ matrix.arch }}-apple-darwin.zip denort",
|
||||
]
|
||||
.join("\n"),
|
||||
|
@ -799,7 +803,9 @@ const ci = {
|
|||
].join("\n"),
|
||||
shell: "pwsh",
|
||||
run: [
|
||||
"Get-FileHash target/release/deno.exe -Algorithm SHA256 | Format-List > target/release/deno-${{ matrix.arch }}-pc-windows-msvc.sha256sum",
|
||||
"Compress-Archive -CompressionLevel Optimal -Force -Path target/release/deno.exe -DestinationPath target/release/deno-${{ matrix.arch }}-pc-windows-msvc.zip",
|
||||
"Get-FileHash target/release/denort.exe -Algorithm SHA256 | Format-List > target/release/denort-${{ matrix.arch }}-pc-windows-msvc.sha256sum",
|
||||
"Compress-Archive -CompressionLevel Optimal -Force -Path target/release/denort.exe -DestinationPath target/release/denort-${{ matrix.arch }}-pc-windows-msvc.zip",
|
||||
].join("\n"),
|
||||
},
|
||||
|
@ -813,6 +819,7 @@ const ci = {
|
|||
].join("\n"),
|
||||
run: [
|
||||
'gsutil -h "Cache-Control: public, max-age=3600" cp ./target/release/*.zip gs://dl.deno.land/canary/$(git rev-parse HEAD)/',
|
||||
'gsutil -h "Cache-Control: public, max-age=3600" cp ./target/release/*.sha256sum gs://dl.deno.land/canary/$(git rev-parse HEAD)/',
|
||||
"echo ${{ github.sha }} > canary-latest.txt",
|
||||
'gsutil -h "Cache-Control: no-cache" cp canary-latest.txt gs://dl.deno.land/canary-$(rustc -vV | sed -n "s|host: ||p")-latest.txt',
|
||||
].join("\n"),
|
||||
|
@ -994,8 +1001,10 @@ const ci = {
|
|||
"github.repository == 'denoland/deno' &&",
|
||||
"startsWith(github.ref, 'refs/tags/')",
|
||||
].join("\n"),
|
||||
run:
|
||||
run: [
|
||||
'gsutil -h "Cache-Control: public, max-age=3600" cp ./target/release/*.zip gs://dl.deno.land/release/${GITHUB_REF#refs/*/}/',
|
||||
'gsutil -h "Cache-Control: public, max-age=3600" cp ./target/release/*.sha256sum gs://dl.deno.land/release/${GITHUB_REF#refs/*/}/',
|
||||
].join("\n"),
|
||||
},
|
||||
{
|
||||
name: "Upload release to dl.deno.land (windows)",
|
||||
|
@ -1009,8 +1018,10 @@ const ci = {
|
|||
env: {
|
||||
CLOUDSDK_PYTHON: "${{env.pythonLocation}}\\python.exe",
|
||||
},
|
||||
run:
|
||||
run: [
|
||||
'gsutil -h "Cache-Control: public, max-age=3600" cp ./target/release/*.zip gs://dl.deno.land/release/${GITHUB_REF#refs/*/}/',
|
||||
'gsutil -h "Cache-Control: public, max-age=3600" cp ./target/release/*.sha256sum gs://dl.deno.land/release/${GITHUB_REF#refs/*/}/',
|
||||
].join("\n"),
|
||||
},
|
||||
{
|
||||
name: "Create release notes",
|
||||
|
@ -1040,15 +1051,25 @@ const ci = {
|
|||
with: {
|
||||
files: [
|
||||
"target/release/deno-x86_64-pc-windows-msvc.zip",
|
||||
"target/release/deno-x86_64-pc-windows-msvc.sha256sum",
|
||||
"target/release/denort-x86_64-pc-windows-msvc.zip",
|
||||
"target/release/denort-x86_64-pc-windows-msvc.sha256sum",
|
||||
"target/release/deno-x86_64-unknown-linux-gnu.zip",
|
||||
"target/release/deno-x86_64-unknown-linux-gnu.sha256sum",
|
||||
"target/release/denort-x86_64-unknown-linux-gnu.zip",
|
||||
"target/release/denort-x86_64-unknown-linux-gnu.sha256sum",
|
||||
"target/release/deno-x86_64-apple-darwin.zip",
|
||||
"target/release/deno-x86_64-apple-darwin.sha256sum",
|
||||
"target/release/denort-x86_64-apple-darwin.zip",
|
||||
"target/release/denort-x86_64-apple-darwin.sha256sum",
|
||||
"target/release/deno-aarch64-unknown-linux-gnu.zip",
|
||||
"target/release/deno-aarch64-unknown-linux-gnu.sha256sum",
|
||||
"target/release/denort-aarch64-unknown-linux-gnu.zip",
|
||||
"target/release/denort-aarch64-unknown-linux-gnu.sha256sum",
|
||||
"target/release/deno-aarch64-apple-darwin.zip",
|
||||
"target/release/deno-aarch64-apple-darwin.sha256sum",
|
||||
"target/release/denort-aarch64-apple-darwin.zip",
|
||||
"target/release/denort-aarch64-apple-darwin.sha256sum",
|
||||
"target/release/deno_src.tar.gz",
|
||||
"target/release/lib.deno.d.ts",
|
||||
].join("\n"),
|
||||
|
@ -1067,6 +1088,7 @@ const ci = {
|
|||
"./target",
|
||||
"!./target/*/gn_out",
|
||||
"!./target/*/*.zip",
|
||||
"!./target/*/*.sha256sum",
|
||||
"!./target/*/*.tar.gz",
|
||||
].join("\n"),
|
||||
key: prCacheKeyPrefix + "${{ github.sha }}",
|
||||
|
|
34
.github/workflows/ci.yml
vendored
34
.github/workflows/ci.yml
vendored
|
@ -367,8 +367,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: '16-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}'
|
||||
restore-keys: '16-cargo-home-${{ matrix.os }}-${{ matrix.arch }}'
|
||||
if: '!(matrix.skip)'
|
||||
- name: Restore cache build output (PR)
|
||||
uses: actions/cache/restore@v4
|
||||
|
@ -381,7 +381,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: '16-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
|
||||
|
@ -448,8 +448,10 @@ jobs:
|
|||
github.repository == 'denoland/deno')
|
||||
run: |-
|
||||
cd target/release
|
||||
shasum -a 256 deno > deno-${{ matrix.arch }}-unknown-linux-gnu.sha256sum
|
||||
zip -r deno-${{ matrix.arch }}-unknown-linux-gnu.zip deno
|
||||
strip denort
|
||||
shasum -a 256 denort > denort-${{ matrix.arch }}-unknown-linux-gnu.sha256sum
|
||||
zip -r denort-${{ matrix.arch }}-unknown-linux-gnu.zip denort
|
||||
./deno types > lib.deno.d.ts
|
||||
- name: Pre-release (mac)
|
||||
|
@ -465,8 +467,10 @@ jobs:
|
|||
echo "Key is $(echo $APPLE_CODESIGN_KEY | base64 -d | wc -c) bytes"
|
||||
rcodesign sign target/release/deno --code-signature-flags=runtime --p12-password="$APPLE_CODESIGN_PASSWORD" --p12-file=<(echo $APPLE_CODESIGN_KEY | base64 -d) --entitlements-xml-file=cli/entitlements.plist
|
||||
cd target/release
|
||||
shasum -a 256 deno > deno-${{ matrix.arch }}-apple-darwin.sha256sum
|
||||
zip -r deno-${{ matrix.arch }}-apple-darwin.zip deno
|
||||
strip denort
|
||||
shasum -a 256 denort > denort-${{ matrix.arch }}-apple-darwin.sha256sum
|
||||
zip -r denort-${{ matrix.arch }}-apple-darwin.zip denort
|
||||
- name: Pre-release (windows)
|
||||
if: |-
|
||||
|
@ -476,7 +480,9 @@ jobs:
|
|||
github.repository == 'denoland/deno')
|
||||
shell: pwsh
|
||||
run: |-
|
||||
Get-FileHash target/release/deno.exe -Algorithm SHA256 | Format-List > target/release/deno-${{ matrix.arch }}-pc-windows-msvc.sha256sum
|
||||
Compress-Archive -CompressionLevel Optimal -Force -Path target/release/deno.exe -DestinationPath target/release/deno-${{ matrix.arch }}-pc-windows-msvc.zip
|
||||
Get-FileHash target/release/denort.exe -Algorithm SHA256 | Format-List > target/release/denort-${{ matrix.arch }}-pc-windows-msvc.sha256sum
|
||||
Compress-Archive -CompressionLevel Optimal -Force -Path target/release/denort.exe -DestinationPath target/release/denort-${{ matrix.arch }}-pc-windows-msvc.zip
|
||||
- name: Upload canary to dl.deno.land
|
||||
if: |-
|
||||
|
@ -486,6 +492,7 @@ jobs:
|
|||
github.ref == 'refs/heads/main')
|
||||
run: |-
|
||||
gsutil -h "Cache-Control: public, max-age=3600" cp ./target/release/*.zip gs://dl.deno.land/canary/$(git rev-parse HEAD)/
|
||||
gsutil -h "Cache-Control: public, max-age=3600" cp ./target/release/*.sha256sum gs://dl.deno.land/canary/$(git rev-parse HEAD)/
|
||||
echo ${{ github.sha }} > canary-latest.txt
|
||||
gsutil -h "Cache-Control: no-cache" cp canary-latest.txt gs://dl.deno.land/canary-$(rustc -vV | sed -n "s|host: ||p")-latest.txt
|
||||
- name: Autobahn testsuite
|
||||
|
@ -615,7 +622,9 @@ jobs:
|
|||
matrix.profile == 'release' &&
|
||||
github.repository == 'denoland/deno' &&
|
||||
startsWith(github.ref, 'refs/tags/'))
|
||||
run: 'gsutil -h "Cache-Control: public, max-age=3600" cp ./target/release/*.zip gs://dl.deno.land/release/${GITHUB_REF#refs/*/}/'
|
||||
run: |-
|
||||
gsutil -h "Cache-Control: public, max-age=3600" cp ./target/release/*.zip gs://dl.deno.land/release/${GITHUB_REF#refs/*/}/
|
||||
gsutil -h "Cache-Control: public, max-age=3600" cp ./target/release/*.sha256sum gs://dl.deno.land/release/${GITHUB_REF#refs/*/}/
|
||||
- name: Upload release to dl.deno.land (windows)
|
||||
if: |-
|
||||
!(matrix.skip) && (matrix.os == 'windows' &&
|
||||
|
@ -625,7 +634,9 @@ jobs:
|
|||
startsWith(github.ref, 'refs/tags/'))
|
||||
env:
|
||||
CLOUDSDK_PYTHON: '${{env.pythonLocation}}\python.exe'
|
||||
run: 'gsutil -h "Cache-Control: public, max-age=3600" cp ./target/release/*.zip gs://dl.deno.land/release/${GITHUB_REF#refs/*/}/'
|
||||
run: |-
|
||||
gsutil -h "Cache-Control: public, max-age=3600" cp ./target/release/*.zip gs://dl.deno.land/release/${GITHUB_REF#refs/*/}/
|
||||
gsutil -h "Cache-Control: public, max-age=3600" cp ./target/release/*.sha256sum gs://dl.deno.land/release/${GITHUB_REF#refs/*/}/
|
||||
- name: Create release notes
|
||||
if: |-
|
||||
!(matrix.skip) && (matrix.job == 'test' &&
|
||||
|
@ -647,15 +658,25 @@ jobs:
|
|||
with:
|
||||
files: |-
|
||||
target/release/deno-x86_64-pc-windows-msvc.zip
|
||||
target/release/deno-x86_64-pc-windows-msvc.sha256sum
|
||||
target/release/denort-x86_64-pc-windows-msvc.zip
|
||||
target/release/denort-x86_64-pc-windows-msvc.sha256sum
|
||||
target/release/deno-x86_64-unknown-linux-gnu.zip
|
||||
target/release/deno-x86_64-unknown-linux-gnu.sha256sum
|
||||
target/release/denort-x86_64-unknown-linux-gnu.zip
|
||||
target/release/denort-x86_64-unknown-linux-gnu.sha256sum
|
||||
target/release/deno-x86_64-apple-darwin.zip
|
||||
target/release/deno-x86_64-apple-darwin.sha256sum
|
||||
target/release/denort-x86_64-apple-darwin.zip
|
||||
target/release/denort-x86_64-apple-darwin.sha256sum
|
||||
target/release/deno-aarch64-unknown-linux-gnu.zip
|
||||
target/release/deno-aarch64-unknown-linux-gnu.sha256sum
|
||||
target/release/denort-aarch64-unknown-linux-gnu.zip
|
||||
target/release/denort-aarch64-unknown-linux-gnu.sha256sum
|
||||
target/release/deno-aarch64-apple-darwin.zip
|
||||
target/release/deno-aarch64-apple-darwin.sha256sum
|
||||
target/release/denort-aarch64-apple-darwin.zip
|
||||
target/release/denort-aarch64-apple-darwin.sha256sum
|
||||
target/release/deno_src.tar.gz
|
||||
target/release/lib.deno.d.ts
|
||||
body_path: target/release/release-notes.md
|
||||
|
@ -668,8 +689,9 @@ jobs:
|
|||
./target
|
||||
!./target/*/gn_out
|
||||
!./target/*/*.zip
|
||||
!./target/*/*.sha256sum
|
||||
!./target/*/*.tar.gz
|
||||
key: '15-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}'
|
||||
key: '16-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}'
|
||||
publish-canary:
|
||||
name: publish canary
|
||||
runs-on: ubuntu-22.04
|
||||
|
|
203
Cargo.lock
generated
203
Cargo.lock
generated
|
@ -1146,11 +1146,10 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno"
|
||||
version = "2.0.0-rc.5"
|
||||
version = "2.0.0-rc.9"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"async-trait",
|
||||
"base32",
|
||||
"base64 0.21.7",
|
||||
"bincode",
|
||||
"bytes",
|
||||
|
@ -1174,6 +1173,8 @@ dependencies = [
|
|||
"deno_lockfile",
|
||||
"deno_npm",
|
||||
"deno_package_json",
|
||||
"deno_path_util",
|
||||
"deno_resolver",
|
||||
"deno_runtime",
|
||||
"deno_semver",
|
||||
"deno_task_shell",
|
||||
|
@ -1272,9 +1273,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_ast"
|
||||
version = "0.42.0"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b08d11d9e4086b00d3428650e31153cf5896586411763cb88a6423ce5b18791"
|
||||
checksum = "89ea2fd038c9c7e3e87e624fd708303cd33f39c33707f6c48fa9a65d65fefc47"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"deno_media_type",
|
||||
|
@ -1316,7 +1317,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_bench_util"
|
||||
version = "0.162.0"
|
||||
version = "0.163.0"
|
||||
dependencies = [
|
||||
"bencher",
|
||||
"deno_core",
|
||||
|
@ -1325,7 +1326,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_broadcast_channel"
|
||||
version = "0.162.0"
|
||||
version = "0.163.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"deno_core",
|
||||
|
@ -1335,7 +1336,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_cache"
|
||||
version = "0.100.0"
|
||||
version = "0.101.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"deno_core",
|
||||
|
@ -1347,11 +1348,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_cache_dir"
|
||||
version = "0.11.1"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6df43311cb7703fa3242c282823a850e4c8d0c06b9527d8209b55bd695452ea5"
|
||||
checksum = "186a102b13b4512841f5f40784cd25822042d22954afe3b5b070d406d15eb4f2"
|
||||
dependencies = [
|
||||
"base32",
|
||||
"deno_media_type",
|
||||
"deno_path_util",
|
||||
"indexmap",
|
||||
"log",
|
||||
"once_cell",
|
||||
|
@ -1365,7 +1368,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_canvas"
|
||||
version = "0.37.0"
|
||||
version = "0.38.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_webgpu",
|
||||
|
@ -1398,7 +1401,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_console"
|
||||
version = "0.168.0"
|
||||
version = "0.169.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
]
|
||||
|
@ -1443,7 +1446,7 @@ checksum = "a13951ea98c0a4c372f162d669193b4c9d991512de9f2381dd161027f34b26b1"
|
|||
|
||||
[[package]]
|
||||
name = "deno_cron"
|
||||
version = "0.48.0"
|
||||
version = "0.49.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -1455,7 +1458,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_crypto"
|
||||
version = "0.182.0"
|
||||
version = "0.183.0"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"aes-gcm",
|
||||
|
@ -1489,9 +1492,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_doc"
|
||||
version = "0.148.0"
|
||||
version = "0.150.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "144fa07977ba9eeeb98bcd267b7f0a6f8033f0f1f20fd210e669b3c4f30cefa2"
|
||||
checksum = "0841188bc852535b76e53be6c3d13c61cfc6751a731969b8959fe31fa696c73f"
|
||||
dependencies = [
|
||||
"ammonia",
|
||||
"anyhow",
|
||||
|
@ -1515,7 +1518,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_fetch"
|
||||
version = "0.192.0"
|
||||
version = "0.193.0"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
|
@ -1547,7 +1550,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_ffi"
|
||||
version = "0.155.0"
|
||||
version = "0.156.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_permissions",
|
||||
|
@ -1564,12 +1567,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_fs"
|
||||
version = "0.78.0"
|
||||
version = "0.79.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"base32",
|
||||
"deno_core",
|
||||
"deno_io",
|
||||
"deno_path_util",
|
||||
"deno_permissions",
|
||||
"filetime",
|
||||
"junction",
|
||||
|
@ -1584,9 +1588,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_graph"
|
||||
version = "0.82.1"
|
||||
version = "0.83.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78b63015c73aa203da206b5d35b4c1eaa23bc7fed37ab325da62d525a5524a04"
|
||||
checksum = "20088a4497b1a212482883dc7b0365e99f703d575fb512d4a793531cdc92ea76"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -1613,7 +1617,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_http"
|
||||
version = "0.166.0"
|
||||
version = "0.167.0"
|
||||
dependencies = [
|
||||
"async-compression",
|
||||
"async-trait",
|
||||
|
@ -1652,7 +1656,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_io"
|
||||
version = "0.78.0"
|
||||
version = "0.79.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"deno_core",
|
||||
|
@ -1673,7 +1677,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_kv"
|
||||
version = "0.76.0"
|
||||
version = "0.77.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -1682,6 +1686,7 @@ dependencies = [
|
|||
"chrono",
|
||||
"deno_core",
|
||||
"deno_fetch",
|
||||
"deno_path_util",
|
||||
"deno_permissions",
|
||||
"deno_tls",
|
||||
"denokv_proto",
|
||||
|
@ -1743,7 +1748,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_napi"
|
||||
version = "0.99.0"
|
||||
version = "0.100.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_permissions",
|
||||
|
@ -1765,7 +1770,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_net"
|
||||
version = "0.160.0"
|
||||
version = "0.161.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_permissions",
|
||||
|
@ -1781,7 +1786,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_node"
|
||||
version = "0.105.0"
|
||||
version = "0.106.0"
|
||||
dependencies = [
|
||||
"aead-gcm-stream",
|
||||
"aes",
|
||||
|
@ -1800,6 +1805,7 @@ dependencies = [
|
|||
"deno_media_type",
|
||||
"deno_net",
|
||||
"deno_package_json",
|
||||
"deno_path_util",
|
||||
"deno_permissions",
|
||||
"deno_whoami",
|
||||
"der",
|
||||
|
@ -1916,11 +1922,23 @@ dependencies = [
|
|||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deno_path_util"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4889646c1ce8437a6fde3acb057fd7e2d039e62c61f5063fc125ed1ede114dc6"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
"thiserror",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deno_permissions"
|
||||
version = "0.28.0"
|
||||
version = "0.29.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_path_util",
|
||||
"deno_terminal 0.2.0",
|
||||
"fqdn",
|
||||
"libc",
|
||||
|
@ -1932,9 +1950,24 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deno_resolver"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base32",
|
||||
"deno_media_type",
|
||||
"deno_package_json",
|
||||
"deno_path_util",
|
||||
"deno_semver",
|
||||
"node_resolver",
|
||||
"test_server",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deno_runtime"
|
||||
version = "0.177.0"
|
||||
version = "0.178.0"
|
||||
dependencies = [
|
||||
"deno_ast",
|
||||
"deno_broadcast_channel",
|
||||
|
@ -1953,6 +1986,7 @@ dependencies = [
|
|||
"deno_napi",
|
||||
"deno_net",
|
||||
"deno_node",
|
||||
"deno_path_util",
|
||||
"deno_permissions",
|
||||
"deno_terminal 0.2.0",
|
||||
"deno_tls",
|
||||
|
@ -1985,6 +2019,7 @@ dependencies = [
|
|||
"serde",
|
||||
"signal-hook",
|
||||
"signal-hook-registry",
|
||||
"tempfile",
|
||||
"test_server",
|
||||
"tokio",
|
||||
"tokio-metrics",
|
||||
|
@ -1997,9 +2032,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_semver"
|
||||
version = "0.5.13"
|
||||
version = "0.5.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6657fecb9ac6a7a71f552c95e8cc492466a75f5660224577e2226bcf30db9768"
|
||||
checksum = "670fec7ef309384e23c2a90ac5d2d9d91a776d225306c75f5cdd28cf6cc8a59f"
|
||||
dependencies = [
|
||||
"monch",
|
||||
"once_cell",
|
||||
|
@ -2047,7 +2082,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_tls"
|
||||
version = "0.155.0"
|
||||
version = "0.156.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_native_certs",
|
||||
|
@ -2095,7 +2130,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_url"
|
||||
version = "0.168.0"
|
||||
version = "0.169.0"
|
||||
dependencies = [
|
||||
"deno_bench_util",
|
||||
"deno_console",
|
||||
|
@ -2106,7 +2141,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_web"
|
||||
version = "0.199.0"
|
||||
version = "0.200.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"base64-simd 0.8.0",
|
||||
|
@ -2127,7 +2162,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_webgpu"
|
||||
version = "0.135.0"
|
||||
version = "0.136.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"raw-window-handle",
|
||||
|
@ -2139,7 +2174,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_webidl"
|
||||
version = "0.168.0"
|
||||
version = "0.169.0"
|
||||
dependencies = [
|
||||
"deno_bench_util",
|
||||
"deno_core",
|
||||
|
@ -2147,7 +2182,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_websocket"
|
||||
version = "0.173.0"
|
||||
version = "0.174.0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"deno_core",
|
||||
|
@ -2168,7 +2203,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_webstorage"
|
||||
version = "0.163.0"
|
||||
version = "0.164.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_web",
|
||||
|
@ -2797,9 +2832,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",
|
||||
|
@ -4071,70 +4106,6 @@ version = "1.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "lexical-core"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cde5de06e8d4c2faabc400238f9ae1c74d5412d03a7bd067645ccbc47070e46"
|
||||
dependencies = [
|
||||
"lexical-parse-float",
|
||||
"lexical-parse-integer",
|
||||
"lexical-util",
|
||||
"lexical-write-float",
|
||||
"lexical-write-integer",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lexical-parse-float"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683b3a5ebd0130b8fb52ba0bdc718cc56815b6a097e28ae5a6997d0ad17dc05f"
|
||||
dependencies = [
|
||||
"lexical-parse-integer",
|
||||
"lexical-util",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lexical-parse-integer"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d0994485ed0c312f6d965766754ea177d07f9c00c9b82a5ee62ed5b47945ee9"
|
||||
dependencies = [
|
||||
"lexical-util",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lexical-util"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5255b9ff16ff898710eb9eb63cb39248ea8a5bb036bea8085b1a767ff6c4e3fc"
|
||||
dependencies = [
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lexical-write-float"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accabaa1c4581f05a3923d1b4cfd124c329352288b7b9da09e766b0668116862"
|
||||
dependencies = [
|
||||
"lexical-util",
|
||||
"lexical-write-integer",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lexical-write-integer"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1b6f3d1f4422866b68192d62f77bc5c700bee84f3069f2469d7bc8c77852446"
|
||||
dependencies = [
|
||||
"lexical-util",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.153"
|
||||
|
@ -4209,9 +4180,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libsui"
|
||||
version = "0.3.1"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56e39af24eff8df7c8b9980ef56a1a1f4d2e77b34b2d5c0529f108c53ae96a7a"
|
||||
checksum = "205eca4e7beaad637dcd38fe41292065894ee7f498077cf3c135d5f7252b9f27"
|
||||
dependencies = [
|
||||
"editpe",
|
||||
"libc",
|
||||
|
@ -4342,9 +4313,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "markup_fmt"
|
||||
version = "0.13.0"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74fc137a4a591720176339bf7e857586a48ff35c0caee7ad6cf709327901232c"
|
||||
checksum = "9dab5ae899659fbe5c8835b2c8ca8d3e357974a3e454138925b404004973361f"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"css_dataset",
|
||||
|
@ -4517,7 +4488,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "napi_sym"
|
||||
version = "0.98.0"
|
||||
version = "0.99.0"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"serde",
|
||||
|
@ -4586,12 +4557,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "node_resolver"
|
||||
version = "0.7.0"
|
||||
version = "0.8.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"deno_media_type",
|
||||
"deno_package_json",
|
||||
"deno_path_util",
|
||||
"futures",
|
||||
"lazy-regex",
|
||||
"once_cell",
|
||||
|
@ -6386,13 +6358,12 @@ checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
|||
|
||||
[[package]]
|
||||
name = "simd-json"
|
||||
version = "0.13.9"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0b84c23a1066e1d650ebc99aa8fb9f8ed0ab96fd36e2e836173c92fc9fb29bc"
|
||||
checksum = "05f0b376aada35f30a0012f5790e50aed62f91804a0682669aefdbe81c7fcb91"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"halfbrown",
|
||||
"lexical-core",
|
||||
"ref-cast",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -7947,9 +7918,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "value-trait"
|
||||
version = "0.8.1"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dad8db98c1e677797df21ba03fca7d3bf9bec3ca38db930954e4fe6e1ea27eb4"
|
||||
checksum = "bcaa56177466248ba59d693a048c0959ddb67f1151b963f904306312548cf392"
|
||||
dependencies = [
|
||||
"float-cmp",
|
||||
"halfbrown",
|
||||
|
@ -8119,9 +8090,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "webpki-root-certs"
|
||||
version = "0.26.5"
|
||||
version = "0.26.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6d93b773107ba49bc84dd3b241e019c702d886fd5c457defe2ea8b1123a5dcd"
|
||||
checksum = "e8c6dfa3ac045bc517de14c7b1384298de1dbd229d38e08e169d9ae8c170937c"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
|
71
Cargo.toml
71
Cargo.toml
|
@ -21,13 +21,14 @@ members = [
|
|||
"ext/napi",
|
||||
"ext/net",
|
||||
"ext/node",
|
||||
"ext/node_resolver",
|
||||
"ext/url",
|
||||
"ext/web",
|
||||
"ext/webgpu",
|
||||
"ext/webidl",
|
||||
"ext/websocket",
|
||||
"ext/webstorage",
|
||||
"resolvers/deno",
|
||||
"resolvers/node",
|
||||
"runtime",
|
||||
"runtime/permissions",
|
||||
"tests",
|
||||
|
@ -44,17 +45,19 @@ license = "MIT"
|
|||
repository = "https://github.com/denoland/deno"
|
||||
|
||||
[workspace.dependencies]
|
||||
deno_ast = { version = "=0.42.0", features = ["transpiling"] }
|
||||
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.163.0", path = "./bench_util" }
|
||||
deno_lockfile = "=0.23.1"
|
||||
deno_media_type = { version = "0.1.4", features = ["module_specifier"] }
|
||||
deno_permissions = { version = "0.28.0", path = "./runtime/permissions" }
|
||||
deno_runtime = { version = "0.177.0", path = "./runtime" }
|
||||
deno_semver = "=0.5.13"
|
||||
deno_npm = "=0.25.2"
|
||||
deno_path_util = "=0.2.0"
|
||||
deno_permissions = { version = "0.29.0", path = "./runtime/permissions" }
|
||||
deno_runtime = { version = "0.178.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.99.0", path = "./cli/napi/sym" }
|
||||
test_util = { package = "test_server", path = "./tests/util/server" }
|
||||
|
||||
denokv_proto = "0.8.1"
|
||||
|
@ -63,29 +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" }
|
||||
node_resolver = { version = "0.7.0", path = "./ext/node_resolver" }
|
||||
deno_broadcast_channel = { version = "0.163.0", path = "./ext/broadcast_channel" }
|
||||
deno_cache = { version = "0.101.0", path = "./ext/cache" }
|
||||
deno_canvas = { version = "0.38.0", path = "./ext/canvas" }
|
||||
deno_console = { version = "0.169.0", path = "./ext/console" }
|
||||
deno_cron = { version = "0.49.0", path = "./ext/cron" }
|
||||
deno_crypto = { version = "0.183.0", path = "./ext/crypto" }
|
||||
deno_fetch = { version = "0.193.0", path = "./ext/fetch" }
|
||||
deno_ffi = { version = "0.156.0", path = "./ext/ffi" }
|
||||
deno_fs = { version = "0.79.0", path = "./ext/fs" }
|
||||
deno_http = { version = "0.167.0", path = "./ext/http" }
|
||||
deno_io = { version = "0.79.0", path = "./ext/io" }
|
||||
deno_kv = { version = "0.77.0", path = "./ext/kv" }
|
||||
deno_napi = { version = "0.100.0", path = "./ext/napi" }
|
||||
deno_net = { version = "0.161.0", path = "./ext/net" }
|
||||
deno_node = { version = "0.106.0", path = "./ext/node" }
|
||||
deno_tls = { version = "0.156.0", path = "./ext/tls" }
|
||||
deno_url = { version = "0.169.0", path = "./ext/url" }
|
||||
deno_web = { version = "0.200.0", path = "./ext/web" }
|
||||
deno_webgpu = { version = "0.136.0", path = "./ext/webgpu" }
|
||||
deno_webidl = { version = "0.169.0", path = "./ext/webidl" }
|
||||
deno_websocket = { version = "0.174.0", path = "./ext/websocket" }
|
||||
deno_webstorage = { version = "0.164.0", path = "./ext/webstorage" }
|
||||
|
||||
# resolvers
|
||||
deno_resolver = { version = "0.1.0", path = "./resolvers/deno" }
|
||||
node_resolver = { version = "0.8.0", path = "./resolvers/node" }
|
||||
|
||||
aes = "=0.8.3"
|
||||
anyhow = "1.0.57"
|
||||
|
@ -101,10 +107,11 @@ cbc = { version = "=0.1.2", features = ["alloc"] }
|
|||
# Instead use util::time::utc_now()
|
||||
chrono = { version = "0.4", default-features = false, features = ["std", "serde"] }
|
||||
console_static_text = "=0.8.1"
|
||||
dashmap = "5.5.3"
|
||||
data-encoding = "2.3.3"
|
||||
data-url = "=0.3.0"
|
||||
deno_cache_dir = "=0.11.1"
|
||||
deno_package_json = { version = "=0.1.1", default-features = false }
|
||||
deno_cache_dir = "=0.13.0"
|
||||
deno_package_json = { version = "0.1.1", default-features = false }
|
||||
dlopen2 = "0.6.1"
|
||||
ecb = "=0.1.2"
|
||||
elliptic-curve = { version = "0.13.4", features = ["alloc", "arithmetic", "ecdh", "std", "pem", "jwk"] }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_bench_util"
|
||||
version = "0.162.0"
|
||||
version = "0.163.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno"
|
||||
version = "2.0.0-rc.5"
|
||||
version = "2.0.0-rc.9"
|
||||
authors.workspace = true
|
||||
default-run = "deno"
|
||||
edition.workspace = true
|
||||
|
@ -67,24 +67,25 @@ deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "proposa
|
|||
deno_cache_dir = { workspace = true }
|
||||
deno_config = { version = "=0.35.0", features = ["workspace", "sync"] }
|
||||
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] }
|
||||
deno_doc = { version = "0.148.0", features = ["html", "syntect"] }
|
||||
deno_graph = { version = "=0.82.1" }
|
||||
deno_doc = { version = "0.150.1", features = ["html", "syntect"] }
|
||||
deno_graph = { version = "=0.83.0" }
|
||||
deno_lint = { version = "=0.67.0", features = ["docs"] }
|
||||
deno_lockfile.workspace = true
|
||||
deno_npm = "=0.25.2"
|
||||
deno_npm.workspace = true
|
||||
deno_package_json.workspace = true
|
||||
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_terminal.workspace = true
|
||||
eszip = "=0.78.0"
|
||||
libsui = "0.3.1"
|
||||
eszip = "=0.79.1"
|
||||
libsui = "0.4.0"
|
||||
napi_sym.workspace = true
|
||||
node_resolver.workspace = true
|
||||
|
||||
anstream = "0.6.14"
|
||||
async-trait.workspace = true
|
||||
base32.workspace = true
|
||||
base64.workspace = true
|
||||
bincode = "=1.3.3"
|
||||
bytes.workspace = true
|
||||
|
@ -95,7 +96,7 @@ clap_complete = "=4.5.24"
|
|||
clap_complete_fig = "=4.5.2"
|
||||
color-print = "0.3.5"
|
||||
console_static_text.workspace = true
|
||||
dashmap = "5.5.3"
|
||||
dashmap.workspace = true
|
||||
data-encoding.workspace = true
|
||||
dissimilar = "=1.0.4"
|
||||
dotenvy = "0.15.7"
|
||||
|
@ -124,7 +125,7 @@ libz-sys.workspace = true
|
|||
log = { workspace = true, features = ["serde"] }
|
||||
lsp-types.workspace = true
|
||||
malva = "=0.10.1"
|
||||
markup_fmt = "=0.13.0"
|
||||
markup_fmt = "=0.13.1"
|
||||
memmem.workspace = true
|
||||
monch.workspace = true
|
||||
notify.workspace = true
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
|
@ -28,13 +29,13 @@ use deno_config::glob::PathOrPatternSet;
|
|||
use deno_core::anyhow::bail;
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::normalize_path;
|
||||
use deno_core::resolve_url_or_path;
|
||||
use deno_core::url::Url;
|
||||
use deno_graph::GraphKind;
|
||||
use deno_runtime::deno_permissions::parse_sys_kind;
|
||||
use deno_path_util::normalize_path;
|
||||
use deno_path_util::url_to_file_path;
|
||||
use deno_runtime::deno_permissions::PermissionsOptions;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
use deno_runtime::deno_permissions::SysDescriptor;
|
||||
use log::debug;
|
||||
use log::Level;
|
||||
use serde::Deserialize;
|
||||
|
@ -44,6 +45,7 @@ use crate::args::resolve_no_prompt;
|
|||
use crate::util::fs::canonicalize_path;
|
||||
|
||||
use super::flags_net;
|
||||
use super::jsr_url;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub enum ConfigFlag {
|
||||
|
@ -546,6 +548,8 @@ pub struct LifecycleScriptsConfig {
|
|||
pub allowed: PackagesAllowedScripts,
|
||||
pub initial_cwd: PathBuf,
|
||||
pub root_dir: PathBuf,
|
||||
/// Part of an explicit `deno install`
|
||||
pub explicit_install: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default)]
|
||||
|
@ -639,6 +643,7 @@ pub struct PermissionFlags {
|
|||
pub allow_write: Option<Vec<String>>,
|
||||
pub deny_write: Option<Vec<String>>,
|
||||
pub no_prompt: bool,
|
||||
pub allow_import: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
impl PermissionFlags {
|
||||
|
@ -658,9 +663,10 @@ impl PermissionFlags {
|
|||
|| self.deny_sys.is_some()
|
||||
|| self.allow_write.is_some()
|
||||
|| self.deny_write.is_some()
|
||||
|| self.allow_import.is_some()
|
||||
}
|
||||
|
||||
pub fn to_options(&self) -> PermissionsOptions {
|
||||
pub fn to_options(&self, cli_arg_urls: &[Cow<Url>]) -> PermissionsOptions {
|
||||
fn handle_allow<T: Default>(
|
||||
allow_all: bool,
|
||||
value: Option<T>,
|
||||
|
@ -673,6 +679,41 @@ impl PermissionFlags {
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_imports(
|
||||
cli_arg_urls: &[Cow<Url>],
|
||||
imports: Option<Vec<String>>,
|
||||
) -> Option<Vec<String>> {
|
||||
if imports.is_some() {
|
||||
return imports;
|
||||
}
|
||||
|
||||
let builtin_allowed_import_hosts = [
|
||||
"deno.land:443",
|
||||
"esm.sh:443",
|
||||
"jsr.io:443",
|
||||
"raw.githubusercontent.com:443",
|
||||
"gist.githubusercontent.com:443",
|
||||
];
|
||||
|
||||
let mut imports =
|
||||
Vec::with_capacity(builtin_allowed_import_hosts.len() + 1);
|
||||
imports
|
||||
.extend(builtin_allowed_import_hosts.iter().map(|s| s.to_string()));
|
||||
|
||||
// also add the JSR_URL env var
|
||||
if let Some(jsr_host) = allow_import_host_from_url(jsr_url()) {
|
||||
imports.push(jsr_host);
|
||||
}
|
||||
// include the cli arg urls
|
||||
for url in cli_arg_urls {
|
||||
if let Some(host) = allow_import_host_from_url(url) {
|
||||
imports.push(host);
|
||||
}
|
||||
}
|
||||
|
||||
Some(imports)
|
||||
}
|
||||
|
||||
PermissionsOptions {
|
||||
allow_all: self.allow_all,
|
||||
allow_env: handle_allow(self.allow_all, self.allow_env.clone()),
|
||||
|
@ -689,11 +730,33 @@ impl PermissionFlags {
|
|||
deny_sys: self.deny_sys.clone(),
|
||||
allow_write: handle_allow(self.allow_all, self.allow_write.clone()),
|
||||
deny_write: self.deny_write.clone(),
|
||||
allow_import: handle_imports(
|
||||
cli_arg_urls,
|
||||
handle_allow(self.allow_all, self.allow_import.clone()),
|
||||
),
|
||||
prompt: !resolve_no_prompt(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the --allow-import host from the provided url
|
||||
fn allow_import_host_from_url(url: &Url) -> Option<String> {
|
||||
let host = url.host()?;
|
||||
if let Some(port) = url.port() {
|
||||
Some(format!("{}:{}", host, port))
|
||||
} else {
|
||||
use deno_core::url::Host::*;
|
||||
match host {
|
||||
Domain(domain) if domain == "jsr.io" && url.scheme() == "https" => None,
|
||||
_ => match url.scheme() {
|
||||
"https" => Some(format!("{}:443", host)),
|
||||
"http" => Some(format!("{}:80", host)),
|
||||
_ => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn join_paths(allowlist: &[String], d: &str) -> String {
|
||||
allowlist
|
||||
.iter()
|
||||
|
@ -881,6 +944,17 @@ impl Flags {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
match &self.permissions.allow_import {
|
||||
Some(allowlist) if allowlist.is_empty() => {
|
||||
args.push("--allow-import".to_string());
|
||||
}
|
||||
Some(allowlist) => {
|
||||
let s = format!("--allow-import={}", allowlist.join(","));
|
||||
args.push(s);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
args
|
||||
}
|
||||
|
||||
|
@ -928,7 +1002,7 @@ impl Flags {
|
|||
if module_specifier.scheme() == "file"
|
||||
|| module_specifier.scheme() == "npm"
|
||||
{
|
||||
if let Ok(p) = specifier_to_file_path(&module_specifier) {
|
||||
if let Ok(p) = url_to_file_path(&module_specifier) {
|
||||
Some(vec![p.parent().unwrap().to_path_buf()])
|
||||
} else {
|
||||
Some(vec![current_dir.to_path_buf()])
|
||||
|
@ -991,6 +1065,7 @@ impl Flags {
|
|||
self.permissions.allow_write = None;
|
||||
self.permissions.allow_sys = None;
|
||||
self.permissions.allow_ffi = None;
|
||||
self.permissions.allow_import = None;
|
||||
}
|
||||
|
||||
pub fn resolve_watch_exclude_set(
|
||||
|
@ -1101,7 +1176,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
|
||||
|
@ -1183,28 +1257,7 @@ pub fn flags_from_vec(args: Vec<OsString>) -> clap::error::Result<Flags> {
|
|||
.get_arguments()
|
||||
.any(|arg| arg.get_id().as_str() == "unstable")
|
||||
{
|
||||
subcommand = subcommand
|
||||
.mut_arg("unstable", |arg| {
|
||||
let new_help = arg
|
||||
.get_help()
|
||||
.unwrap()
|
||||
.to_string()
|
||||
.split_once("\n")
|
||||
.unwrap()
|
||||
.0
|
||||
.to_string();
|
||||
arg.help_heading(UNSTABLE_HEADING).help(new_help)
|
||||
})
|
||||
.mut_args(|arg| {
|
||||
// long_help here is being used as a metadata, see unstable args definition
|
||||
if arg.get_help_heading() == Some(UNSTABLE_HEADING)
|
||||
&& arg.get_long_help().is_some()
|
||||
{
|
||||
arg.hide(false)
|
||||
} else {
|
||||
arg
|
||||
}
|
||||
});
|
||||
subcommand = enable_unstable(subcommand);
|
||||
}
|
||||
|
||||
help_parse(&mut flags, subcommand);
|
||||
|
@ -1339,6 +1392,31 @@ pub fn flags_from_vec(args: Vec<OsString>) -> clap::error::Result<Flags> {
|
|||
Ok(flags)
|
||||
}
|
||||
|
||||
fn enable_unstable(command: Command) -> Command {
|
||||
command
|
||||
.mut_arg("unstable", |arg| {
|
||||
let new_help = arg
|
||||
.get_help()
|
||||
.unwrap()
|
||||
.to_string()
|
||||
.split_once("\n")
|
||||
.unwrap()
|
||||
.0
|
||||
.to_string();
|
||||
arg.help_heading(UNSTABLE_HEADING).help(new_help)
|
||||
})
|
||||
.mut_args(|arg| {
|
||||
// long_help here is being used as a metadata, see unstable args definition
|
||||
if arg.get_help_heading() == Some(UNSTABLE_HEADING)
|
||||
&& arg.get_long_help().is_some()
|
||||
{
|
||||
arg.hide(false)
|
||||
} else {
|
||||
arg
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! heading {
|
||||
($($name:ident = $title:expr),+; $total:literal) => {
|
||||
$(const $name: &str = $title;)+
|
||||
|
@ -1707,6 +1785,7 @@ Future runs of this module will trigger no downloads or compilation unless --rel
|
|||
)
|
||||
.arg(frozen_lockfile_arg())
|
||||
.arg(allow_scripts_arg())
|
||||
.arg(allow_import_arg())
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1766,6 +1845,7 @@ Unless --reload is specified, this command will not re-download already cached d
|
|||
.required_unless_present("help")
|
||||
.value_hint(ValueHint::FilePath),
|
||||
)
|
||||
.arg(allow_import_arg())
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -1775,11 +1855,15 @@ fn compile_subcommand() -> Command {
|
|||
"compile",
|
||||
cstr!("Compiles the given script into a self contained executable.
|
||||
|
||||
<p(245)>deno compile -A jsr:@std/http/file-server</>
|
||||
<p(245)>deno compile --allow-read --allow-net jsr:@std/http/file-server</>
|
||||
<p(245)>deno compile --output file_server jsr:@std/http/file-server</>
|
||||
|
||||
Any flags specified which affect runtime behavior will be applied to the resulting binary.
|
||||
|
||||
This allows distribution of a Deno application to systems that do not have Deno installed.
|
||||
Under the hood, it bundles a slimmed down version of the Deno runtime along with your
|
||||
JavaScript or TypeScript code.
|
||||
|
||||
Cross-compiling to different target architectures is supported using the <c>--target</> flag.
|
||||
On the first invocation with deno will download the proper binary and cache it in <c>$DENO_DIR</>.
|
||||
|
||||
|
@ -1994,6 +2078,7 @@ Show documentation for runtime built-ins:
|
|||
.arg(no_lock_arg())
|
||||
.arg(no_npm_arg())
|
||||
.arg(no_remote_arg())
|
||||
.arg(allow_import_arg())
|
||||
.arg(
|
||||
Arg::new("json")
|
||||
.long("json")
|
||||
|
@ -2145,6 +2230,9 @@ Supported file types which are behind corresponding unstable flags (see formatti
|
|||
Format stdin and write to stdout:
|
||||
<p(245)>cat file.ts | deno fmt -</>
|
||||
|
||||
Check if the files are formatted:
|
||||
<p(245)>deno fmt --check</>
|
||||
|
||||
Ignore formatting code by preceding it with an ignore comment:
|
||||
<p(245)>// deno-fmt-ignore</>
|
||||
|
||||
|
@ -2295,7 +2383,7 @@ Ignore formatting a file by adding an ignore comment at the top of the file:
|
|||
}
|
||||
|
||||
fn init_subcommand() -> Command {
|
||||
command("init", "Initialize a new project", UnstableArgsConfig::None).defer(
|
||||
command("init", "scaffolds a basic Deno project with a script, test, and configuration file", UnstableArgsConfig::None).defer(
|
||||
|cmd| {
|
||||
cmd
|
||||
.arg(Arg::new("dir").value_hint(ValueHint::DirPath))
|
||||
|
@ -2340,7 +2428,7 @@ The following information is shown:
|
|||
.arg(
|
||||
location_arg()
|
||||
.conflicts_with("file")
|
||||
.help("Show files used for origin bound APIs like the Web Storage API when running a script with '--location=<HREF>'")
|
||||
.help(cstr!("Show files used for origin bound APIs like the Web Storage API when running a script with <c>--location=<<HREF>></>"))
|
||||
)
|
||||
.arg(no_check_arg().hide(true)) // TODO(lucacasonato): remove for 2.0
|
||||
.arg(no_config_arg())
|
||||
|
@ -2358,6 +2446,7 @@ The following information is shown:
|
|||
.help("UNSTABLE: Outputs the information in JSON format")
|
||||
.action(ArgAction::SetTrue),
|
||||
))
|
||||
.arg(allow_import_arg())
|
||||
}
|
||||
|
||||
fn install_subcommand() -> Command {
|
||||
|
@ -2381,7 +2470,7 @@ If the <bold>--global</> flag is set, installs a script as an executable in the
|
|||
<p(245)>deno install --global --allow-net --allow-read jsr:@std/http/file-server</>
|
||||
<p(245)>deno install -g https://examples.deno.land/color-logging.ts</>
|
||||
|
||||
To change the executable name, use -n/--name:
|
||||
To change the executable name, use <c>-n</>/<c>--name</>:
|
||||
<p(245)>deno install -g --allow-net --allow-read -n serve jsr:@std/http/file-server</>
|
||||
|
||||
The executable name is inferred by default:
|
||||
|
@ -2663,7 +2752,12 @@ To ignore linting on an entire file, you can add an ignore comment at the top of
|
|||
}
|
||||
|
||||
fn repl_subcommand() -> Command {
|
||||
command("repl", "Read Eval Print Loop", UnstableArgsConfig::ResolutionAndRuntime)
|
||||
command("repl", cstr!(
|
||||
"Starts a read-eval-print-loop, which lets you interactively build up program state in the global context.
|
||||
It is especially useful for quick prototyping and checking snippets of code.
|
||||
|
||||
TypeScript is supported, however it is not type-checked, only transpiled."
|
||||
), UnstableArgsConfig::ResolutionAndRuntime)
|
||||
.defer(|cmd| runtime_args(cmd, true, true)
|
||||
.arg(check_arg(false))
|
||||
.arg(
|
||||
|
@ -2746,8 +2840,6 @@ fn serve_subcommand() -> Command {
|
|||
|
||||
The serve command uses the default exports of the main module to determine which servers to start.
|
||||
|
||||
See https://docs.deno.com/runtime/manual/tools/serve for more detailed information.
|
||||
|
||||
Start a server defined in server.ts:
|
||||
<p(245)>deno serve server.ts</>
|
||||
|
||||
|
@ -2758,7 +2850,7 @@ Start a server defined in server.ts, watching for changes and running on port 50
|
|||
.arg(
|
||||
Arg::new("port")
|
||||
.long("port")
|
||||
.help("The TCP port to serve on, defaulting to 8000. Pass 0 to pick a random free port")
|
||||
.help(cstr!("The TCP port to serve on. Pass 0 to pick a random free port <p(245)>[default: 8000]</>"))
|
||||
.value_parser(value_parser!(u16)),
|
||||
)
|
||||
.arg(
|
||||
|
@ -2968,11 +3060,13 @@ fn parallel_arg(descr: &str) -> Arg {
|
|||
fn types_subcommand() -> Command {
|
||||
command(
|
||||
"types",
|
||||
"Print runtime TypeScript declarations.
|
||||
cstr!(
|
||||
"Print runtime TypeScript declarations.
|
||||
|
||||
<p(245)>deno types > lib.deno.d.ts</>
|
||||
|
||||
The declaration file could be saved and used for typing information.",
|
||||
The declaration file could be saved and used for typing information."
|
||||
),
|
||||
UnstableArgsConfig::None,
|
||||
)
|
||||
}
|
||||
|
@ -3082,7 +3176,7 @@ See the Deno 1.x to 2.x Migration Guide for migration instructions: https://docs
|
|||
}
|
||||
|
||||
fn publish_subcommand() -> Command {
|
||||
command("publish", "Publish the current working directory's package or workspace", UnstableArgsConfig::ResolutionOnly)
|
||||
command("publish", "Publish the current working directory's package or workspace to JSR", UnstableArgsConfig::ResolutionOnly)
|
||||
.defer(|cmd| {
|
||||
cmd
|
||||
.arg(
|
||||
|
@ -3151,47 +3245,44 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
|
|||
.after_help(cstr!(r#"<y>Permission options:</>
|
||||
<y>Docs</>: <c>https://docs.deno.com/go/permissions</>
|
||||
|
||||
<g>-A, --allow-all</> Allow all permissions.
|
||||
<g>--no-prompt</> Always throw if required permission wasn't passed.
|
||||
<p(245)>Can also be set via the DENO_NO_PROMPT environment variable.</>
|
||||
<g>-R, --allow-read[=<<PATH>...]</> Allow file system read access. Optionally specify allowed paths.
|
||||
<p(245)>--allow-read | --allow-read="/etc,/var/log.txt"</>
|
||||
<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>-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"</>
|
||||
<g>-E, --allow-env[=<<VARIABLE_NAME>...]</> Allow access to environment variables. Optionally specify accessible environment variables.
|
||||
<p(245)>--allow-env | --allow-env="PORT,HOME,PATH"</>
|
||||
<g>-S, --allow-sys[=<<API_NAME>...]</> Allow access to OS information. Optionally allow specific APIs by function name.
|
||||
<p(245)>--allow-sys | --allow-sys="systemMemoryInfo,osRelease"</>
|
||||
<g>--allow-run[=<<PROGRAM_NAME>...]</> Allow running subprocesses. Optionally specify allowed runnable program names.
|
||||
<p(245)>--allow-run | --allow-run="whoami,ps"</>
|
||||
<g>--allow-ffi[=<<PATH>...]</> (Unstable) Allow loading dynamic libraries. Optionally specify allowed directories or files.
|
||||
<p(245)>--allow-ffi | --allow-ffi="./libfoo.so"</>
|
||||
<g> --deny-read[=<<PATH>...]</> Deny file system read access. Optionally specify denied paths.
|
||||
<p(245)>--deny-read | --deny-read="/etc,/var/log.txt"</>
|
||||
<g> --deny-write[=<<PATH>...]</> Deny file system write access. Optionally specify denied paths.
|
||||
<p(245)>--deny-write | --deny-write="/etc,/var/log.txt"</>
|
||||
<g> --deny-net[=<<IP_OR_HOSTNAME>...]</> Deny network access. Optionally specify defined IP addresses and host names, with ports as necessary.
|
||||
<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.
|
||||
<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"</>
|
||||
<g>--deny-ffi[=<<PATH>...]</> (Unstable) Deny loading dynamic libraries. Optionally specify denied directories or files.
|
||||
<p(245)>--deny-ffi | --deny-ffi="./libfoo.so"</>
|
||||
<g>-A, --allow-all</> Allow all permissions.
|
||||
<g>--no-prompt</> Always throw if required permission wasn't passed.
|
||||
<p(245)>Can also be set via the DENO_NO_PROMPT environment variable.</>
|
||||
<g>-R, --allow-read[=<<PATH>...]</> Allow file system read access. Optionally specify allowed paths.
|
||||
<p(245)>--allow-read | --allow-read="/etc,/var/log.txt"</>
|
||||
<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</>
|
||||
<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"</>
|
||||
<g>-E, --allow-env[=<<VARIABLE_NAME>...]</> Allow access to environment variables. Optionally specify accessible environment variables.
|
||||
<p(245)>--allow-env | --allow-env="PORT,HOME,PATH"</>
|
||||
<g>-S, --allow-sys[=<<API_NAME>...]</> Allow access to OS information. Optionally allow specific APIs by function name.
|
||||
<p(245)>--allow-sys | --allow-sys="systemMemoryInfo,osRelease"</>
|
||||
<g>--allow-run[=<<PROGRAM_NAME>...]</> Allow running subprocesses. Optionally specify allowed runnable program names.
|
||||
<p(245)>--allow-run | --allow-run="whoami,ps"</>
|
||||
<g>--allow-ffi[=<<PATH>...]</> (Unstable) Allow loading dynamic libraries. Optionally specify allowed directories or files.
|
||||
<p(245)>--allow-ffi | --allow-ffi="./libfoo.so"</>
|
||||
<g> --deny-read[=<<PATH>...]</> Deny file system read access. Optionally specify denied paths.
|
||||
<p(245)>--deny-read | --deny-read="/etc,/var/log.txt"</>
|
||||
<g> --deny-write[=<<PATH>...]</> Deny file system write access. Optionally specify denied paths.
|
||||
<p(245)>--deny-write | --deny-write="/etc,/var/log.txt"</>
|
||||
<g> --deny-net[=<<IP_OR_HOSTNAME>...]</> Deny network access. Optionally specify defined IP addresses and host names, with ports as necessary.
|
||||
<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> --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"</>
|
||||
<g>--deny-ffi[=<<PATH>...]</> (Unstable) Deny loading dynamic libraries. Optionally specify denied directories or files.
|
||||
<p(245)>--deny-ffi | --deny-ffi="./libfoo.so"</>
|
||||
"#))
|
||||
.arg(
|
||||
{
|
||||
let mut arg = Arg::new("allow-all")
|
||||
.short('A')
|
||||
.long("allow-all")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Allow all permissions")
|
||||
.hide(true)
|
||||
;
|
||||
let mut arg = allow_all_arg().hide(true);
|
||||
if let Some(requires) = requires {
|
||||
arg = arg.requires(requires)
|
||||
}
|
||||
|
@ -3200,7 +3291,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
|
|||
)
|
||||
.arg(
|
||||
{
|
||||
let mut arg = Arg::new("allow-read")
|
||||
let mut arg = Arg::new("allow-read")
|
||||
.long("allow-read")
|
||||
.short('R')
|
||||
.num_args(0..)
|
||||
|
@ -3218,7 +3309,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
|
|||
)
|
||||
.arg(
|
||||
{
|
||||
let mut arg = Arg::new("deny-read")
|
||||
let mut arg = Arg::new("deny-read")
|
||||
.long("deny-read")
|
||||
.num_args(0..)
|
||||
.action(ArgAction::Append)
|
||||
|
@ -3235,7 +3326,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
|
|||
)
|
||||
.arg(
|
||||
{
|
||||
let mut arg = Arg::new("allow-write")
|
||||
let mut arg = Arg::new("allow-write")
|
||||
.long("allow-write")
|
||||
.short('W')
|
||||
.num_args(0..)
|
||||
|
@ -3253,7 +3344,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
|
|||
)
|
||||
.arg(
|
||||
{
|
||||
let mut arg = Arg::new("deny-write")
|
||||
let mut arg = Arg::new("deny-write")
|
||||
.long("deny-write")
|
||||
.num_args(0..)
|
||||
.action(ArgAction::Append)
|
||||
|
@ -3270,7 +3361,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
|
|||
)
|
||||
.arg(
|
||||
{
|
||||
let mut arg = Arg::new("allow-net")
|
||||
let mut arg = Arg::new("allow-net")
|
||||
.long("allow-net")
|
||||
.short('N')
|
||||
.num_args(0..)
|
||||
|
@ -3289,7 +3380,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
|
|||
)
|
||||
.arg(
|
||||
{
|
||||
let mut arg = Arg::new("deny-net")
|
||||
let mut arg = Arg::new("deny-net")
|
||||
.long("deny-net")
|
||||
.num_args(0..)
|
||||
.use_value_delimiter(true)
|
||||
|
@ -3372,7 +3463,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
|
|||
.require_equals(true)
|
||||
.value_name("API_NAME")
|
||||
.help("Allow access to OS information. Optionally allow specific APIs by function name")
|
||||
.value_parser(|key: &str| parse_sys_kind(key).map(ToString::to_string))
|
||||
.value_parser(|key: &str| SysDescriptor::parse(key.to_string()).map(|s| s.into_string()))
|
||||
.hide(true)
|
||||
;
|
||||
if let Some(requires) = requires {
|
||||
|
@ -3383,14 +3474,14 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
|
|||
)
|
||||
.arg(
|
||||
{
|
||||
let mut arg = Arg::new("deny-sys")
|
||||
let mut arg = Arg::new("deny-sys")
|
||||
.long("deny-sys")
|
||||
.num_args(0..)
|
||||
.use_value_delimiter(true)
|
||||
.require_equals(true)
|
||||
.value_name("API_NAME")
|
||||
.help("Deny access to OS information. Optionally deny specific APIs by function name")
|
||||
.value_parser(|key: &str| parse_sys_kind(key).map(ToString::to_string))
|
||||
.value_parser(|key: &str| SysDescriptor::parse(key.to_string()).map(|s| s.into_string()))
|
||||
.hide(true)
|
||||
;
|
||||
if let Some(requires) = requires {
|
||||
|
@ -3418,7 +3509,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
|
|||
)
|
||||
.arg(
|
||||
{
|
||||
let mut arg = Arg::new("deny-run")
|
||||
let mut arg = Arg::new("deny-run")
|
||||
.long("deny-run")
|
||||
.num_args(0..)
|
||||
.use_value_delimiter(true)
|
||||
|
@ -3474,8 +3565,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
|
|||
.long("allow-hrtime")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("REMOVED in Deno 2.0")
|
||||
.hide(true)
|
||||
;
|
||||
.hide(true);
|
||||
if let Some(requires) = requires {
|
||||
arg = arg.requires(requires)
|
||||
}
|
||||
|
@ -3488,8 +3578,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
|
|||
.long("deny-hrtime")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("REMOVED in Deno 2.0")
|
||||
.hide(true)
|
||||
;
|
||||
.hide(true);
|
||||
if let Some(requires) = requires {
|
||||
arg = arg.requires(requires)
|
||||
}
|
||||
|
@ -3509,6 +3598,34 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
|
|||
arg
|
||||
}
|
||||
)
|
||||
.arg(
|
||||
{
|
||||
let mut arg = allow_import_arg().hide(true);
|
||||
if let Some(requires) = requires {
|
||||
// allow this for install --global
|
||||
if requires != "global" {
|
||||
arg = arg.requires(requires)
|
||||
}
|
||||
}
|
||||
arg
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn allow_all_arg() -> Arg {
|
||||
Arg::new("allow-all")
|
||||
.short('A')
|
||||
.long("allow-all")
|
||||
.conflicts_with("allow-read")
|
||||
.conflicts_with("allow-write")
|
||||
.conflicts_with("allow-net")
|
||||
.conflicts_with("allow-env")
|
||||
.conflicts_with("allow-run")
|
||||
.conflicts_with("allow-sys")
|
||||
.conflicts_with("allow-ffi")
|
||||
.conflicts_with("allow-import")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Allow all permissions")
|
||||
}
|
||||
|
||||
fn runtime_args(
|
||||
|
@ -3537,6 +3654,20 @@ fn runtime_args(
|
|||
.arg(strace_ops_arg())
|
||||
}
|
||||
|
||||
fn allow_import_arg() -> Arg {
|
||||
Arg::new("allow-import")
|
||||
.long("allow-import")
|
||||
.short('I')
|
||||
.num_args(0..)
|
||||
.use_value_delimiter(true)
|
||||
.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</>"
|
||||
))
|
||||
.value_parser(flags_net::validator)
|
||||
}
|
||||
|
||||
fn inspect_args(app: Command) -> Command {
|
||||
app
|
||||
.arg(
|
||||
|
@ -3683,7 +3814,9 @@ fn location_arg() -> Arg {
|
|||
url.set_password(None).unwrap();
|
||||
Ok(url)
|
||||
})
|
||||
.help("Value of 'globalThis.location' used by some web APIs")
|
||||
.help(cstr!(
|
||||
"Value of <p(245)>globalThis.location</> used by some web APIs"
|
||||
))
|
||||
.value_hint(ValueHint::Url)
|
||||
}
|
||||
|
||||
|
@ -4174,6 +4307,7 @@ fn cache_parse(
|
|||
unstable_args_parse(flags, matches, UnstableArgsConfig::ResolutionOnly);
|
||||
frozen_lockfile_arg_parse(flags, matches);
|
||||
allow_scripts_arg_parse(flags, matches)?;
|
||||
allow_import_parse(flags, matches);
|
||||
let files = matches.remove_many::<String>("file").unwrap().collect();
|
||||
flags.subcommand = DenoSubcommand::Cache(CacheFlags { files });
|
||||
Ok(())
|
||||
|
@ -4195,6 +4329,7 @@ fn check_parse(
|
|||
doc: matches.get_flag("doc"),
|
||||
doc_only: matches.get_flag("doc-only"),
|
||||
});
|
||||
allow_import_parse(flags, matches);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -4320,6 +4455,7 @@ fn doc_parse(
|
|||
no_lock_arg_parse(flags, matches);
|
||||
no_npm_arg_parse(flags, matches);
|
||||
no_remote_arg_parse(flags, matches);
|
||||
allow_import_parse(flags, matches);
|
||||
|
||||
let source_files_val = matches.remove_many::<String>("source_file");
|
||||
let source_files = if let Some(val) = source_files_val {
|
||||
|
@ -4460,6 +4596,7 @@ fn info_parse(
|
|||
lock_args_parse(flags, matches);
|
||||
no_remote_arg_parse(flags, matches);
|
||||
no_npm_arg_parse(flags, matches);
|
||||
allow_import_parse(flags, matches);
|
||||
let json = matches.get_flag("json");
|
||||
flags.subcommand = DenoSubcommand::Info(InfoFlags {
|
||||
file: matches.remove_one::<String>("file"),
|
||||
|
@ -4495,6 +4632,7 @@ fn install_parse(
|
|||
force,
|
||||
}),
|
||||
});
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -4532,7 +4670,7 @@ fn json_reference_parse(
|
|||
app.build();
|
||||
|
||||
fn serialize_command(
|
||||
command: &mut Command,
|
||||
mut command: Command,
|
||||
top_level: bool,
|
||||
) -> deno_core::serde_json::Value {
|
||||
let args = command
|
||||
|
@ -4540,7 +4678,7 @@ fn json_reference_parse(
|
|||
.filter(|arg| {
|
||||
!arg.is_hide_set()
|
||||
&& if top_level {
|
||||
true
|
||||
arg.is_global_set()
|
||||
} else {
|
||||
!arg.is_global_set()
|
||||
}
|
||||
|
@ -4549,40 +4687,49 @@ fn json_reference_parse(
|
|||
let name = arg.get_id().as_str();
|
||||
let short = arg.get_short();
|
||||
let long = arg.get_long();
|
||||
let aliases = arg.get_visible_aliases();
|
||||
let required = arg.is_required_set();
|
||||
let help = arg.get_help().map(|help| help.to_string());
|
||||
let help = arg.get_help().map(|help| help.ansi().to_string());
|
||||
let help_heading = arg
|
||||
.get_help_heading()
|
||||
.map(|help_heading| help_heading.to_string());
|
||||
let usage = arg.to_string();
|
||||
|
||||
json!({
|
||||
"name": name,
|
||||
"short": short,
|
||||
"long": long,
|
||||
"aliases": aliases,
|
||||
"required": required,
|
||||
"help": help,
|
||||
"help_heading": help_heading,
|
||||
"usage": usage,
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let name = command.get_name().to_string();
|
||||
let about = command.get_about().map(|about| about.to_string());
|
||||
let visible_aliases = command
|
||||
.get_visible_aliases()
|
||||
.map(|s| s.to_string())
|
||||
.collect::<Vec<_>>();
|
||||
let usage = command.render_usage().to_string();
|
||||
let about = command.get_about().map(|about| about.ansi().to_string());
|
||||
let usage = command.render_usage().ansi().to_string();
|
||||
|
||||
let subcommands = command
|
||||
.get_subcommands_mut()
|
||||
.map(|command| serialize_command(command, false))
|
||||
.get_subcommands()
|
||||
.map(|command| {
|
||||
serialize_command(
|
||||
if command
|
||||
.get_arguments()
|
||||
.any(|arg| arg.get_id().as_str() == "unstable")
|
||||
{
|
||||
enable_unstable(command.clone())
|
||||
} else {
|
||||
command.clone()
|
||||
},
|
||||
false,
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
json!({
|
||||
"name": name,
|
||||
"about": about,
|
||||
"visible_aliases": visible_aliases,
|
||||
"args": args,
|
||||
"subcommands": subcommands,
|
||||
"usage": usage,
|
||||
|
@ -4590,7 +4737,7 @@ fn json_reference_parse(
|
|||
}
|
||||
|
||||
flags.subcommand = DenoSubcommand::JSONReference(JSONReferenceFlags {
|
||||
json: serialize_command(&mut app, true),
|
||||
json: serialize_command(app, true),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -5175,13 +5322,22 @@ fn permission_args_parse(
|
|||
}
|
||||
|
||||
if matches.get_flag("allow-hrtime") || matches.get_flag("deny-hrtime") {
|
||||
log::warn!("⚠️ Warning: `allow-hrtime` and `deny-hrtime` have been removed in Deno 2, as high resolution time is now always allowed.");
|
||||
// use eprintln instead of log::warn because logging hasn't been initialized yet
|
||||
#[allow(clippy::print_stderr)]
|
||||
{
|
||||
eprintln!(
|
||||
"{} `allow-hrtime` and `deny-hrtime` have been removed in Deno 2, as high resolution time is now always allowed",
|
||||
deno_runtime::colors::yellow("Warning")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if matches.get_flag("allow-all") {
|
||||
flags.allow_all();
|
||||
}
|
||||
|
||||
allow_import_parse(flags, matches);
|
||||
|
||||
if matches.get_flag("no-prompt") {
|
||||
flags.permissions.no_prompt = true;
|
||||
}
|
||||
|
@ -5189,6 +5345,13 @@ fn permission_args_parse(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn allow_import_parse(flags: &mut Flags, matches: &mut ArgMatches) {
|
||||
if let Some(imports_wl) = matches.remove_many::<String>("allow-import") {
|
||||
let imports_allowlist = flags_net::parse(imports_wl.collect()).unwrap();
|
||||
flags.permissions.allow_import = Some(imports_allowlist);
|
||||
}
|
||||
}
|
||||
|
||||
fn unsafely_ignore_certificate_errors_parse(
|
||||
flags: &mut Flags,
|
||||
matches: &mut ArgMatches,
|
||||
|
@ -6215,7 +6378,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn short_permission_flags() {
|
||||
let r = flags_from_vec(svec!["deno", "run", "-RNESW", "gist.ts"]);
|
||||
let r = flags_from_vec(svec!["deno", "run", "-RNESWI", "gist.ts"]);
|
||||
assert_eq!(
|
||||
r.unwrap(),
|
||||
Flags {
|
||||
|
@ -6226,6 +6389,7 @@ mod tests {
|
|||
allow_read: Some(vec![]),
|
||||
allow_write: Some(vec![]),
|
||||
allow_env: Some(vec![]),
|
||||
allow_import: Some(vec![]),
|
||||
allow_net: Some(vec![]),
|
||||
allow_sys: Some(vec![]),
|
||||
..Default::default()
|
||||
|
@ -10777,7 +10941,7 @@ mod tests {
|
|||
}
|
||||
);
|
||||
// just make sure this doesn't panic
|
||||
let _ = flags.permissions.to_options();
|
||||
let _ = flags.permissions.to_options(&[]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -10852,4 +11016,46 @@ mod tests {
|
|||
Usage: deno repl [OPTIONS] [-- [ARGS]...]\n"
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_allow_import_host_from_url() {
|
||||
fn parse(text: &str) -> Option<String> {
|
||||
allow_import_host_from_url(&Url::parse(text).unwrap())
|
||||
}
|
||||
|
||||
assert_eq!(parse("https://jsr.io"), None);
|
||||
assert_eq!(
|
||||
parse("http://127.0.0.1:4250"),
|
||||
Some("127.0.0.1:4250".to_string())
|
||||
);
|
||||
assert_eq!(parse("http://jsr.io"), Some("jsr.io:80".to_string()));
|
||||
assert_eq!(
|
||||
parse("https://example.com"),
|
||||
Some("example.com:443".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
parse("http://example.com"),
|
||||
Some("example.com:80".to_string())
|
||||
);
|
||||
assert_eq!(parse("file:///example.com"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn allow_all_conflicts_allow_perms() {
|
||||
let flags = [
|
||||
"--allow-read",
|
||||
"--allow-write",
|
||||
"--allow-net",
|
||||
"--allow-env",
|
||||
"--allow-run",
|
||||
"--allow-sys",
|
||||
"--allow-ffi",
|
||||
"--allow-import",
|
||||
];
|
||||
for flag in flags {
|
||||
let r =
|
||||
flags_from_vec(svec!["deno", "run", "--allow-all", flag, "foo.ts"]);
|
||||
assert!(r.is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
148
cli/args/mod.rs
148
cli/args/mod.rs
|
@ -20,13 +20,13 @@ use deno_config::workspace::WorkspaceDiscoverOptions;
|
|||
use deno_config::workspace::WorkspaceDiscoverStart;
|
||||
use deno_config::workspace::WorkspaceLintConfig;
|
||||
use deno_config::workspace::WorkspaceResolver;
|
||||
use deno_core::normalize_path;
|
||||
use deno_core::resolve_url_or_path;
|
||||
use deno_graph::GraphKind;
|
||||
use deno_npm::npm_rc::NpmRc;
|
||||
use deno_npm::npm_rc::ResolvedNpmRc;
|
||||
use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
|
||||
use deno_npm::NpmSystemInfo;
|
||||
use deno_path_util::normalize_path;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use import_map::resolve_import_map_value_from_specifier;
|
||||
|
||||
|
@ -69,6 +69,8 @@ use std::collections::HashMap;
|
|||
use std::env;
|
||||
use std::io::BufReader;
|
||||
use std::io::Cursor;
|
||||
use std::io::Read;
|
||||
use std::io::Seek;
|
||||
use std::net::SocketAddr;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::path::Path;
|
||||
|
@ -742,15 +744,33 @@ pub enum NpmProcessStateKind {
|
|||
Byonm,
|
||||
}
|
||||
|
||||
pub(crate) const NPM_RESOLUTION_STATE_ENV_VAR_NAME: &str =
|
||||
"DENO_DONT_USE_INTERNAL_NODE_COMPAT_STATE";
|
||||
|
||||
static NPM_PROCESS_STATE: Lazy<Option<NpmProcessState>> = Lazy::new(|| {
|
||||
let state = std::env::var(NPM_RESOLUTION_STATE_ENV_VAR_NAME).ok()?;
|
||||
let state: NpmProcessState = serde_json::from_str(&state).ok()?;
|
||||
// remove the environment variable so that sub processes
|
||||
// that are spawned do not also use this.
|
||||
std::env::remove_var(NPM_RESOLUTION_STATE_ENV_VAR_NAME);
|
||||
use deno_runtime::ops::process::NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME;
|
||||
let fd = std::env::var(NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME).ok()?;
|
||||
std::env::remove_var(NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME);
|
||||
let fd = fd.parse::<usize>().ok()?;
|
||||
let mut file = {
|
||||
use deno_runtime::deno_io::FromRawIoHandle;
|
||||
unsafe { std::fs::File::from_raw_io_handle(fd as _) }
|
||||
};
|
||||
let mut buf = Vec::new();
|
||||
// seek to beginning. after the file is written the position will be inherited by this subprocess,
|
||||
// and also this file might have been read before
|
||||
file.seek(std::io::SeekFrom::Start(0)).unwrap();
|
||||
file
|
||||
.read_to_end(&mut buf)
|
||||
.inspect_err(|e| {
|
||||
log::error!("failed to read npm process state from fd {fd}: {e}");
|
||||
})
|
||||
.ok()?;
|
||||
let state: NpmProcessState = serde_json::from_slice(&buf)
|
||||
.inspect_err(|e| {
|
||||
log::error!(
|
||||
"failed to deserialize npm process state: {e} {}",
|
||||
String::from_utf8_lossy(&buf)
|
||||
)
|
||||
})
|
||||
.ok()?;
|
||||
Some(state)
|
||||
});
|
||||
|
||||
|
@ -769,6 +789,7 @@ pub struct CliOptions {
|
|||
// application need not concern itself with, so keep these private
|
||||
flags: Arc<Flags>,
|
||||
initial_cwd: PathBuf,
|
||||
main_module_cell: std::sync::OnceLock<Result<ModuleSpecifier, AnyError>>,
|
||||
maybe_node_modules_folder: Option<PathBuf>,
|
||||
npmrc: Arc<ResolvedNpmRc>,
|
||||
maybe_lockfile: Option<Arc<CliLockfile>>,
|
||||
|
@ -825,6 +846,7 @@ impl CliOptions {
|
|||
npmrc,
|
||||
maybe_node_modules_folder,
|
||||
overrides: Default::default(),
|
||||
main_module_cell: std::sync::OnceLock::new(),
|
||||
start_dir,
|
||||
deno_dir_provider,
|
||||
})
|
||||
|
@ -1105,40 +1127,39 @@ impl CliOptions {
|
|||
self.flags.env_file.as_ref()
|
||||
}
|
||||
|
||||
pub fn resolve_main_module(&self) -> Result<ModuleSpecifier, AnyError> {
|
||||
let main_module = match &self.flags.subcommand {
|
||||
DenoSubcommand::Compile(compile_flags) => {
|
||||
resolve_url_or_path(&compile_flags.source_file, self.initial_cwd())?
|
||||
}
|
||||
DenoSubcommand::Eval(_) => {
|
||||
resolve_url_or_path("./$deno$eval.ts", self.initial_cwd())?
|
||||
}
|
||||
DenoSubcommand::Repl(_) => {
|
||||
resolve_url_or_path("./$deno$repl.ts", self.initial_cwd())?
|
||||
}
|
||||
DenoSubcommand::Run(run_flags) => {
|
||||
if run_flags.is_stdin() {
|
||||
std::env::current_dir()
|
||||
.context("Unable to get CWD")
|
||||
.and_then(|cwd| {
|
||||
resolve_url_or_path("./$deno$stdin.ts", &cwd)
|
||||
.map_err(AnyError::from)
|
||||
})?
|
||||
} else if NpmPackageReqReference::from_str(&run_flags.script).is_ok() {
|
||||
ModuleSpecifier::parse(&run_flags.script)?
|
||||
} else {
|
||||
resolve_url_or_path(&run_flags.script, self.initial_cwd())?
|
||||
}
|
||||
}
|
||||
DenoSubcommand::Serve(run_flags) => {
|
||||
resolve_url_or_path(&run_flags.script, self.initial_cwd())?
|
||||
}
|
||||
_ => {
|
||||
bail!("No main module.")
|
||||
}
|
||||
};
|
||||
pub fn resolve_main_module(&self) -> Result<&ModuleSpecifier, AnyError> {
|
||||
self
|
||||
.main_module_cell
|
||||
.get_or_init(|| {
|
||||
let main_module = match &self.flags.subcommand {
|
||||
DenoSubcommand::Compile(compile_flags) => {
|
||||
resolve_url_or_path(&compile_flags.source_file, self.initial_cwd())?
|
||||
}
|
||||
DenoSubcommand::Eval(_) => {
|
||||
resolve_url_or_path("./$deno$eval.ts", self.initial_cwd())?
|
||||
}
|
||||
DenoSubcommand::Repl(_) => {
|
||||
resolve_url_or_path("./$deno$repl.ts", self.initial_cwd())?
|
||||
}
|
||||
DenoSubcommand::Run(run_flags) => {
|
||||
if run_flags.is_stdin() {
|
||||
resolve_url_or_path("./$deno$stdin.ts", self.initial_cwd())?
|
||||
} else {
|
||||
resolve_url_or_path(&run_flags.script, self.initial_cwd())?
|
||||
}
|
||||
}
|
||||
DenoSubcommand::Serve(run_flags) => {
|
||||
resolve_url_or_path(&run_flags.script, self.initial_cwd())?
|
||||
}
|
||||
_ => {
|
||||
bail!("No main module.")
|
||||
}
|
||||
};
|
||||
|
||||
Ok(main_module)
|
||||
Ok(main_module)
|
||||
})
|
||||
.as_ref()
|
||||
.map_err(|err| deno_core::anyhow::anyhow!("{}", err))
|
||||
}
|
||||
|
||||
pub fn resolve_file_header_overrides(
|
||||
|
@ -1159,7 +1180,7 @@ impl CliOptions {
|
|||
(maybe_main_specifier, maybe_content_type)
|
||||
{
|
||||
HashMap::from([(
|
||||
main_specifier,
|
||||
main_specifier.clone(),
|
||||
HashMap::from([("content-type".to_string(), content_type.to_string())]),
|
||||
)])
|
||||
} else {
|
||||
|
@ -1322,11 +1343,9 @@ impl CliOptions {
|
|||
)?;
|
||||
|
||||
Ok(deno_lint::linter::LintConfig {
|
||||
default_jsx_factory: transpile_options
|
||||
.jsx_automatic
|
||||
default_jsx_factory: (!transpile_options.jsx_automatic)
|
||||
.then(|| transpile_options.jsx_factory.clone()),
|
||||
default_jsx_fragment_factory: transpile_options
|
||||
.jsx_automatic
|
||||
default_jsx_fragment_factory: (!transpile_options.jsx_automatic)
|
||||
.then(|| transpile_options.jsx_fragment_factory.clone()),
|
||||
})
|
||||
}
|
||||
|
@ -1480,7 +1499,34 @@ impl CliOptions {
|
|||
}
|
||||
|
||||
pub fn permissions_options(&self) -> PermissionsOptions {
|
||||
self.flags.permissions.to_options()
|
||||
fn files_to_urls(files: &[String]) -> Vec<Cow<'_, Url>> {
|
||||
files
|
||||
.iter()
|
||||
.filter_map(|f| Url::parse(f).ok().map(Cow::Owned))
|
||||
.collect()
|
||||
}
|
||||
|
||||
// get a list of urls to imply for --allow-import
|
||||
let cli_arg_urls = self
|
||||
.resolve_main_module()
|
||||
.ok()
|
||||
.map(|url| vec![Cow::Borrowed(url)])
|
||||
.or_else(|| match &self.flags.subcommand {
|
||||
DenoSubcommand::Cache(cache_flags) => {
|
||||
Some(files_to_urls(&cache_flags.files))
|
||||
}
|
||||
DenoSubcommand::Check(check_flags) => {
|
||||
Some(files_to_urls(&check_flags.files))
|
||||
}
|
||||
DenoSubcommand::Install(InstallFlags {
|
||||
kind: InstallKind::Global(flags),
|
||||
}) => Url::parse(&flags.module_url)
|
||||
.ok()
|
||||
.map(|url| vec![Cow::Owned(url)]),
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or_default();
|
||||
self.flags.permissions.to_options(&cli_arg_urls)
|
||||
}
|
||||
|
||||
pub fn reload_flag(&self) -> bool {
|
||||
|
@ -1654,6 +1700,12 @@ impl CliOptions {
|
|||
allowed: self.flags.allow_scripts.clone(),
|
||||
initial_cwd: self.initial_cwd.clone(),
|
||||
root_dir: self.workspace().root_dir_path(),
|
||||
explicit_install: matches!(
|
||||
self.sub_command(),
|
||||
DenoSubcommand::Install(_)
|
||||
| DenoSubcommand::Cache(_)
|
||||
| DenoSubcommand::Add(_)
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
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.
|
||||
|
|
112
cli/cache/mod.rs
vendored
112
cli/cache/mod.rs
vendored
|
@ -1,14 +1,17 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use crate::args::jsr_url;
|
||||
use crate::args::CacheSetting;
|
||||
use crate::errors::get_error_class_name;
|
||||
use crate::file_fetcher::FetchNoFollowOptions;
|
||||
use crate::file_fetcher::FetchOptions;
|
||||
use crate::file_fetcher::FetchPermissionsOption;
|
||||
use crate::file_fetcher::FetchPermissionsOptionRef;
|
||||
use crate::file_fetcher::FileFetcher;
|
||||
use crate::file_fetcher::FileOrRedirect;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::util::fs::atomic_write_file_with_retries;
|
||||
use crate::util::fs::atomic_write_file_with_retries_and_fs;
|
||||
use crate::util::fs::AtomicWriteFileFsAdapter;
|
||||
use crate::util::path::specifier_has_extension;
|
||||
|
||||
use deno_ast::MediaType;
|
||||
|
@ -19,6 +22,7 @@ use deno_graph::source::CacheInfo;
|
|||
use deno_graph::source::LoadFuture;
|
||||
use deno_graph::source::LoadResponse;
|
||||
use deno_graph::source::Loader;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
@ -75,8 +79,12 @@ impl deno_cache_dir::DenoCacheEnv for RealDenoCacheEnv {
|
|||
atomic_write_file_with_retries(path, bytes, CACHE_PERM)
|
||||
}
|
||||
|
||||
fn remove_file(&self, path: &Path) -> std::io::Result<()> {
|
||||
std::fs::remove_file(path)
|
||||
fn canonicalize_path(&self, path: &Path) -> std::io::Result<PathBuf> {
|
||||
crate::util::fs::canonicalize_path(path)
|
||||
}
|
||||
|
||||
fn create_dir_all(&self, path: &Path) -> std::io::Result<()> {
|
||||
std::fs::create_dir_all(path)
|
||||
}
|
||||
|
||||
fn modified(&self, path: &Path) -> std::io::Result<Option<SystemTime>> {
|
||||
|
@ -98,12 +106,79 @@ impl deno_cache_dir::DenoCacheEnv for RealDenoCacheEnv {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DenoCacheEnvFsAdapter<'a>(
|
||||
pub &'a dyn deno_runtime::deno_fs::FileSystem,
|
||||
);
|
||||
|
||||
impl<'a> deno_cache_dir::DenoCacheEnv for DenoCacheEnvFsAdapter<'a> {
|
||||
fn read_file_bytes(&self, path: &Path) -> std::io::Result<Vec<u8>> {
|
||||
self
|
||||
.0
|
||||
.read_file_sync(path, None)
|
||||
.map_err(|err| err.into_io_error())
|
||||
}
|
||||
|
||||
fn atomic_write_file(
|
||||
&self,
|
||||
path: &Path,
|
||||
bytes: &[u8],
|
||||
) -> std::io::Result<()> {
|
||||
atomic_write_file_with_retries_and_fs(
|
||||
&AtomicWriteFileFsAdapter {
|
||||
fs: self.0,
|
||||
write_mode: CACHE_PERM,
|
||||
},
|
||||
path,
|
||||
bytes,
|
||||
)
|
||||
}
|
||||
|
||||
fn canonicalize_path(&self, path: &Path) -> std::io::Result<PathBuf> {
|
||||
self.0.realpath_sync(path).map_err(|e| e.into_io_error())
|
||||
}
|
||||
|
||||
fn create_dir_all(&self, path: &Path) -> std::io::Result<()> {
|
||||
self
|
||||
.0
|
||||
.mkdir_sync(path, true, None)
|
||||
.map_err(|e| e.into_io_error())
|
||||
}
|
||||
|
||||
fn modified(&self, path: &Path) -> std::io::Result<Option<SystemTime>> {
|
||||
self
|
||||
.0
|
||||
.stat_sync(path)
|
||||
.map(|stat| {
|
||||
stat
|
||||
.mtime
|
||||
.map(|ts| SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(ts))
|
||||
})
|
||||
.map_err(|e| e.into_io_error())
|
||||
}
|
||||
|
||||
fn is_file(&self, path: &Path) -> bool {
|
||||
self.0.is_file_sync(path)
|
||||
}
|
||||
|
||||
fn time_now(&self) -> SystemTime {
|
||||
SystemTime::now()
|
||||
}
|
||||
}
|
||||
|
||||
pub type GlobalHttpCache = deno_cache_dir::GlobalHttpCache<RealDenoCacheEnv>;
|
||||
pub type LocalHttpCache = deno_cache_dir::LocalHttpCache<RealDenoCacheEnv>;
|
||||
pub type LocalLspHttpCache =
|
||||
deno_cache_dir::LocalLspHttpCache<RealDenoCacheEnv>;
|
||||
pub use deno_cache_dir::HttpCache;
|
||||
|
||||
pub struct FetchCacherOptions {
|
||||
pub file_header_overrides: HashMap<ModuleSpecifier, HashMap<String, String>>,
|
||||
pub permissions: PermissionsContainer,
|
||||
/// If we're publishing for `deno publish`.
|
||||
pub is_deno_publish: bool,
|
||||
}
|
||||
|
||||
/// A "wrapper" for the FileFetcher and DiskCache for the Deno CLI that provides
|
||||
/// a concise interface to the DENO_DIR when building module graphs.
|
||||
pub struct FetchCacher {
|
||||
|
@ -112,26 +187,27 @@ pub struct FetchCacher {
|
|||
global_http_cache: Arc<GlobalHttpCache>,
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
module_info_cache: Arc<ModuleInfoCache>,
|
||||
permissions: FetchPermissionsOption,
|
||||
permissions: PermissionsContainer,
|
||||
cache_info_enabled: bool,
|
||||
is_deno_publish: bool,
|
||||
}
|
||||
|
||||
impl FetchCacher {
|
||||
pub fn new(
|
||||
file_fetcher: Arc<FileFetcher>,
|
||||
file_header_overrides: HashMap<ModuleSpecifier, HashMap<String, String>>,
|
||||
global_http_cache: Arc<GlobalHttpCache>,
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
module_info_cache: Arc<ModuleInfoCache>,
|
||||
permissions: FetchPermissionsOption,
|
||||
options: FetchCacherOptions,
|
||||
) -> Self {
|
||||
Self {
|
||||
file_fetcher,
|
||||
file_header_overrides,
|
||||
global_http_cache,
|
||||
npm_resolver,
|
||||
module_info_cache,
|
||||
permissions,
|
||||
file_header_overrides: options.file_header_overrides,
|
||||
permissions: options.permissions,
|
||||
is_deno_publish: options.is_deno_publish,
|
||||
cache_info_enabled: false,
|
||||
}
|
||||
}
|
||||
|
@ -208,10 +284,24 @@ impl Loader for FetchCacher {
|
|||
}
|
||||
}
|
||||
|
||||
if self.is_deno_publish
|
||||
&& matches!(specifier.scheme(), "http" | "https")
|
||||
&& !specifier.as_str().starts_with(jsr_url().as_str())
|
||||
{
|
||||
// mark non-JSR remote modules as external so we don't need --allow-import
|
||||
// permissions as these will error out later when publishing
|
||||
return Box::pin(futures::future::ready(Ok(Some(
|
||||
LoadResponse::External {
|
||||
specifier: specifier.clone(),
|
||||
},
|
||||
))));
|
||||
}
|
||||
|
||||
let file_fetcher = self.file_fetcher.clone();
|
||||
let file_header_overrides = self.file_header_overrides.clone();
|
||||
let permissions = self.permissions.clone();
|
||||
let specifier = specifier.clone();
|
||||
let is_statically_analyzable = !options.was_dynamic_root;
|
||||
|
||||
async move {
|
||||
let maybe_cache_setting = match options.cache_setting {
|
||||
|
@ -230,7 +320,11 @@ impl Loader for FetchCacher {
|
|||
.fetch_no_follow_with_options(FetchNoFollowOptions {
|
||||
fetch_options: FetchOptions {
|
||||
specifier: &specifier,
|
||||
permissions: permissions.as_ref(),
|
||||
permissions: if is_statically_analyzable {
|
||||
FetchPermissionsOptionRef::StaticContainer(&permissions)
|
||||
} else {
|
||||
FetchPermissionsOptionRef::DynamicContainer(&permissions)
|
||||
},
|
||||
maybe_accept: None,
|
||||
maybe_cache_setting: maybe_cache_setting.as_ref(),
|
||||
},
|
||||
|
|
|
@ -32,17 +32,19 @@ use crate::module_loader::ModuleLoadPreparer;
|
|||
use crate::node::CliCjsCodeAnalyzer;
|
||||
use crate::node::CliNodeCodeTranslator;
|
||||
use crate::npm::create_cli_npm_resolver;
|
||||
use crate::npm::CliByonmNpmResolverCreateOptions;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::npm::CliNpmResolverByonmCreateOptions;
|
||||
use crate::npm::CliNpmResolverCreateOptions;
|
||||
use crate::npm::CliNpmResolverManagedCreateOptions;
|
||||
use crate::npm::CliNpmResolverManagedSnapshotOption;
|
||||
use crate::resolver::CjsResolutionStore;
|
||||
use crate::resolver::CliDenoResolverFs;
|
||||
use crate::resolver::CliGraphResolver;
|
||||
use crate::resolver::CliGraphResolverOptions;
|
||||
use crate::resolver::CliNodeResolver;
|
||||
use crate::resolver::CliSloppyImportsResolver;
|
||||
use crate::resolver::NpmModuleLoader;
|
||||
use crate::resolver::SloppyImportsResolver;
|
||||
use crate::resolver::SloppyImportsCachedFs;
|
||||
use crate::standalone::DenoCompileBinaryWriter;
|
||||
use crate::tools::check::TypeChecker;
|
||||
use crate::tools::coverage::CoverageCollector;
|
||||
|
@ -185,7 +187,8 @@ struct CliFactoryServices {
|
|||
node_resolver: Deferred<Arc<NodeResolver>>,
|
||||
npm_resolver: Deferred<Arc<dyn CliNpmResolver>>,
|
||||
permission_desc_parser: Deferred<Arc<RuntimePermissionDescriptorParser>>,
|
||||
sloppy_imports_resolver: Deferred<Option<Arc<SloppyImportsResolver>>>,
|
||||
root_permissions_container: Deferred<PermissionsContainer>,
|
||||
sloppy_imports_resolver: Deferred<Option<Arc<CliSloppyImportsResolver>>>,
|
||||
text_only_progress_bar: Deferred<ProgressBar>,
|
||||
type_checker: Deferred<Arc<TypeChecker>>,
|
||||
cjs_resolutions: Deferred<Arc<CjsResolutionStore>>,
|
||||
|
@ -298,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,
|
||||
)))
|
||||
})
|
||||
|
@ -359,8 +362,8 @@ impl CliFactory {
|
|||
let cli_options = self.cli_options()?;
|
||||
// For `deno install` we want to force the managed resolver so it can set up `node_modules/` directory.
|
||||
create_cli_npm_resolver(if cli_options.use_byonm() && !matches!(cli_options.sub_command(), DenoSubcommand::Install(_) | DenoSubcommand::Add(_) | DenoSubcommand::Remove(_)) {
|
||||
CliNpmResolverCreateOptions::Byonm(CliNpmResolverByonmCreateOptions {
|
||||
fs: fs.clone(),
|
||||
CliNpmResolverCreateOptions::Byonm(CliByonmNpmResolverCreateOptions {
|
||||
fs: CliDenoResolverFs(fs.clone()),
|
||||
root_node_modules_dir: Some(match cli_options.node_modules_dir_path() {
|
||||
Some(node_modules_path) => node_modules_path.to_path_buf(),
|
||||
// path needs to be canonicalized for node resolution
|
||||
|
@ -403,17 +406,16 @@ impl CliFactory {
|
|||
|
||||
pub fn sloppy_imports_resolver(
|
||||
&self,
|
||||
) -> Result<Option<&Arc<SloppyImportsResolver>>, AnyError> {
|
||||
) -> Result<Option<&Arc<CliSloppyImportsResolver>>, AnyError> {
|
||||
self
|
||||
.services
|
||||
.sloppy_imports_resolver
|
||||
.get_or_try_init(|| {
|
||||
Ok(
|
||||
self
|
||||
.cli_options()?
|
||||
.unstable_sloppy_imports()
|
||||
.then(|| Arc::new(SloppyImportsResolver::new(self.fs().clone()))),
|
||||
)
|
||||
Ok(self.cli_options()?.unstable_sloppy_imports().then(|| {
|
||||
Arc::new(CliSloppyImportsResolver::new(SloppyImportsCachedFs::new(
|
||||
self.fs().clone(),
|
||||
)))
|
||||
}))
|
||||
})
|
||||
.map(|maybe| maybe.as_ref())
|
||||
}
|
||||
|
@ -626,6 +628,7 @@ impl CliFactory {
|
|||
self.maybe_file_watcher_reporter().clone(),
|
||||
self.file_fetcher()?.clone(),
|
||||
self.global_http_cache()?.clone(),
|
||||
self.root_permissions_container()?.clone(),
|
||||
)))
|
||||
})
|
||||
.await
|
||||
|
@ -659,6 +662,7 @@ impl CliFactory {
|
|||
Ok(Arc::new(MainModuleGraphContainer::new(
|
||||
self.cli_options()?.clone(),
|
||||
self.module_load_preparer().await?.clone(),
|
||||
self.root_permissions_container()?.clone(),
|
||||
)))
|
||||
})
|
||||
.await
|
||||
|
@ -755,15 +759,20 @@ impl CliFactory {
|
|||
))
|
||||
}
|
||||
|
||||
pub fn create_permissions_container(
|
||||
pub fn root_permissions_container(
|
||||
&self,
|
||||
) -> Result<PermissionsContainer, AnyError> {
|
||||
let desc_parser = self.permission_desc_parser()?.clone();
|
||||
let permissions = Permissions::from_options(
|
||||
desc_parser.as_ref(),
|
||||
&self.cli_options()?.permissions_options(),
|
||||
)?;
|
||||
Ok(PermissionsContainer::new(desc_parser, permissions))
|
||||
) -> Result<&PermissionsContainer, AnyError> {
|
||||
self
|
||||
.services
|
||||
.root_permissions_container
|
||||
.get_or_try_init(|| {
|
||||
let desc_parser = self.permission_desc_parser()?.clone();
|
||||
let permissions = Permissions::from_options(
|
||||
desc_parser.as_ref(),
|
||||
&self.cli_options()?.permissions_options(),
|
||||
)?;
|
||||
Ok(PermissionsContainer::new(desc_parser, permissions))
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn create_cli_main_worker_factory(
|
||||
|
@ -774,6 +783,7 @@ impl CliFactory {
|
|||
let npm_resolver = self.npm_resolver().await?;
|
||||
let fs = self.fs();
|
||||
let cli_node_resolver = self.cli_node_resolver().await?;
|
||||
let cli_npm_resolver = self.npm_resolver().await?.clone();
|
||||
let maybe_file_watcher_communicator = if cli_options.has_hmr() {
|
||||
Some(self.watcher_communicator.clone().unwrap())
|
||||
} else {
|
||||
|
@ -803,6 +813,7 @@ impl CliFactory {
|
|||
self.main_module_graph_container().await?.clone(),
|
||||
self.module_load_preparer().await?.clone(),
|
||||
cli_node_resolver.clone(),
|
||||
cli_npm_resolver.clone(),
|
||||
NpmModuleLoader::new(
|
||||
self.cjs_resolutions().clone(),
|
||||
self.node_code_translator().await?.clone(),
|
||||
|
@ -814,8 +825,8 @@ impl CliFactory {
|
|||
)),
|
||||
node_resolver.clone(),
|
||||
npm_resolver.clone(),
|
||||
self.permission_desc_parser()?.clone(),
|
||||
self.root_cert_store_provider().clone(),
|
||||
self.root_permissions_container()?.clone(),
|
||||
StorageKeyResolver::from_options(cli_options),
|
||||
cli_options.sub_command().clone(),
|
||||
self.create_cli_main_worker_options()?,
|
||||
|
|
|
@ -21,6 +21,7 @@ use deno_core::url::Url;
|
|||
use deno_core::ModuleSpecifier;
|
||||
use deno_graph::source::LoaderChecksum;
|
||||
|
||||
use deno_path_util::url_to_file_path;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_runtime::deno_web::BlobStore;
|
||||
use log::debug;
|
||||
|
@ -135,7 +136,7 @@ impl MemoryFiles {
|
|||
|
||||
/// Fetch a source file from the local file system.
|
||||
fn fetch_local(specifier: &ModuleSpecifier) -> Result<File, AnyError> {
|
||||
let local = specifier.to_file_path().map_err(|_| {
|
||||
let local = url_to_file_path(specifier).map_err(|_| {
|
||||
uri_error(format!("Invalid file path.\n Specifier: {specifier}"))
|
||||
})?;
|
||||
// If it doesnt have a extension, we want to treat it as typescript by default
|
||||
|
@ -173,30 +174,8 @@ fn get_validated_scheme(
|
|||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum FetchPermissionsOptionRef<'a> {
|
||||
AllowAll,
|
||||
Container(&'a PermissionsContainer),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum FetchPermissionsOption {
|
||||
AllowAll,
|
||||
Container(PermissionsContainer),
|
||||
}
|
||||
|
||||
impl FetchPermissionsOption {
|
||||
pub fn as_ref(&self) -> FetchPermissionsOptionRef {
|
||||
match self {
|
||||
FetchPermissionsOption::AllowAll => FetchPermissionsOptionRef::AllowAll,
|
||||
FetchPermissionsOption::Container(container) => {
|
||||
FetchPermissionsOptionRef::Container(container)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PermissionsContainer> for FetchPermissionsOption {
|
||||
fn from(value: PermissionsContainer) -> Self {
|
||||
Self::Container(value)
|
||||
}
|
||||
DynamicContainer(&'a PermissionsContainer),
|
||||
StaticContainer(&'a PermissionsContainer),
|
||||
}
|
||||
|
||||
pub struct FetchOptions<'a> {
|
||||
|
@ -564,7 +543,6 @@ impl FileFetcher {
|
|||
}
|
||||
|
||||
/// Fetch a source file and asynchronously return it.
|
||||
#[allow(dead_code)] // todo(25469): undo when merging
|
||||
#[inline(always)]
|
||||
pub async fn fetch(
|
||||
&self,
|
||||
|
@ -572,7 +550,10 @@ impl FileFetcher {
|
|||
permissions: &PermissionsContainer,
|
||||
) -> Result<File, AnyError> {
|
||||
self
|
||||
.fetch_inner(specifier, FetchPermissionsOptionRef::Container(permissions))
|
||||
.fetch_inner(
|
||||
specifier,
|
||||
FetchPermissionsOptionRef::StaticContainer(permissions),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
|
@ -647,8 +628,17 @@ impl FileFetcher {
|
|||
FetchPermissionsOptionRef::AllowAll => {
|
||||
// allow
|
||||
}
|
||||
FetchPermissionsOptionRef::Container(permissions) => {
|
||||
permissions.check_specifier(specifier)?;
|
||||
FetchPermissionsOptionRef::StaticContainer(permissions) => {
|
||||
permissions.check_specifier(
|
||||
specifier,
|
||||
deno_runtime::deno_permissions::CheckSpecifierKind::Static,
|
||||
)?;
|
||||
}
|
||||
FetchPermissionsOptionRef::DynamicContainer(permissions) => {
|
||||
permissions.check_specifier(
|
||||
specifier,
|
||||
deno_runtime::deno_permissions::CheckSpecifierKind::Dynamic,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
if let Some(file) = self.memory_files.get(specifier) {
|
||||
|
@ -736,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)),
|
||||
|
@ -974,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,
|
||||
|
@ -1000,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();
|
||||
|
||||
|
@ -1166,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 =
|
||||
|
@ -1334,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,
|
||||
|
@ -1360,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,
|
||||
|
|
|
@ -9,9 +9,9 @@ use deno_core::error::AnyError;
|
|||
use deno_core::parking_lot::RwLock;
|
||||
use deno_graph::ModuleGraph;
|
||||
use deno_runtime::colors;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
|
||||
use crate::args::CliOptions;
|
||||
use crate::file_fetcher::FetchPermissionsOption;
|
||||
use crate::module_loader::ModuleLoadPreparer;
|
||||
use crate::util::fs::collect_specifiers;
|
||||
use crate::util::path::is_script_ext;
|
||||
|
@ -45,12 +45,14 @@ pub struct MainModuleGraphContainer {
|
|||
inner: Arc<RwLock<Arc<ModuleGraph>>>,
|
||||
cli_options: Arc<CliOptions>,
|
||||
module_load_preparer: Arc<ModuleLoadPreparer>,
|
||||
root_permissions: PermissionsContainer,
|
||||
}
|
||||
|
||||
impl MainModuleGraphContainer {
|
||||
pub fn new(
|
||||
cli_options: Arc<CliOptions>,
|
||||
module_load_preparer: Arc<ModuleLoadPreparer>,
|
||||
root_permissions: PermissionsContainer,
|
||||
) -> Self {
|
||||
Self {
|
||||
update_queue: Default::default(),
|
||||
|
@ -59,6 +61,7 @@ impl MainModuleGraphContainer {
|
|||
)))),
|
||||
cli_options,
|
||||
module_load_preparer,
|
||||
root_permissions,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,7 +79,7 @@ impl MainModuleGraphContainer {
|
|||
specifiers,
|
||||
false,
|
||||
self.cli_options.ts_type_lib_window(),
|
||||
FetchPermissionsOption::AllowAll,
|
||||
self.root_permissions.clone(),
|
||||
ext_overwrite,
|
||||
)
|
||||
.await?;
|
||||
|
|
|
@ -11,17 +11,19 @@ use crate::cache::ModuleInfoCache;
|
|||
use crate::cache::ParsedSourceCache;
|
||||
use crate::colors;
|
||||
use crate::errors::get_error_class_name;
|
||||
use crate::file_fetcher::FetchPermissionsOption;
|
||||
use crate::file_fetcher::FileFetcher;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::resolver::CliGraphResolver;
|
||||
use crate::resolver::SloppyImportsResolver;
|
||||
use crate::resolver::CliSloppyImportsResolver;
|
||||
use crate::resolver::SloppyImportsCachedFs;
|
||||
use crate::tools::check;
|
||||
use crate::tools::check::TypeChecker;
|
||||
use crate::util::file_watcher::WatcherCommunicator;
|
||||
use crate::util::fs::canonicalize_path;
|
||||
use deno_config::workspace::JsrPackageConfig;
|
||||
use deno_core::anyhow::bail;
|
||||
use deno_graph::source::LoaderChecksum;
|
||||
use deno_graph::FillFromLockfileOptions;
|
||||
use deno_graph::JsrLoadError;
|
||||
use deno_graph::ModuleLoadError;
|
||||
use deno_graph::WorkspaceFastCheckOption;
|
||||
|
@ -31,7 +33,6 @@ use deno_core::error::AnyError;
|
|||
use deno_core::parking_lot::Mutex;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_graph::source::Loader;
|
||||
use deno_graph::source::ResolutionMode;
|
||||
use deno_graph::source::ResolveError;
|
||||
use deno_graph::GraphKind;
|
||||
use deno_graph::ModuleError;
|
||||
|
@ -39,12 +40,13 @@ use deno_graph::ModuleGraph;
|
|||
use deno_graph::ModuleGraphError;
|
||||
use deno_graph::ResolutionError;
|
||||
use deno_graph::SpecifierError;
|
||||
use deno_path_util::url_to_file_path;
|
||||
use deno_resolver::sloppy_imports::SloppyImportsResolutionMode;
|
||||
use deno_runtime::deno_fs::FileSystem;
|
||||
use deno_runtime::deno_node;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_semver::jsr::JsrDepPackageReq;
|
||||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::Version;
|
||||
use import_map::ImportMapError;
|
||||
use std::collections::HashSet;
|
||||
use std::error::Error;
|
||||
|
@ -52,14 +54,14 @@ use std::ops::Deref;
|
|||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone)]
|
||||
pub struct GraphValidOptions {
|
||||
pub check_js: bool,
|
||||
pub follow_type_only: bool,
|
||||
pub is_vendoring: bool,
|
||||
/// Whether to exit the process for lockfile errors.
|
||||
/// Otherwise, surfaces lockfile errors as errors.
|
||||
pub exit_lockfile_errors: bool,
|
||||
pub kind: GraphKind,
|
||||
/// Whether to exit the process for integrity check errors such as
|
||||
/// lockfile checksum mismatches and JSR integrity failures.
|
||||
/// Otherwise, surfaces integrity errors as errors.
|
||||
pub exit_integrity_errors: bool,
|
||||
}
|
||||
|
||||
/// Check if `roots` and their deps are available. Returns `Ok(())` if
|
||||
|
@ -75,17 +77,54 @@ pub fn graph_valid(
|
|||
roots: &[ModuleSpecifier],
|
||||
options: GraphValidOptions,
|
||||
) -> Result<(), AnyError> {
|
||||
if options.exit_lockfile_errors {
|
||||
graph_exit_lock_errors(graph);
|
||||
if options.exit_integrity_errors {
|
||||
graph_exit_integrity_errors(graph);
|
||||
}
|
||||
|
||||
let mut errors = graph
|
||||
let mut errors = graph_walk_errors(
|
||||
graph,
|
||||
fs,
|
||||
roots,
|
||||
GraphWalkErrorsOptions {
|
||||
check_js: options.check_js,
|
||||
kind: options.kind,
|
||||
},
|
||||
);
|
||||
if let Some(error) = errors.next() {
|
||||
Err(error)
|
||||
} else {
|
||||
// finally surface the npm resolution result
|
||||
if let Err(err) = &graph.npm_dep_graph_result {
|
||||
return Err(custom_error(
|
||||
get_error_class_name(err),
|
||||
format_deno_graph_error(err.as_ref().deref()),
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct GraphWalkErrorsOptions {
|
||||
pub check_js: bool,
|
||||
pub kind: GraphKind,
|
||||
}
|
||||
|
||||
/// Walks the errors found in the module graph that should be surfaced to users
|
||||
/// and enhances them with CLI information.
|
||||
pub fn graph_walk_errors<'a>(
|
||||
graph: &'a ModuleGraph,
|
||||
fs: &'a Arc<dyn FileSystem>,
|
||||
roots: &'a [ModuleSpecifier],
|
||||
options: GraphWalkErrorsOptions,
|
||||
) -> impl Iterator<Item = AnyError> + 'a {
|
||||
graph
|
||||
.walk(
|
||||
roots.iter(),
|
||||
deno_graph::WalkOptions {
|
||||
check_js: options.check_js,
|
||||
follow_type_only: options.follow_type_only,
|
||||
follow_dynamic: options.is_vendoring,
|
||||
kind: options.kind,
|
||||
follow_dynamic: false,
|
||||
prefer_fast_check_graph: false,
|
||||
},
|
||||
)
|
||||
|
@ -109,7 +148,7 @@ pub fn graph_valid(
|
|||
)
|
||||
}
|
||||
ModuleGraphError::ModuleError(error) => {
|
||||
enhanced_lockfile_error_message(error)
|
||||
enhanced_integrity_error_message(error)
|
||||
.or_else(|| enhanced_sloppy_imports_error_message(fs, error))
|
||||
.unwrap_or_else(|| format_deno_graph_error(error))
|
||||
}
|
||||
|
@ -132,56 +171,18 @@ pub fn graph_valid(
|
|||
return None;
|
||||
}
|
||||
|
||||
if options.is_vendoring {
|
||||
// warn about failing dynamic imports when vendoring, but don't fail completely
|
||||
if matches!(
|
||||
error,
|
||||
ModuleGraphError::ModuleError(ModuleError::MissingDynamic(_, _))
|
||||
) {
|
||||
log::warn!("Ignoring: {}", message);
|
||||
return None;
|
||||
}
|
||||
|
||||
// ignore invalid downgrades and invalid local imports when vendoring
|
||||
match &error {
|
||||
ModuleGraphError::ResolutionError(err)
|
||||
| ModuleGraphError::TypesResolutionError(err) => {
|
||||
if matches!(
|
||||
err,
|
||||
ResolutionError::InvalidDowngrade { .. }
|
||||
| ResolutionError::InvalidLocalImport { .. }
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
ModuleGraphError::ModuleError(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
Some(custom_error(get_error_class_name(&error.into()), message))
|
||||
});
|
||||
if let Some(error) = errors.next() {
|
||||
Err(error)
|
||||
} else {
|
||||
// finally surface the npm resolution result
|
||||
if let Err(err) = &graph.npm_dep_graph_result {
|
||||
return Err(custom_error(
|
||||
get_error_class_name(err),
|
||||
format_deno_graph_error(err.as_ref().deref()),
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn graph_exit_lock_errors(graph: &ModuleGraph) {
|
||||
pub fn graph_exit_integrity_errors(graph: &ModuleGraph) {
|
||||
for error in graph.module_errors() {
|
||||
exit_for_lockfile_error(error);
|
||||
exit_for_integrity_error(error);
|
||||
}
|
||||
}
|
||||
|
||||
fn exit_for_lockfile_error(err: &ModuleError) {
|
||||
if let Some(err_message) = enhanced_lockfile_error_message(err) {
|
||||
fn exit_for_integrity_error(err: &ModuleError) {
|
||||
if let Some(err_message) = enhanced_integrity_error_message(err) {
|
||||
log::error!("{} {}", colors::red("error:"), err_message);
|
||||
std::process::exit(10);
|
||||
}
|
||||
|
@ -249,6 +250,19 @@ impl ModuleGraphCreator {
|
|||
package_configs: &[JsrPackageConfig],
|
||||
build_fast_check_graph: bool,
|
||||
) -> Result<ModuleGraph, AnyError> {
|
||||
fn graph_has_external_remote(graph: &ModuleGraph) -> bool {
|
||||
// Earlier on, we marked external non-JSR modules as external.
|
||||
// If the graph contains any of those, it would cause type checking
|
||||
// to crash, so since publishing is going to fail anyway, skip type
|
||||
// checking.
|
||||
graph.modules().any(|module| match module {
|
||||
deno_graph::Module::External(external_module) => {
|
||||
matches!(external_module.specifier.scheme(), "http" | "https")
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
let mut roots = Vec::new();
|
||||
for package_config in package_configs {
|
||||
roots.extend(package_config.config_file.resolve_export_value_urls()?);
|
||||
|
@ -262,9 +276,12 @@ impl ModuleGraphCreator {
|
|||
})
|
||||
.await?;
|
||||
self.graph_valid(&graph)?;
|
||||
if self.options.type_check_mode().is_true() {
|
||||
if self.options.type_check_mode().is_true()
|
||||
&& !graph_has_external_remote(&graph)
|
||||
{
|
||||
self.type_check_graph(graph.clone()).await?;
|
||||
}
|
||||
|
||||
if build_fast_check_graph {
|
||||
let fast_check_workspace_members = package_configs
|
||||
.iter()
|
||||
|
@ -279,6 +296,7 @@ impl ModuleGraphCreator {
|
|||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(graph)
|
||||
}
|
||||
|
||||
|
@ -370,6 +388,7 @@ pub struct ModuleGraphBuilder {
|
|||
maybe_file_watcher_reporter: Option<FileWatcherReporter>,
|
||||
file_fetcher: Arc<FileFetcher>,
|
||||
global_http_cache: Arc<GlobalHttpCache>,
|
||||
root_permissions_container: PermissionsContainer,
|
||||
}
|
||||
|
||||
impl ModuleGraphBuilder {
|
||||
|
@ -386,6 +405,7 @@ impl ModuleGraphBuilder {
|
|||
maybe_file_watcher_reporter: Option<FileWatcherReporter>,
|
||||
file_fetcher: Arc<FileFetcher>,
|
||||
global_http_cache: Arc<GlobalHttpCache>,
|
||||
root_permissions_container: PermissionsContainer,
|
||||
) -> Self {
|
||||
Self {
|
||||
options,
|
||||
|
@ -399,6 +419,7 @@ impl ModuleGraphBuilder {
|
|||
maybe_file_watcher_reporter,
|
||||
file_fetcher,
|
||||
global_http_cache,
|
||||
root_permissions_container,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -553,33 +574,19 @@ impl ModuleGraphBuilder {
|
|||
// populate the information from the lockfile
|
||||
if let Some(lockfile) = &self.lockfile {
|
||||
let lockfile = lockfile.lock();
|
||||
for (from, to) in &lockfile.content.redirects {
|
||||
if let Ok(from) = ModuleSpecifier::parse(from) {
|
||||
if let Ok(to) = ModuleSpecifier::parse(to) {
|
||||
if !matches!(from.scheme(), "file" | "npm" | "jsr") {
|
||||
graph.redirects.insert(from, to);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (req_dep, value) in &lockfile.content.packages.specifiers {
|
||||
match req_dep.kind {
|
||||
deno_semver::package::PackageKind::Jsr => {
|
||||
if let Ok(version) = Version::parse_standard(value) {
|
||||
graph.packages.add_nv(
|
||||
req_dep.req.clone(),
|
||||
PackageNv {
|
||||
name: req_dep.req.name.clone(),
|
||||
version,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
deno_semver::package::PackageKind::Npm => {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
graph.fill_from_lockfile(FillFromLockfileOptions {
|
||||
redirects: lockfile
|
||||
.content
|
||||
.redirects
|
||||
.iter()
|
||||
.map(|(from, to)| (from.as_str(), to.as_str())),
|
||||
package_specifiers: lockfile
|
||||
.content
|
||||
.packages
|
||||
.specifiers
|
||||
.iter()
|
||||
.map(|(dep, id)| (dep, id.as_str())),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -587,6 +594,12 @@ impl ModuleGraphBuilder {
|
|||
let initial_package_deps_len = graph.packages.package_deps_sum();
|
||||
let initial_package_mappings_len = graph.packages.mappings().len();
|
||||
|
||||
if roots.iter().any(|r| r.scheme() == "npm")
|
||||
&& self.npm_resolver.as_byonm().is_some()
|
||||
{
|
||||
bail!("Resolving npm specifier entrypoints this way is currently not supported with \"nodeModules\": \"manual\". In the meantime, try with --node-modules-dir=auto instead");
|
||||
}
|
||||
|
||||
graph.build(roots, loader, options).await;
|
||||
|
||||
let has_redirects_changed = graph.redirects.len() != initial_redirects_len;
|
||||
|
@ -670,20 +683,26 @@ impl ModuleGraphBuilder {
|
|||
|
||||
/// Creates the default loader used for creating a graph.
|
||||
pub fn create_graph_loader(&self) -> cache::FetchCacher {
|
||||
self.create_fetch_cacher(FetchPermissionsOption::AllowAll)
|
||||
self.create_fetch_cacher(self.root_permissions_container.clone())
|
||||
}
|
||||
|
||||
pub fn create_fetch_cacher(
|
||||
&self,
|
||||
permissions: FetchPermissionsOption,
|
||||
permissions: PermissionsContainer,
|
||||
) -> cache::FetchCacher {
|
||||
cache::FetchCacher::new(
|
||||
self.file_fetcher.clone(),
|
||||
self.options.resolve_file_header_overrides(),
|
||||
self.global_http_cache.clone(),
|
||||
self.npm_resolver.clone(),
|
||||
self.module_info_cache.clone(),
|
||||
permissions,
|
||||
cache::FetchCacherOptions {
|
||||
file_header_overrides: self.options.resolve_file_header_overrides(),
|
||||
permissions,
|
||||
is_deno_publish: matches!(
|
||||
self.options.sub_command(),
|
||||
crate::args::DenoSubcommand::Publish { .. }
|
||||
),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -707,10 +726,13 @@ impl ModuleGraphBuilder {
|
|||
&self.fs,
|
||||
roots,
|
||||
GraphValidOptions {
|
||||
is_vendoring: false,
|
||||
follow_type_only: self.options.type_check_mode().is_true(),
|
||||
kind: if self.options.type_check_mode().is_true() {
|
||||
GraphKind::All
|
||||
} else {
|
||||
GraphKind::CodeOnly
|
||||
},
|
||||
check_js: self.options.check_js(),
|
||||
exit_lockfile_errors: true,
|
||||
exit_integrity_errors: true,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -751,8 +773,8 @@ fn enhanced_sloppy_imports_error_message(
|
|||
match error {
|
||||
ModuleError::LoadingErr(specifier, _, ModuleLoadError::Loader(_)) // ex. "Is a directory" error
|
||||
| ModuleError::Missing(specifier, _) => {
|
||||
let additional_message = SloppyImportsResolver::new(fs.clone())
|
||||
.resolve(specifier, ResolutionMode::Execution)?
|
||||
let additional_message = CliSloppyImportsResolver::new(SloppyImportsCachedFs::new(fs.clone()))
|
||||
.resolve(specifier, SloppyImportsResolutionMode::Execution)?
|
||||
.as_suggestion_message();
|
||||
Some(format!(
|
||||
"{} {} or run with --unstable-sloppy-imports",
|
||||
|
@ -764,7 +786,7 @@ fn enhanced_sloppy_imports_error_message(
|
|||
}
|
||||
}
|
||||
|
||||
fn enhanced_lockfile_error_message(err: &ModuleError) -> Option<String> {
|
||||
fn enhanced_integrity_error_message(err: &ModuleError) -> Option<String> {
|
||||
match err {
|
||||
ModuleError::LoadingErr(
|
||||
specifier,
|
||||
|
@ -928,13 +950,13 @@ pub fn has_graph_root_local_dependent_changed(
|
|||
std::iter::once(root),
|
||||
deno_graph::WalkOptions {
|
||||
follow_dynamic: true,
|
||||
follow_type_only: true,
|
||||
kind: GraphKind::All,
|
||||
prefer_fast_check_graph: true,
|
||||
check_js: true,
|
||||
},
|
||||
);
|
||||
while let Some((s, _)) = dependent_specifiers.next() {
|
||||
if let Ok(path) = specifier_to_file_path(s) {
|
||||
if let Ok(path) = url_to_file_path(s) {
|
||||
if let Ok(path) = canonicalize_path(&path) {
|
||||
if canonicalized_changed_paths.contains(&path) {
|
||||
return true;
|
||||
|
|
|
@ -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;
|
||||
|
@ -23,8 +26,8 @@ use deno_core::serde::Serialize;
|
|||
use deno_core::serde_json;
|
||||
use deno_core::serde_json::json;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_path_util::url_to_file_path;
|
||||
use deno_runtime::deno_node::PathClean;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
use deno_semver::jsr::JsrPackageNvReference;
|
||||
use deno_semver::jsr::JsrPackageReqReference;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
|
@ -401,7 +404,7 @@ impl<'a> TsResponseImportMapper<'a> {
|
|||
.flatten()?;
|
||||
let root_folder = package_json.path.parent()?;
|
||||
|
||||
let specifier_path = specifier_to_file_path(specifier).ok()?;
|
||||
let specifier_path = url_to_file_path(specifier).ok()?;
|
||||
let mut search_paths = vec![specifier_path.clone()];
|
||||
// TypeScript will provide a .js extension for quick fixes, so do
|
||||
// a search for the .d.ts file instead
|
||||
|
@ -1151,6 +1154,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.
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::lsp::logging::lsp_warn;
|
|||
|
||||
use deno_core::url::Url;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
use deno_path_util::url_to_file_path;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
@ -24,7 +24,7 @@ pub fn calculate_fs_version(
|
|||
) -> Option<String> {
|
||||
match specifier.scheme() {
|
||||
"npm" | "node" | "data" | "blob" => None,
|
||||
"file" => specifier_to_file_path(specifier)
|
||||
"file" => url_to_file_path(specifier)
|
||||
.ok()
|
||||
.and_then(|path| calculate_fs_version_at_path(&path)),
|
||||
_ => calculate_fs_version_in_cache(cache, specifier, file_referrer),
|
||||
|
@ -82,7 +82,7 @@ impl Default for LspCache {
|
|||
impl LspCache {
|
||||
pub fn new(global_cache_url: Option<Url>) -> Self {
|
||||
let global_cache_path = global_cache_url.and_then(|s| {
|
||||
specifier_to_file_path(&s)
|
||||
url_to_file_path(&s)
|
||||
.inspect(|p| {
|
||||
lsp_log!("Resolved global cache path: \"{}\"", p.to_string_lossy());
|
||||
})
|
||||
|
@ -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 {
|
||||
|
@ -165,7 +165,7 @@ impl LspCache {
|
|||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
) -> Option<ModuleSpecifier> {
|
||||
let path = specifier_to_file_path(specifier).ok()?;
|
||||
let path = url_to_file_path(specifier).ok()?;
|
||||
let vendor = self
|
||||
.vendors_by_scope
|
||||
.iter()
|
||||
|
@ -176,7 +176,7 @@ impl LspCache {
|
|||
}
|
||||
|
||||
pub fn is_valid_file_referrer(&self, specifier: &ModuleSpecifier) -> bool {
|
||||
if let Ok(path) = specifier_to_file_path(specifier) {
|
||||
if let Ok(path) = url_to_file_path(specifier) {
|
||||
if !path.starts_with(&self.deno_dir().root) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ use deno_core::serde::Serialize;
|
|||
use deno_core::serde_json::json;
|
||||
use deno_core::url::Position;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
use deno_path_util::url_to_file_path;
|
||||
use deno_semver::jsr::JsrPackageReqReference;
|
||||
use deno_semver::package::PackageNv;
|
||||
use import_map::ImportMap;
|
||||
|
@ -380,7 +380,7 @@ fn get_local_completions(
|
|||
ResolutionMode::Execution,
|
||||
)
|
||||
.ok()?;
|
||||
let resolved_parent_path = specifier_to_file_path(&resolved_parent).ok()?;
|
||||
let resolved_parent_path = url_to_file_path(&resolved_parent).ok()?;
|
||||
let raw_parent =
|
||||
&text[..text.char_indices().rfind(|(_, c)| *c == '/')?.0 + 1];
|
||||
if resolved_parent_path.is_dir() {
|
||||
|
|
|
@ -36,8 +36,8 @@ use deno_core::ModuleSpecifier;
|
|||
use deno_lint::linter::LintConfig as DenoLintConfig;
|
||||
use deno_npm::npm_rc::ResolvedNpmRc;
|
||||
use deno_package_json::PackageJsonCache;
|
||||
use deno_path_util::url_to_file_path;
|
||||
use deno_runtime::deno_node::PackageJson;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
use indexmap::IndexSet;
|
||||
use lsp_types::ClientCapabilities;
|
||||
use std::collections::BTreeMap;
|
||||
|
@ -59,7 +59,8 @@ use crate::args::LintOptions;
|
|||
use crate::cache::FastInsecureHasher;
|
||||
use crate::file_fetcher::FileFetcher;
|
||||
use crate::lsp::logging::lsp_warn;
|
||||
use crate::resolver::SloppyImportsResolver;
|
||||
use crate::resolver::CliSloppyImportsResolver;
|
||||
use crate::resolver::SloppyImportsCachedFs;
|
||||
use crate::tools::lint::CliLinter;
|
||||
use crate::tools::lint::CliLinterOptions;
|
||||
use crate::tools::lint::LintRuleProvider;
|
||||
|
@ -801,7 +802,7 @@ impl Settings {
|
|||
/// Returns `None` if the value should be deferred to the presence of a
|
||||
/// `deno.json` file.
|
||||
pub fn specifier_enabled(&self, specifier: &ModuleSpecifier) -> Option<bool> {
|
||||
let Ok(path) = specifier_to_file_path(specifier) else {
|
||||
let Ok(path) = url_to_file_path(specifier) else {
|
||||
// Non-file URLs are not disabled by these settings.
|
||||
return Some(true);
|
||||
};
|
||||
|
@ -810,7 +811,7 @@ impl Settings {
|
|||
let mut disable_paths = vec![];
|
||||
let mut enable_paths = None;
|
||||
if let Some(folder_uri) = folder_uri {
|
||||
if let Ok(folder_path) = specifier_to_file_path(folder_uri) {
|
||||
if let Ok(folder_path) = url_to_file_path(folder_uri) {
|
||||
disable_paths = settings
|
||||
.disable_paths
|
||||
.iter()
|
||||
|
@ -847,12 +848,12 @@ impl Settings {
|
|||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
) -> (&WorkspaceSettings, Option<&ModuleSpecifier>) {
|
||||
let Ok(path) = specifier_to_file_path(specifier) else {
|
||||
let Ok(path) = url_to_file_path(specifier) else {
|
||||
return (&self.unscoped, self.first_folder.as_ref());
|
||||
};
|
||||
for (folder_uri, settings) in self.by_workspace_folder.iter().rev() {
|
||||
if let Some(settings) = settings {
|
||||
let Ok(folder_path) = specifier_to_file_path(folder_uri) else {
|
||||
let Ok(folder_path) = url_to_file_path(folder_uri) else {
|
||||
continue;
|
||||
};
|
||||
if path.starts_with(folder_path) {
|
||||
|
@ -1181,7 +1182,7 @@ pub struct ConfigData {
|
|||
pub lockfile: Option<Arc<CliLockfile>>,
|
||||
pub npmrc: Option<Arc<ResolvedNpmRc>>,
|
||||
pub resolver: Arc<WorkspaceResolver>,
|
||||
pub sloppy_imports_resolver: Option<Arc<SloppyImportsResolver>>,
|
||||
pub sloppy_imports_resolver: Option<Arc<CliSloppyImportsResolver>>,
|
||||
pub import_map_from_settings: Option<ModuleSpecifier>,
|
||||
watched_files: HashMap<ModuleSpecifier, ConfigWatchedFileType>,
|
||||
}
|
||||
|
@ -1584,9 +1585,11 @@ impl ConfigData {
|
|||
.is_ok()
|
||||
|| member_dir.workspace.has_unstable("sloppy-imports");
|
||||
let sloppy_imports_resolver = unstable_sloppy_imports.then(|| {
|
||||
Arc::new(SloppyImportsResolver::new_without_stat_cache(Arc::new(
|
||||
deno_runtime::deno_fs::RealFs,
|
||||
)))
|
||||
Arc::new(CliSloppyImportsResolver::new(
|
||||
SloppyImportsCachedFs::new_without_stat_cache(Arc::new(
|
||||
deno_runtime::deno_fs::RealFs,
|
||||
)),
|
||||
))
|
||||
});
|
||||
let resolver = Arc::new(resolver);
|
||||
let lint_rule_provider = LintRuleProvider::new(
|
||||
|
@ -1767,7 +1770,7 @@ impl ConfigTree {
|
|||
let config_file_path = (|| {
|
||||
let config_setting = ws_settings.config.as_ref()?;
|
||||
let config_uri = folder_uri.join(config_setting).ok()?;
|
||||
specifier_to_file_path(&config_uri).ok()
|
||||
url_to_file_path(&config_uri).ok()
|
||||
})();
|
||||
if config_file_path.is_some() || ws_settings.import_map.is_some() {
|
||||
scopes.insert(
|
||||
|
@ -1844,7 +1847,7 @@ impl ConfigTree {
|
|||
let scope = config_file.specifier.join(".").unwrap();
|
||||
let json_text = serde_json::to_string(&config_file.json).unwrap();
|
||||
let test_fs = deno_runtime::deno_fs::InMemoryFs::default();
|
||||
let config_path = specifier_to_file_path(&config_file.specifier).unwrap();
|
||||
let config_path = url_to_file_path(&config_file.specifier).unwrap();
|
||||
test_fs.setup_text_files(vec![(
|
||||
config_path.to_string_lossy().to_string(),
|
||||
json_text,
|
||||
|
|
|
@ -19,8 +19,8 @@ use super::urls::LspUrlMap;
|
|||
use crate::graph_util;
|
||||
use crate::graph_util::enhanced_resolution_error_message;
|
||||
use crate::lsp::lsp_custom::DiagnosticBatchNotificationParams;
|
||||
use crate::resolver::SloppyImportsResolution;
|
||||
use crate::resolver::SloppyImportsResolver;
|
||||
use crate::resolver::CliSloppyImportsResolver;
|
||||
use crate::resolver::SloppyImportsCachedFs;
|
||||
use crate::tools::lint::CliLinter;
|
||||
use crate::tools::lint::CliLinterOptions;
|
||||
use crate::tools::lint::LintRuleProvider;
|
||||
|
@ -40,11 +40,12 @@ use deno_core::unsync::spawn_blocking;
|
|||
use deno_core::unsync::JoinHandle;
|
||||
use deno_core::url::Url;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_graph::source::ResolutionMode;
|
||||
use deno_graph::source::ResolveError;
|
||||
use deno_graph::Resolution;
|
||||
use deno_graph::ResolutionError;
|
||||
use deno_graph::SpecifierError;
|
||||
use deno_resolver::sloppy_imports::SloppyImportsResolution;
|
||||
use deno_resolver::sloppy_imports::SloppyImportsResolutionMode;
|
||||
use deno_runtime::deno_fs;
|
||||
use deno_runtime::deno_node;
|
||||
use deno_runtime::tokio_util::create_basic_runtime;
|
||||
|
@ -1263,7 +1264,9 @@ impl DenoDiagnostic {
|
|||
Self::NotInstalledJsr(pkg_req, specifier) => (lsp::DiagnosticSeverity::ERROR, format!("JSR package \"{pkg_req}\" is not installed or doesn't exist."), Some(json!({ "specifier": specifier }))),
|
||||
Self::NotInstalledNpm(pkg_req, specifier) => (lsp::DiagnosticSeverity::ERROR, format!("NPM package \"{pkg_req}\" is not installed or doesn't exist."), Some(json!({ "specifier": specifier }))),
|
||||
Self::NoLocal(specifier) => {
|
||||
let maybe_sloppy_resolution = SloppyImportsResolver::new(Arc::new(deno_fs::RealFs)).resolve(specifier, ResolutionMode::Execution);
|
||||
let maybe_sloppy_resolution = CliSloppyImportsResolver::new(
|
||||
SloppyImportsCachedFs::new(Arc::new(deno_fs::RealFs))
|
||||
).resolve(specifier, SloppyImportsResolutionMode::Execution);
|
||||
let data = maybe_sloppy_resolution.as_ref().map(|res| {
|
||||
json!({
|
||||
"specifier": specifier,
|
||||
|
@ -1514,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(
|
||||
|
|
|
@ -26,8 +26,8 @@ use deno_core::parking_lot::Mutex;
|
|||
use deno_core::ModuleSpecifier;
|
||||
use deno_graph::source::ResolutionMode;
|
||||
use deno_graph::Resolution;
|
||||
use deno_path_util::url_to_file_path;
|
||||
use deno_runtime::deno_node;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
use deno_semver::jsr::JsrPackageReqReference;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use deno_semver::package::PackageReq;
|
||||
|
@ -849,7 +849,7 @@ impl FileSystemDocuments {
|
|||
file_referrer: Option<&ModuleSpecifier>,
|
||||
) -> Option<Arc<Document>> {
|
||||
let doc = if specifier.scheme() == "file" {
|
||||
let path = specifier_to_file_path(specifier).ok()?;
|
||||
let path = url_to_file_path(specifier).ok()?;
|
||||
let bytes = fs::read(path).ok()?;
|
||||
let content =
|
||||
deno_graph::source::decode_owned_source(specifier, bytes, None).ok()?;
|
||||
|
@ -1136,7 +1136,7 @@ impl Documents {
|
|||
return true;
|
||||
}
|
||||
if specifier.scheme() == "file" {
|
||||
return specifier_to_file_path(&specifier)
|
||||
return url_to_file_path(&specifier)
|
||||
.map(|p| p.is_file())
|
||||
.unwrap_or(false);
|
||||
}
|
||||
|
@ -1325,7 +1325,7 @@ impl Documents {
|
|||
let fs_docs = &self.file_system_docs;
|
||||
// Clean up non-existent documents.
|
||||
fs_docs.docs.retain(|specifier, _| {
|
||||
let Ok(path) = specifier_to_file_path(specifier) else {
|
||||
let Ok(path) = url_to_file_path(specifier) else {
|
||||
// Remove non-file schemed docs (deps). They may not be dependencies
|
||||
// anymore after updating resolvers.
|
||||
return false;
|
||||
|
|
|
@ -15,9 +15,9 @@ use deno_core::url::Url;
|
|||
use deno_core::ModuleSpecifier;
|
||||
use deno_graph::GraphKind;
|
||||
use deno_graph::Resolution;
|
||||
use deno_path_util::url_to_file_path;
|
||||
use deno_runtime::deno_tls::rustls::RootCertStore;
|
||||
use deno_runtime::deno_tls::RootCertStoreProvider;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
use deno_semver::jsr::JsrPackageReqReference;
|
||||
use indexmap::Equivalent;
|
||||
use indexmap::IndexSet;
|
||||
|
@ -207,11 +207,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>,
|
||||
|
@ -274,10 +274,9 @@ impl LanguageServer {
|
|||
factory.fs(),
|
||||
&roots,
|
||||
graph_util::GraphValidOptions {
|
||||
is_vendoring: false,
|
||||
follow_type_only: true,
|
||||
kind: GraphKind::All,
|
||||
check_js: false,
|
||||
exit_lockfile_errors: false,
|
||||
exit_integrity_errors: false,
|
||||
},
|
||||
)?;
|
||||
|
||||
|
@ -627,7 +626,7 @@ impl Inner {
|
|||
let maybe_root_path = self
|
||||
.config
|
||||
.root_uri()
|
||||
.and_then(|uri| specifier_to_file_path(uri).ok());
|
||||
.and_then(|uri| url_to_file_path(uri).ok());
|
||||
let root_cert_store = get_root_cert_store(
|
||||
maybe_root_path,
|
||||
workspace_settings.certificate_stores.clone(),
|
||||
|
@ -803,7 +802,7 @@ impl Inner {
|
|||
let mut roots = config
|
||||
.workspace_folders
|
||||
.iter()
|
||||
.filter_map(|p| specifier_to_file_path(&p.0).ok())
|
||||
.filter_map(|p| url_to_file_path(&p.0).ok())
|
||||
.collect::<Vec<_>>();
|
||||
roots.sort();
|
||||
let roots = roots
|
||||
|
@ -1125,7 +1124,7 @@ impl Inner {
|
|||
{
|
||||
return;
|
||||
}
|
||||
match specifier_to_file_path(&specifier) {
|
||||
match url_to_file_path(&specifier) {
|
||||
Ok(path) if is_importable_ext(&path) => {}
|
||||
_ => return,
|
||||
}
|
||||
|
@ -1363,7 +1362,7 @@ impl Inner {
|
|||
{
|
||||
specifier = uri_to_url(¶ms.text_document.uri);
|
||||
}
|
||||
let file_path = specifier_to_file_path(&specifier).map_err(|err| {
|
||||
let file_path = url_to_file_path(&specifier).map_err(|err| {
|
||||
error!("{:#}", err);
|
||||
LspError::invalid_request()
|
||||
})?;
|
||||
|
@ -1613,8 +1612,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());
|
||||
|
@ -1722,9 +1721,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
|
||||
|
@ -2509,7 +2513,7 @@ impl Inner {
|
|||
let maybe_root_path_owned = self
|
||||
.config
|
||||
.root_uri()
|
||||
.and_then(|uri| specifier_to_file_path(uri).ok());
|
||||
.and_then(|uri| url_to_file_path(uri).ok());
|
||||
let mut resolved_items = Vec::<CallHierarchyIncomingCall>::new();
|
||||
for item in incoming_calls.iter() {
|
||||
if let Some(resolved) = item.try_resolve_call_hierarchy_incoming_call(
|
||||
|
@ -2555,7 +2559,7 @@ impl Inner {
|
|||
let maybe_root_path_owned = self
|
||||
.config
|
||||
.root_uri()
|
||||
.and_then(|uri| specifier_to_file_path(uri).ok());
|
||||
.and_then(|uri| url_to_file_path(uri).ok());
|
||||
let mut resolved_items = Vec::<CallHierarchyOutgoingCall>::new();
|
||||
for item in outgoing_calls.iter() {
|
||||
if let Some(resolved) = item.try_resolve_call_hierarchy_outgoing_call(
|
||||
|
@ -2604,7 +2608,7 @@ impl Inner {
|
|||
let maybe_root_path_owned = self
|
||||
.config
|
||||
.root_uri()
|
||||
.and_then(|uri| specifier_to_file_path(uri).ok());
|
||||
.and_then(|uri| url_to_file_path(uri).ok());
|
||||
let mut resolved_items = Vec::<CallHierarchyItem>::new();
|
||||
match one_or_many {
|
||||
tsc::OneOrMany::One(item) => {
|
||||
|
@ -3614,6 +3618,11 @@ impl Inner {
|
|||
}),
|
||||
// bit of a hack to force the lsp to cache the @types/node package
|
||||
type_check_mode: crate::args::TypeCheckMode::Local,
|
||||
permissions: crate::args::PermissionFlags {
|
||||
// allow remote import permissions in the lsp for now
|
||||
allow_import: Some(vec![]),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
}),
|
||||
initial_cwd,
|
||||
|
|
|
@ -10,10 +10,10 @@ use deno_graph::source::Resolver;
|
|||
use deno_graph::GraphImport;
|
||||
use deno_graph::ModuleSpecifier;
|
||||
use deno_npm::NpmSystemInfo;
|
||||
use deno_path_util::url_to_file_path;
|
||||
use deno_runtime::deno_fs;
|
||||
use deno_runtime::deno_node::NodeResolver;
|
||||
use deno_runtime::deno_node::PackageJson;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
use deno_semver::jsr::JsrPackageReqReference;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use deno_semver::package::PackageNv;
|
||||
|
@ -42,13 +42,14 @@ use crate::lsp::config::Config;
|
|||
use crate::lsp::config::ConfigData;
|
||||
use crate::lsp::logging::lsp_warn;
|
||||
use crate::npm::create_cli_npm_resolver_for_lsp;
|
||||
use crate::npm::CliByonmNpmResolverCreateOptions;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::npm::CliNpmResolverByonmCreateOptions;
|
||||
use crate::npm::CliNpmResolverCreateOptions;
|
||||
use crate::npm::CliNpmResolverManagedCreateOptions;
|
||||
use crate::npm::CliNpmResolverManagedSnapshotOption;
|
||||
use crate::npm::ManagedCliNpmResolver;
|
||||
use crate::resolver::CjsResolutionStore;
|
||||
use crate::resolver::CliDenoResolverFs;
|
||||
use crate::resolver::CliGraphResolver;
|
||||
use crate::resolver::CliGraphResolverOptions;
|
||||
use crate::resolver::CliNodeResolver;
|
||||
|
@ -327,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 {
|
||||
|
@ -372,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,
|
||||
|
@ -439,11 +460,11 @@ async fn create_npm_resolver(
|
|||
) -> Option<Arc<dyn CliNpmResolver>> {
|
||||
let enable_byonm = config_data.map(|d| d.byonm).unwrap_or(false);
|
||||
let options = if enable_byonm {
|
||||
CliNpmResolverCreateOptions::Byonm(CliNpmResolverByonmCreateOptions {
|
||||
fs: Arc::new(deno_fs::RealFs),
|
||||
CliNpmResolverCreateOptions::Byonm(CliByonmNpmResolverCreateOptions {
|
||||
fs: CliDenoResolverFs(Arc::new(deno_fs::RealFs)),
|
||||
root_node_modules_dir: config_data.and_then(|config_data| {
|
||||
config_data.node_modules_dir.clone().or_else(|| {
|
||||
specifier_to_file_path(&config_data.scope)
|
||||
url_to_file_path(&config_data.scope)
|
||||
.ok()
|
||||
.map(|p| p.join("node_modules/"))
|
||||
})
|
||||
|
|
|
@ -62,7 +62,7 @@ use deno_core::ModuleSpecifier;
|
|||
use deno_core::OpState;
|
||||
use deno_core::PollEventLoopOptions;
|
||||
use deno_core::RuntimeOptions;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
use deno_path_util::url_to_file_path;
|
||||
use deno_runtime::inspector_server::InspectorServer;
|
||||
use deno_runtime::tokio_util::create_basic_runtime;
|
||||
use indexmap::IndexMap;
|
||||
|
@ -3191,7 +3191,7 @@ impl CallHierarchyItem {
|
|||
let use_file_name = self.is_source_file_item();
|
||||
let maybe_file_path = if uri.scheme().is_some_and(|s| s.as_str() == "file")
|
||||
{
|
||||
specifier_to_file_path(&uri_to_url(&uri)).ok()
|
||||
url_to_file_path(&uri_to_url(&uri)).ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
25
cli/main.rs
25
cli/main.rs
|
@ -392,6 +392,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."
|
||||
]
|
||||
)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ use crate::graph_container::ModuleGraphUpdatePermit;
|
|||
use crate::graph_util::CreateGraphOptions;
|
||||
use crate::graph_util::ModuleGraphBuilder;
|
||||
use crate::node;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::resolver::CliGraphResolver;
|
||||
use crate::resolver::CliNodeResolver;
|
||||
use crate::resolver::ModuleCodeStringSource;
|
||||
|
@ -104,7 +105,7 @@ impl ModuleLoadPreparer {
|
|||
roots: &[ModuleSpecifier],
|
||||
is_dynamic: bool,
|
||||
lib: TsTypeLib,
|
||||
permissions: crate::file_fetcher::FetchPermissionsOption,
|
||||
permissions: PermissionsContainer,
|
||||
ext_overwrite: Option<&String>,
|
||||
) -> Result<(), AnyError> {
|
||||
log::debug!("Preparing module load.");
|
||||
|
@ -203,6 +204,7 @@ struct SharedCliModuleLoaderState {
|
|||
main_module_graph_container: Arc<MainModuleGraphContainer>,
|
||||
module_load_preparer: Arc<ModuleLoadPreparer>,
|
||||
node_resolver: Arc<CliNodeResolver>,
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
npm_module_loader: NpmModuleLoader,
|
||||
parsed_source_cache: Arc<ParsedSourceCache>,
|
||||
resolver: Arc<CliGraphResolver>,
|
||||
|
@ -221,6 +223,7 @@ impl CliModuleLoaderFactory {
|
|||
main_module_graph_container: Arc<MainModuleGraphContainer>,
|
||||
module_load_preparer: Arc<ModuleLoadPreparer>,
|
||||
node_resolver: Arc<CliNodeResolver>,
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
npm_module_loader: NpmModuleLoader,
|
||||
parsed_source_cache: Arc<ParsedSourceCache>,
|
||||
resolver: Arc<CliGraphResolver>,
|
||||
|
@ -241,6 +244,7 @@ impl CliModuleLoaderFactory {
|
|||
main_module_graph_container,
|
||||
module_load_preparer,
|
||||
node_resolver,
|
||||
npm_resolver,
|
||||
npm_module_loader,
|
||||
parsed_source_cache,
|
||||
resolver,
|
||||
|
@ -252,13 +256,15 @@ impl CliModuleLoaderFactory {
|
|||
&self,
|
||||
graph_container: TGraphContainer,
|
||||
lib: TsTypeLib,
|
||||
root_permissions: PermissionsContainer,
|
||||
dynamic_permissions: PermissionsContainer,
|
||||
is_worker: bool,
|
||||
parent_permissions: PermissionsContainer,
|
||||
permissions: PermissionsContainer,
|
||||
) -> ModuleLoaderAndSourceMapGetter {
|
||||
let loader = Rc::new(CliModuleLoader(Rc::new(CliModuleLoaderInner {
|
||||
lib,
|
||||
root_permissions,
|
||||
dynamic_permissions,
|
||||
is_worker,
|
||||
parent_permissions,
|
||||
permissions,
|
||||
graph_container,
|
||||
emitter: self.shared.emitter.clone(),
|
||||
parsed_source_cache: self.shared.parsed_source_cache.clone(),
|
||||
|
@ -274,20 +280,20 @@ impl ModuleLoaderFactory for CliModuleLoaderFactory {
|
|||
fn create_for_main(
|
||||
&self,
|
||||
root_permissions: PermissionsContainer,
|
||||
dynamic_permissions: PermissionsContainer,
|
||||
) -> ModuleLoaderAndSourceMapGetter {
|
||||
self.create_with_lib(
|
||||
(*self.shared.main_module_graph_container).clone(),
|
||||
self.shared.lib_window,
|
||||
/* is worker */ false,
|
||||
root_permissions.clone(),
|
||||
root_permissions,
|
||||
dynamic_permissions,
|
||||
)
|
||||
}
|
||||
|
||||
fn create_for_worker(
|
||||
&self,
|
||||
root_permissions: PermissionsContainer,
|
||||
dynamic_permissions: PermissionsContainer,
|
||||
parent_permissions: PermissionsContainer,
|
||||
permissions: PermissionsContainer,
|
||||
) -> ModuleLoaderAndSourceMapGetter {
|
||||
self.create_with_lib(
|
||||
// create a fresh module graph for the worker
|
||||
|
@ -295,21 +301,21 @@ impl ModuleLoaderFactory for CliModuleLoaderFactory {
|
|||
self.shared.graph_kind,
|
||||
))),
|
||||
self.shared.lib_worker,
|
||||
root_permissions,
|
||||
dynamic_permissions,
|
||||
/* is worker */ true,
|
||||
parent_permissions,
|
||||
permissions,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct CliModuleLoaderInner<TGraphContainer: ModuleGraphContainer> {
|
||||
lib: TsTypeLib,
|
||||
is_worker: bool,
|
||||
/// The initial set of permissions used to resolve the static imports in the
|
||||
/// worker. These are "allow all" for main worker, and parent thread
|
||||
/// permissions for Web Worker.
|
||||
root_permissions: PermissionsContainer,
|
||||
/// Permissions used to resolve dynamic imports, these get passed as
|
||||
/// "root permissions" for Web Worker.
|
||||
dynamic_permissions: PermissionsContainer,
|
||||
parent_permissions: PermissionsContainer,
|
||||
permissions: PermissionsContainer,
|
||||
shared: Arc<SharedCliModuleLoaderState>,
|
||||
emitter: Arc<Emitter>,
|
||||
parsed_source_cache: Arc<ParsedSourceCache>,
|
||||
|
@ -476,7 +482,6 @@ impl<TGraphContainer: ModuleGraphContainer>
|
|||
Some(Module::Npm(module)) => {
|
||||
let package_folder = self
|
||||
.shared
|
||||
.node_resolver
|
||||
.npm_resolver
|
||||
.as_managed()
|
||||
.unwrap() // byonm won't create a Module::Npm
|
||||
|
@ -769,11 +774,12 @@ impl<TGraphContainer: ModuleGraphContainer> ModuleLoader
|
|||
}
|
||||
}
|
||||
|
||||
let root_permissions = if is_dynamic {
|
||||
inner.dynamic_permissions.clone()
|
||||
let permissions = if is_dynamic {
|
||||
inner.permissions.clone()
|
||||
} else {
|
||||
inner.root_permissions.clone()
|
||||
inner.parent_permissions.clone()
|
||||
};
|
||||
let is_dynamic = is_dynamic || inner.is_worker; // consider workers as dynamic for permissions
|
||||
let lib = inner.lib;
|
||||
let mut update_permit = graph_container.acquire_update_permit().await;
|
||||
let graph = update_permit.graph_mut();
|
||||
|
@ -783,7 +789,7 @@ impl<TGraphContainer: ModuleGraphContainer> ModuleLoader
|
|||
&[specifier],
|
||||
is_dynamic,
|
||||
lib,
|
||||
root_permissions.into(),
|
||||
permissions,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "napi_sym"
|
||||
version = "0.98.0"
|
||||
version = "0.99.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
353
cli/npm/byonm.rs
353
cli/npm/byonm.rs
|
@ -1,276 +1,36 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_ast::ModuleSpecifier;
|
||||
use deno_core::anyhow::bail;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json;
|
||||
use deno_package_json::PackageJsonDepValue;
|
||||
use deno_runtime::deno_fs::FileSystem;
|
||||
use deno_runtime::deno_node::DenoPkgJsonFsAdapter;
|
||||
use deno_core::url::Url;
|
||||
use deno_resolver::npm::ByonmNpmResolver;
|
||||
use deno_resolver::npm::ByonmNpmResolverCreateOptions;
|
||||
use deno_runtime::deno_node::NodePermissions;
|
||||
use deno_runtime::deno_node::NodeRequireResolver;
|
||||
use deno_runtime::deno_node::NpmProcessStateProvider;
|
||||
use deno_runtime::deno_node::PackageJson;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
use deno_runtime::ops::process::NpmProcessStateProvider;
|
||||
use deno_semver::package::PackageReq;
|
||||
use deno_semver::Version;
|
||||
use node_resolver::errors::PackageFolderResolveError;
|
||||
use node_resolver::errors::PackageFolderResolveIoError;
|
||||
use node_resolver::errors::PackageJsonLoadError;
|
||||
use node_resolver::errors::PackageNotFoundError;
|
||||
use node_resolver::load_pkg_json;
|
||||
use node_resolver::NpmResolver;
|
||||
|
||||
use crate::args::NpmProcessState;
|
||||
use crate::args::NpmProcessStateKind;
|
||||
use crate::util::fs::canonicalize_path_maybe_not_exists_with_fs;
|
||||
use crate::resolver::CliDenoResolverFs;
|
||||
|
||||
use super::managed::normalize_pkg_name_for_node_modules_deno_folder;
|
||||
use super::CliNpmResolver;
|
||||
use super::InnerCliNpmResolverRef;
|
||||
|
||||
pub struct CliNpmResolverByonmCreateOptions {
|
||||
pub fs: Arc<dyn FileSystem>,
|
||||
// todo(dsherret): investigate removing this
|
||||
pub root_node_modules_dir: Option<PathBuf>,
|
||||
}
|
||||
|
||||
pub fn create_byonm_npm_resolver(
|
||||
options: CliNpmResolverByonmCreateOptions,
|
||||
) -> Arc<dyn CliNpmResolver> {
|
||||
Arc::new(ByonmCliNpmResolver {
|
||||
fs: options.fs,
|
||||
root_node_modules_dir: options.root_node_modules_dir,
|
||||
})
|
||||
}
|
||||
pub type CliByonmNpmResolverCreateOptions =
|
||||
ByonmNpmResolverCreateOptions<CliDenoResolverFs>;
|
||||
pub type CliByonmNpmResolver = ByonmNpmResolver<CliDenoResolverFs>;
|
||||
|
||||
// todo(dsherret): the services hanging off `CliNpmResolver` doesn't seem ideal. We should probably decouple.
|
||||
#[derive(Debug)]
|
||||
pub struct ByonmCliNpmResolver {
|
||||
fs: Arc<dyn FileSystem>,
|
||||
root_node_modules_dir: Option<PathBuf>,
|
||||
}
|
||||
struct CliByonmWrapper(Arc<CliByonmNpmResolver>);
|
||||
|
||||
impl ByonmCliNpmResolver {
|
||||
fn load_pkg_json(
|
||||
&self,
|
||||
path: &Path,
|
||||
) -> Result<Option<Arc<PackageJson>>, PackageJsonLoadError> {
|
||||
load_pkg_json(&DenoPkgJsonFsAdapter(self.fs.as_ref()), path)
|
||||
}
|
||||
|
||||
/// Finds the ancestor package.json that contains the specified dependency.
|
||||
pub fn find_ancestor_package_json_with_dep(
|
||||
&self,
|
||||
dep_name: &str,
|
||||
referrer: &ModuleSpecifier,
|
||||
) -> Option<Arc<PackageJson>> {
|
||||
let referrer_path = referrer.to_file_path().ok()?;
|
||||
let mut current_folder = referrer_path.parent()?;
|
||||
loop {
|
||||
let pkg_json_path = current_folder.join("package.json");
|
||||
if let Ok(Some(pkg_json)) = self.load_pkg_json(&pkg_json_path) {
|
||||
if let Some(deps) = &pkg_json.dependencies {
|
||||
if deps.contains_key(dep_name) {
|
||||
return Some(pkg_json);
|
||||
}
|
||||
}
|
||||
if let Some(deps) = &pkg_json.dev_dependencies {
|
||||
if deps.contains_key(dep_name) {
|
||||
return Some(pkg_json);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(parent) = current_folder.parent() {
|
||||
current_folder = parent;
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_pkg_json_and_alias_for_req(
|
||||
&self,
|
||||
req: &PackageReq,
|
||||
referrer: &ModuleSpecifier,
|
||||
) -> Result<Option<(Arc<PackageJson>, String)>, AnyError> {
|
||||
fn resolve_alias_from_pkg_json(
|
||||
req: &PackageReq,
|
||||
pkg_json: &PackageJson,
|
||||
) -> Option<String> {
|
||||
let deps = pkg_json.resolve_local_package_json_deps();
|
||||
for (key, value) in deps {
|
||||
if let Ok(value) = value {
|
||||
match value {
|
||||
PackageJsonDepValue::Req(dep_req) => {
|
||||
if dep_req.name == req.name
|
||||
&& dep_req.version_req.intersects(&req.version_req)
|
||||
{
|
||||
return Some(key);
|
||||
}
|
||||
}
|
||||
PackageJsonDepValue::Workspace(_workspace) => {
|
||||
if key == req.name && req.version_req.tag() == Some("workspace") {
|
||||
return Some(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
// attempt to resolve the npm specifier from the referrer's package.json,
|
||||
if let Ok(file_path) = specifier_to_file_path(referrer) {
|
||||
let mut current_path = file_path.as_path();
|
||||
while let Some(dir_path) = current_path.parent() {
|
||||
let package_json_path = dir_path.join("package.json");
|
||||
if let Some(pkg_json) = self.load_pkg_json(&package_json_path)? {
|
||||
if let Some(alias) =
|
||||
resolve_alias_from_pkg_json(req, pkg_json.as_ref())
|
||||
{
|
||||
return Ok(Some((pkg_json, alias)));
|
||||
}
|
||||
}
|
||||
current_path = dir_path;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise, fall fallback to the project's package.json
|
||||
if let Some(root_node_modules_dir) = &self.root_node_modules_dir {
|
||||
let root_pkg_json_path =
|
||||
root_node_modules_dir.parent().unwrap().join("package.json");
|
||||
if let Some(pkg_json) = self.load_pkg_json(&root_pkg_json_path)? {
|
||||
if let Some(alias) = resolve_alias_from_pkg_json(req, pkg_json.as_ref())
|
||||
{
|
||||
return Ok(Some((pkg_json, alias)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn resolve_folder_in_root_node_modules(
|
||||
&self,
|
||||
req: &PackageReq,
|
||||
) -> Option<PathBuf> {
|
||||
// now check if node_modules/.deno/ matches this constraint
|
||||
let root_node_modules_dir = self.root_node_modules_dir.as_ref()?;
|
||||
let node_modules_deno_dir = root_node_modules_dir.join(".deno");
|
||||
let Ok(entries) = self.fs.read_dir_sync(&node_modules_deno_dir) else {
|
||||
return None;
|
||||
};
|
||||
let search_prefix = format!(
|
||||
"{}@",
|
||||
normalize_pkg_name_for_node_modules_deno_folder(&req.name)
|
||||
);
|
||||
let mut best_version = None;
|
||||
|
||||
// example entries:
|
||||
// - @denotest+add@1.0.0
|
||||
// - @denotest+add@1.0.0_1
|
||||
for entry in entries {
|
||||
if !entry.is_directory {
|
||||
continue;
|
||||
}
|
||||
let Some(version_and_copy_idx) = entry.name.strip_prefix(&search_prefix)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let version = version_and_copy_idx
|
||||
.rsplit_once('_')
|
||||
.map(|(v, _)| v)
|
||||
.unwrap_or(version_and_copy_idx);
|
||||
let Ok(version) = Version::parse_from_npm(version) else {
|
||||
continue;
|
||||
};
|
||||
if req.version_req.matches(&version) {
|
||||
if let Some((best_version_version, _)) = &best_version {
|
||||
if version > *best_version_version {
|
||||
best_version = Some((version, entry.name));
|
||||
}
|
||||
} else {
|
||||
best_version = Some((version, entry.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
best_version.map(|(_version, entry_name)| {
|
||||
join_package_name(
|
||||
&node_modules_deno_dir.join(entry_name).join("node_modules"),
|
||||
&req.name,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl NpmResolver for ByonmCliNpmResolver {
|
||||
fn resolve_package_folder_from_package(
|
||||
&self,
|
||||
name: &str,
|
||||
referrer: &ModuleSpecifier,
|
||||
) -> Result<PathBuf, PackageFolderResolveError> {
|
||||
fn inner(
|
||||
fs: &dyn FileSystem,
|
||||
name: &str,
|
||||
referrer: &ModuleSpecifier,
|
||||
) -> Result<PathBuf, PackageFolderResolveError> {
|
||||
let maybe_referrer_file = specifier_to_file_path(referrer).ok();
|
||||
let maybe_start_folder =
|
||||
maybe_referrer_file.as_ref().and_then(|f| f.parent());
|
||||
if let Some(start_folder) = maybe_start_folder {
|
||||
for current_folder in start_folder.ancestors() {
|
||||
let node_modules_folder = if current_folder.ends_with("node_modules")
|
||||
{
|
||||
Cow::Borrowed(current_folder)
|
||||
} else {
|
||||
Cow::Owned(current_folder.join("node_modules"))
|
||||
};
|
||||
|
||||
let sub_dir = join_package_name(&node_modules_folder, name);
|
||||
if fs.is_dir_sync(&sub_dir) {
|
||||
return Ok(sub_dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(
|
||||
PackageNotFoundError {
|
||||
package_name: name.to_string(),
|
||||
referrer: referrer.clone(),
|
||||
referrer_extra: None,
|
||||
}
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
||||
let path = inner(&*self.fs, name, referrer)?;
|
||||
self.fs.realpath_sync(&path).map_err(|err| {
|
||||
PackageFolderResolveIoError {
|
||||
package_name: name.to_string(),
|
||||
referrer: referrer.clone(),
|
||||
source: err.into_io_error(),
|
||||
}
|
||||
.into()
|
||||
})
|
||||
}
|
||||
|
||||
fn in_npm_package(&self, specifier: &ModuleSpecifier) -> bool {
|
||||
specifier.scheme() == "file"
|
||||
&& specifier
|
||||
.path()
|
||||
.to_ascii_lowercase()
|
||||
.contains("/node_modules/")
|
||||
}
|
||||
}
|
||||
|
||||
impl NodeRequireResolver for ByonmCliNpmResolver {
|
||||
impl NodeRequireResolver for CliByonmWrapper {
|
||||
fn ensure_read_permission(
|
||||
&self,
|
||||
permissions: &mut dyn NodePermissions,
|
||||
|
@ -286,110 +46,54 @@ impl NodeRequireResolver for ByonmCliNpmResolver {
|
|||
}
|
||||
}
|
||||
|
||||
impl NpmProcessStateProvider for ByonmCliNpmResolver {
|
||||
impl NpmProcessStateProvider for CliByonmWrapper {
|
||||
fn get_npm_process_state(&self) -> String {
|
||||
serde_json::to_string(&NpmProcessState {
|
||||
kind: NpmProcessStateKind::Byonm,
|
||||
local_node_modules_path: self
|
||||
.root_node_modules_dir
|
||||
.as_ref()
|
||||
.0
|
||||
.root_node_modules_dir()
|
||||
.map(|p| p.to_string_lossy().to_string()),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl CliNpmResolver for ByonmCliNpmResolver {
|
||||
impl CliNpmResolver for CliByonmNpmResolver {
|
||||
fn into_npm_resolver(self: Arc<Self>) -> Arc<dyn NpmResolver> {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_require_resolver(self: Arc<Self>) -> Arc<dyn NodeRequireResolver> {
|
||||
self
|
||||
Arc::new(CliByonmWrapper(self))
|
||||
}
|
||||
|
||||
fn into_process_state_provider(
|
||||
self: Arc<Self>,
|
||||
) -> Arc<dyn NpmProcessStateProvider> {
|
||||
self
|
||||
Arc::new(CliByonmWrapper(self))
|
||||
}
|
||||
|
||||
fn clone_snapshotted(&self) -> Arc<dyn CliNpmResolver> {
|
||||
Arc::new(Self {
|
||||
fs: self.fs.clone(),
|
||||
root_node_modules_dir: self.root_node_modules_dir.clone(),
|
||||
})
|
||||
Arc::new(self.clone())
|
||||
}
|
||||
|
||||
fn as_inner(&self) -> InnerCliNpmResolverRef {
|
||||
InnerCliNpmResolverRef::Byonm(self)
|
||||
}
|
||||
|
||||
fn root_node_modules_path(&self) -> Option<&PathBuf> {
|
||||
self.root_node_modules_dir.as_ref()
|
||||
fn root_node_modules_path(&self) -> Option<&Path> {
|
||||
self.root_node_modules_dir()
|
||||
}
|
||||
|
||||
fn resolve_pkg_folder_from_deno_module_req(
|
||||
&self,
|
||||
req: &PackageReq,
|
||||
referrer: &ModuleSpecifier,
|
||||
referrer: &Url,
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
fn node_resolve_dir(
|
||||
fs: &dyn FileSystem,
|
||||
alias: &str,
|
||||
start_dir: &Path,
|
||||
) -> Result<Option<PathBuf>, AnyError> {
|
||||
for ancestor in start_dir.ancestors() {
|
||||
let node_modules_folder = ancestor.join("node_modules");
|
||||
let sub_dir = join_package_name(&node_modules_folder, alias);
|
||||
if fs.is_dir_sync(&sub_dir) {
|
||||
return Ok(Some(canonicalize_path_maybe_not_exists_with_fs(
|
||||
&sub_dir, fs,
|
||||
)?));
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
// now attempt to resolve if it's found in any package.json
|
||||
let maybe_pkg_json_and_alias =
|
||||
self.resolve_pkg_json_and_alias_for_req(req, referrer)?;
|
||||
match maybe_pkg_json_and_alias {
|
||||
Some((pkg_json, alias)) => {
|
||||
// now try node resolution
|
||||
if let Some(resolved) =
|
||||
node_resolve_dir(self.fs.as_ref(), &alias, pkg_json.dir_path())?
|
||||
{
|
||||
return Ok(resolved);
|
||||
}
|
||||
|
||||
bail!(
|
||||
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,
|
||||
);
|
||||
}
|
||||
None => {
|
||||
// now check if node_modules/.deno/ matches this constraint
|
||||
if let Some(folder) = self.resolve_folder_in_root_node_modules(req) {
|
||||
return Ok(folder);
|
||||
}
|
||||
|
||||
bail!(
|
||||
concat!(
|
||||
"Could not find a matching package for 'npm:{}' in the node_modules ",
|
||||
"directory. Ensure you have all your JSR and npm dependencies listed ",
|
||||
"in your deno.json or package.json, then run `deno install`. Alternatively, ",
|
||||
r#"turn on auto-install by specifying `"nodeModulesDir": "auto"` in your "#,
|
||||
"deno.json file."
|
||||
),
|
||||
req,
|
||||
);
|
||||
}
|
||||
}
|
||||
ByonmNpmResolver::resolve_pkg_folder_from_deno_module_req(
|
||||
self, req, referrer,
|
||||
)
|
||||
}
|
||||
|
||||
fn check_state_hash(&self) -> Option<u64> {
|
||||
|
@ -398,12 +102,3 @@ impl CliNpmResolver for ByonmCliNpmResolver {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn join_package_name(path: &Path, package_name: &str) -> PathBuf {
|
||||
let mut path = path.to_path_buf();
|
||||
// ensure backslashes are used on windows
|
||||
for part in package_name.split('/') {
|
||||
path = path.join(part);
|
||||
}
|
||||
path
|
||||
}
|
||||
|
|
|
@ -1,295 +0,0 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use deno_ast::ModuleSpecifier;
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::url::Url;
|
||||
use deno_npm::NpmPackageCacheFolderId;
|
||||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::Version;
|
||||
|
||||
use crate::util::fs::canonicalize_path;
|
||||
use crate::util::path::root_url_to_safe_local_dirname;
|
||||
|
||||
/// The global cache directory of npm packages.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NpmCacheDir {
|
||||
root_dir: PathBuf,
|
||||
// cached url representation of the root directory
|
||||
root_dir_url: Url,
|
||||
// A list of all registry that were discovered via `.npmrc` files
|
||||
// turned into a safe directory names.
|
||||
known_registries_dirnames: Vec<String>,
|
||||
}
|
||||
|
||||
impl NpmCacheDir {
|
||||
pub fn new(root_dir: PathBuf, known_registries_urls: Vec<Url>) -> Self {
|
||||
fn try_get_canonicalized_root_dir(
|
||||
root_dir: &Path,
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
if !root_dir.exists() {
|
||||
std::fs::create_dir_all(root_dir)
|
||||
.with_context(|| format!("Error creating {}", root_dir.display()))?;
|
||||
}
|
||||
Ok(canonicalize_path(root_dir)?)
|
||||
}
|
||||
|
||||
// this may fail on readonly file systems, so just ignore if so
|
||||
let root_dir =
|
||||
try_get_canonicalized_root_dir(&root_dir).unwrap_or(root_dir);
|
||||
let root_dir_url = Url::from_directory_path(&root_dir).unwrap();
|
||||
|
||||
let known_registries_dirnames: Vec<_> = known_registries_urls
|
||||
.into_iter()
|
||||
.map(|url| {
|
||||
root_url_to_safe_local_dirname(&url)
|
||||
.to_string_lossy()
|
||||
.replace('\\', "/")
|
||||
})
|
||||
.collect();
|
||||
|
||||
Self {
|
||||
root_dir,
|
||||
root_dir_url,
|
||||
known_registries_dirnames,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn root_dir(&self) -> &Path {
|
||||
&self.root_dir
|
||||
}
|
||||
|
||||
pub fn root_dir_url(&self) -> &Url {
|
||||
&self.root_dir_url
|
||||
}
|
||||
|
||||
pub fn package_folder_for_id(
|
||||
&self,
|
||||
folder_id: &NpmPackageCacheFolderId,
|
||||
registry_url: &Url,
|
||||
) -> PathBuf {
|
||||
if folder_id.copy_index == 0 {
|
||||
self.package_folder_for_nv(&folder_id.nv, registry_url)
|
||||
} else {
|
||||
self
|
||||
.package_name_folder(&folder_id.nv.name, registry_url)
|
||||
.join(format!("{}_{}", folder_id.nv.version, folder_id.copy_index))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn package_folder_for_nv(
|
||||
&self,
|
||||
package: &PackageNv,
|
||||
registry_url: &Url,
|
||||
) -> PathBuf {
|
||||
self
|
||||
.package_name_folder(&package.name, registry_url)
|
||||
.join(package.version.to_string())
|
||||
}
|
||||
|
||||
pub fn package_name_folder(&self, name: &str, registry_url: &Url) -> PathBuf {
|
||||
let mut dir = self.registry_folder(registry_url);
|
||||
if name.to_lowercase() != name {
|
||||
let encoded_name = mixed_case_package_name_encode(name);
|
||||
// Using the encoded directory may have a collision with an actual package name
|
||||
// so prefix it with an underscore since npm packages can't start with that
|
||||
dir.join(format!("_{encoded_name}"))
|
||||
} else {
|
||||
// ensure backslashes are used on windows
|
||||
for part in name.split('/') {
|
||||
dir = dir.join(part);
|
||||
}
|
||||
dir
|
||||
}
|
||||
}
|
||||
|
||||
fn registry_folder(&self, registry_url: &Url) -> PathBuf {
|
||||
self
|
||||
.root_dir
|
||||
.join(root_url_to_safe_local_dirname(registry_url))
|
||||
}
|
||||
|
||||
pub fn resolve_package_folder_id_from_specifier(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
) -> Option<NpmPackageCacheFolderId> {
|
||||
let mut maybe_relative_url = None;
|
||||
|
||||
// Iterate through known registries and try to get a match.
|
||||
for registry_dirname in &self.known_registries_dirnames {
|
||||
let registry_root_dir = self
|
||||
.root_dir_url
|
||||
.join(&format!("{}/", registry_dirname))
|
||||
// this not succeeding indicates a fatal issue, so unwrap
|
||||
.unwrap();
|
||||
|
||||
let Some(relative_url) = registry_root_dir.make_relative(specifier)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if relative_url.starts_with("../") {
|
||||
continue;
|
||||
}
|
||||
|
||||
maybe_relative_url = Some(relative_url);
|
||||
break;
|
||||
}
|
||||
|
||||
let mut relative_url = maybe_relative_url?;
|
||||
|
||||
// base32 decode the url if it starts with an underscore
|
||||
// * Ex. _{base32(package_name)}/
|
||||
if let Some(end_url) = relative_url.strip_prefix('_') {
|
||||
let mut parts = end_url
|
||||
.split('/')
|
||||
.map(ToOwned::to_owned)
|
||||
.collect::<Vec<_>>();
|
||||
match mixed_case_package_name_decode(&parts[0]) {
|
||||
Some(part) => {
|
||||
parts[0] = part;
|
||||
}
|
||||
None => return None,
|
||||
}
|
||||
relative_url = parts.join("/");
|
||||
}
|
||||
|
||||
// examples:
|
||||
// * chalk/5.0.1/
|
||||
// * @types/chalk/5.0.1/
|
||||
// * some-package/5.0.1_1/ -- where the `_1` (/_\d+/) is a copy of the folder for peer deps
|
||||
let is_scoped_package = relative_url.starts_with('@');
|
||||
let mut parts = relative_url
|
||||
.split('/')
|
||||
.enumerate()
|
||||
.take(if is_scoped_package { 3 } else { 2 })
|
||||
.map(|(_, part)| part)
|
||||
.collect::<Vec<_>>();
|
||||
if parts.len() < 2 {
|
||||
return None;
|
||||
}
|
||||
let version_part = parts.pop().unwrap();
|
||||
let name = parts.join("/");
|
||||
let (version, copy_index) =
|
||||
if let Some((version, copy_count)) = version_part.split_once('_') {
|
||||
(version, copy_count.parse::<u8>().ok()?)
|
||||
} else {
|
||||
(version_part, 0)
|
||||
};
|
||||
Some(NpmPackageCacheFolderId {
|
||||
nv: PackageNv {
|
||||
name,
|
||||
version: Version::parse_from_npm(version).ok()?,
|
||||
},
|
||||
copy_index,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_cache_location(&self) -> PathBuf {
|
||||
self.root_dir.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mixed_case_package_name_encode(name: &str) -> String {
|
||||
// use base32 encoding because it's reversible and the character set
|
||||
// only includes the characters within 0-9 and A-Z so it can be lower cased
|
||||
base32::encode(
|
||||
base32::Alphabet::Rfc4648Lower { padding: false },
|
||||
name.as_bytes(),
|
||||
)
|
||||
.to_lowercase()
|
||||
}
|
||||
|
||||
pub fn mixed_case_package_name_decode(name: &str) -> Option<String> {
|
||||
base32::decode(base32::Alphabet::Rfc4648Lower { padding: false }, name)
|
||||
.and_then(|b| String::from_utf8(b).ok())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use deno_core::url::Url;
|
||||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::Version;
|
||||
|
||||
use super::NpmCacheDir;
|
||||
use crate::npm::cache_dir::NpmPackageCacheFolderId;
|
||||
|
||||
#[test]
|
||||
fn should_get_package_folder() {
|
||||
let deno_dir = crate::cache::DenoDir::new(None).unwrap();
|
||||
let root_dir = deno_dir.npm_folder_path();
|
||||
let registry_url = Url::parse("https://registry.npmjs.org/").unwrap();
|
||||
let cache = NpmCacheDir::new(root_dir.clone(), vec![registry_url.clone()]);
|
||||
|
||||
assert_eq!(
|
||||
cache.package_folder_for_id(
|
||||
&NpmPackageCacheFolderId {
|
||||
nv: PackageNv {
|
||||
name: "json".to_string(),
|
||||
version: Version::parse_from_npm("1.2.5").unwrap(),
|
||||
},
|
||||
copy_index: 0,
|
||||
},
|
||||
®istry_url,
|
||||
),
|
||||
root_dir
|
||||
.join("registry.npmjs.org")
|
||||
.join("json")
|
||||
.join("1.2.5"),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
cache.package_folder_for_id(
|
||||
&NpmPackageCacheFolderId {
|
||||
nv: PackageNv {
|
||||
name: "json".to_string(),
|
||||
version: Version::parse_from_npm("1.2.5").unwrap(),
|
||||
},
|
||||
copy_index: 1,
|
||||
},
|
||||
®istry_url,
|
||||
),
|
||||
root_dir
|
||||
.join("registry.npmjs.org")
|
||||
.join("json")
|
||||
.join("1.2.5_1"),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
cache.package_folder_for_id(
|
||||
&NpmPackageCacheFolderId {
|
||||
nv: PackageNv {
|
||||
name: "JSON".to_string(),
|
||||
version: Version::parse_from_npm("2.1.5").unwrap(),
|
||||
},
|
||||
copy_index: 0,
|
||||
},
|
||||
®istry_url,
|
||||
),
|
||||
root_dir
|
||||
.join("registry.npmjs.org")
|
||||
.join("_jjju6tq")
|
||||
.join("2.1.5"),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
cache.package_folder_for_id(
|
||||
&NpmPackageCacheFolderId {
|
||||
nv: PackageNv {
|
||||
name: "@types/JSON".to_string(),
|
||||
version: Version::parse_from_npm("2.1.5").unwrap(),
|
||||
},
|
||||
copy_index: 0,
|
||||
},
|
||||
®istry_url,
|
||||
),
|
||||
root_dir
|
||||
.join("registry.npmjs.org")
|
||||
.join("_ib2hs4dfomxuuu2pjy")
|
||||
.join("2.1.5"),
|
||||
);
|
||||
}
|
||||
}
|
44
cli/npm/managed/cache/mod.rs
vendored
44
cli/npm/managed/cache/mod.rs
vendored
|
@ -8,6 +8,7 @@ use std::path::PathBuf;
|
|||
use std::sync::Arc;
|
||||
|
||||
use deno_ast::ModuleSpecifier;
|
||||
use deno_cache_dir::npm::NpmCacheDir;
|
||||
use deno_core::anyhow::bail;
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::error::AnyError;
|
||||
|
@ -18,10 +19,10 @@ use deno_npm::npm_rc::ResolvedNpmRc;
|
|||
use deno_npm::registry::NpmPackageInfo;
|
||||
use deno_npm::NpmPackageCacheFolderId;
|
||||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::Version;
|
||||
|
||||
use crate::args::CacheSetting;
|
||||
use crate::cache::CACHE_PERM;
|
||||
use crate::npm::NpmCacheDir;
|
||||
use crate::util::fs::atomic_write_file_with_retries;
|
||||
use crate::util::fs::hard_link_dir_recursive;
|
||||
|
||||
|
@ -87,9 +88,12 @@ impl NpmCache {
|
|||
) -> Result<(), AnyError> {
|
||||
let registry_url = self.npmrc.get_registry_url(&folder_id.nv.name);
|
||||
assert_ne!(folder_id.copy_index, 0);
|
||||
let package_folder = self
|
||||
.cache_dir
|
||||
.package_folder_for_id(folder_id, registry_url);
|
||||
let package_folder = self.cache_dir.package_folder_for_id(
|
||||
&folder_id.nv.name,
|
||||
&folder_id.nv.version.to_string(),
|
||||
folder_id.copy_index,
|
||||
registry_url,
|
||||
);
|
||||
|
||||
if package_folder.exists()
|
||||
// if this file exists, then the package didn't successfully initialize
|
||||
|
@ -100,9 +104,12 @@ impl NpmCache {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
let original_package_folder = self
|
||||
.cache_dir
|
||||
.package_folder_for_nv(&folder_id.nv, registry_url);
|
||||
let original_package_folder = self.cache_dir.package_folder_for_id(
|
||||
&folder_id.nv.name,
|
||||
&folder_id.nv.version.to_string(),
|
||||
0, // original copy index
|
||||
registry_url,
|
||||
);
|
||||
|
||||
// it seems Windows does an "AccessDenied" error when moving a
|
||||
// directory with hard links, so that's why this solution is done
|
||||
|
@ -114,7 +121,12 @@ impl NpmCache {
|
|||
|
||||
pub fn package_folder_for_id(&self, id: &NpmPackageCacheFolderId) -> PathBuf {
|
||||
let registry_url = self.npmrc.get_registry_url(&id.nv.name);
|
||||
self.cache_dir.package_folder_for_id(id, registry_url)
|
||||
self.cache_dir.package_folder_for_id(
|
||||
&id.nv.name,
|
||||
&id.nv.version.to_string(),
|
||||
id.copy_index,
|
||||
registry_url,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn package_folder_for_nv(&self, package: &PackageNv) -> PathBuf {
|
||||
|
@ -127,7 +139,12 @@ impl NpmCache {
|
|||
package: &PackageNv,
|
||||
registry_url: &Url,
|
||||
) -> PathBuf {
|
||||
self.cache_dir.package_folder_for_nv(package, registry_url)
|
||||
self.cache_dir.package_folder_for_id(
|
||||
&package.name,
|
||||
&package.version.to_string(),
|
||||
0, // original copy_index
|
||||
registry_url,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn package_name_folder(&self, name: &str) -> PathBuf {
|
||||
|
@ -146,6 +163,15 @@ impl NpmCache {
|
|||
self
|
||||
.cache_dir
|
||||
.resolve_package_folder_id_from_specifier(specifier)
|
||||
.and_then(|cache_id| {
|
||||
Some(NpmPackageCacheFolderId {
|
||||
nv: PackageNv {
|
||||
name: cache_id.name,
|
||||
version: Version::parse_from_npm(&cache_id.version).ok()?,
|
||||
},
|
||||
copy_index: cache_id.copy_index,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn load_package_info(
|
||||
|
|
|
@ -7,6 +7,7 @@ use std::sync::Arc;
|
|||
use cache::RegistryInfoDownloader;
|
||||
use cache::TarballCache;
|
||||
use deno_ast::ModuleSpecifier;
|
||||
use deno_cache_dir::npm::NpmCacheDir;
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json;
|
||||
|
@ -22,7 +23,7 @@ use deno_npm::NpmSystemInfo;
|
|||
use deno_runtime::deno_fs::FileSystem;
|
||||
use deno_runtime::deno_node::NodePermissions;
|
||||
use deno_runtime::deno_node::NodeRequireResolver;
|
||||
use deno_runtime::deno_node::NpmProcessStateProvider;
|
||||
use deno_runtime::ops::process::NpmProcessStateProvider;
|
||||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::package::PackageReq;
|
||||
use node_resolver::errors::PackageFolderResolveError;
|
||||
|
@ -35,6 +36,7 @@ use crate::args::LifecycleScriptsConfig;
|
|||
use crate::args::NpmInstallDepsProvider;
|
||||
use crate::args::NpmProcessState;
|
||||
use crate::args::NpmProcessStateKind;
|
||||
use crate::cache::DenoCacheEnvFsAdapter;
|
||||
use crate::cache::FastInsecureHasher;
|
||||
use crate::http_util::HttpClientProvider;
|
||||
use crate::util::fs::canonicalize_path_maybe_not_exists_with_fs;
|
||||
|
@ -45,12 +47,10 @@ use self::cache::NpmCache;
|
|||
use self::registry::CliNpmRegistryApi;
|
||||
use self::resolution::NpmResolution;
|
||||
use self::resolvers::create_npm_fs_resolver;
|
||||
pub use self::resolvers::normalize_pkg_name_for_node_modules_deno_folder;
|
||||
use self::resolvers::NpmPackageFsResolver;
|
||||
|
||||
use super::CliNpmResolver;
|
||||
use super::InnerCliNpmResolverRef;
|
||||
use super::NpmCacheDir;
|
||||
|
||||
mod cache;
|
||||
mod registry;
|
||||
|
@ -188,6 +188,7 @@ fn create_inner(
|
|||
fn create_cache(options: &CliNpmResolverManagedCreateOptions) -> Arc<NpmCache> {
|
||||
Arc::new(NpmCache::new(
|
||||
NpmCacheDir::new(
|
||||
&DenoCacheEnvFsAdapter(options.fs.as_ref()),
|
||||
options.npm_global_cache_dir.clone(),
|
||||
options.npmrc.get_all_known_registries_urls(),
|
||||
),
|
||||
|
@ -427,6 +428,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,
|
||||
|
@ -573,7 +584,7 @@ impl NpmProcessStateProvider for ManagedCliNpmResolver {
|
|||
fn get_npm_process_state(&self) -> String {
|
||||
npm_process_state(
|
||||
self.resolution.serialized_valid_snapshot(),
|
||||
self.fs_resolver.node_modules_path().map(|p| p.as_path()),
|
||||
self.fs_resolver.node_modules_path(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -630,7 +641,7 @@ impl CliNpmResolver for ManagedCliNpmResolver {
|
|||
InnerCliNpmResolverRef::Managed(self)
|
||||
}
|
||||
|
||||
fn root_node_modules_path(&self) -> Option<&PathBuf> {
|
||||
fn root_node_modules_path(&self) -> Option<&Path> {
|
||||
self.fs_resolver.node_modules_path()
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ pub trait NpmPackageFsResolver: Send + Sync {
|
|||
fn root_dir_url(&self) -> &Url;
|
||||
|
||||
/// The local node_modules folder if it is applicable to the implementation.
|
||||
fn node_modules_path(&self) -> Option<&PathBuf>;
|
||||
fn node_modules_path(&self) -> Option<&Path>;
|
||||
|
||||
fn maybe_package_folder(&self, package_id: &NpmPackageId) -> Option<PathBuf>;
|
||||
|
||||
|
|
|
@ -69,7 +69,11 @@ impl<'a> BinEntries<'a> {
|
|||
fn for_each_entry(
|
||||
&mut self,
|
||||
snapshot: &NpmResolutionSnapshot,
|
||||
mut f: impl FnMut(
|
||||
mut already_seen: impl FnMut(
|
||||
&Path,
|
||||
&str, // bin script
|
||||
) -> Result<(), AnyError>,
|
||||
mut new: impl FnMut(
|
||||
&NpmResolutionPackage,
|
||||
&Path,
|
||||
&str, // bin name
|
||||
|
@ -90,18 +94,20 @@ impl<'a> BinEntries<'a> {
|
|||
deno_npm::registry::NpmPackageVersionBinEntry::String(script) => {
|
||||
let name = default_bin_name(package);
|
||||
if !seen.insert(name) {
|
||||
already_seen(package_path, script)?;
|
||||
// we already set up a bin entry with this name
|
||||
continue;
|
||||
}
|
||||
f(package, package_path, name, script)?;
|
||||
new(package, package_path, name, script)?;
|
||||
}
|
||||
deno_npm::registry::NpmPackageVersionBinEntry::Map(entries) => {
|
||||
for (name, script) in entries {
|
||||
if !seen.insert(name) {
|
||||
already_seen(package_path, script)?;
|
||||
// we already set up a bin entry with this name
|
||||
continue;
|
||||
}
|
||||
f(package, package_path, name, script)?;
|
||||
new(package, package_path, name, script)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -118,10 +124,14 @@ impl<'a> BinEntries<'a> {
|
|||
) -> Vec<(String, PathBuf)> {
|
||||
let mut bins = Vec::new();
|
||||
self
|
||||
.for_each_entry(snapshot, |_, package_path, name, script| {
|
||||
bins.push((name.to_string(), package_path.join(script)));
|
||||
Ok(())
|
||||
})
|
||||
.for_each_entry(
|
||||
snapshot,
|
||||
|_, _| Ok(()),
|
||||
|_, package_path, name, script| {
|
||||
bins.push((name.to_string(), package_path.join(script)));
|
||||
Ok(())
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
bins
|
||||
}
|
||||
|
@ -139,15 +149,26 @@ impl<'a> BinEntries<'a> {
|
|||
)?;
|
||||
}
|
||||
|
||||
self.for_each_entry(snapshot, |package, package_path, name, script| {
|
||||
set_up_bin_entry(
|
||||
package,
|
||||
name,
|
||||
script,
|
||||
package_path,
|
||||
bin_node_modules_dir_path,
|
||||
)
|
||||
})?;
|
||||
self.for_each_entry(
|
||||
snapshot,
|
||||
|_package_path, _script| {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let path = _package_path.join(_script);
|
||||
make_executable_if_exists(&path)?;
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
|package, package_path, name, script| {
|
||||
set_up_bin_entry(
|
||||
package,
|
||||
name,
|
||||
script,
|
||||
package_path,
|
||||
bin_node_modules_dir_path,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -254,6 +275,32 @@ fn set_up_bin_shim(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
/// Make the file at `path` executable if it exists.
|
||||
/// Returns `true` if the file exists, `false` otherwise.
|
||||
fn make_executable_if_exists(path: &Path) -> Result<bool, AnyError> {
|
||||
use std::io;
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let mut perms = match std::fs::metadata(path) {
|
||||
Ok(metadata) => metadata.permissions(),
|
||||
Err(err) => {
|
||||
if err.kind() == io::ErrorKind::NotFound {
|
||||
return Ok(false);
|
||||
}
|
||||
return Err(err.into());
|
||||
}
|
||||
};
|
||||
if perms.mode() & 0o111 == 0 {
|
||||
// if the original file is not executable, make it executable
|
||||
perms.set_mode(perms.mode() | 0o111);
|
||||
std::fs::set_permissions(path, perms).with_context(|| {
|
||||
format!("Setting permissions on '{}'", path.display())
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn symlink_bin_entry(
|
||||
_package: &NpmResolutionPackage,
|
||||
|
@ -267,32 +314,20 @@ fn symlink_bin_entry(
|
|||
let link = bin_node_modules_dir_path.join(bin_name);
|
||||
let original = package_path.join(bin_script);
|
||||
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let mut perms = match std::fs::metadata(&original) {
|
||||
Ok(metadata) => metadata.permissions(),
|
||||
Err(err) => {
|
||||
if err.kind() == io::ErrorKind::NotFound {
|
||||
log::warn!(
|
||||
"{} Trying to set up '{}' bin for \"{}\", but the entry point \"{}\" doesn't exist.",
|
||||
deno_terminal::colors::yellow("Warning"),
|
||||
bin_name,
|
||||
package_path.display(),
|
||||
original.display()
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
return Err(err).with_context(|| {
|
||||
format!("Can't set up '{}' bin at {}", bin_name, original.display())
|
||||
});
|
||||
}
|
||||
};
|
||||
if perms.mode() & 0o111 == 0 {
|
||||
// if the original file is not executable, make it executable
|
||||
perms.set_mode(perms.mode() | 0o111);
|
||||
std::fs::set_permissions(&original, perms).with_context(|| {
|
||||
format!("Setting permissions on '{}'", original.display())
|
||||
})?;
|
||||
let found = make_executable_if_exists(&original).with_context(|| {
|
||||
format!("Can't set up '{}' bin at {}", bin_name, original.display())
|
||||
})?;
|
||||
if !found {
|
||||
log::warn!(
|
||||
"{} Trying to set up '{}' bin for \"{}\", but the entry point \"{}\" doesn't exist.",
|
||||
deno_terminal::colors::yellow("Warning"),
|
||||
bin_name,
|
||||
package_path.display(),
|
||||
original.display()
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let original_relative =
|
||||
crate::util::path::relative_path(bin_node_modules_dir_path, &original)
|
||||
.unwrap_or(original);
|
||||
|
|
|
@ -2,8 +2,11 @@
|
|||
|
||||
use super::bin_entries::BinEntries;
|
||||
use crate::args::LifecycleScriptsConfig;
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_npm::resolution::NpmResolutionSnapshot;
|
||||
use deno_runtime::deno_io::FromRawIoHandle;
|
||||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::Version;
|
||||
use std::borrow::Cow;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
@ -111,8 +114,19 @@ impl<'a> LifecycleScripts<'a> {
|
|||
.push((package, package_path.into_owned()));
|
||||
}
|
||||
} else if !self.strategy.has_run(package)
|
||||
&& !self.strategy.has_warned(package)
|
||||
&& (self.config.explicit_install || !self.strategy.has_warned(package))
|
||||
{
|
||||
// Skip adding `esbuild` as it is known that it can work properly without lifecycle script
|
||||
// being run, and it's also very popular - any project using Vite would raise warnings.
|
||||
{
|
||||
let nv = &package.id.nv;
|
||||
if nv.name == "esbuild"
|
||||
&& nv.version >= Version::parse_standard("0.18.0").unwrap()
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self
|
||||
.packages_with_scripts_not_run
|
||||
.push((package, package_path.into_owned()));
|
||||
|
@ -151,9 +165,24 @@ impl<'a> LifecycleScripts<'a> {
|
|||
);
|
||||
|
||||
let mut env_vars = crate::task_runner::real_env_vars();
|
||||
// we want to pass the current state of npm resolution down to the deno subprocess
|
||||
// (that may be running as part of the script). we do this with an inherited temp file
|
||||
//
|
||||
// SAFETY: we are sharing a single temp file across all of the scripts. the file position
|
||||
// will be shared among these, which is okay since we run only one script at a time.
|
||||
// However, if we concurrently run scripts in the future we will
|
||||
// have to have multiple temp files.
|
||||
let temp_file_fd =
|
||||
deno_runtime::ops::process::npm_process_state_tempfile(
|
||||
process_state.as_bytes(),
|
||||
).context("failed to create npm process state tempfile for running lifecycle scripts")?;
|
||||
// SAFETY: fd/handle is valid
|
||||
let _temp_file =
|
||||
unsafe { std::fs::File::from_raw_io_handle(temp_file_fd) }; // make sure the file gets closed
|
||||
env_vars.insert(
|
||||
crate::args::NPM_RESOLUTION_STATE_ENV_VAR_NAME.to_string(),
|
||||
process_state,
|
||||
deno_runtime::ops::process::NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME
|
||||
.to_string(),
|
||||
(temp_file_fd as usize).to_string(),
|
||||
);
|
||||
for (package, package_path) in self.packages_with_scripts {
|
||||
// add custom commands for binaries from the package's dependencies. this will take precedence over the
|
||||
|
|
|
@ -73,7 +73,7 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver {
|
|||
self.cache.root_dir_url()
|
||||
}
|
||||
|
||||
fn node_modules_path(&self) -> Option<&PathBuf> {
|
||||
fn node_modules_path(&self) -> Option<&Path> {
|
||||
None
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ use crate::args::LifecycleScriptsConfig;
|
|||
use crate::colors;
|
||||
use async_trait::async_trait;
|
||||
use deno_ast::ModuleSpecifier;
|
||||
use deno_cache_dir::npm::mixed_case_package_name_decode;
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::futures::stream::FuturesUnordered;
|
||||
|
@ -30,6 +31,7 @@ use deno_npm::NpmPackageCacheFolderId;
|
|||
use deno_npm::NpmPackageId;
|
||||
use deno_npm::NpmResolutionPackage;
|
||||
use deno_npm::NpmSystemInfo;
|
||||
use deno_resolver::npm::normalize_pkg_name_for_node_modules_deno_folder;
|
||||
use deno_runtime::deno_fs;
|
||||
use deno_runtime::deno_node::NodePermissions;
|
||||
use deno_semver::package::PackageNv;
|
||||
|
@ -42,8 +44,6 @@ use serde::Serialize;
|
|||
|
||||
use crate::args::NpmInstallDepsProvider;
|
||||
use crate::cache::CACHE_PERM;
|
||||
use crate::npm::cache_dir::mixed_case_package_name_decode;
|
||||
use crate::npm::cache_dir::mixed_case_package_name_encode;
|
||||
use crate::util::fs::atomic_write_file_with_retries;
|
||||
use crate::util::fs::canonicalize_path_maybe_not_exists_with_fs;
|
||||
use crate::util::fs::clone_dir_recursive;
|
||||
|
@ -159,8 +159,8 @@ impl NpmPackageFsResolver for LocalNpmPackageResolver {
|
|||
&self.root_node_modules_url
|
||||
}
|
||||
|
||||
fn node_modules_path(&self) -> Option<&PathBuf> {
|
||||
Some(&self.root_node_modules_path)
|
||||
fn node_modules_path(&self) -> Option<&Path> {
|
||||
Some(self.root_node_modules_path.as_ref())
|
||||
}
|
||||
|
||||
fn maybe_package_folder(&self, id: &NpmPackageId) -> Option<PathBuf> {
|
||||
|
@ -920,20 +920,6 @@ impl SetupCache {
|
|||
}
|
||||
}
|
||||
|
||||
/// Normalizes a package name for use at `node_modules/.deno/<pkg-name>@<version>[_<copy_index>]`
|
||||
pub fn normalize_pkg_name_for_node_modules_deno_folder(name: &str) -> Cow<str> {
|
||||
let name = if name.to_lowercase() == name {
|
||||
Cow::Borrowed(name)
|
||||
} else {
|
||||
Cow::Owned(format!("_{}", mixed_case_package_name_encode(name)))
|
||||
};
|
||||
if name.starts_with('@') {
|
||||
name.replace('/', "+").into()
|
||||
} else {
|
||||
name
|
||||
}
|
||||
}
|
||||
|
||||
fn get_package_folder_id_folder_name(
|
||||
folder_id: &NpmPackageCacheFolderId,
|
||||
) -> String {
|
||||
|
|
|
@ -15,7 +15,6 @@ use crate::args::NpmInstallDepsProvider;
|
|||
use crate::util::progress_bar::ProgressBar;
|
||||
|
||||
pub use self::common::NpmPackageFsResolver;
|
||||
pub use self::local::normalize_pkg_name_for_node_modules_deno_folder;
|
||||
|
||||
use self::global::GlobalNpmPackageResolver;
|
||||
use self::local::LocalNpmPackageResolver;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
mod byonm;
|
||||
mod cache_dir;
|
||||
mod common;
|
||||
mod managed;
|
||||
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -13,8 +13,9 @@ use deno_ast::ModuleSpecifier;
|
|||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json;
|
||||
use deno_npm::registry::NpmPackageInfo;
|
||||
use deno_resolver::npm::ByonmNpmResolver;
|
||||
use deno_runtime::deno_node::NodeRequireResolver;
|
||||
use deno_runtime::deno_node::NpmProcessStateProvider;
|
||||
use deno_runtime::ops::process::NpmProcessStateProvider;
|
||||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::package::PackageReq;
|
||||
use node_resolver::NpmResolver;
|
||||
|
@ -22,16 +23,15 @@ use node_resolver::NpmResolver;
|
|||
use crate::args::npm_registry_url;
|
||||
use crate::file_fetcher::FileFetcher;
|
||||
|
||||
pub use self::byonm::ByonmCliNpmResolver;
|
||||
pub use self::byonm::CliNpmResolverByonmCreateOptions;
|
||||
pub use self::cache_dir::NpmCacheDir;
|
||||
pub use self::byonm::CliByonmNpmResolver;
|
||||
pub use self::byonm::CliByonmNpmResolverCreateOptions;
|
||||
pub use self::managed::CliNpmResolverManagedCreateOptions;
|
||||
pub use self::managed::CliNpmResolverManagedSnapshotOption;
|
||||
pub use self::managed::ManagedCliNpmResolver;
|
||||
|
||||
pub enum CliNpmResolverCreateOptions {
|
||||
Managed(CliNpmResolverManagedCreateOptions),
|
||||
Byonm(CliNpmResolverByonmCreateOptions),
|
||||
Byonm(CliByonmNpmResolverCreateOptions),
|
||||
}
|
||||
|
||||
pub async fn create_cli_npm_resolver_for_lsp(
|
||||
|
@ -42,7 +42,7 @@ pub async fn create_cli_npm_resolver_for_lsp(
|
|||
Managed(options) => {
|
||||
managed::create_managed_npm_resolver_for_lsp(options).await
|
||||
}
|
||||
Byonm(options) => byonm::create_byonm_npm_resolver(options),
|
||||
Byonm(options) => Arc::new(ByonmNpmResolver::new(options)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,14 +52,14 @@ pub async fn create_cli_npm_resolver(
|
|||
use CliNpmResolverCreateOptions::*;
|
||||
match options {
|
||||
Managed(options) => managed::create_managed_npm_resolver(options).await,
|
||||
Byonm(options) => Ok(byonm::create_byonm_npm_resolver(options)),
|
||||
Byonm(options) => Ok(Arc::new(ByonmNpmResolver::new(options))),
|
||||
}
|
||||
}
|
||||
|
||||
pub enum InnerCliNpmResolverRef<'a> {
|
||||
Managed(&'a ManagedCliNpmResolver),
|
||||
#[allow(dead_code)]
|
||||
Byonm(&'a ByonmCliNpmResolver),
|
||||
Byonm(&'a CliByonmNpmResolver),
|
||||
}
|
||||
|
||||
pub trait CliNpmResolver: NpmResolver {
|
||||
|
@ -80,14 +80,14 @@ pub trait CliNpmResolver: NpmResolver {
|
|||
}
|
||||
}
|
||||
|
||||
fn as_byonm(&self) -> Option<&ByonmCliNpmResolver> {
|
||||
fn as_byonm(&self) -> Option<&CliByonmNpmResolver> {
|
||||
match self.as_inner() {
|
||||
InnerCliNpmResolverRef::Managed(_) => None,
|
||||
InnerCliNpmResolverRef::Byonm(inner) => Some(inner),
|
||||
}
|
||||
}
|
||||
|
||||
fn root_node_modules_path(&self) -> Option<&PathBuf>;
|
||||
fn root_node_modules_path(&self) -> Option<&Path>;
|
||||
|
||||
fn resolve_pkg_folder_from_deno_module_req(
|
||||
&self,
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use std::time;
|
||||
|
||||
use deno_core::error::generic_error;
|
||||
|
@ -12,9 +11,7 @@ use deno_core::op2;
|
|||
use deno_core::v8;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_core::OpState;
|
||||
use deno_runtime::deno_permissions::create_child_permissions;
|
||||
use deno_runtime::deno_permissions::ChildPermissionsArg;
|
||||
use deno_runtime::deno_permissions::PermissionDescriptorParser;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use tokio::sync::mpsc::UnboundedSender;
|
||||
use uuid::Uuid;
|
||||
|
@ -61,19 +58,8 @@ pub fn op_pledge_test_permissions(
|
|||
#[serde] args: ChildPermissionsArg,
|
||||
) -> Result<Uuid, AnyError> {
|
||||
let token = Uuid::new_v4();
|
||||
let permission_desc_parser = state
|
||||
.borrow::<Arc<dyn PermissionDescriptorParser>>()
|
||||
.clone();
|
||||
let parent_permissions = state.borrow_mut::<PermissionsContainer>();
|
||||
let worker_permissions = {
|
||||
let mut parent_permissions = parent_permissions.inner.lock();
|
||||
let perms = create_child_permissions(
|
||||
permission_desc_parser.as_ref(),
|
||||
&mut parent_permissions,
|
||||
args,
|
||||
)?;
|
||||
PermissionsContainer::new(permission_desc_parser, perms)
|
||||
};
|
||||
let worker_permissions = parent_permissions.create_child_permissions(args)?;
|
||||
let parent_permissions = parent_permissions.clone();
|
||||
|
||||
if state.try_take::<PermissionsHolder>().is_some() {
|
||||
|
@ -83,7 +69,6 @@ pub fn op_pledge_test_permissions(
|
|||
state.put::<PermissionsHolder>(PermissionsHolder(token, parent_permissions));
|
||||
|
||||
// NOTE: This call overrides current permission set for the worker
|
||||
state.put(worker_permissions.inner.clone());
|
||||
state.put::<PermissionsContainer>(worker_permissions);
|
||||
|
||||
Ok(token)
|
||||
|
@ -100,7 +85,6 @@ pub fn op_restore_test_permissions(
|
|||
}
|
||||
|
||||
let permissions = permissions_holder.1;
|
||||
state.put(permissions.inner.clone());
|
||||
state.put::<PermissionsContainer>(permissions);
|
||||
Ok(())
|
||||
} else {
|
||||
|
|
|
@ -16,13 +16,10 @@ use deno_core::op2;
|
|||
use deno_core::v8;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_core::OpState;
|
||||
use deno_runtime::deno_permissions::create_child_permissions;
|
||||
use deno_runtime::deno_permissions::ChildPermissionsArg;
|
||||
use deno_runtime::deno_permissions::PermissionDescriptorParser;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use uuid::Uuid;
|
||||
|
||||
deno_core::extension!(deno_test,
|
||||
|
@ -56,19 +53,8 @@ pub fn op_pledge_test_permissions(
|
|||
#[serde] args: ChildPermissionsArg,
|
||||
) -> Result<Uuid, AnyError> {
|
||||
let token = Uuid::new_v4();
|
||||
let permission_desc_parser = state
|
||||
.borrow::<Arc<dyn PermissionDescriptorParser>>()
|
||||
.clone();
|
||||
let parent_permissions = state.borrow_mut::<PermissionsContainer>();
|
||||
let worker_permissions = {
|
||||
let mut parent_permissions = parent_permissions.inner.lock();
|
||||
let perms = create_child_permissions(
|
||||
permission_desc_parser.as_ref(),
|
||||
&mut parent_permissions,
|
||||
args,
|
||||
)?;
|
||||
PermissionsContainer::new(permission_desc_parser, perms)
|
||||
};
|
||||
let worker_permissions = parent_permissions.create_child_permissions(args)?;
|
||||
let parent_permissions = parent_permissions.clone();
|
||||
|
||||
if state.try_take::<PermissionsHolder>().is_some() {
|
||||
|
@ -77,7 +63,6 @@ pub fn op_pledge_test_permissions(
|
|||
state.put::<PermissionsHolder>(PermissionsHolder(token, parent_permissions));
|
||||
|
||||
// NOTE: This call overrides current permission set for the worker
|
||||
state.put(worker_permissions.inner.clone());
|
||||
state.put::<PermissionsContainer>(worker_permissions);
|
||||
|
||||
Ok(token)
|
||||
|
@ -94,7 +79,6 @@ pub fn op_restore_test_permissions(
|
|||
}
|
||||
|
||||
let permissions = permissions_holder.1;
|
||||
state.put(permissions.inner.clone());
|
||||
state.put::<PermissionsContainer>(permissions);
|
||||
Ok(())
|
||||
} else {
|
||||
|
|
568
cli/resolver.rs
568
cli/resolver.rs
|
@ -22,12 +22,13 @@ use deno_graph::NpmLoadError;
|
|||
use deno_graph::NpmResolvePkgReqsResult;
|
||||
use deno_npm::resolution::NpmResolutionError;
|
||||
use deno_package_json::PackageJsonDepValue;
|
||||
use deno_resolver::sloppy_imports::SloppyImportsResolutionMode;
|
||||
use deno_resolver::sloppy_imports::SloppyImportsResolver;
|
||||
use deno_runtime::colors;
|
||||
use deno_runtime::deno_fs;
|
||||
use deno_runtime::deno_fs::FileSystem;
|
||||
use deno_runtime::deno_node::is_builtin_node_module;
|
||||
use deno_runtime::deno_node::NodeResolver;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use deno_semver::package::PackageReq;
|
||||
use node_resolver::errors::ClosestPkgJsonError;
|
||||
|
@ -60,13 +61,52 @@ pub struct ModuleCodeStringSource {
|
|||
pub media_type: MediaType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CliDenoResolverFs(pub Arc<dyn FileSystem>);
|
||||
|
||||
impl deno_resolver::fs::DenoResolverFs for CliDenoResolverFs {
|
||||
fn read_to_string_lossy(&self, path: &Path) -> std::io::Result<String> {
|
||||
self
|
||||
.0
|
||||
.read_text_file_lossy_sync(path, None)
|
||||
.map_err(|e| e.into_io_error())
|
||||
}
|
||||
|
||||
fn realpath_sync(&self, path: &Path) -> std::io::Result<PathBuf> {
|
||||
self.0.realpath_sync(path).map_err(|e| e.into_io_error())
|
||||
}
|
||||
|
||||
fn is_dir_sync(&self, path: &Path) -> bool {
|
||||
self.0.is_dir_sync(path)
|
||||
}
|
||||
|
||||
fn read_dir_sync(
|
||||
&self,
|
||||
dir_path: &Path,
|
||||
) -> std::io::Result<Vec<deno_resolver::fs::DirEntry>> {
|
||||
self
|
||||
.0
|
||||
.read_dir_sync(dir_path)
|
||||
.map(|entries| {
|
||||
entries
|
||||
.into_iter()
|
||||
.map(|e| deno_resolver::fs::DirEntry {
|
||||
name: e.name,
|
||||
is_file: e.is_file,
|
||||
is_directory: e.is_directory,
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.map_err(|err| err.into_io_error())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CliNodeResolver {
|
||||
cjs_resolutions: Arc<CjsResolutionStore>,
|
||||
fs: Arc<dyn deno_fs::FileSystem>,
|
||||
node_resolver: Arc<NodeResolver>,
|
||||
// todo(dsherret): remove this pub(crate)
|
||||
pub(crate) npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
}
|
||||
|
||||
impl CliNodeResolver {
|
||||
|
@ -421,13 +461,16 @@ impl CjsResolutionStore {
|
|||
}
|
||||
}
|
||||
|
||||
pub type CliSloppyImportsResolver =
|
||||
SloppyImportsResolver<SloppyImportsCachedFs>;
|
||||
|
||||
/// A resolver that takes care of resolution, taking into account loaded
|
||||
/// import map, JSX settings.
|
||||
#[derive(Debug)]
|
||||
pub struct CliGraphResolver {
|
||||
node_resolver: Option<Arc<CliNodeResolver>>,
|
||||
npm_resolver: Option<Arc<dyn CliNpmResolver>>,
|
||||
sloppy_imports_resolver: Option<Arc<SloppyImportsResolver>>,
|
||||
sloppy_imports_resolver: Option<Arc<CliSloppyImportsResolver>>,
|
||||
workspace_resolver: Arc<WorkspaceResolver>,
|
||||
maybe_default_jsx_import_source: Option<String>,
|
||||
maybe_default_jsx_import_source_types: Option<String>,
|
||||
|
@ -441,7 +484,7 @@ pub struct CliGraphResolver {
|
|||
pub struct CliGraphResolverOptions<'a> {
|
||||
pub node_resolver: Option<Arc<CliNodeResolver>>,
|
||||
pub npm_resolver: Option<Arc<dyn CliNpmResolver>>,
|
||||
pub sloppy_imports_resolver: Option<Arc<SloppyImportsResolver>>,
|
||||
pub sloppy_imports_resolver: Option<Arc<CliSloppyImportsResolver>>,
|
||||
pub workspace_resolver: Arc<WorkspaceResolver>,
|
||||
pub bare_node_builtins_enabled: bool,
|
||||
pub maybe_jsx_import_source_config: Option<JsxImportSourceConfig>,
|
||||
|
@ -565,7 +608,15 @@ impl Resolver for CliGraphResolver {
|
|||
if let Some(sloppy_imports_resolver) = &self.sloppy_imports_resolver {
|
||||
Ok(
|
||||
sloppy_imports_resolver
|
||||
.resolve(&specifier, mode)
|
||||
.resolve(
|
||||
&specifier,
|
||||
match mode {
|
||||
ResolutionMode::Execution => {
|
||||
SloppyImportsResolutionMode::Execution
|
||||
}
|
||||
ResolutionMode::Types => SloppyImportsResolutionMode::Types,
|
||||
},
|
||||
)
|
||||
.map(|s| s.into_specifier())
|
||||
.unwrap_or(specifier),
|
||||
)
|
||||
|
@ -847,96 +898,18 @@ impl<'a> deno_graph::source::NpmResolver for WorkerCliNpmGraphResolver<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum SloppyImportsFsEntry {
|
||||
File,
|
||||
Dir,
|
||||
}
|
||||
|
||||
impl SloppyImportsFsEntry {
|
||||
pub fn from_fs_stat(
|
||||
stat: &deno_runtime::deno_io::fs::FsStat,
|
||||
) -> Option<SloppyImportsFsEntry> {
|
||||
if stat.is_file {
|
||||
Some(SloppyImportsFsEntry::File)
|
||||
} else if stat.is_directory {
|
||||
Some(SloppyImportsFsEntry::Dir)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum SloppyImportsResolution {
|
||||
/// Ex. `./file.js` to `./file.ts`
|
||||
JsToTs(ModuleSpecifier),
|
||||
/// Ex. `./file` to `./file.ts`
|
||||
NoExtension(ModuleSpecifier),
|
||||
/// Ex. `./dir` to `./dir/index.ts`
|
||||
Directory(ModuleSpecifier),
|
||||
}
|
||||
|
||||
impl SloppyImportsResolution {
|
||||
pub fn as_specifier(&self) -> &ModuleSpecifier {
|
||||
match self {
|
||||
Self::JsToTs(specifier) => specifier,
|
||||
Self::NoExtension(specifier) => specifier,
|
||||
Self::Directory(specifier) => specifier,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_specifier(self) -> ModuleSpecifier {
|
||||
match self {
|
||||
Self::JsToTs(specifier) => specifier,
|
||||
Self::NoExtension(specifier) => specifier,
|
||||
Self::Directory(specifier) => specifier,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_suggestion_message(&self) -> String {
|
||||
format!("Maybe {}", self.as_base_message())
|
||||
}
|
||||
|
||||
pub fn as_quick_fix_message(&self) -> String {
|
||||
let message = self.as_base_message();
|
||||
let mut chars = message.chars();
|
||||
format!(
|
||||
"{}{}.",
|
||||
chars.next().unwrap().to_uppercase(),
|
||||
chars.as_str()
|
||||
)
|
||||
}
|
||||
|
||||
fn as_base_message(&self) -> String {
|
||||
match self {
|
||||
SloppyImportsResolution::JsToTs(specifier) => {
|
||||
let media_type = MediaType::from_specifier(specifier);
|
||||
format!("change the extension to '{}'", media_type.as_ts_extension())
|
||||
}
|
||||
SloppyImportsResolution::NoExtension(specifier) => {
|
||||
let media_type = MediaType::from_specifier(specifier);
|
||||
format!("add a '{}' extension", media_type.as_ts_extension())
|
||||
}
|
||||
SloppyImportsResolution::Directory(specifier) => {
|
||||
let file_name = specifier
|
||||
.path()
|
||||
.rsplit_once('/')
|
||||
.map(|(_, file_name)| file_name)
|
||||
.unwrap_or(specifier.path());
|
||||
format!("specify path to '{}' file in directory instead", file_name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SloppyImportsResolver {
|
||||
fs: Arc<dyn FileSystem>,
|
||||
cache: Option<DashMap<PathBuf, Option<SloppyImportsFsEntry>>>,
|
||||
pub struct SloppyImportsCachedFs {
|
||||
fs: Arc<dyn deno_fs::FileSystem>,
|
||||
cache: Option<
|
||||
DashMap<
|
||||
PathBuf,
|
||||
Option<deno_resolver::sloppy_imports::SloppyImportsFsEntry>,
|
||||
>,
|
||||
>,
|
||||
}
|
||||
|
||||
impl SloppyImportsResolver {
|
||||
impl SloppyImportsCachedFs {
|
||||
pub fn new(fs: Arc<dyn FileSystem>) -> Self {
|
||||
Self {
|
||||
fs,
|
||||
|
@ -947,409 +920,34 @@ impl SloppyImportsResolver {
|
|||
pub fn new_without_stat_cache(fs: Arc<dyn FileSystem>) -> Self {
|
||||
Self { fs, cache: None }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve(
|
||||
impl deno_resolver::sloppy_imports::SloppyImportResolverFs
|
||||
for SloppyImportsCachedFs
|
||||
{
|
||||
fn stat_sync(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
mode: ResolutionMode,
|
||||
) -> Option<SloppyImportsResolution> {
|
||||
fn path_without_ext(
|
||||
path: &Path,
|
||||
media_type: MediaType,
|
||||
) -> Option<Cow<str>> {
|
||||
let old_path_str = path.to_string_lossy();
|
||||
match media_type {
|
||||
MediaType::Unknown => Some(old_path_str),
|
||||
_ => old_path_str
|
||||
.strip_suffix(media_type.as_ts_extension())
|
||||
.map(|s| Cow::Owned(s.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
fn media_types_to_paths(
|
||||
path_no_ext: &str,
|
||||
original_media_type: MediaType,
|
||||
probe_media_type_types: Vec<MediaType>,
|
||||
reason: SloppyImportsResolutionReason,
|
||||
) -> Vec<(PathBuf, SloppyImportsResolutionReason)> {
|
||||
probe_media_type_types
|
||||
.into_iter()
|
||||
.filter(|media_type| *media_type != original_media_type)
|
||||
.map(|media_type| {
|
||||
(
|
||||
PathBuf::from(format!(
|
||||
"{}{}",
|
||||
path_no_ext,
|
||||
media_type.as_ts_extension()
|
||||
)),
|
||||
reason,
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
if specifier.scheme() != "file" {
|
||||
return None;
|
||||
}
|
||||
|
||||
let path = specifier_to_file_path(specifier).ok()?;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum SloppyImportsResolutionReason {
|
||||
JsToTs,
|
||||
NoExtension,
|
||||
Directory,
|
||||
}
|
||||
|
||||
let probe_paths: Vec<(PathBuf, SloppyImportsResolutionReason)> =
|
||||
match self.stat_sync(&path) {
|
||||
Some(SloppyImportsFsEntry::File) => {
|
||||
if mode.is_types() {
|
||||
let media_type = MediaType::from_specifier(specifier);
|
||||
// attempt to resolve the .d.ts file before the .js file
|
||||
let probe_media_type_types = match media_type {
|
||||
MediaType::JavaScript => {
|
||||
vec![(MediaType::Dts), MediaType::JavaScript]
|
||||
}
|
||||
MediaType::Mjs => {
|
||||
vec![MediaType::Dmts, MediaType::Dts, MediaType::Mjs]
|
||||
}
|
||||
MediaType::Cjs => {
|
||||
vec![MediaType::Dcts, MediaType::Dts, MediaType::Cjs]
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
let path_no_ext = path_without_ext(&path, media_type)?;
|
||||
media_types_to_paths(
|
||||
&path_no_ext,
|
||||
media_type,
|
||||
probe_media_type_types,
|
||||
SloppyImportsResolutionReason::JsToTs,
|
||||
)
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
entry @ None | entry @ Some(SloppyImportsFsEntry::Dir) => {
|
||||
let media_type = MediaType::from_specifier(specifier);
|
||||
let probe_media_type_types = match media_type {
|
||||
MediaType::JavaScript => (
|
||||
if mode.is_types() {
|
||||
vec![MediaType::TypeScript, MediaType::Tsx, MediaType::Dts]
|
||||
} else {
|
||||
vec![MediaType::TypeScript, MediaType::Tsx]
|
||||
},
|
||||
SloppyImportsResolutionReason::JsToTs,
|
||||
),
|
||||
MediaType::Jsx => {
|
||||
(vec![MediaType::Tsx], SloppyImportsResolutionReason::JsToTs)
|
||||
}
|
||||
MediaType::Mjs => (
|
||||
if mode.is_types() {
|
||||
vec![MediaType::Mts, MediaType::Dmts, MediaType::Dts]
|
||||
} else {
|
||||
vec![MediaType::Mts]
|
||||
},
|
||||
SloppyImportsResolutionReason::JsToTs,
|
||||
),
|
||||
MediaType::Cjs => (
|
||||
if mode.is_types() {
|
||||
vec![MediaType::Cts, MediaType::Dcts, MediaType::Dts]
|
||||
} else {
|
||||
vec![MediaType::Cts]
|
||||
},
|
||||
SloppyImportsResolutionReason::JsToTs,
|
||||
),
|
||||
MediaType::TypeScript
|
||||
| MediaType::Mts
|
||||
| MediaType::Cts
|
||||
| MediaType::Dts
|
||||
| MediaType::Dmts
|
||||
| MediaType::Dcts
|
||||
| MediaType::Tsx
|
||||
| MediaType::Json
|
||||
| MediaType::Wasm
|
||||
| MediaType::TsBuildInfo
|
||||
| MediaType::SourceMap => {
|
||||
return None;
|
||||
}
|
||||
MediaType::Unknown => (
|
||||
if mode.is_types() {
|
||||
vec![
|
||||
MediaType::TypeScript,
|
||||
MediaType::Tsx,
|
||||
MediaType::Mts,
|
||||
MediaType::Dts,
|
||||
MediaType::Dmts,
|
||||
MediaType::Dcts,
|
||||
MediaType::JavaScript,
|
||||
MediaType::Jsx,
|
||||
MediaType::Mjs,
|
||||
]
|
||||
} else {
|
||||
vec![
|
||||
MediaType::TypeScript,
|
||||
MediaType::JavaScript,
|
||||
MediaType::Tsx,
|
||||
MediaType::Jsx,
|
||||
MediaType::Mts,
|
||||
MediaType::Mjs,
|
||||
]
|
||||
},
|
||||
SloppyImportsResolutionReason::NoExtension,
|
||||
),
|
||||
};
|
||||
let mut probe_paths = match path_without_ext(&path, media_type) {
|
||||
Some(path_no_ext) => media_types_to_paths(
|
||||
&path_no_ext,
|
||||
media_type,
|
||||
probe_media_type_types.0,
|
||||
probe_media_type_types.1,
|
||||
),
|
||||
None => vec![],
|
||||
};
|
||||
|
||||
if matches!(entry, Some(SloppyImportsFsEntry::Dir)) {
|
||||
// try to resolve at the index file
|
||||
if mode.is_types() {
|
||||
probe_paths.push((
|
||||
path.join("index.ts"),
|
||||
SloppyImportsResolutionReason::Directory,
|
||||
));
|
||||
|
||||
probe_paths.push((
|
||||
path.join("index.mts"),
|
||||
SloppyImportsResolutionReason::Directory,
|
||||
));
|
||||
probe_paths.push((
|
||||
path.join("index.d.ts"),
|
||||
SloppyImportsResolutionReason::Directory,
|
||||
));
|
||||
probe_paths.push((
|
||||
path.join("index.d.mts"),
|
||||
SloppyImportsResolutionReason::Directory,
|
||||
));
|
||||
probe_paths.push((
|
||||
path.join("index.js"),
|
||||
SloppyImportsResolutionReason::Directory,
|
||||
));
|
||||
probe_paths.push((
|
||||
path.join("index.mjs"),
|
||||
SloppyImportsResolutionReason::Directory,
|
||||
));
|
||||
probe_paths.push((
|
||||
path.join("index.tsx"),
|
||||
SloppyImportsResolutionReason::Directory,
|
||||
));
|
||||
probe_paths.push((
|
||||
path.join("index.jsx"),
|
||||
SloppyImportsResolutionReason::Directory,
|
||||
));
|
||||
} else {
|
||||
probe_paths.push((
|
||||
path.join("index.ts"),
|
||||
SloppyImportsResolutionReason::Directory,
|
||||
));
|
||||
probe_paths.push((
|
||||
path.join("index.mts"),
|
||||
SloppyImportsResolutionReason::Directory,
|
||||
));
|
||||
probe_paths.push((
|
||||
path.join("index.tsx"),
|
||||
SloppyImportsResolutionReason::Directory,
|
||||
));
|
||||
probe_paths.push((
|
||||
path.join("index.js"),
|
||||
SloppyImportsResolutionReason::Directory,
|
||||
));
|
||||
probe_paths.push((
|
||||
path.join("index.mjs"),
|
||||
SloppyImportsResolutionReason::Directory,
|
||||
));
|
||||
probe_paths.push((
|
||||
path.join("index.jsx"),
|
||||
SloppyImportsResolutionReason::Directory,
|
||||
));
|
||||
}
|
||||
}
|
||||
if probe_paths.is_empty() {
|
||||
return None;
|
||||
}
|
||||
probe_paths
|
||||
}
|
||||
};
|
||||
|
||||
for (probe_path, reason) in probe_paths {
|
||||
if self.stat_sync(&probe_path) == Some(SloppyImportsFsEntry::File) {
|
||||
if let Ok(specifier) = ModuleSpecifier::from_file_path(probe_path) {
|
||||
match reason {
|
||||
SloppyImportsResolutionReason::JsToTs => {
|
||||
return Some(SloppyImportsResolution::JsToTs(specifier));
|
||||
}
|
||||
SloppyImportsResolutionReason::NoExtension => {
|
||||
return Some(SloppyImportsResolution::NoExtension(specifier));
|
||||
}
|
||||
SloppyImportsResolutionReason::Directory => {
|
||||
return Some(SloppyImportsResolution::Directory(specifier));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn stat_sync(&self, path: &Path) -> Option<SloppyImportsFsEntry> {
|
||||
path: &Path,
|
||||
) -> Option<deno_resolver::sloppy_imports::SloppyImportsFsEntry> {
|
||||
if let Some(cache) = &self.cache {
|
||||
if let Some(entry) = cache.get(path) {
|
||||
return *entry;
|
||||
}
|
||||
}
|
||||
|
||||
let entry = self
|
||||
.fs
|
||||
.stat_sync(path)
|
||||
.ok()
|
||||
.and_then(|stat| SloppyImportsFsEntry::from_fs_stat(&stat));
|
||||
let entry = self.fs.stat_sync(path).ok().and_then(|stat| {
|
||||
if stat.is_file {
|
||||
Some(deno_resolver::sloppy_imports::SloppyImportsFsEntry::File)
|
||||
} else if stat.is_directory {
|
||||
Some(deno_resolver::sloppy_imports::SloppyImportsFsEntry::Dir)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(cache) = &self.cache {
|
||||
cache.insert(path.to_owned(), entry);
|
||||
}
|
||||
entry
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use test_util::TestContext;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_unstable_sloppy_imports() {
|
||||
fn resolve(specifier: &ModuleSpecifier) -> Option<SloppyImportsResolution> {
|
||||
resolve_with_mode(specifier, ResolutionMode::Execution)
|
||||
}
|
||||
|
||||
fn resolve_types(
|
||||
specifier: &ModuleSpecifier,
|
||||
) -> Option<SloppyImportsResolution> {
|
||||
resolve_with_mode(specifier, ResolutionMode::Types)
|
||||
}
|
||||
|
||||
fn resolve_with_mode(
|
||||
specifier: &ModuleSpecifier,
|
||||
mode: ResolutionMode,
|
||||
) -> Option<SloppyImportsResolution> {
|
||||
SloppyImportsResolver::new(Arc::new(deno_fs::RealFs))
|
||||
.resolve(specifier, mode)
|
||||
}
|
||||
|
||||
let context = TestContext::default();
|
||||
let temp_dir = context.temp_dir().path();
|
||||
|
||||
// scenarios like resolving ./example.js to ./example.ts
|
||||
for (ext_from, ext_to) in [("js", "ts"), ("js", "tsx"), ("mjs", "mts")] {
|
||||
let ts_file = temp_dir.join(format!("file.{}", ext_to));
|
||||
ts_file.write("");
|
||||
assert_eq!(resolve(&ts_file.url_file()), None);
|
||||
assert_eq!(
|
||||
resolve(
|
||||
&temp_dir
|
||||
.url_dir()
|
||||
.join(&format!("file.{}", ext_from))
|
||||
.unwrap()
|
||||
),
|
||||
Some(SloppyImportsResolution::JsToTs(ts_file.url_file())),
|
||||
);
|
||||
ts_file.remove_file();
|
||||
}
|
||||
|
||||
// no extension scenarios
|
||||
for ext in ["js", "ts", "js", "tsx", "jsx", "mjs", "mts"] {
|
||||
let file = temp_dir.join(format!("file.{}", ext));
|
||||
file.write("");
|
||||
assert_eq!(
|
||||
resolve(
|
||||
&temp_dir
|
||||
.url_dir()
|
||||
.join("file") // no ext
|
||||
.unwrap()
|
||||
),
|
||||
Some(SloppyImportsResolution::NoExtension(file.url_file()))
|
||||
);
|
||||
file.remove_file();
|
||||
}
|
||||
|
||||
// .ts and .js exists, .js specified (goes to specified)
|
||||
{
|
||||
let ts_file = temp_dir.join("file.ts");
|
||||
ts_file.write("");
|
||||
let js_file = temp_dir.join("file.js");
|
||||
js_file.write("");
|
||||
assert_eq!(resolve(&js_file.url_file()), None);
|
||||
}
|
||||
|
||||
// only js exists, .js specified
|
||||
{
|
||||
let js_only_file = temp_dir.join("js_only.js");
|
||||
js_only_file.write("");
|
||||
assert_eq!(resolve(&js_only_file.url_file()), None);
|
||||
assert_eq!(resolve_types(&js_only_file.url_file()), None);
|
||||
}
|
||||
|
||||
// resolving a directory to an index file
|
||||
{
|
||||
let routes_dir = temp_dir.join("routes");
|
||||
routes_dir.create_dir_all();
|
||||
let index_file = routes_dir.join("index.ts");
|
||||
index_file.write("");
|
||||
assert_eq!(
|
||||
resolve(&routes_dir.url_file()),
|
||||
Some(SloppyImportsResolution::Directory(index_file.url_file())),
|
||||
);
|
||||
}
|
||||
|
||||
// both a directory and a file with specifier is present
|
||||
{
|
||||
let api_dir = temp_dir.join("api");
|
||||
api_dir.create_dir_all();
|
||||
let bar_file = api_dir.join("bar.ts");
|
||||
bar_file.write("");
|
||||
let api_file = temp_dir.join("api.ts");
|
||||
api_file.write("");
|
||||
assert_eq!(
|
||||
resolve(&api_dir.url_file()),
|
||||
Some(SloppyImportsResolution::NoExtension(api_file.url_file())),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sloppy_import_resolution_suggestion_message() {
|
||||
// directory
|
||||
assert_eq!(
|
||||
SloppyImportsResolution::Directory(
|
||||
ModuleSpecifier::parse("file:///dir/index.js").unwrap()
|
||||
)
|
||||
.as_suggestion_message(),
|
||||
"Maybe specify path to 'index.js' file in directory instead"
|
||||
);
|
||||
// no ext
|
||||
assert_eq!(
|
||||
SloppyImportsResolution::NoExtension(
|
||||
ModuleSpecifier::parse("file:///dir/index.mjs").unwrap()
|
||||
)
|
||||
.as_suggestion_message(),
|
||||
"Maybe add a '.mjs' extension"
|
||||
);
|
||||
// js to ts
|
||||
assert_eq!(
|
||||
SloppyImportsResolution::JsToTs(
|
||||
ModuleSpecifier::parse("file:///dir/index.mts").unwrap()
|
||||
)
|
||||
.as_suggestion_message(),
|
||||
"Maybe change the extension to '.mts'"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -427,13 +427,9 @@ impl<'a> DenoCompileBinaryWriter<'a> {
|
|||
binary_name
|
||||
)
|
||||
}
|
||||
ReleaseChannel::Stable => {
|
||||
_ => {
|
||||
format!("release/v{}/{}", env!("CARGO_PKG_VERSION"), binary_name)
|
||||
}
|
||||
_ => bail!(
|
||||
"`deno compile` current doesn't support {} release channel",
|
||||
crate::version::DENO_VERSION_INFO.release_channel.name()
|
||||
),
|
||||
};
|
||||
|
||||
let download_directory = self.deno_dir.dl_folder_path();
|
||||
|
|
|
@ -102,7 +102,7 @@ impl FileSystem for DenoCompileFileSystem {
|
|||
&self,
|
||||
path: &Path,
|
||||
recursive: bool,
|
||||
mode: u32,
|
||||
mode: Option<u32>,
|
||||
) -> FsResult<()> {
|
||||
self.error_if_in_vfs(path)?;
|
||||
RealFs.mkdir_sync(path, recursive, mode)
|
||||
|
@ -111,7 +111,7 @@ impl FileSystem for DenoCompileFileSystem {
|
|||
&self,
|
||||
path: PathBuf,
|
||||
recursive: bool,
|
||||
mode: u32,
|
||||
mode: Option<u32>,
|
||||
) -> FsResult<()> {
|
||||
self.error_if_in_vfs(&path)?;
|
||||
RealFs.mkdir_async(path, recursive, mode).await
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#![allow(unused_imports)]
|
||||
|
||||
use deno_ast::MediaType;
|
||||
use deno_cache_dir::npm::NpmCacheDir;
|
||||
use deno_config::workspace::MappedResolution;
|
||||
use deno_config::workspace::MappedResolutionError;
|
||||
use deno_config::workspace::ResolverWorkspaceJsrPackage;
|
||||
|
@ -55,15 +56,16 @@ use crate::args::StorageKeyResolver;
|
|||
use crate::cache::Caches;
|
||||
use crate::cache::DenoDirProvider;
|
||||
use crate::cache::NodeAnalysisCache;
|
||||
use crate::cache::RealDenoCacheEnv;
|
||||
use crate::http_util::HttpClientProvider;
|
||||
use crate::node::CliCjsCodeAnalyzer;
|
||||
use crate::npm::create_cli_npm_resolver;
|
||||
use crate::npm::CliNpmResolverByonmCreateOptions;
|
||||
use crate::npm::CliByonmNpmResolverCreateOptions;
|
||||
use crate::npm::CliNpmResolverCreateOptions;
|
||||
use crate::npm::CliNpmResolverManagedCreateOptions;
|
||||
use crate::npm::CliNpmResolverManagedSnapshotOption;
|
||||
use crate::npm::NpmCacheDir;
|
||||
use crate::resolver::CjsResolutionStore;
|
||||
use crate::resolver::CliDenoResolverFs;
|
||||
use crate::resolver::CliNodeResolver;
|
||||
use crate::resolver::NpmModuleLoader;
|
||||
use crate::util::progress_bar::ProgressBar;
|
||||
|
@ -130,8 +132,6 @@ struct SharedModuleLoaderState {
|
|||
#[derive(Clone)]
|
||||
struct EmbeddedModuleLoader {
|
||||
shared: Arc<SharedModuleLoaderState>,
|
||||
root_permissions: PermissionsContainer,
|
||||
dynamic_permissions: PermissionsContainer,
|
||||
}
|
||||
|
||||
pub const MODULE_NOT_FOUND: &str = "Module not found";
|
||||
|
@ -402,28 +402,23 @@ struct StandaloneModuleLoaderFactory {
|
|||
impl ModuleLoaderFactory for StandaloneModuleLoaderFactory {
|
||||
fn create_for_main(
|
||||
&self,
|
||||
root_permissions: PermissionsContainer,
|
||||
dynamic_permissions: PermissionsContainer,
|
||||
_root_permissions: PermissionsContainer,
|
||||
) -> ModuleLoaderAndSourceMapGetter {
|
||||
ModuleLoaderAndSourceMapGetter {
|
||||
module_loader: Rc::new(EmbeddedModuleLoader {
|
||||
shared: self.shared.clone(),
|
||||
root_permissions,
|
||||
dynamic_permissions,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn create_for_worker(
|
||||
&self,
|
||||
root_permissions: PermissionsContainer,
|
||||
dynamic_permissions: PermissionsContainer,
|
||||
_parent_permissions: PermissionsContainer,
|
||||
_permissions: PermissionsContainer,
|
||||
) -> ModuleLoaderAndSourceMapGetter {
|
||||
ModuleLoaderAndSourceMapGetter {
|
||||
module_loader: Rc::new(EmbeddedModuleLoader {
|
||||
shared: self.shared.clone(),
|
||||
root_permissions,
|
||||
dynamic_permissions,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -471,6 +466,7 @@ pub async fn run(
|
|||
let main_module = root_dir_url.join(&metadata.entrypoint_key).unwrap();
|
||||
let root_node_modules_path = root_path.join("node_modules");
|
||||
let npm_cache_dir = NpmCacheDir::new(
|
||||
&RealDenoCacheEnv,
|
||||
root_node_modules_path.clone(),
|
||||
vec![npm_registry_url.clone()],
|
||||
);
|
||||
|
@ -535,8 +531,8 @@ pub async fn run(
|
|||
let fs = Arc::new(DenoCompileFileSystem::new(vfs))
|
||||
as Arc<dyn deno_fs::FileSystem>;
|
||||
let npm_resolver = create_cli_npm_resolver(
|
||||
CliNpmResolverCreateOptions::Byonm(CliNpmResolverByonmCreateOptions {
|
||||
fs: fs.clone(),
|
||||
CliNpmResolverCreateOptions::Byonm(CliByonmNpmResolverCreateOptions {
|
||||
fs: CliDenoResolverFs(fs.clone()),
|
||||
root_node_modules_dir,
|
||||
}),
|
||||
)
|
||||
|
@ -664,7 +660,8 @@ pub async fn run(
|
|||
};
|
||||
|
||||
let permissions = {
|
||||
let mut permissions = metadata.permissions.to_options();
|
||||
let mut permissions =
|
||||
metadata.permissions.to_options(/* cli_arg_urls */ &[]);
|
||||
// if running with an npm vfs, grant read access to it
|
||||
if let Some(vfs_root) = maybe_vfs_root {
|
||||
match &mut permissions.allow_read {
|
||||
|
@ -697,8 +694,6 @@ pub async fn run(
|
|||
}
|
||||
checker
|
||||
});
|
||||
let permission_desc_parser =
|
||||
Arc::new(RuntimePermissionDescriptorParser::new(fs.clone()));
|
||||
let worker_factory = CliMainWorkerFactory::new(
|
||||
Arc::new(BlobStore::default()),
|
||||
// Code cache is not supported for standalone binary yet.
|
||||
|
@ -711,8 +706,8 @@ pub async fn run(
|
|||
Box::new(module_loader_factory),
|
||||
node_resolver,
|
||||
npm_resolver,
|
||||
permission_desc_parser,
|
||||
root_cert_store_provider,
|
||||
permissions,
|
||||
StorageKeyResolver::empty(),
|
||||
crate::args::DenoSubcommand::Run(Default::default()),
|
||||
CliMainWorkerOptions {
|
||||
|
@ -752,7 +747,7 @@ pub async fn run(
|
|||
deno_core::JsRuntime::init_platform(None, true);
|
||||
|
||||
let mut worker = worker_factory
|
||||
.create_main_worker(WorkerExecutionMode::Run, main_module, permissions)
|
||||
.create_main_worker(WorkerExecutionMode::Run, main_module)
|
||||
.await?;
|
||||
|
||||
let exit_code = worker.run().await?;
|
||||
|
|
|
@ -51,6 +51,7 @@ pub async fn check(
|
|||
|
||||
let specifiers_for_typecheck = if check_flags.doc || check_flags.doc_only {
|
||||
let file_fetcher = factory.file_fetcher()?;
|
||||
let root_permissions = factory.root_permissions_container()?;
|
||||
|
||||
let mut specifiers_for_typecheck = if check_flags.doc {
|
||||
specifiers.clone()
|
||||
|
@ -59,7 +60,7 @@ pub async fn check(
|
|||
};
|
||||
|
||||
for s in specifiers {
|
||||
let file = file_fetcher.fetch_bypass_permissions(&s).await?;
|
||||
let file = file_fetcher.fetch(&s, root_permissions).await?;
|
||||
let snippet_files = extract::extract_snippet_files(file)?;
|
||||
for snippet_file in snippet_files {
|
||||
specifiers_for_typecheck.push(snippet_file.specifier.clone());
|
||||
|
|
|
@ -135,7 +135,7 @@ pub async fn compile(
|
|||
file,
|
||||
eszip,
|
||||
root_dir_url,
|
||||
&module_specifier,
|
||||
module_specifier,
|
||||
&compile_flags,
|
||||
cli_options,
|
||||
)
|
||||
|
|
|
@ -7,7 +7,9 @@ use crate::args::Flags;
|
|||
use crate::colors;
|
||||
use crate::display;
|
||||
use crate::factory::CliFactory;
|
||||
use crate::graph_util::graph_exit_lock_errors;
|
||||
use crate::graph_util::graph_exit_integrity_errors;
|
||||
use crate::graph_util::graph_walk_errors;
|
||||
use crate::graph_util::GraphWalkErrorsOptions;
|
||||
use crate::tsc::get_types_declaration_file_text;
|
||||
use crate::util::fs::collect_specifiers;
|
||||
use deno_ast::diagnostics::Diagnostic;
|
||||
|
@ -107,7 +109,7 @@ pub async fn doc(
|
|||
}
|
||||
DocSourceFileFlag::Paths(ref source_files) => {
|
||||
let module_graph_creator = factory.module_graph_creator().await?;
|
||||
let maybe_lockfile = cli_options.maybe_lockfile();
|
||||
let fs = factory.fs();
|
||||
|
||||
let module_specifiers = collect_specifiers(
|
||||
FilePatterns {
|
||||
|
@ -127,8 +129,18 @@ pub async fn doc(
|
|||
.create_graph(GraphKind::TypesOnly, module_specifiers.clone())
|
||||
.await?;
|
||||
|
||||
if maybe_lockfile.is_some() {
|
||||
graph_exit_lock_errors(&graph);
|
||||
graph_exit_integrity_errors(&graph);
|
||||
let errors = graph_walk_errors(
|
||||
&graph,
|
||||
fs,
|
||||
&module_specifiers,
|
||||
GraphWalkErrorsOptions {
|
||||
check_js: false,
|
||||
kind: GraphKind::TypesOnly,
|
||||
},
|
||||
);
|
||||
for error in errors {
|
||||
log::warn!("{} {}", colors::yellow("Warning"), error);
|
||||
}
|
||||
|
||||
let doc_parser = doc::DocParser::new(
|
||||
|
|
|
@ -437,25 +437,15 @@ pub fn format_html(
|
|||
)
|
||||
.map_err(|error| match error {
|
||||
markup_fmt::FormatError::Syntax(error) => {
|
||||
// TODO(bartlomieju): rework when better error support in `markup_fmt` lands
|
||||
fn inner(
|
||||
error: &markup_fmt::SyntaxError,
|
||||
file_path: &Path,
|
||||
) -> Option<String> {
|
||||
let error_str = format!("{}", error);
|
||||
let error_str = error_str.strip_prefix("syntax error '")?;
|
||||
|
||||
let reason = error_str
|
||||
.split("' at")
|
||||
.collect::<Vec<_>>()
|
||||
.first()
|
||||
.map(|s| s.to_string())?;
|
||||
|
||||
let url = Url::from_file_path(file_path).ok()?;
|
||||
|
||||
let error_msg = format!(
|
||||
"Syntax error ({}) at {}:{}:{}\n",
|
||||
reason,
|
||||
error.kind,
|
||||
url.as_str(),
|
||||
error.line,
|
||||
error.column
|
||||
|
|
|
@ -29,7 +29,7 @@ use crate::args::Flags;
|
|||
use crate::args::InfoFlags;
|
||||
use crate::display;
|
||||
use crate::factory::CliFactory;
|
||||
use crate::graph_util::graph_exit_lock_errors;
|
||||
use crate::graph_util::graph_exit_integrity_errors;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::npm::ManagedCliNpmResolver;
|
||||
use crate::util::checksum;
|
||||
|
@ -75,14 +75,18 @@ pub async fn info(
|
|||
|
||||
// write out the lockfile if there is one
|
||||
if let Some(lockfile) = &maybe_lockfile {
|
||||
graph_exit_lock_errors(&graph);
|
||||
graph_exit_integrity_errors(&graph);
|
||||
lockfile.write_if_changed()?;
|
||||
}
|
||||
|
||||
if info_flags.json {
|
||||
let mut json_graph = serde_json::json!(graph);
|
||||
if let Some(output) = json_graph.as_object_mut() {
|
||||
output.insert("version".to_string(), JSON_SCHEMA_VERSION.into());
|
||||
output.shift_insert(
|
||||
0,
|
||||
"version".to_string(),
|
||||
JSON_SCHEMA_VERSION.into(),
|
||||
);
|
||||
}
|
||||
add_npm_packages_to_json(&mut json_graph, npm_resolver.as_ref());
|
||||
display::write_json_to_stdout(&json_graph)?;
|
||||
|
@ -644,8 +648,21 @@ impl<'a> GraphDisplayContext<'a> {
|
|||
ModuleError::InvalidTypeAssertion { .. } => {
|
||||
self.build_error_msg(specifier, "(invalid import attribute)")
|
||||
}
|
||||
ModuleError::LoadingErr(_, _, _) => {
|
||||
self.build_error_msg(specifier, "(loading error)")
|
||||
ModuleError::LoadingErr(_, _, err) => {
|
||||
use deno_graph::ModuleLoadError::*;
|
||||
let message = match err {
|
||||
HttpsChecksumIntegrity(_) => "(checksum integrity error)",
|
||||
Decode(_) => "(loading decode error)",
|
||||
Loader(err) => match deno_core::error::get_custom_error_class(err) {
|
||||
Some("NotCapable") => "(not capable, requires --allow-import)",
|
||||
_ => "(loading error)",
|
||||
},
|
||||
Jsr(_) => "(loading error)",
|
||||
NodeUnknownBuiltinModule(_) => "(unknown node built-in error)",
|
||||
Npm(_) => "(npm loading error)",
|
||||
TooManyRedirects => "(too many redirects error)",
|
||||
};
|
||||
self.build_error_msg(specifier, message.as_ref())
|
||||
}
|
||||
ModuleError::ParseErr(_, _) => {
|
||||
self.build_error_msg(specifier, "(parsing error)")
|
||||
|
|
|
@ -14,7 +14,7 @@ use deno_graph::ModuleGraph;
|
|||
use deno_lint::diagnostic::LintDiagnostic;
|
||||
use deno_lint::rules::LintRule;
|
||||
|
||||
use crate::resolver::SloppyImportsResolver;
|
||||
use crate::resolver::CliSloppyImportsResolver;
|
||||
|
||||
mod no_sloppy_imports;
|
||||
mod no_slow_types;
|
||||
|
@ -144,13 +144,13 @@ impl ConfiguredRules {
|
|||
}
|
||||
|
||||
pub struct LintRuleProvider {
|
||||
sloppy_imports_resolver: Option<Arc<SloppyImportsResolver>>,
|
||||
sloppy_imports_resolver: Option<Arc<CliSloppyImportsResolver>>,
|
||||
workspace_resolver: Option<Arc<WorkspaceResolver>>,
|
||||
}
|
||||
|
||||
impl LintRuleProvider {
|
||||
pub fn new(
|
||||
sloppy_imports_resolver: Option<Arc<SloppyImportsResolver>>,
|
||||
sloppy_imports_resolver: Option<Arc<CliSloppyImportsResolver>>,
|
||||
workspace_resolver: Option<Arc<WorkspaceResolver>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
|
|
@ -16,24 +16,25 @@ use deno_lint::diagnostic::LintDiagnosticRange;
|
|||
use deno_lint::diagnostic::LintFix;
|
||||
use deno_lint::diagnostic::LintFixChange;
|
||||
use deno_lint::rules::LintRule;
|
||||
use deno_resolver::sloppy_imports::SloppyImportsResolution;
|
||||
use deno_resolver::sloppy_imports::SloppyImportsResolutionMode;
|
||||
use text_lines::LineAndColumnIndex;
|
||||
|
||||
use crate::graph_util::CliJsrUrlProvider;
|
||||
use crate::resolver::SloppyImportsResolution;
|
||||
use crate::resolver::SloppyImportsResolver;
|
||||
use crate::resolver::CliSloppyImportsResolver;
|
||||
|
||||
use super::ExtendedLintRule;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NoSloppyImportsRule {
|
||||
sloppy_imports_resolver: Option<Arc<SloppyImportsResolver>>,
|
||||
sloppy_imports_resolver: Option<Arc<CliSloppyImportsResolver>>,
|
||||
// None for making printing out the lint rules easy
|
||||
workspace_resolver: Option<Arc<WorkspaceResolver>>,
|
||||
}
|
||||
|
||||
impl NoSloppyImportsRule {
|
||||
pub fn new(
|
||||
sloppy_imports_resolver: Option<Arc<SloppyImportsResolver>>,
|
||||
sloppy_imports_resolver: Option<Arc<CliSloppyImportsResolver>>,
|
||||
workspace_resolver: Option<Arc<WorkspaceResolver>>,
|
||||
) -> Self {
|
||||
NoSloppyImportsRule {
|
||||
|
@ -172,7 +173,7 @@ impl LintRule for NoSloppyImportsRule {
|
|||
#[derive(Debug)]
|
||||
struct SloppyImportCaptureResolver<'a> {
|
||||
workspace_resolver: &'a WorkspaceResolver,
|
||||
sloppy_imports_resolver: &'a SloppyImportsResolver,
|
||||
sloppy_imports_resolver: &'a CliSloppyImportsResolver,
|
||||
captures: RefCell<HashMap<Range, SloppyImportsResolution>>,
|
||||
}
|
||||
|
||||
|
@ -194,7 +195,13 @@ impl<'a> deno_graph::source::Resolver for SloppyImportCaptureResolver<'a> {
|
|||
}
|
||||
| deno_config::workspace::MappedResolution::ImportMap {
|
||||
specifier, ..
|
||||
} => match self.sloppy_imports_resolver.resolve(&specifier, mode) {
|
||||
} => match self.sloppy_imports_resolver.resolve(
|
||||
&specifier,
|
||||
match mode {
|
||||
ResolutionMode::Execution => SloppyImportsResolutionMode::Execution,
|
||||
ResolutionMode::Types => SloppyImportsResolutionMode::Types,
|
||||
},
|
||||
) {
|
||||
Some(res) => {
|
||||
self
|
||||
.captures
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
use std::borrow::Cow;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use deno_ast::diagnostics::Diagnostic;
|
||||
use deno_ast::diagnostics::DiagnosticLevel;
|
||||
|
@ -21,6 +20,7 @@ use deno_ast::SourceRanged;
|
|||
use deno_ast::SourceTextInfo;
|
||||
use deno_core::anyhow::anyhow;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::parking_lot::Mutex;
|
||||
use deno_core::url::Url;
|
||||
use deno_graph::FastCheckDiagnostic;
|
||||
use deno_semver::Version;
|
||||
|
@ -36,7 +36,7 @@ impl PublishDiagnosticsCollector {
|
|||
pub fn print_and_error(&self) -> Result<(), AnyError> {
|
||||
let mut errors = 0;
|
||||
let mut has_slow_types_errors = false;
|
||||
let mut diagnostics = self.diagnostics.lock().unwrap().take();
|
||||
let mut diagnostics = self.diagnostics.lock().take();
|
||||
|
||||
diagnostics.sort_by_cached_key(|d| d.sorting_key());
|
||||
|
||||
|
@ -75,8 +75,16 @@ impl PublishDiagnosticsCollector {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn has_error(&self) -> bool {
|
||||
self
|
||||
.diagnostics
|
||||
.lock()
|
||||
.iter()
|
||||
.any(|d| matches!(d.level(), DiagnosticLevel::Error))
|
||||
}
|
||||
|
||||
pub fn push(&self, diagnostic: PublishDiagnostic) {
|
||||
self.diagnostics.lock().unwrap().push(diagnostic);
|
||||
self.diagnostics.lock().push(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ impl GraphDiagnosticsCollector {
|
|||
follow_dynamic: true,
|
||||
// search the entire graph and not just the fast check subset
|
||||
prefer_fast_check_graph: false,
|
||||
follow_type_only: true,
|
||||
kind: deno_graph::GraphKind::All,
|
||||
};
|
||||
let mut iter = graph.walk(graph.roots.iter(), options);
|
||||
while let Some((specifier, entry)) = iter.next() {
|
||||
|
|
|
@ -43,7 +43,8 @@ use crate::cache::ParsedSourceCache;
|
|||
use crate::factory::CliFactory;
|
||||
use crate::graph_util::ModuleGraphCreator;
|
||||
use crate::http_util::HttpClient;
|
||||
use crate::resolver::SloppyImportsResolver;
|
||||
use crate::resolver::CliSloppyImportsResolver;
|
||||
use crate::resolver::SloppyImportsCachedFs;
|
||||
use crate::tools::check::CheckOptions;
|
||||
use crate::tools::lint::collect_no_slow_type_diagnostics;
|
||||
use crate::tools::registry::diagnostics::PublishDiagnostic;
|
||||
|
@ -108,7 +109,9 @@ pub async fn publish(
|
|||
}
|
||||
let specifier_unfurler = Arc::new(SpecifierUnfurler::new(
|
||||
if cli_options.unstable_sloppy_imports() {
|
||||
Some(SloppyImportsResolver::new(cli_factory.fs().clone()))
|
||||
Some(CliSloppyImportsResolver::new(SloppyImportsCachedFs::new(
|
||||
cli_factory.fs().clone(),
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
|
@ -341,13 +344,11 @@ impl PublishPreparer {
|
|||
bail!("Exiting due to DENO_INTERNAL_FAST_CHECK_OVERWRITE")
|
||||
} else {
|
||||
log::info!("Checking for slow types in the public API...");
|
||||
let mut any_pkg_had_diagnostics = false;
|
||||
for package in package_configs {
|
||||
let export_urls = package.config_file.resolve_export_value_urls()?;
|
||||
let diagnostics =
|
||||
collect_no_slow_type_diagnostics(&graph, &export_urls);
|
||||
if !diagnostics.is_empty() {
|
||||
any_pkg_had_diagnostics = true;
|
||||
for diagnostic in diagnostics {
|
||||
diagnostics_collector
|
||||
.push(PublishDiagnostic::FastCheck(diagnostic));
|
||||
|
@ -355,7 +356,9 @@ impl PublishPreparer {
|
|||
}
|
||||
}
|
||||
|
||||
if any_pkg_had_diagnostics {
|
||||
// skip type checking the slow type graph if there are any errors because
|
||||
// errors like remote modules existing will cause type checking to crash
|
||||
if diagnostics_collector.has_error() {
|
||||
Ok(Arc::new(graph))
|
||||
} else {
|
||||
// fast check passed, type check the output as a temporary measure
|
||||
|
|
|
@ -16,6 +16,7 @@ pub async fn cache_top_level_deps(
|
|||
) -> Result<(), AnyError> {
|
||||
let npm_resolver = factory.npm_resolver().await?;
|
||||
let cli_options = factory.cli_options()?;
|
||||
let root_permissions = factory.root_permissions_container()?;
|
||||
if let Some(npm_resolver) = npm_resolver.as_managed() {
|
||||
if !npm_resolver.ensure_top_level_package_json_install().await? {
|
||||
if let Some(lockfile) = cli_options.maybe_lockfile() {
|
||||
|
@ -106,7 +107,7 @@ pub async fn cache_top_level_deps(
|
|||
&roots,
|
||||
false,
|
||||
deno_config::deno_json::TsTypeLib::DenoWorker,
|
||||
crate::file_fetcher::FetchPermissionsOption::AllowAll,
|
||||
root_permissions.clone(),
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
|
|
@ -12,9 +12,10 @@ use deno_graph::DynamicTemplatePart;
|
|||
use deno_graph::ParserModuleAnalyzer;
|
||||
use deno_graph::TypeScriptReference;
|
||||
use deno_package_json::PackageJsonDepValue;
|
||||
use deno_resolver::sloppy_imports::SloppyImportsResolutionMode;
|
||||
use deno_runtime::deno_node::is_builtin_node_module;
|
||||
|
||||
use crate::resolver::SloppyImportsResolver;
|
||||
use crate::resolver::CliSloppyImportsResolver;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SpecifierUnfurlerDiagnostic {
|
||||
|
@ -42,14 +43,14 @@ impl SpecifierUnfurlerDiagnostic {
|
|||
}
|
||||
|
||||
pub struct SpecifierUnfurler {
|
||||
sloppy_imports_resolver: Option<SloppyImportsResolver>,
|
||||
sloppy_imports_resolver: Option<CliSloppyImportsResolver>,
|
||||
workspace_resolver: WorkspaceResolver,
|
||||
bare_node_builtins: bool,
|
||||
}
|
||||
|
||||
impl SpecifierUnfurler {
|
||||
pub fn new(
|
||||
sloppy_imports_resolver: Option<SloppyImportsResolver>,
|
||||
sloppy_imports_resolver: Option<CliSloppyImportsResolver>,
|
||||
workspace_resolver: WorkspaceResolver,
|
||||
bare_node_builtins: bool,
|
||||
) -> Self {
|
||||
|
@ -179,7 +180,7 @@ impl SpecifierUnfurler {
|
|||
let resolved =
|
||||
if let Some(sloppy_imports_resolver) = &self.sloppy_imports_resolver {
|
||||
sloppy_imports_resolver
|
||||
.resolve(&resolved, deno_graph::source::ResolutionMode::Execution)
|
||||
.resolve(&resolved, SloppyImportsResolutionMode::Execution)
|
||||
.map(|res| res.into_specifier())
|
||||
.unwrap_or(resolved)
|
||||
} else {
|
||||
|
@ -388,6 +389,8 @@ fn to_range(
|
|||
mod tests {
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::resolver::SloppyImportsCachedFs;
|
||||
|
||||
use super::*;
|
||||
use deno_ast::MediaType;
|
||||
use deno_ast::ModuleSpecifier;
|
||||
|
@ -455,7 +458,9 @@ mod tests {
|
|||
);
|
||||
let fs = Arc::new(RealFs);
|
||||
let unfurler = SpecifierUnfurler::new(
|
||||
Some(SloppyImportsResolver::new(fs)),
|
||||
Some(CliSloppyImportsResolver::new(SloppyImportsCachedFs::new(
|
||||
fs,
|
||||
))),
|
||||
workspace_resolver,
|
||||
true,
|
||||
);
|
||||
|
|
|
@ -162,7 +162,7 @@ pub async fn run(
|
|||
let factory = CliFactory::from_flags(flags);
|
||||
let cli_options = factory.cli_options()?;
|
||||
let main_module = cli_options.resolve_main_module()?;
|
||||
let permissions = factory.create_permissions_container()?;
|
||||
let permissions = factory.root_permissions_container()?;
|
||||
let npm_resolver = factory.npm_resolver().await?.clone();
|
||||
let resolver = factory.resolver().await?.clone();
|
||||
let file_fetcher = factory.file_fetcher()?;
|
||||
|
@ -177,7 +177,7 @@ pub async fn run(
|
|||
.create_custom_worker(
|
||||
WorkerExecutionMode::Repl,
|
||||
main_module.clone(),
|
||||
permissions,
|
||||
permissions.clone(),
|
||||
vec![crate::ops::testing::deno_test::init_ops(test_event_sender)],
|
||||
Default::default(),
|
||||
)
|
||||
|
@ -189,7 +189,7 @@ pub async fn run(
|
|||
npm_resolver,
|
||||
resolver,
|
||||
worker,
|
||||
main_module,
|
||||
main_module.clone(),
|
||||
test_event_receiver,
|
||||
)
|
||||
.await?;
|
||||
|
|
|
@ -60,10 +60,9 @@ pub async fn run_script(
|
|||
|
||||
maybe_npm_install(&factory).await?;
|
||||
|
||||
let permissions = factory.create_permissions_container()?;
|
||||
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
||||
let mut worker = worker_factory
|
||||
.create_main_worker(mode, main_module, permissions)
|
||||
.create_main_worker(mode, main_module.clone())
|
||||
.await?;
|
||||
|
||||
let exit_code = worker.run().await?;
|
||||
|
@ -79,7 +78,6 @@ pub async fn run_from_stdin(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
|||
|
||||
let file_fetcher = factory.file_fetcher()?;
|
||||
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
||||
let permissions = factory.create_permissions_container()?;
|
||||
let mut source = Vec::new();
|
||||
std::io::stdin().read_to_end(&mut source)?;
|
||||
// Save a fake file into file fetcher cache
|
||||
|
@ -91,7 +89,7 @@ pub async fn run_from_stdin(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
|||
});
|
||||
|
||||
let mut worker = worker_factory
|
||||
.create_main_worker(WorkerExecutionMode::Run, main_module, permissions)
|
||||
.create_main_worker(WorkerExecutionMode::Run, main_module.clone())
|
||||
.await?;
|
||||
let exit_code = worker.run().await?;
|
||||
Ok(exit_code)
|
||||
|
@ -125,11 +123,10 @@ async fn run_with_watch(
|
|||
|
||||
let _ = watcher_communicator.watch_paths(cli_options.watch_paths());
|
||||
|
||||
let permissions = factory.create_permissions_container()?;
|
||||
let mut worker = factory
|
||||
.create_cli_main_worker_factory()
|
||||
.await?
|
||||
.create_main_worker(mode, main_module, permissions)
|
||||
.create_main_worker(mode, main_module.clone())
|
||||
.await?;
|
||||
|
||||
if watch_flags.hmr {
|
||||
|
@ -173,10 +170,9 @@ pub async fn eval_command(
|
|||
source: source_code.into_bytes().into(),
|
||||
});
|
||||
|
||||
let permissions = factory.create_permissions_container()?;
|
||||
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
||||
let mut worker = worker_factory
|
||||
.create_main_worker(WorkerExecutionMode::Eval, main_module, permissions)
|
||||
.create_main_worker(WorkerExecutionMode::Eval, main_module.clone())
|
||||
.await?;
|
||||
let exit_code = worker.run().await?;
|
||||
Ok(exit_code)
|
||||
|
|
|
@ -5,7 +5,6 @@ use std::sync::Arc;
|
|||
use deno_core::error::AnyError;
|
||||
use deno_core::futures::TryFutureExt;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
|
||||
use super::run::check_permission_before_script;
|
||||
use super::run::maybe_npm_install;
|
||||
|
@ -44,13 +43,11 @@ pub async fn serve(
|
|||
|
||||
maybe_npm_install(&factory).await?;
|
||||
|
||||
let permissions = factory.create_permissions_container()?;
|
||||
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
||||
|
||||
do_serve(
|
||||
worker_factory,
|
||||
main_module,
|
||||
permissions,
|
||||
main_module.clone(),
|
||||
serve_flags.worker_count,
|
||||
false,
|
||||
)
|
||||
|
@ -60,7 +57,6 @@ pub async fn serve(
|
|||
async fn do_serve(
|
||||
worker_factory: CliMainWorkerFactory,
|
||||
main_module: ModuleSpecifier,
|
||||
permissions: PermissionsContainer,
|
||||
worker_count: Option<usize>,
|
||||
hmr: bool,
|
||||
) -> Result<i32, AnyError> {
|
||||
|
@ -71,7 +67,6 @@ async fn do_serve(
|
|||
worker_count,
|
||||
},
|
||||
main_module.clone(),
|
||||
permissions.clone(),
|
||||
)
|
||||
.await?;
|
||||
let worker_count = match worker_count {
|
||||
|
@ -87,15 +82,13 @@ async fn do_serve(
|
|||
for i in 0..extra_workers {
|
||||
let worker_factory = worker_factory.clone();
|
||||
let main_module = main_module.clone();
|
||||
let permissions = permissions.clone();
|
||||
let (tx, rx) = tokio::sync::oneshot::channel();
|
||||
channels.push(rx);
|
||||
std::thread::Builder::new()
|
||||
.name(format!("serve-worker-{i}"))
|
||||
.spawn(move || {
|
||||
deno_runtime::tokio_util::create_and_run_current_thread(async move {
|
||||
let result =
|
||||
run_worker(i, worker_factory, main_module, permissions, hmr).await;
|
||||
let result = run_worker(i, worker_factory, main_module, hmr).await;
|
||||
let _ = tx.send(result);
|
||||
});
|
||||
})?;
|
||||
|
@ -124,7 +117,6 @@ async fn run_worker(
|
|||
worker_count: usize,
|
||||
worker_factory: CliMainWorkerFactory,
|
||||
main_module: ModuleSpecifier,
|
||||
permissions: PermissionsContainer,
|
||||
hmr: bool,
|
||||
) -> Result<i32, AnyError> {
|
||||
let mut worker = worker_factory
|
||||
|
@ -134,7 +126,6 @@ async fn run_worker(
|
|||
worker_count: Some(worker_count),
|
||||
},
|
||||
main_module,
|
||||
permissions,
|
||||
)
|
||||
.await?;
|
||||
if hmr {
|
||||
|
@ -171,11 +162,9 @@ async fn serve_with_watch(
|
|||
maybe_npm_install(&factory).await?;
|
||||
|
||||
let _ = watcher_communicator.watch_paths(cli_options.watch_paths());
|
||||
|
||||
let permissions = factory.create_permissions_container()?;
|
||||
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
||||
|
||||
do_serve(worker_factory, main_module, permissions, worker_count, hmr)
|
||||
do_serve(worker_factory, main_module.clone(), worker_count, hmr)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -16,7 +16,7 @@ use deno_core::anyhow::anyhow;
|
|||
use deno_core::anyhow::bail;
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::normalize_path;
|
||||
use deno_path_util::normalize_path;
|
||||
use deno_task_shell::ShellCommand;
|
||||
|
||||
use crate::args::CliOptions;
|
||||
|
@ -190,9 +190,7 @@ async fn run_task(opts: RunTaskOptions<'_>) -> Result<i32, AnyError> {
|
|||
custom_commands,
|
||||
init_cwd: opts.cli_options.initial_cwd(),
|
||||
argv: cli_options.argv(),
|
||||
root_node_modules_dir: npm_resolver
|
||||
.root_node_modules_path()
|
||||
.map(|p| p.as_path()),
|
||||
root_node_modules_dir: npm_resolver.root_node_modules_path(),
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
|
194
cli/util/fs.rs
194
cli/util/fs.rs
|
@ -20,7 +20,6 @@ use deno_core::error::AnyError;
|
|||
use deno_core::unsync::spawn_blocking;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_runtime::deno_fs::FileSystem;
|
||||
use deno_runtime::deno_node::PathClean;
|
||||
|
||||
use crate::util::path::get_atomic_file_path;
|
||||
use crate::util::progress_bar::ProgressBar;
|
||||
|
@ -37,10 +36,98 @@ pub fn atomic_write_file_with_retries<T: AsRef<[u8]>>(
|
|||
file_path: &Path,
|
||||
data: T,
|
||||
mode: u32,
|
||||
) -> std::io::Result<()> {
|
||||
struct RealAtomicWriteFileFs {
|
||||
mode: u32,
|
||||
}
|
||||
|
||||
impl AtomicWriteFileFs for RealAtomicWriteFileFs {
|
||||
fn write_file(&self, path: &Path, bytes: &[u8]) -> std::io::Result<()> {
|
||||
write_file(path, bytes, self.mode)
|
||||
}
|
||||
fn rename_file(&self, from: &Path, to: &Path) -> std::io::Result<()> {
|
||||
std::fs::rename(from, to)
|
||||
}
|
||||
fn remove_file(&self, path: &Path) -> std::io::Result<()> {
|
||||
std::fs::remove_file(path)
|
||||
}
|
||||
fn create_dir_all(&self, dir_path: &Path) -> std::io::Result<()> {
|
||||
std::fs::create_dir_all(dir_path)
|
||||
}
|
||||
fn path_exists(&self, path: &Path) -> bool {
|
||||
path.exists()
|
||||
}
|
||||
}
|
||||
|
||||
atomic_write_file_with_retries_and_fs(
|
||||
&RealAtomicWriteFileFs { mode },
|
||||
file_path,
|
||||
data.as_ref(),
|
||||
)
|
||||
}
|
||||
|
||||
pub trait AtomicWriteFileFs {
|
||||
fn write_file(&self, path: &Path, bytes: &[u8]) -> std::io::Result<()>;
|
||||
fn rename_file(&self, from: &Path, to: &Path) -> std::io::Result<()>;
|
||||
fn remove_file(&self, path: &Path) -> std::io::Result<()>;
|
||||
fn create_dir_all(&self, dir_path: &Path) -> std::io::Result<()>;
|
||||
fn path_exists(&self, path: &Path) -> bool;
|
||||
}
|
||||
|
||||
pub struct AtomicWriteFileFsAdapter<'a> {
|
||||
pub fs: &'a dyn FileSystem,
|
||||
pub write_mode: u32,
|
||||
}
|
||||
|
||||
impl<'a> AtomicWriteFileFs for AtomicWriteFileFsAdapter<'a> {
|
||||
fn write_file(&self, path: &Path, bytes: &[u8]) -> std::io::Result<()> {
|
||||
self
|
||||
.fs
|
||||
.write_file_sync(
|
||||
path,
|
||||
deno_runtime::deno_fs::OpenOptions::write(
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
Some(self.write_mode),
|
||||
),
|
||||
None,
|
||||
bytes,
|
||||
)
|
||||
.map_err(|e| e.into_io_error())
|
||||
}
|
||||
|
||||
fn rename_file(&self, from: &Path, to: &Path) -> std::io::Result<()> {
|
||||
self.fs.rename_sync(from, to).map_err(|e| e.into_io_error())
|
||||
}
|
||||
|
||||
fn remove_file(&self, path: &Path) -> std::io::Result<()> {
|
||||
self
|
||||
.fs
|
||||
.remove_sync(path, false)
|
||||
.map_err(|e| e.into_io_error())
|
||||
}
|
||||
|
||||
fn create_dir_all(&self, dir_path: &Path) -> std::io::Result<()> {
|
||||
self
|
||||
.fs
|
||||
.mkdir_sync(dir_path, /* recursive */ true, None)
|
||||
.map_err(|e| e.into_io_error())
|
||||
}
|
||||
|
||||
fn path_exists(&self, path: &Path) -> bool {
|
||||
self.fs.exists_sync(path)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn atomic_write_file_with_retries_and_fs<T: AsRef<[u8]>>(
|
||||
fs: &impl AtomicWriteFileFs,
|
||||
file_path: &Path,
|
||||
data: T,
|
||||
) -> std::io::Result<()> {
|
||||
let mut count = 0;
|
||||
loop {
|
||||
match atomic_write_file(file_path, data.as_ref(), mode) {
|
||||
match atomic_write_file(fs, file_path, data.as_ref()) {
|
||||
Ok(()) => return Ok(()),
|
||||
Err(err) => {
|
||||
if count >= 5 {
|
||||
|
@ -61,63 +148,54 @@ pub fn atomic_write_file_with_retries<T: AsRef<[u8]>>(
|
|||
///
|
||||
/// This also handles creating the directory if a NotFound error
|
||||
/// occurs.
|
||||
fn atomic_write_file<T: AsRef<[u8]>>(
|
||||
fn atomic_write_file(
|
||||
fs: &impl AtomicWriteFileFs,
|
||||
file_path: &Path,
|
||||
data: T,
|
||||
mode: u32,
|
||||
data: &[u8],
|
||||
) -> std::io::Result<()> {
|
||||
fn atomic_write_file_raw(
|
||||
fs: &impl AtomicWriteFileFs,
|
||||
temp_file_path: &Path,
|
||||
file_path: &Path,
|
||||
data: &[u8],
|
||||
mode: u32,
|
||||
) -> std::io::Result<()> {
|
||||
write_file(temp_file_path, data, mode)?;
|
||||
std::fs::rename(temp_file_path, file_path).map_err(|err| {
|
||||
fs.write_file(temp_file_path, data)?;
|
||||
fs.rename_file(temp_file_path, file_path).map_err(|err| {
|
||||
// clean up the created temp file on error
|
||||
let _ = std::fs::remove_file(temp_file_path);
|
||||
let _ = fs.remove_file(temp_file_path);
|
||||
err
|
||||
})
|
||||
}
|
||||
|
||||
fn inner(file_path: &Path, data: &[u8], mode: u32) -> std::io::Result<()> {
|
||||
let temp_file_path = get_atomic_file_path(file_path);
|
||||
let temp_file_path = get_atomic_file_path(file_path);
|
||||
|
||||
if let Err(write_err) =
|
||||
atomic_write_file_raw(&temp_file_path, file_path, data, mode)
|
||||
{
|
||||
if write_err.kind() == ErrorKind::NotFound {
|
||||
let parent_dir_path = file_path.parent().unwrap();
|
||||
match std::fs::create_dir_all(parent_dir_path) {
|
||||
Ok(()) => {
|
||||
return atomic_write_file_raw(
|
||||
&temp_file_path,
|
||||
file_path,
|
||||
data,
|
||||
mode,
|
||||
)
|
||||
if let Err(write_err) =
|
||||
atomic_write_file_raw(fs, &temp_file_path, file_path, data)
|
||||
{
|
||||
if write_err.kind() == ErrorKind::NotFound {
|
||||
let parent_dir_path = file_path.parent().unwrap();
|
||||
match fs.create_dir_all(parent_dir_path) {
|
||||
Ok(()) => {
|
||||
return atomic_write_file_raw(fs, &temp_file_path, file_path, data)
|
||||
.map_err(|err| add_file_context_to_err(file_path, err));
|
||||
}
|
||||
Err(create_err) => {
|
||||
if !parent_dir_path.exists() {
|
||||
return Err(Error::new(
|
||||
create_err.kind(),
|
||||
format!(
|
||||
"{:#} (for '{}')\nCheck the permission of the directory.",
|
||||
create_err,
|
||||
parent_dir_path.display()
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
Err(create_err) => {
|
||||
if !fs.path_exists(parent_dir_path) {
|
||||
return Err(Error::new(
|
||||
create_err.kind(),
|
||||
format!(
|
||||
"{:#} (for '{}')\nCheck the permission of the directory.",
|
||||
create_err,
|
||||
parent_dir_path.display()
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
return Err(add_file_context_to_err(file_path, write_err));
|
||||
}
|
||||
Ok(())
|
||||
return Err(add_file_context_to_err(file_path, write_err));
|
||||
}
|
||||
|
||||
inner(file_path, data.as_ref(), mode)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Creates a std::fs::File handling if the parent does not exist.
|
||||
|
@ -211,48 +289,18 @@ pub fn canonicalize_path(path: &Path) -> Result<PathBuf, Error> {
|
|||
pub fn canonicalize_path_maybe_not_exists(
|
||||
path: &Path,
|
||||
) -> Result<PathBuf, Error> {
|
||||
canonicalize_path_maybe_not_exists_with_custom_fn(path, canonicalize_path)
|
||||
deno_path_util::canonicalize_path_maybe_not_exists(path, &canonicalize_path)
|
||||
}
|
||||
|
||||
pub fn canonicalize_path_maybe_not_exists_with_fs(
|
||||
path: &Path,
|
||||
fs: &dyn FileSystem,
|
||||
) -> Result<PathBuf, Error> {
|
||||
canonicalize_path_maybe_not_exists_with_custom_fn(path, |path| {
|
||||
deno_path_util::canonicalize_path_maybe_not_exists(path, &|path| {
|
||||
fs.realpath_sync(path).map_err(|err| err.into_io_error())
|
||||
})
|
||||
}
|
||||
|
||||
fn canonicalize_path_maybe_not_exists_with_custom_fn(
|
||||
path: &Path,
|
||||
canonicalize: impl Fn(&Path) -> Result<PathBuf, Error>,
|
||||
) -> Result<PathBuf, Error> {
|
||||
let path = path.to_path_buf().clean();
|
||||
let mut path = path.as_path();
|
||||
let mut names_stack = Vec::new();
|
||||
loop {
|
||||
match canonicalize(path) {
|
||||
Ok(mut canonicalized_path) => {
|
||||
for name in names_stack.into_iter().rev() {
|
||||
canonicalized_path = canonicalized_path.join(name);
|
||||
}
|
||||
return Ok(canonicalized_path);
|
||||
}
|
||||
Err(err) if err.kind() == ErrorKind::NotFound => {
|
||||
names_stack.push(match path.file_name() {
|
||||
Some(name) => name.to_owned(),
|
||||
None => return Err(err),
|
||||
});
|
||||
path = match path.parent() {
|
||||
Some(parent) => parent,
|
||||
None => return Err(err),
|
||||
};
|
||||
}
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Collects module specifiers that satisfy the given predicate as a file path, by recursively walking `include`.
|
||||
/// Specifiers that start with http and https are left intact.
|
||||
/// Note: This ignores all .git and node_modules folders.
|
||||
|
@ -708,8 +756,8 @@ pub fn specifier_from_file_path(
|
|||
mod tests {
|
||||
use super::*;
|
||||
use deno_core::futures;
|
||||
use deno_core::normalize_path;
|
||||
use deno_core::parking_lot::Mutex;
|
||||
use deno_path_util::normalize_path;
|
||||
use pretty_assertions::assert_eq;
|
||||
use test_util::PathRef;
|
||||
use test_util::TempDir;
|
||||
|
|
|
@ -165,48 +165,6 @@ pub fn relative_path(from: &Path, to: &Path) -> Option<PathBuf> {
|
|||
pathdiff::diff_paths(to, from)
|
||||
}
|
||||
|
||||
/// Gets if the provided character is not supported on all
|
||||
/// kinds of file systems.
|
||||
pub fn is_banned_path_char(c: char) -> bool {
|
||||
matches!(c, '<' | '>' | ':' | '"' | '|' | '?' | '*')
|
||||
}
|
||||
|
||||
/// Gets a safe local directory name for the provided url.
|
||||
///
|
||||
/// For example:
|
||||
/// https://deno.land:8080/path -> deno.land_8080/path
|
||||
pub fn root_url_to_safe_local_dirname(root: &ModuleSpecifier) -> PathBuf {
|
||||
fn sanitize_segment(text: &str) -> String {
|
||||
text
|
||||
.chars()
|
||||
.map(|c| if is_banned_segment_char(c) { '_' } else { c })
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn is_banned_segment_char(c: char) -> bool {
|
||||
matches!(c, '/' | '\\') || is_banned_path_char(c)
|
||||
}
|
||||
|
||||
let mut result = String::new();
|
||||
if let Some(domain) = root.domain() {
|
||||
result.push_str(&sanitize_segment(domain));
|
||||
}
|
||||
if let Some(port) = root.port() {
|
||||
if !result.is_empty() {
|
||||
result.push('_');
|
||||
}
|
||||
result.push_str(&port.to_string());
|
||||
}
|
||||
let mut result = PathBuf::from(result);
|
||||
if let Some(segments) = root.path_segments() {
|
||||
for segment in segments.filter(|s| !s.is_empty()) {
|
||||
result = result.join(sanitize_segment(segment));
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Slightly different behaviour than the default matching
|
||||
/// where an exact path needs to be matched to be opted-in
|
||||
/// rather than just a partial directory match.
|
||||
|
|
141
cli/worker.rs
141
cli/worker.rs
|
@ -29,12 +29,14 @@ use deno_runtime::deno_tls::RootCertStoreProvider;
|
|||
use deno_runtime::deno_web::BlobStore;
|
||||
use deno_runtime::fmt_errors::format_js_error;
|
||||
use deno_runtime::inspector_server::InspectorServer;
|
||||
use deno_runtime::ops::process::NpmProcessStateProviderRc;
|
||||
use deno_runtime::ops::worker_host::CreateWebWorkerCb;
|
||||
use deno_runtime::permissions::RuntimePermissionDescriptorParser;
|
||||
use deno_runtime::web_worker::WebWorker;
|
||||
use deno_runtime::web_worker::WebWorkerOptions;
|
||||
use deno_runtime::web_worker::WebWorkerServiceOptions;
|
||||
use deno_runtime::worker::MainWorker;
|
||||
use deno_runtime::worker::WorkerOptions;
|
||||
use deno_runtime::worker::WorkerServiceOptions;
|
||||
use deno_runtime::BootstrapOptions;
|
||||
use deno_runtime::WorkerExecutionMode;
|
||||
use deno_runtime::WorkerLogLevel;
|
||||
|
@ -62,13 +64,12 @@ pub trait ModuleLoaderFactory: Send + Sync {
|
|||
fn create_for_main(
|
||||
&self,
|
||||
root_permissions: PermissionsContainer,
|
||||
dynamic_permissions: PermissionsContainer,
|
||||
) -> ModuleLoaderAndSourceMapGetter;
|
||||
|
||||
fn create_for_worker(
|
||||
&self,
|
||||
root_permissions: PermissionsContainer,
|
||||
dynamic_permissions: PermissionsContainer,
|
||||
parent_permissions: PermissionsContainer,
|
||||
permissions: PermissionsContainer,
|
||||
) -> ModuleLoaderAndSourceMapGetter;
|
||||
}
|
||||
|
||||
|
@ -134,8 +135,8 @@ struct SharedWorkerState {
|
|||
module_loader_factory: Box<dyn ModuleLoaderFactory>,
|
||||
node_resolver: Arc<NodeResolver>,
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
permission_desc_parser: Arc<RuntimePermissionDescriptorParser>,
|
||||
root_cert_store_provider: Arc<dyn RootCertStoreProvider>,
|
||||
root_permissions: PermissionsContainer,
|
||||
shared_array_buffer_store: SharedArrayBufferStore,
|
||||
storage_key_resolver: StorageKeyResolver,
|
||||
options: CliMainWorkerOptions,
|
||||
|
@ -147,13 +148,13 @@ impl SharedWorkerState {
|
|||
NodeExtInitServices {
|
||||
node_require_resolver: self.npm_resolver.clone().into_require_resolver(),
|
||||
node_resolver: self.node_resolver.clone(),
|
||||
npm_process_state_provider: self
|
||||
.npm_resolver
|
||||
.clone()
|
||||
.into_process_state_provider(),
|
||||
npm_resolver: self.npm_resolver.clone().into_npm_resolver(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn npm_process_state_provider(&self) -> NpmProcessStateProviderRc {
|
||||
self.npm_resolver.clone().into_process_state_provider()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CliMainWorker {
|
||||
|
@ -430,8 +431,8 @@ impl CliMainWorkerFactory {
|
|||
module_loader_factory: Box<dyn ModuleLoaderFactory>,
|
||||
node_resolver: Arc<NodeResolver>,
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
permission_parser: Arc<RuntimePermissionDescriptorParser>,
|
||||
root_cert_store_provider: Arc<dyn RootCertStoreProvider>,
|
||||
root_permissions: PermissionsContainer,
|
||||
storage_key_resolver: StorageKeyResolver,
|
||||
subcommand: DenoSubcommand,
|
||||
options: CliMainWorkerOptions,
|
||||
|
@ -450,8 +451,8 @@ impl CliMainWorkerFactory {
|
|||
module_loader_factory,
|
||||
node_resolver,
|
||||
npm_resolver,
|
||||
permission_desc_parser: permission_parser,
|
||||
root_cert_store_provider,
|
||||
root_permissions,
|
||||
shared_array_buffer_store: Default::default(),
|
||||
storage_key_resolver,
|
||||
options,
|
||||
|
@ -464,13 +465,12 @@ impl CliMainWorkerFactory {
|
|||
&self,
|
||||
mode: WorkerExecutionMode,
|
||||
main_module: ModuleSpecifier,
|
||||
permissions: PermissionsContainer,
|
||||
) -> Result<CliMainWorker, AnyError> {
|
||||
self
|
||||
.create_custom_worker(
|
||||
mode,
|
||||
main_module,
|
||||
permissions,
|
||||
self.shared.root_permissions.clone(),
|
||||
vec![],
|
||||
Default::default(),
|
||||
)
|
||||
|
@ -530,13 +530,9 @@ impl CliMainWorkerFactory {
|
|||
(main_module, is_cjs)
|
||||
};
|
||||
|
||||
let ModuleLoaderAndSourceMapGetter { module_loader } =
|
||||
shared.module_loader_factory.create_for_main(
|
||||
PermissionsContainer::allow_all(
|
||||
self.shared.permission_desc_parser.clone(),
|
||||
),
|
||||
permissions.clone(),
|
||||
);
|
||||
let ModuleLoaderAndSourceMapGetter { module_loader } = shared
|
||||
.module_loader_factory
|
||||
.create_for_main(permissions.clone());
|
||||
let maybe_inspector_server = shared.maybe_inspector_server.clone();
|
||||
|
||||
let create_web_worker_cb =
|
||||
|
@ -572,6 +568,22 @@ impl CliMainWorkerFactory {
|
|||
}
|
||||
}
|
||||
|
||||
let services = WorkerServiceOptions {
|
||||
root_cert_store_provider: Some(shared.root_cert_store_provider.clone()),
|
||||
module_loader,
|
||||
fs: shared.fs.clone(),
|
||||
node_services: Some(shared.create_node_init_services()),
|
||||
npm_process_state_provider: Some(shared.npm_process_state_provider()),
|
||||
blob_store: shared.blob_store.clone(),
|
||||
broadcast_channel: shared.broadcast_channel.clone(),
|
||||
shared_array_buffer_store: Some(shared.shared_array_buffer_store.clone()),
|
||||
compiled_wasm_module_store: Some(
|
||||
shared.compiled_wasm_module_store.clone(),
|
||||
),
|
||||
feature_checker,
|
||||
permissions,
|
||||
v8_code_cache: shared.code_cache.clone(),
|
||||
};
|
||||
let options = WorkerOptions {
|
||||
bootstrap: BootstrapOptions {
|
||||
deno_version: crate::version::DENO_VERSION_INFO.deno.to_string(),
|
||||
|
@ -606,7 +618,6 @@ impl CliMainWorkerFactory {
|
|||
.options
|
||||
.unsafely_ignore_certificate_errors
|
||||
.clone(),
|
||||
root_cert_store_provider: Some(shared.root_cert_store_provider.clone()),
|
||||
seed: shared.options.seed,
|
||||
format_js_error_fn: Some(Arc::new(format_js_error)),
|
||||
create_web_worker_cb,
|
||||
|
@ -614,28 +625,16 @@ impl CliMainWorkerFactory {
|
|||
should_break_on_first_statement: shared.options.inspect_brk,
|
||||
should_wait_for_inspector_session: shared.options.inspect_wait,
|
||||
strace_ops: shared.options.strace_ops.clone(),
|
||||
module_loader,
|
||||
fs: shared.fs.clone(),
|
||||
node_services: Some(shared.create_node_init_services()),
|
||||
get_error_class_fn: Some(&errors::get_error_class_name),
|
||||
cache_storage_dir,
|
||||
origin_storage_dir,
|
||||
blob_store: shared.blob_store.clone(),
|
||||
broadcast_channel: shared.broadcast_channel.clone(),
|
||||
shared_array_buffer_store: Some(shared.shared_array_buffer_store.clone()),
|
||||
compiled_wasm_module_store: Some(
|
||||
shared.compiled_wasm_module_store.clone(),
|
||||
),
|
||||
stdio,
|
||||
feature_checker,
|
||||
permission_desc_parser: shared.permission_desc_parser.clone(),
|
||||
skip_op_registration: shared.options.skip_op_registration,
|
||||
v8_code_cache: shared.code_cache.clone(),
|
||||
};
|
||||
|
||||
let mut worker = MainWorker::bootstrap_from_options(
|
||||
main_module.clone(),
|
||||
permissions,
|
||||
services,
|
||||
options,
|
||||
);
|
||||
|
||||
|
@ -767,7 +766,26 @@ fn create_web_worker_callback(
|
|||
}
|
||||
}
|
||||
|
||||
let services = WebWorkerServiceOptions {
|
||||
root_cert_store_provider: Some(shared.root_cert_store_provider.clone()),
|
||||
module_loader,
|
||||
fs: shared.fs.clone(),
|
||||
node_services: Some(shared.create_node_init_services()),
|
||||
blob_store: shared.blob_store.clone(),
|
||||
broadcast_channel: shared.broadcast_channel.clone(),
|
||||
shared_array_buffer_store: Some(shared.shared_array_buffer_store.clone()),
|
||||
compiled_wasm_module_store: Some(
|
||||
shared.compiled_wasm_module_store.clone(),
|
||||
),
|
||||
maybe_inspector_server,
|
||||
feature_checker,
|
||||
npm_process_state_provider: Some(shared.npm_process_state_provider()),
|
||||
permissions: args.permissions,
|
||||
};
|
||||
let options = WebWorkerOptions {
|
||||
name: args.name,
|
||||
main_module: args.main_module.clone(),
|
||||
worker_id: args.worker_id,
|
||||
bootstrap: BootstrapOptions {
|
||||
deno_version: crate::version::DENO_VERSION_INFO.deno.to_string(),
|
||||
args: shared.options.argv.clone(),
|
||||
|
@ -778,7 +796,7 @@ fn create_web_worker_callback(
|
|||
enable_op_summary_metrics: shared.options.enable_op_summary_metrics,
|
||||
enable_testing_features: shared.options.enable_testing_features,
|
||||
locale: deno_core::v8::icu::get_language_tag(),
|
||||
location: Some(args.main_module.clone()),
|
||||
location: Some(args.main_module),
|
||||
no_color: !colors::use_color(),
|
||||
color_level: colors::get_color_level(),
|
||||
is_stdout_tty: deno_terminal::is_stdout_tty(),
|
||||
|
@ -800,38 +818,19 @@ fn create_web_worker_callback(
|
|||
.options
|
||||
.unsafely_ignore_certificate_errors
|
||||
.clone(),
|
||||
root_cert_store_provider: Some(shared.root_cert_store_provider.clone()),
|
||||
seed: shared.options.seed,
|
||||
create_web_worker_cb,
|
||||
format_js_error_fn: Some(Arc::new(format_js_error)),
|
||||
module_loader,
|
||||
fs: shared.fs.clone(),
|
||||
node_services: Some(shared.create_node_init_services()),
|
||||
worker_type: args.worker_type,
|
||||
maybe_inspector_server,
|
||||
get_error_class_fn: Some(&errors::get_error_class_name),
|
||||
blob_store: shared.blob_store.clone(),
|
||||
broadcast_channel: shared.broadcast_channel.clone(),
|
||||
shared_array_buffer_store: Some(shared.shared_array_buffer_store.clone()),
|
||||
compiled_wasm_module_store: Some(
|
||||
shared.compiled_wasm_module_store.clone(),
|
||||
),
|
||||
stdio: stdio.clone(),
|
||||
cache_storage_dir,
|
||||
feature_checker,
|
||||
permission_desc_parser: shared.permission_desc_parser.clone(),
|
||||
strace_ops: shared.options.strace_ops.clone(),
|
||||
close_on_idle: args.close_on_idle,
|
||||
maybe_worker_metadata: args.maybe_worker_metadata,
|
||||
};
|
||||
|
||||
WebWorker::bootstrap_from_options(
|
||||
args.name,
|
||||
args.permissions,
|
||||
args.main_module,
|
||||
args.worker_id,
|
||||
options,
|
||||
)
|
||||
WebWorker::bootstrap_from_options(services, options)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -841,23 +840,43 @@ fn create_web_worker_callback(
|
|||
mod tests {
|
||||
use super::*;
|
||||
use deno_core::resolve_path;
|
||||
use deno_core::FsModuleLoader;
|
||||
use deno_fs::RealFs;
|
||||
use deno_runtime::deno_permissions::Permissions;
|
||||
use deno_runtime::permissions::RuntimePermissionDescriptorParser;
|
||||
|
||||
fn create_test_worker() -> MainWorker {
|
||||
let main_module =
|
||||
resolve_path("./hello.js", &std::env::current_dir().unwrap()).unwrap();
|
||||
let permissions = PermissionsContainer::new(
|
||||
Arc::new(RuntimePermissionDescriptorParser::new(Arc::new(RealFs))),
|
||||
Permissions::none_without_prompt(),
|
||||
);
|
||||
|
||||
let fs = Arc::new(RealFs);
|
||||
let permission_desc_parser =
|
||||
Arc::new(RuntimePermissionDescriptorParser::new(fs.clone()));
|
||||
let options = WorkerOptions {
|
||||
startup_snapshot: crate::js::deno_isolate_init(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
MainWorker::bootstrap_from_options(main_module, permissions, options)
|
||||
MainWorker::bootstrap_from_options(
|
||||
main_module,
|
||||
WorkerServiceOptions {
|
||||
module_loader: Rc::new(FsModuleLoader),
|
||||
permissions: PermissionsContainer::new(
|
||||
permission_desc_parser,
|
||||
Permissions::none_without_prompt(),
|
||||
),
|
||||
blob_store: Default::default(),
|
||||
broadcast_channel: Default::default(),
|
||||
feature_checker: Default::default(),
|
||||
node_services: Default::default(),
|
||||
npm_process_state_provider: Default::default(),
|
||||
root_cert_store_provider: Default::default(),
|
||||
shared_array_buffer_store: Default::default(),
|
||||
compiled_wasm_module_store: Default::default(),
|
||||
v8_code_cache: Default::default(),
|
||||
fs,
|
||||
},
|
||||
options,
|
||||
)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_broadcast_channel"
|
||||
version = "0.162.0"
|
||||
version = "0.163.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.101.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_canvas"
|
||||
version = "0.37.0"
|
||||
version = "0.38.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_console"
|
||||
version = "0.168.0"
|
||||
version = "0.169.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_cron"
|
||||
version = "0.48.0"
|
||||
version = "0.49.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_crypto"
|
||||
version = "0.182.0"
|
||||
version = "0.183.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_fetch"
|
||||
version = "0.192.0"
|
||||
version = "0.193.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_ffi"
|
||||
version = "0.155.0"
|
||||
version = "0.156.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_fs"
|
||||
version = "0.78.0"
|
||||
version = "0.79.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
@ -21,6 +21,7 @@ async-trait.workspace = true
|
|||
base32.workspace = true
|
||||
deno_core.workspace = true
|
||||
deno_io.workspace = true
|
||||
deno_path_util.workspace = true
|
||||
deno_permissions.workspace = true
|
||||
filetime.workspace = true
|
||||
libc.workspace = true
|
||||
|
|
|
@ -12,12 +12,12 @@ use std::path::PathBuf;
|
|||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_core::normalize_path;
|
||||
use deno_core::parking_lot::Mutex;
|
||||
use deno_io::fs::File;
|
||||
use deno_io::fs::FsError;
|
||||
use deno_io::fs::FsResult;
|
||||
use deno_io::fs::FsStat;
|
||||
use deno_path_util::normalize_path;
|
||||
|
||||
use crate::interface::AccessCheckCb;
|
||||
use crate::interface::FsDirEntry;
|
||||
|
@ -44,7 +44,7 @@ impl InMemoryFs {
|
|||
pub fn setup_text_files(&self, files: Vec<(String, String)>) {
|
||||
for (path, text) in files {
|
||||
let path = PathBuf::from(path);
|
||||
self.mkdir_sync(path.parent().unwrap(), true, 0).unwrap();
|
||||
self.mkdir_sync(path.parent().unwrap(), true, None).unwrap();
|
||||
self
|
||||
.write_file_sync(
|
||||
&path,
|
||||
|
@ -101,7 +101,7 @@ impl FileSystem for InMemoryFs {
|
|||
&self,
|
||||
path: &Path,
|
||||
recursive: bool,
|
||||
_mode: u32,
|
||||
_mode: Option<u32>,
|
||||
) -> FsResult<()> {
|
||||
let path = normalize_path(path);
|
||||
|
||||
|
@ -119,7 +119,7 @@ impl FileSystem for InMemoryFs {
|
|||
},
|
||||
None => {
|
||||
if recursive {
|
||||
self.mkdir_sync(parent, true, 0)?;
|
||||
self.mkdir_sync(parent, true, None)?;
|
||||
} else {
|
||||
return Err(FsError::Io(Error::new(
|
||||
ErrorKind::NotFound,
|
||||
|
@ -149,7 +149,7 @@ impl FileSystem for InMemoryFs {
|
|||
&self,
|
||||
path: PathBuf,
|
||||
recursive: bool,
|
||||
mode: u32,
|
||||
mode: Option<u32>,
|
||||
) -> FsResult<()> {
|
||||
self.mkdir_sync(&path, recursive, mode)
|
||||
}
|
||||
|
|
|
@ -121,13 +121,17 @@ pub trait FileSystem: std::fmt::Debug + MaybeSend + MaybeSync {
|
|||
access_check: Option<AccessCheckCb<'a>>,
|
||||
) -> FsResult<Rc<dyn File>>;
|
||||
|
||||
fn mkdir_sync(&self, path: &Path, recursive: bool, mode: u32)
|
||||
-> FsResult<()>;
|
||||
fn mkdir_sync(
|
||||
&self,
|
||||
path: &Path,
|
||||
recursive: bool,
|
||||
mode: Option<u32>,
|
||||
) -> FsResult<()>;
|
||||
async fn mkdir_async(
|
||||
&self,
|
||||
path: PathBuf,
|
||||
recursive: bool,
|
||||
mode: u32,
|
||||
mode: Option<u32>,
|
||||
) -> FsResult<()>;
|
||||
|
||||
fn chmod_sync(&self, path: &Path, mode: u32) -> FsResult<()>;
|
||||
|
|
|
@ -197,7 +197,7 @@ where
|
|||
.check_write(&path, "Deno.mkdirSync()")?;
|
||||
|
||||
let fs = state.borrow::<FileSystemRc>();
|
||||
fs.mkdir_sync(&path, recursive, mode)
|
||||
fs.mkdir_sync(&path, recursive, Some(mode))
|
||||
.context_path("mkdir", &path)?;
|
||||
|
||||
Ok(())
|
||||
|
@ -221,7 +221,7 @@ where
|
|||
(state.borrow::<FileSystemRc>().clone(), path)
|
||||
};
|
||||
|
||||
fs.mkdir_async(path.clone(), recursive, mode)
|
||||
fs.mkdir_async(path.clone(), recursive, Some(mode))
|
||||
.await
|
||||
.context_path("mkdir", &path)?;
|
||||
|
||||
|
@ -886,7 +886,7 @@ where
|
|||
const MAX_TRIES: u32 = 10;
|
||||
for _ in 0..MAX_TRIES {
|
||||
let path = tmp_name(&mut rng, &dir, prefix.as_deref(), suffix.as_deref())?;
|
||||
match fs.mkdir_sync(&path, false, 0o700) {
|
||||
match fs.mkdir_sync(&path, false, Some(0o700)) {
|
||||
Ok(_) => {
|
||||
// PERMISSIONS: ensure the absolute path is not leaked
|
||||
let path = strip_dir_prefix(&dir, dir_arg.as_deref(), path)?;
|
||||
|
@ -928,7 +928,11 @@ where
|
|||
const MAX_TRIES: u32 = 10;
|
||||
for _ in 0..MAX_TRIES {
|
||||
let path = tmp_name(&mut rng, &dir, prefix.as_deref(), suffix.as_deref())?;
|
||||
match fs.clone().mkdir_async(path.clone(), false, 0o700).await {
|
||||
match fs
|
||||
.clone()
|
||||
.mkdir_async(path.clone(), false, Some(0o700))
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
// PERMISSIONS: ensure the absolute path is not leaked
|
||||
let path = strip_dir_prefix(&dir, dir_arg.as_deref(), path)?;
|
||||
|
|
|
@ -11,13 +11,13 @@ use std::path::Path;
|
|||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
|
||||
use deno_core::normalize_path;
|
||||
use deno_core::unsync::spawn_blocking;
|
||||
use deno_io::fs::File;
|
||||
use deno_io::fs::FsError;
|
||||
use deno_io::fs::FsResult;
|
||||
use deno_io::fs::FsStat;
|
||||
use deno_io::StdFileResourceInner;
|
||||
use deno_path_util::normalize_path;
|
||||
|
||||
use crate::interface::AccessCheckCb;
|
||||
use crate::interface::FsDirEntry;
|
||||
|
@ -101,7 +101,7 @@ impl FileSystem for RealFs {
|
|||
&self,
|
||||
path: &Path,
|
||||
recursive: bool,
|
||||
mode: u32,
|
||||
mode: Option<u32>,
|
||||
) -> FsResult<()> {
|
||||
mkdir(path, recursive, mode)
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ impl FileSystem for RealFs {
|
|||
&self,
|
||||
path: PathBuf,
|
||||
recursive: bool,
|
||||
mode: u32,
|
||||
mode: Option<u32>,
|
||||
) -> FsResult<()> {
|
||||
spawn_blocking(move || mkdir(&path, recursive, mode)).await?
|
||||
}
|
||||
|
@ -407,11 +407,11 @@ impl FileSystem for RealFs {
|
|||
}
|
||||
}
|
||||
|
||||
fn mkdir(path: &Path, recursive: bool, mode: u32) -> FsResult<()> {
|
||||
fn mkdir(path: &Path, recursive: bool, mode: Option<u32>) -> FsResult<()> {
|
||||
let mut builder = fs::DirBuilder::new();
|
||||
builder.recursive(recursive);
|
||||
#[cfg(unix)]
|
||||
{
|
||||
if let Some(mode) = mode {
|
||||
use std::os::unix::fs::DirBuilderExt;
|
||||
builder.mode(mode);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_http"
|
||||
version = "0.166.0"
|
||||
version = "0.167.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_io"
|
||||
version = "0.78.0"
|
||||
version = "0.79.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -11,11 +11,7 @@ use deno_core::RcRef;
|
|||
use tokio::io::AsyncReadExt;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
#[cfg(unix)]
|
||||
pub type RawBiPipeHandle = std::os::fd::RawFd;
|
||||
|
||||
#[cfg(windows)]
|
||||
pub type RawBiPipeHandle = std::os::windows::io::RawHandle;
|
||||
pub type RawBiPipeHandle = super::RawIoHandle;
|
||||
|
||||
/// One end of a bidirectional pipe. This implements the
|
||||
/// `Resource` trait.
|
||||
|
|
107
ext/io/lib.rs
107
ext/io/lib.rs
|
@ -67,6 +67,7 @@ pub use pipe::AsyncPipeRead;
|
|||
pub use pipe::AsyncPipeWrite;
|
||||
pub use pipe::PipeRead;
|
||||
pub use pipe::PipeWrite;
|
||||
pub use pipe::RawPipeHandle;
|
||||
|
||||
pub use bi_pipe::bi_pipe_pair_raw;
|
||||
pub use bi_pipe::BiPipe;
|
||||
|
@ -75,6 +76,112 @@ pub use bi_pipe::BiPipeResource;
|
|||
pub use bi_pipe::BiPipeWrite;
|
||||
pub use bi_pipe::RawBiPipeHandle;
|
||||
|
||||
/// Abstraction over `AsRawFd` (unix) and `AsRawHandle` (windows)
|
||||
pub trait AsRawIoHandle {
|
||||
fn as_raw_io_handle(&self) -> RawIoHandle;
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl<T> AsRawIoHandle for T
|
||||
where
|
||||
T: std::os::unix::io::AsRawFd,
|
||||
{
|
||||
fn as_raw_io_handle(&self) -> RawIoHandle {
|
||||
self.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl<T> AsRawIoHandle for T
|
||||
where
|
||||
T: std::os::windows::io::AsRawHandle,
|
||||
{
|
||||
fn as_raw_io_handle(&self) -> RawIoHandle {
|
||||
self.as_raw_handle()
|
||||
}
|
||||
}
|
||||
|
||||
/// Abstraction over `IntoRawFd` (unix) and `IntoRawHandle` (windows)
|
||||
pub trait IntoRawIoHandle {
|
||||
fn into_raw_io_handle(self) -> RawIoHandle;
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl<T> IntoRawIoHandle for T
|
||||
where
|
||||
T: std::os::unix::io::IntoRawFd,
|
||||
{
|
||||
fn into_raw_io_handle(self) -> RawIoHandle {
|
||||
self.into_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl<T> IntoRawIoHandle for T
|
||||
where
|
||||
T: std::os::windows::io::IntoRawHandle,
|
||||
{
|
||||
fn into_raw_io_handle(self) -> RawIoHandle {
|
||||
self.into_raw_handle()
|
||||
}
|
||||
}
|
||||
|
||||
/// Abstraction over `FromRawFd` (unix) and `FromRawHandle` (windows)
|
||||
pub trait FromRawIoHandle: Sized {
|
||||
/// Constructs a type from a raw io handle (fd/HANDLE).
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Refer to the standard library docs ([unix](https://doc.rust-lang.org/stable/std/os/windows/io/trait.FromRawHandle.html#tymethod.from_raw_handle)) ([windows](https://doc.rust-lang.org/stable/std/os/fd/trait.FromRawFd.html#tymethod.from_raw_fd))
|
||||
///
|
||||
unsafe fn from_raw_io_handle(handle: RawIoHandle) -> Self;
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl<T> FromRawIoHandle for T
|
||||
where
|
||||
T: std::os::unix::io::FromRawFd,
|
||||
{
|
||||
unsafe fn from_raw_io_handle(fd: RawIoHandle) -> T {
|
||||
// SAFETY: upheld by caller
|
||||
unsafe { T::from_raw_fd(fd) }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl<T> FromRawIoHandle for T
|
||||
where
|
||||
T: std::os::windows::io::FromRawHandle,
|
||||
{
|
||||
unsafe fn from_raw_io_handle(fd: RawIoHandle) -> T {
|
||||
// SAFETY: upheld by caller
|
||||
unsafe { T::from_raw_handle(fd) }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub type RawIoHandle = std::os::fd::RawFd;
|
||||
|
||||
#[cfg(windows)]
|
||||
pub type RawIoHandle = std::os::windows::io::RawHandle;
|
||||
|
||||
pub fn close_raw_handle(handle: RawIoHandle) {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
// SAFETY: libc call
|
||||
unsafe {
|
||||
libc::close(handle);
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
// SAFETY: win32 call
|
||||
unsafe {
|
||||
windows_sys::Win32::Foundation::CloseHandle(handle as _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store the stdio fd/handles in global statics in order to keep them
|
||||
// alive for the duration of the application since the last handle/fd
|
||||
// being dropped will close the corresponding pipe.
|
||||
|
|
|
@ -3,6 +3,8 @@ use std::io;
|
|||
use std::pin::Pin;
|
||||
use std::process::Stdio;
|
||||
|
||||
pub type RawPipeHandle = super::RawIoHandle;
|
||||
|
||||
// The synchronous read end of a unidirectional pipe.
|
||||
pub struct PipeRead {
|
||||
file: std::fs::File,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_kv"
|
||||
version = "0.76.0"
|
||||
version = "0.77.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
@ -21,6 +21,7 @@ bytes.workspace = true
|
|||
chrono = { workspace = true, features = ["now"] }
|
||||
deno_core.workspace = true
|
||||
deno_fetch.workspace = true
|
||||
deno_path_util.workspace = true
|
||||
deno_permissions.workspace = true
|
||||
deno_tls.workspace = true
|
||||
denokv_proto.workspace = true
|
||||
|
|
|
@ -16,9 +16,9 @@ use std::sync::OnceLock;
|
|||
use async_trait::async_trait;
|
||||
use deno_core::error::type_error;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::normalize_path;
|
||||
use deno_core::unsync::spawn_blocking;
|
||||
use deno_core::OpState;
|
||||
use deno_path_util::normalize_path;
|
||||
pub use denokv_sqlite::SqliteBackendError;
|
||||
use denokv_sqlite::SqliteConfig;
|
||||
use denokv_sqlite::SqliteNotifier;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_napi"
|
||||
version = "0.99.0"
|
||||
version = "0.100.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.161.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -69,7 +69,6 @@ impl From<SocketAddr> for IpAddr {
|
|||
}
|
||||
|
||||
pub(crate) fn accept_err(e: std::io::Error) -> AnyError {
|
||||
// FIXME(bartlomieju): compatibility with current JS implementation
|
||||
if let std::io::ErrorKind::Interrupted = e.kind() {
|
||||
bad_resource("Listener has been closed")
|
||||
} else {
|
||||
|
|
|
@ -298,10 +298,10 @@ where
|
|||
.resource_table
|
||||
.take::<TcpStreamResource>(rid)?;
|
||||
// This TCP connection might be used somewhere else. If it's the case, we cannot proceed with the
|
||||
// process of starting a TLS connection on top of this TCP connection, so we just return a bad
|
||||
// resource error. See also: https://github.com/denoland/deno/pull/16242
|
||||
// process of starting a TLS connection on top of this TCP connection, so we just return a Busy error.
|
||||
// See also: https://github.com/denoland/deno/pull/16242
|
||||
let resource = Rc::try_unwrap(resource_rc)
|
||||
.map_err(|_| bad_resource("TCP stream is currently in use"))?;
|
||||
.map_err(|_| custom_error("Busy", "TCP stream is currently in use"))?;
|
||||
let (read_half, write_half) = resource.into_inner();
|
||||
let tcp_stream = read_half.reunite(write_half)?;
|
||||
|
||||
|
@ -526,7 +526,6 @@ pub async fn op_net_accept_tls(
|
|||
match listener.accept().try_or_cancel(&cancel_handle).await {
|
||||
Ok(tuple) => tuple,
|
||||
Err(err) if err.kind() == ErrorKind::Interrupted => {
|
||||
// FIXME(bartlomieju): compatibility with current JS implementation.
|
||||
return Err(bad_resource("Listener has been closed"));
|
||||
}
|
||||
Err(err) => return Err(err.into()),
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::io::TcpStreamResource;
|
||||
use crate::ops_tls::TlsStreamResource;
|
||||
use deno_core::error::bad_resource;
|
||||
use deno_core::error::bad_resource_id;
|
||||
use deno_core::error::custom_error;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::AsyncRefCell;
|
||||
use deno_core::CancelHandle;
|
||||
|
@ -70,7 +70,7 @@ impl<T: NetworkStreamListenerTrait + 'static> NetworkListenerResource<T> {
|
|||
) -> Result<Option<NetworkStreamListener>, AnyError> {
|
||||
if let Ok(resource_rc) = resource_table.take::<Self>(listener_rid) {
|
||||
let resource = Rc::try_unwrap(resource_rc)
|
||||
.map_err(|_| bad_resource("Listener is currently in use"))?;
|
||||
.map_err(|_| custom_error("Busy", "Listener is currently in use"))?;
|
||||
return Ok(Some(resource.listener.into_inner().into()));
|
||||
}
|
||||
Ok(None)
|
||||
|
@ -334,7 +334,7 @@ pub fn take_network_stream_resource(
|
|||
{
|
||||
// This TCP connection might be used somewhere else.
|
||||
let resource = Rc::try_unwrap(resource_rc)
|
||||
.map_err(|_| bad_resource("TCP stream is currently in use"))?;
|
||||
.map_err(|_| custom_error("Busy", "TCP stream is currently in use"))?;
|
||||
let (read_half, write_half) = resource.into_inner();
|
||||
let tcp_stream = read_half.reunite(write_half)?;
|
||||
return Ok(NetworkStream::Tcp(tcp_stream));
|
||||
|
@ -344,7 +344,7 @@ pub fn take_network_stream_resource(
|
|||
{
|
||||
// This TLS connection might be used somewhere else.
|
||||
let resource = Rc::try_unwrap(resource_rc)
|
||||
.map_err(|_| bad_resource("TLS stream is currently in use"))?;
|
||||
.map_err(|_| custom_error("Busy", "TLS stream is currently in use"))?;
|
||||
let (read_half, write_half) = resource.into_inner();
|
||||
let tls_stream = read_half.unsplit(write_half);
|
||||
return Ok(NetworkStream::Tls(tls_stream));
|
||||
|
@ -356,7 +356,7 @@ pub fn take_network_stream_resource(
|
|||
{
|
||||
// This UNIX socket might be used somewhere else.
|
||||
let resource = Rc::try_unwrap(resource_rc)
|
||||
.map_err(|_| bad_resource("UNIX stream is currently in use"))?;
|
||||
.map_err(|_| custom_error("Busy", "Unix socket is currently in use"))?;
|
||||
let (read_half, write_half) = resource.into_inner();
|
||||
let unix_stream = read_half.reunite(write_half)?;
|
||||
return Ok(NetworkStream::Unix(unix_stream));
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_node"
|
||||
version = "0.105.0"
|
||||
version = "0.106.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
@ -34,6 +34,7 @@ deno_io.workspace = true
|
|||
deno_media_type.workspace = true
|
||||
deno_net.workspace = true
|
||||
deno_package_json.workspace = true
|
||||
deno_path_util.workspace = true
|
||||
deno_permissions.workspace = true
|
||||
deno_whoami = "0.1.0"
|
||||
der = { version = "0.7.9", features = ["derive"] }
|
||||
|
@ -87,7 +88,7 @@ sha1.workspace = true
|
|||
sha2.workspace = true
|
||||
sha3 = { version = "0.10.8", features = ["oid"] }
|
||||
signature.workspace = true
|
||||
simd-json = "0.13.4"
|
||||
simd-json = "0.14.0"
|
||||
sm3 = "0.4.2"
|
||||
spki.workspace = true
|
||||
stable_deref_trait = "1.2.0"
|
||||
|
|
|
@ -16,7 +16,6 @@ use deno_core::url::Url;
|
|||
use deno_core::v8;
|
||||
use deno_core::v8::ExternalReference;
|
||||
use deno_core::JsRuntime;
|
||||
use deno_core::OpState;
|
||||
use deno_fs::sync::MaybeSend;
|
||||
use deno_fs::sync::MaybeSync;
|
||||
use node_resolver::NpmResolverRc;
|
||||
|
@ -120,24 +119,6 @@ impl NodePermissions for deno_permissions::PermissionsContainer {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub type NpmProcessStateProviderRc =
|
||||
deno_fs::sync::MaybeArc<dyn NpmProcessStateProvider>;
|
||||
|
||||
pub trait NpmProcessStateProvider:
|
||||
std::fmt::Debug + MaybeSend + MaybeSync
|
||||
{
|
||||
/// Gets a string containing the serialized npm state of the process.
|
||||
///
|
||||
/// This will be set on the `DENO_DONT_USE_INTERNAL_NODE_COMPAT_STATE` environment
|
||||
/// variable when doing a `child_process.fork`. The implementor can then check this environment
|
||||
/// variable on startup to repopulate the internal npm state.
|
||||
fn get_npm_process_state(&self) -> String {
|
||||
// This method is only used in the CLI.
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub type NodeRequireResolverRc =
|
||||
deno_fs::sync::MaybeArc<dyn NodeRequireResolver>;
|
||||
|
@ -165,17 +146,9 @@ fn op_node_build_os() -> String {
|
|||
env!("TARGET").split('-').nth(2).unwrap().to_string()
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[string]
|
||||
fn op_npm_process_state(state: &mut OpState) -> Result<String, AnyError> {
|
||||
let npm_resolver = state.borrow_mut::<NpmProcessStateProviderRc>();
|
||||
Ok(npm_resolver.get_npm_process_state())
|
||||
}
|
||||
|
||||
pub struct NodeExtInitServices {
|
||||
pub node_require_resolver: NodeRequireResolverRc,
|
||||
pub node_resolver: NodeResolverRc,
|
||||
pub npm_process_state_provider: NpmProcessStateProviderRc,
|
||||
pub npm_resolver: NpmResolverRc,
|
||||
}
|
||||
|
||||
|
@ -194,6 +167,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,
|
||||
|
@ -374,7 +348,6 @@ deno_core::extension!(deno_node,
|
|||
ops::os::op_cpus<P>,
|
||||
ops::os::op_homedir<P>,
|
||||
op_node_build_os,
|
||||
op_npm_process_state,
|
||||
ops::require::op_require_can_parse_as_esm,
|
||||
ops::require::op_require_init_paths,
|
||||
ops::require::op_require_node_module_paths<P>,
|
||||
|
@ -662,7 +635,6 @@ deno_core::extension!(deno_node,
|
|||
state.put(init.node_require_resolver.clone());
|
||||
state.put(init.node_resolver.clone());
|
||||
state.put(init.npm_resolver.clone());
|
||||
state.put(init.npm_process_state_provider.clone());
|
||||
}
|
||||
},
|
||||
global_template_middleware = global_template_middleware,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
use deno_core::anyhow::Context;
|
||||
use deno_core::error::generic_error;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::normalize_path;
|
||||
use deno_core::op2;
|
||||
use deno_core::url::Url;
|
||||
use deno_core::v8;
|
||||
|
@ -12,6 +11,7 @@ use deno_core::ModuleSpecifier;
|
|||
use deno_core::OpState;
|
||||
use deno_fs::FileSystemRc;
|
||||
use deno_package_json::PackageJsonRc;
|
||||
use deno_path_util::normalize_path;
|
||||
use node_resolver::NodeModuleKind;
|
||||
use node_resolver::NodeResolutionMode;
|
||||
use node_resolver::REQUIRE_CONDITIONS;
|
||||
|
@ -104,7 +104,7 @@ where
|
|||
} else {
|
||||
let current_dir =
|
||||
&(fs.cwd().map_err(AnyError::from)).context("Unable to get CWD")?;
|
||||
deno_core::normalize_path(current_dir.join(from))
|
||||
deno_path_util::normalize_path(current_dir.join(from))
|
||||
};
|
||||
|
||||
ensure_read_permission::<P>(state, &from)?;
|
||||
|
|
|
@ -13,4 +13,5 @@ export {
|
|||
kMaxLength,
|
||||
kStringMaxLength,
|
||||
SlowBuffer,
|
||||
transcode,
|
||||
} from "ext:deno_node/internal/buffer.mjs";
|
||||
|
|
|
@ -10,7 +10,6 @@ import { internals } from "ext:core/mod.js";
|
|||
import {
|
||||
op_bootstrap_unstable_args,
|
||||
op_node_child_ipc_pipe,
|
||||
op_npm_process_state,
|
||||
} from "ext:core/ops";
|
||||
|
||||
import {
|
||||
|
@ -54,6 +53,7 @@ import {
|
|||
convertToValidSignal,
|
||||
kEmptyObject,
|
||||
} from "ext:deno_node/internal/util.mjs";
|
||||
import { kNeedsNpmProcessState } from "ext:runtime/40_process.js";
|
||||
|
||||
const MAX_BUFFER = 1024 * 1024;
|
||||
|
||||
|
@ -168,9 +168,8 @@ export function fork(
|
|||
options.execPath = options.execPath || Deno.execPath();
|
||||
options.shell = false;
|
||||
|
||||
Object.assign(options.env ??= {}, {
|
||||
DENO_DONT_USE_INTERNAL_NODE_COMPAT_STATE: op_npm_process_state(),
|
||||
});
|
||||
// deno-lint-ignore no-explicit-any
|
||||
(options as any)[kNeedsNpmProcessState] = true;
|
||||
|
||||
return spawn(options.execPath, args, options);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -56,7 +56,12 @@ import { StringPrototypeSlice } from "ext:deno_node/internal/primordials.mjs";
|
|||
import { StreamBase } from "ext:deno_node/internal_binding/stream_wrap.ts";
|
||||
import { Pipe, socketType } from "ext:deno_node/internal_binding/pipe_wrap.ts";
|
||||
import { Socket } from "node:net";
|
||||
import { kDetached, kExtraStdio, kIpc } from "ext:runtime/40_process.js";
|
||||
import {
|
||||
kDetached,
|
||||
kExtraStdio,
|
||||
kIpc,
|
||||
kNeedsNpmProcessState,
|
||||
} from "ext:runtime/40_process.js";
|
||||
|
||||
export function mapValues<T, O>(
|
||||
record: Readonly<Record<string, T>>,
|
||||
|
@ -281,6 +286,8 @@ export class ChildProcess extends EventEmitter {
|
|||
[kIpc]: ipc, // internal
|
||||
[kExtraStdio]: extraStdioNormalized,
|
||||
[kDetached]: detached,
|
||||
// deno-lint-ignore no-explicit-any
|
||||
[kNeedsNpmProcessState]: (options ?? {} as any)[kNeedsNpmProcessState],
|
||||
}).spawn();
|
||||
this.pid = this.#process.pid;
|
||||
|
||||
|
|
|
@ -951,7 +951,6 @@ export class Socket extends Duplex {
|
|||
*/
|
||||
override pause(): this {
|
||||
if (
|
||||
this[kBuffer] &&
|
||||
!this.connecting &&
|
||||
this._handle &&
|
||||
this._handle.reading
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -1,179 +0,0 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use std::path::Component;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use url::Url;
|
||||
|
||||
/// Extension to path_clean::PathClean
|
||||
pub trait PathClean<T> {
|
||||
fn clean(&self) -> T;
|
||||
}
|
||||
|
||||
impl PathClean<PathBuf> for PathBuf {
|
||||
fn clean(&self) -> PathBuf {
|
||||
fn is_clean_path(path: &Path) -> bool {
|
||||
let path = path.to_string_lossy();
|
||||
let mut current_index = 0;
|
||||
while let Some(index) = path[current_index..].find("\\.") {
|
||||
let trailing_index = index + current_index + 2;
|
||||
let mut trailing_chars = path[trailing_index..].chars();
|
||||
match trailing_chars.next() {
|
||||
Some('.') => match trailing_chars.next() {
|
||||
Some('/') | Some('\\') | None => {
|
||||
return false;
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
Some('/') | Some('\\') => {
|
||||
return false;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
current_index = trailing_index;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
let path = path_clean::PathClean::clean(self);
|
||||
if cfg!(windows) && !is_clean_path(&path) {
|
||||
// temporary workaround because path_clean::PathClean::clean is
|
||||
// not good enough on windows
|
||||
let mut components = Vec::new();
|
||||
|
||||
for component in path.components() {
|
||||
match component {
|
||||
Component::CurDir => {
|
||||
// skip
|
||||
}
|
||||
Component::ParentDir => {
|
||||
let maybe_last_component = components.pop();
|
||||
if !matches!(maybe_last_component, Some(Component::Normal(_))) {
|
||||
panic!("Error normalizing: {}", path.display());
|
||||
}
|
||||
}
|
||||
Component::Normal(_) | Component::RootDir | Component::Prefix(_) => {
|
||||
components.push(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
components.into_iter().collect::<PathBuf>()
|
||||
} else {
|
||||
path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn to_file_specifier(path: &Path) -> Url {
|
||||
match Url::from_file_path(path) {
|
||||
Ok(url) => url,
|
||||
Err(_) => panic!("Invalid path: {}", path.display()),
|
||||
}
|
||||
}
|
||||
|
||||
// todo(dsherret): we have the below code also in deno_core and it
|
||||
// would be good to somehow re-use it in both places (we don't want
|
||||
// to create a dependency on deno_core here)
|
||||
|
||||
#[cfg(not(windows))]
|
||||
#[inline]
|
||||
pub fn strip_unc_prefix(path: PathBuf) -> PathBuf {
|
||||
path
|
||||
}
|
||||
|
||||
/// Strips the unc prefix (ex. \\?\) from Windows paths.
|
||||
#[cfg(windows)]
|
||||
pub fn strip_unc_prefix(path: PathBuf) -> PathBuf {
|
||||
use std::path::Component;
|
||||
use std::path::Prefix;
|
||||
|
||||
let mut components = path.components();
|
||||
match components.next() {
|
||||
Some(Component::Prefix(prefix)) => {
|
||||
match prefix.kind() {
|
||||
// \\?\device
|
||||
Prefix::Verbatim(device) => {
|
||||
let mut path = PathBuf::new();
|
||||
path.push(format!(r"\\{}\", device.to_string_lossy()));
|
||||
path.extend(components.filter(|c| !matches!(c, Component::RootDir)));
|
||||
path
|
||||
}
|
||||
// \\?\c:\path
|
||||
Prefix::VerbatimDisk(_) => {
|
||||
let mut path = PathBuf::new();
|
||||
path.push(prefix.as_os_str().to_string_lossy().replace(r"\\?\", ""));
|
||||
path.extend(components);
|
||||
path
|
||||
}
|
||||
// \\?\UNC\hostname\share_name\path
|
||||
Prefix::VerbatimUNC(hostname, share_name) => {
|
||||
let mut path = PathBuf::new();
|
||||
path.push(format!(
|
||||
r"\\{}\{}\",
|
||||
hostname.to_string_lossy(),
|
||||
share_name.to_string_lossy()
|
||||
));
|
||||
path.extend(components.filter(|c| !matches!(c, Component::RootDir)));
|
||||
path
|
||||
}
|
||||
_ => path,
|
||||
}
|
||||
}
|
||||
_ => path,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[cfg(windows)]
|
||||
#[test]
|
||||
fn test_path_clean() {
|
||||
use super::*;
|
||||
|
||||
run_test("C:\\test\\./file.txt", "C:\\test\\file.txt");
|
||||
run_test("C:\\test\\../other/file.txt", "C:\\other\\file.txt");
|
||||
run_test("C:\\test\\../other\\file.txt", "C:\\other\\file.txt");
|
||||
|
||||
fn run_test(input: &str, expected: &str) {
|
||||
assert_eq!(PathBuf::from(input).clean(), PathBuf::from(expected));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[test]
|
||||
fn test_strip_unc_prefix() {
|
||||
use std::path::PathBuf;
|
||||
|
||||
run_test(r"C:\", r"C:\");
|
||||
run_test(r"C:\test\file.txt", r"C:\test\file.txt");
|
||||
|
||||
run_test(r"\\?\C:\", r"C:\");
|
||||
run_test(r"\\?\C:\test\file.txt", r"C:\test\file.txt");
|
||||
|
||||
run_test(r"\\.\C:\", r"\\.\C:\");
|
||||
run_test(r"\\.\C:\Test\file.txt", r"\\.\C:\Test\file.txt");
|
||||
|
||||
run_test(r"\\?\UNC\localhost\", r"\\localhost");
|
||||
run_test(r"\\?\UNC\localhost\c$\", r"\\localhost\c$");
|
||||
run_test(
|
||||
r"\\?\UNC\localhost\c$\Windows\file.txt",
|
||||
r"\\localhost\c$\Windows\file.txt",
|
||||
);
|
||||
run_test(r"\\?\UNC\wsl$\deno.json", r"\\wsl$\deno.json");
|
||||
|
||||
run_test(r"\\?\server1", r"\\server1");
|
||||
run_test(r"\\?\server1\e$\", r"\\server1\e$\");
|
||||
run_test(
|
||||
r"\\?\server1\e$\test\file.txt",
|
||||
r"\\server1\e$\test\file.txt",
|
||||
);
|
||||
|
||||
fn run_test(input: &str, expected: &str) {
|
||||
assert_eq!(
|
||||
super::strip_unc_prefix(PathBuf::from(input)),
|
||||
PathBuf::from(expected)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue