1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-21 04:52:26 -05:00

Merge branch 'main' into lsc_cache

This commit is contained in:
Bartek Iwańczuk 2025-01-17 13:41:42 +01:00
commit d62e31af02
No known key found for this signature in database
GPG key ID: 0C6BCDDC3B3AD750
103 changed files with 1772 additions and 770 deletions

View file

@ -5,7 +5,7 @@ import { stringify } from "jsr:@std/yaml@^0.221/stringify";
// Bump this number when you want to purge the cache.
// 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 = 35;
const cacheVersion = 36;
const ubuntuX86Runner = "ubuntu-24.04";
const ubuntuX86XlRunner = "ubuntu-24.04-xl";

View file

@ -184,8 +184,8 @@ jobs:
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
key: '35-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}'
restore-keys: '35-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-'
key: '36-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}'
restore-keys: '36-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-'
if: '!(matrix.skip)'
- uses: dsherret/rust-toolchain-file@v1
if: '!(matrix.skip)'
@ -379,7 +379,7 @@ jobs:
!./target/*/*.zip
!./target/*/*.tar.gz
key: never_saved
restore-keys: '35-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-'
restore-keys: '36-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-'
- name: Apply and update mtime cache
if: '!(matrix.skip) && (!startsWith(github.ref, ''refs/tags/''))'
uses: ./.github/mtime_cache
@ -689,7 +689,7 @@ jobs:
!./target/*/gn_root
!./target/*/*.zip
!./target/*/*.tar.gz
key: '35-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}'
key: '36-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}'
publish-canary:
name: publish canary
runs-on: ubuntu-24.04

96
Cargo.lock generated
View file

@ -1244,7 +1244,7 @@ dependencies = [
[[package]]
name = "deno"
version = "2.1.5"
version = "2.1.6"
dependencies = [
"anstream",
"async-trait",
@ -1422,7 +1422,7 @@ dependencies = [
[[package]]
name = "deno_bench_util"
version = "0.179.0"
version = "0.180.0"
dependencies = [
"bencher",
"deno_core",
@ -1431,7 +1431,7 @@ dependencies = [
[[package]]
name = "deno_broadcast_channel"
version = "0.179.0"
version = "0.180.0"
dependencies = [
"async-trait",
"deno_core",
@ -1443,7 +1443,7 @@ dependencies = [
[[package]]
name = "deno_cache"
version = "0.117.0"
version = "0.118.0"
dependencies = [
"anyhow",
"async-stream",
@ -1497,7 +1497,7 @@ dependencies = [
[[package]]
name = "deno_canvas"
version = "0.54.0"
version = "0.55.0"
dependencies = [
"deno_core",
"deno_error",
@ -1536,7 +1536,7 @@ dependencies = [
[[package]]
name = "deno_console"
version = "0.185.0"
version = "0.186.0"
dependencies = [
"deno_core",
]
@ -1587,7 +1587,7 @@ checksum = "fe4dccb6147bb3f3ba0c7a48e993bfeb999d2c2e47a81badee80e2b370c8d695"
[[package]]
name = "deno_cron"
version = "0.65.0"
version = "0.66.0"
dependencies = [
"anyhow",
"async-trait",
@ -1601,7 +1601,7 @@ dependencies = [
[[package]]
name = "deno_crypto"
version = "0.199.0"
version = "0.200.0"
dependencies = [
"aes",
"aes-gcm",
@ -1694,7 +1694,7 @@ dependencies = [
[[package]]
name = "deno_fetch"
version = "0.209.0"
version = "0.210.0"
dependencies = [
"base64 0.21.7",
"bytes",
@ -1731,7 +1731,7 @@ dependencies = [
[[package]]
name = "deno_ffi"
version = "0.172.0"
version = "0.173.0"
dependencies = [
"deno_core",
"deno_error",
@ -1752,7 +1752,7 @@ dependencies = [
[[package]]
name = "deno_fs"
version = "0.95.0"
version = "0.96.0"
dependencies = [
"async-trait",
"base32",
@ -1810,7 +1810,7 @@ dependencies = [
[[package]]
name = "deno_http"
version = "0.183.0"
version = "0.184.0"
dependencies = [
"async-compression",
"async-trait",
@ -1850,7 +1850,7 @@ dependencies = [
[[package]]
name = "deno_io"
version = "0.95.0"
version = "0.96.0"
dependencies = [
"async-trait",
"deno_core",
@ -1872,7 +1872,7 @@ dependencies = [
[[package]]
name = "deno_kv"
version = "0.93.0"
version = "0.94.0"
dependencies = [
"anyhow",
"async-trait",
@ -1905,7 +1905,7 @@ dependencies = [
[[package]]
name = "deno_lib"
version = "0.1.1"
version = "0.2.0"
dependencies = [
"deno_cache_dir",
"deno_error",
@ -1971,7 +1971,7 @@ dependencies = [
[[package]]
name = "deno_napi"
version = "0.116.0"
version = "0.117.0"
dependencies = [
"deno_core",
"deno_error",
@ -2000,7 +2000,7 @@ dependencies = [
[[package]]
name = "deno_net"
version = "0.177.0"
version = "0.178.0"
dependencies = [
"deno_core",
"deno_error",
@ -2019,7 +2019,7 @@ dependencies = [
[[package]]
name = "deno_node"
version = "0.123.0"
version = "0.124.0"
dependencies = [
"aead-gcm-stream",
"aes",
@ -2042,6 +2042,7 @@ dependencies = [
"deno_package_json",
"deno_path_util",
"deno_permissions",
"deno_process",
"deno_whoami",
"der",
"digest",
@ -2079,7 +2080,6 @@ dependencies = [
"p384",
"path-clean",
"pbkdf2",
"pin-project-lite",
"pkcs8",
"rand",
"regex",
@ -2132,7 +2132,7 @@ dependencies = [
[[package]]
name = "deno_npm_cache"
version = "0.4.0"
version = "0.5.0"
dependencies = [
"async-trait",
"base64 0.21.7",
@ -2179,7 +2179,7 @@ dependencies = [
[[package]]
name = "deno_os"
version = "0.1.0"
version = "0.3.0"
dependencies = [
"deno_core",
"deno_error",
@ -2231,7 +2231,7 @@ dependencies = [
[[package]]
name = "deno_permissions"
version = "0.44.0"
version = "0.45.0"
dependencies = [
"capacity_builder 0.5.0",
"deno_core",
@ -2249,9 +2249,36 @@ dependencies = [
"winapi",
]
[[package]]
name = "deno_process"
version = "0.1.0"
dependencies = [
"deno_core",
"deno_error",
"deno_fs",
"deno_io",
"deno_os",
"deno_path_util",
"deno_permissions",
"libc",
"log",
"memchr",
"nix",
"pin-project-lite",
"rand",
"serde",
"simd-json",
"tempfile",
"thiserror 2.0.3",
"tokio",
"which",
"winapi",
"windows-sys 0.59.0",
]
[[package]]
name = "deno_resolver"
version = "0.16.0"
version = "0.17.0"
dependencies = [
"anyhow",
"async-trait",
@ -2277,7 +2304,7 @@ dependencies = [
[[package]]
name = "deno_runtime"
version = "0.193.0"
version = "0.194.0"
dependencies = [
"color-print",
"deno_ast",
@ -2301,6 +2328,7 @@ dependencies = [
"deno_os",
"deno_path_util",
"deno_permissions",
"deno_process",
"deno_resolver",
"deno_telemetry",
"deno_terminal 0.2.0",
@ -2382,7 +2410,7 @@ dependencies = [
[[package]]
name = "deno_telemetry"
version = "0.7.0"
version = "0.8.0"
dependencies = [
"async-trait",
"deno_core",
@ -2425,7 +2453,7 @@ dependencies = [
[[package]]
name = "deno_tls"
version = "0.172.0"
version = "0.173.0"
dependencies = [
"deno_core",
"deno_error",
@ -2476,7 +2504,7 @@ dependencies = [
[[package]]
name = "deno_url"
version = "0.185.0"
version = "0.186.0"
dependencies = [
"deno_bench_util",
"deno_console",
@ -2489,7 +2517,7 @@ dependencies = [
[[package]]
name = "deno_web"
version = "0.216.0"
version = "0.217.0"
dependencies = [
"async-trait",
"base64-simd 0.8.0",
@ -2512,7 +2540,7 @@ dependencies = [
[[package]]
name = "deno_webgpu"
version = "0.152.0"
version = "0.153.0"
dependencies = [
"deno_core",
"deno_error",
@ -2526,7 +2554,7 @@ dependencies = [
[[package]]
name = "deno_webidl"
version = "0.185.0"
version = "0.186.0"
dependencies = [
"deno_bench_util",
"deno_core",
@ -2534,7 +2562,7 @@ dependencies = [
[[package]]
name = "deno_websocket"
version = "0.190.0"
version = "0.191.0"
dependencies = [
"bytes",
"deno_core",
@ -2557,7 +2585,7 @@ dependencies = [
[[package]]
name = "deno_webstorage"
version = "0.180.0"
version = "0.181.0"
dependencies = [
"deno_core",
"deno_error",
@ -5129,7 +5157,7 @@ dependencies = [
[[package]]
name = "napi_sym"
version = "0.115.0"
version = "0.116.0"
dependencies = [
"quote",
"serde",
@ -5184,7 +5212,7 @@ dependencies = [
[[package]]
name = "node_resolver"
version = "0.23.0"
version = "0.24.0"
dependencies = [
"anyhow",
"async-trait",

View file

@ -51,17 +51,17 @@ repository = "https://github.com/denoland/deno"
deno_ast = { version = "=0.44.0", features = ["transpiling"] }
deno_core = { version = "0.330.0" }
deno_bench_util = { version = "0.179.0", path = "./bench_util" }
deno_bench_util = { version = "0.180.0", path = "./bench_util" }
deno_config = { version = "=0.45.0", features = ["workspace", "sync"] }
deno_lockfile = "=0.24.0"
deno_media_type = { version = "0.2.3", features = ["module_specifier"] }
deno_npm = "=0.27.2"
deno_path_util = "=0.3.0"
deno_permissions = { version = "0.44.0", path = "./runtime/permissions" }
deno_runtime = { version = "0.193.0", path = "./runtime" }
deno_permissions = { version = "0.45.0", path = "./runtime/permissions" }
deno_runtime = { version = "0.194.0", path = "./runtime" }
deno_semver = "=0.7.1"
deno_terminal = "0.2.0"
napi_sym = { version = "0.115.0", path = "./ext/napi/sym" }
napi_sym = { version = "0.116.0", path = "./ext/napi/sym" }
test_util = { package = "test_server", path = "./tests/util/server" }
denokv_proto = "0.9.0"
@ -70,36 +70,37 @@ denokv_remote = "0.9.0"
denokv_sqlite = { default-features = false, version = "0.9.0" }
# exts
deno_broadcast_channel = { version = "0.179.0", path = "./ext/broadcast_channel" }
deno_cache = { version = "0.117.0", path = "./ext/cache" }
deno_canvas = { version = "0.54.0", path = "./ext/canvas" }
deno_console = { version = "0.185.0", path = "./ext/console" }
deno_cron = { version = "0.65.0", path = "./ext/cron" }
deno_crypto = { version = "0.199.0", path = "./ext/crypto" }
deno_fetch = { version = "0.209.0", path = "./ext/fetch" }
deno_ffi = { version = "0.172.0", path = "./ext/ffi" }
deno_fs = { version = "0.95.0", path = "./ext/fs" }
deno_http = { version = "0.183.0", path = "./ext/http" }
deno_io = { version = "0.95.0", path = "./ext/io" }
deno_kv = { version = "0.93.0", path = "./ext/kv" }
deno_napi = { version = "0.116.0", path = "./ext/napi" }
deno_net = { version = "0.177.0", path = "./ext/net" }
deno_node = { version = "0.123.0", path = "./ext/node" }
deno_os = { version = "0.1.0", path = "./ext/os" }
deno_telemetry = { version = "0.7.0", path = "./ext/telemetry" }
deno_tls = { version = "0.172.0", path = "./ext/tls" }
deno_url = { version = "0.185.0", path = "./ext/url" }
deno_web = { version = "0.216.0", path = "./ext/web" }
deno_webgpu = { version = "0.152.0", path = "./ext/webgpu" }
deno_webidl = { version = "0.185.0", path = "./ext/webidl" }
deno_websocket = { version = "0.190.0", path = "./ext/websocket" }
deno_webstorage = { version = "0.180.0", path = "./ext/webstorage" }
deno_broadcast_channel = { version = "0.180.0", path = "./ext/broadcast_channel" }
deno_cache = { version = "0.118.0", path = "./ext/cache" }
deno_canvas = { version = "0.55.0", path = "./ext/canvas" }
deno_console = { version = "0.186.0", path = "./ext/console" }
deno_cron = { version = "0.66.0", path = "./ext/cron" }
deno_crypto = { version = "0.200.0", path = "./ext/crypto" }
deno_fetch = { version = "0.210.0", path = "./ext/fetch" }
deno_ffi = { version = "0.173.0", path = "./ext/ffi" }
deno_fs = { version = "0.96.0", path = "./ext/fs" }
deno_http = { version = "0.184.0", path = "./ext/http" }
deno_io = { version = "0.96.0", path = "./ext/io" }
deno_kv = { version = "0.94.0", path = "./ext/kv" }
deno_napi = { version = "0.117.0", path = "./ext/napi" }
deno_net = { version = "0.178.0", path = "./ext/net" }
deno_node = { version = "0.124.0", path = "./ext/node" }
deno_os = { version = "0.3.0", path = "./ext/os" }
deno_process = { version = "0.1.0", path = "./ext/process" }
deno_telemetry = { version = "0.8.0", path = "./ext/telemetry" }
deno_tls = { version = "0.173.0", path = "./ext/tls" }
deno_url = { version = "0.186.0", path = "./ext/url" }
deno_web = { version = "0.217.0", path = "./ext/web" }
deno_webgpu = { version = "0.153.0", path = "./ext/webgpu" }
deno_webidl = { version = "0.186.0", path = "./ext/webidl" }
deno_websocket = { version = "0.191.0", path = "./ext/websocket" }
deno_webstorage = { version = "0.181.0", path = "./ext/webstorage" }
# workspace libraries
deno_lib = { version = "=0.1.1", path = "./cli/lib" }
deno_npm_cache = { version = "0.4.0", path = "./resolvers/npm_cache" }
deno_resolver = { version = "0.16.0", path = "./resolvers/deno" }
node_resolver = { version = "0.23.0", path = "./resolvers/node" }
deno_lib = { version = "0.2.0", path = "./cli/lib" }
deno_npm_cache = { version = "0.5.0", path = "./resolvers/npm_cache" }
deno_resolver = { version = "0.17.0", path = "./resolvers/deno" }
node_resolver = { version = "0.24.0", path = "./resolvers/node" }
aes = "=0.8.3"
anyhow = "1.0.57"

View file

@ -6,6 +6,32 @@ https://github.com/denoland/deno/releases
We also have one-line install commands at:
https://github.com/denoland/deno_install
### 2.1.6 / 2025.01.16
- fix(check/lsp): correctly resolve compilerOptions.types (#27686)
- fix(check/lsp): fix bugs with tsc type resolution, allow npm packages to
augment `ImportMeta` (#27690)
- fix(compile): store embedded fs case sensitivity (#27653)
- fix(compile/windows): better handling of deno_dir on different drive letter
than code (#27654)
- fix(ext/console): change Temporal color (#27684)
- fix(ext/node): add `writev` method to `FileHandle` (#27563)
- fix(ext/node): add chown method to FileHandle class (#27638)
- fix(ext/node): apply `@npmcli/agent` workaround to `npm-check-updates`
(#27639)
- fix(ext/node): fix playwright http client (#27662)
- fix(ext/node): show bare-node-builtin hint when using an import map (#27632)
- fix(ext/node): use primordials in `ext/node/polyfills/_fs_common.ts` (#27589)
- fix(lsp): handle pathless untitled URIs (#27637)
- fix(lsp/check): don't resolve unknown media types to a `.js` extension
(#27631)
- fix(node): Prevent node:child_process from always inheriting the parent
environment (#27343) (#27340)
- fix(node/fs): add utimes method to the FileHandle class (#27582)
- fix(outdated): Use `latest` tag even when it's the same as the current version
(#27699)
- fix(outdated): retain strict semver specifier when updating (#27701)
### 2.1.5 / 2025.01.09
- feat(unstable): implement QUIC (#21942)

View file

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

View file

@ -2,7 +2,7 @@
[package]
name = "deno"
version = "2.1.5"
version = "2.1.6"
authors.workspace = true
default-run = "deno"
edition.workspace = true

View file

@ -719,7 +719,7 @@ pub enum NpmProcessStateKind {
}
static NPM_PROCESS_STATE: Lazy<Option<NpmProcessState>> = Lazy::new(|| {
use deno_runtime::ops::process::NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME;
use deno_runtime::deno_process::NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME;
let fd = std::env::var(NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME).ok()?;
std::env::remove_var(NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME);
let fd = fd.parse::<usize>().ok()?;

View file

@ -2,7 +2,7 @@
[package]
name = "deno_lib"
version = "0.1.1"
version = "0.2.0"
authors.workspace = true
edition.workspace = true
license.workspace = true
@ -28,7 +28,7 @@ node_resolver = { workspace = true, features = ["sync"] }
parking_lot.workspace = true
ring.workspace = true
serde = { workspace = true, features = ["derive"] }
sys_traits.workspace = true
sys_traits = { workspace = true, features = ["getrandom"] }
thiserror.workspace = true
tokio.workspace = true
url.workspace = true

View file

@ -25,12 +25,12 @@ use deno_runtime::deno_node::NodeExtInitServices;
use deno_runtime::deno_node::NodeRequireLoader;
use deno_runtime::deno_node::NodeResolver;
use deno_runtime::deno_permissions::PermissionsContainer;
use deno_runtime::deno_process::NpmProcessStateProviderRc;
use deno_runtime::deno_telemetry::OtelConfig;
use deno_runtime::deno_tls::RootCertStoreProvider;
use deno_runtime::deno_web::BlobStore;
use deno_runtime::fmt_errors::format_js_error;
use deno_runtime::inspector_server::InspectorServer;
use deno_runtime::ops::process::NpmProcessStateProviderRc;
use deno_runtime::ops::worker_host::CreateWebWorkerCb;
use deno_runtime::web_worker::WebWorker;
use deno_runtime::web_worker::WebWorkerOptions;

View file

@ -73,6 +73,7 @@ use super::documents::Document;
use super::documents::DocumentsFilter;
use super::language_server;
use super::language_server::StateSnapshot;
use super::logging::lsp_log;
use super::performance::Performance;
use super::performance::PerformanceMark;
use super::refactor::RefactorCodeActionData;
@ -4340,7 +4341,9 @@ impl TscSpecifierMap {
if let Some(specifier) = self.normalized_specifiers.get(original) {
return Ok(specifier.clone());
}
let specifier_str = original.replace(".d.ts.d.ts", ".d.ts");
let specifier_str = original
.replace(".d.ts.d.ts", ".d.ts")
.replace("$node_modules", "node_modules");
let specifier = match ModuleSpecifier::parse(&specifier_str) {
Ok(s) => s,
Err(err) => return Err(err),
@ -4695,7 +4698,24 @@ fn op_script_names(state: &mut OpState) -> ScriptNames {
.graph_imports_by_referrer(scope)
{
for specifier in specifiers {
script_names.insert(specifier.to_string());
if let Ok(req_ref) =
deno_semver::npm::NpmPackageReqReference::from_specifier(specifier)
{
let Some((resolved, _)) =
state.state_snapshot.resolver.npm_to_file_url(
&req_ref,
scope,
ResolutionMode::Import,
Some(scope),
)
else {
lsp_log!("failed to resolve {req_ref} to file URL");
continue;
};
script_names.insert(resolved.to_string());
} else {
script_names.insert(specifier.to_string());
}
}
}
}
@ -6245,7 +6265,40 @@ mod tests {
"kind": "keyword"
}
],
"documentation": []
"documentation": [
{
"text": "Outputs a message to the console",
"kind": "text",
},
],
"tags": [
{
"name": "param",
"text": [
{
"text": "data",
"kind": "parameterName",
},
{
"text": " ",
"kind": "space",
},
{
"text": "Values to be printed to the console",
"kind": "text",
},
],
},
{
"name": "example",
"text": [
{
"text": "```ts\nconsole.log('Hello', 'World', 123);\n```",
"kind": "text",
},
],
},
]
})
);
}

View file

@ -5,7 +5,7 @@ use std::sync::Arc;
use deno_core::serde_json;
use deno_resolver::npm::ByonmNpmResolver;
use deno_resolver::npm::ByonmNpmResolverCreateOptions;
use deno_runtime::ops::process::NpmProcessStateProvider;
use deno_runtime::deno_process::NpmProcessStateProvider;
use crate::args::NpmProcessState;
use crate::args::NpmProcessStateKind;

View file

@ -240,7 +240,7 @@ impl<'a> LifecycleScripts<'a> {
// However, if we concurrently run scripts in the future we will
// have to have multiple temp files.
let temp_file_fd =
deno_runtime::ops::process::npm_process_state_tempfile(
deno_runtime::deno_process::npm_process_state_tempfile(
process_state.as_bytes(),
)
.map_err(LifecycleScriptsError::CreateNpmProcessState)?;
@ -248,7 +248,7 @@ impl<'a> LifecycleScripts<'a> {
let _temp_file =
unsafe { std::fs::File::from_raw_io_handle(temp_file_fd) }; // make sure the file gets closed
env_vars.insert(
deno_runtime::ops::process::NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME
deno_runtime::deno_process::NPM_RESOLUTION_STATE_FD_ENV_VAR_NAME
.to_string(),
(temp_file_fd as usize).to_string(),
);

View file

@ -14,7 +14,7 @@ use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
use deno_resolver::npm::managed::ManagedNpmResolverCreateOptions;
use deno_resolver::npm::managed::NpmResolutionCell;
use deno_resolver::npm::ManagedNpmResolverRc;
use deno_runtime::ops::process::NpmProcessStateProvider;
use deno_runtime::deno_process::NpmProcessStateProvider;
use thiserror::Error;
use super::CliNpmRegistryInfoProvider;

View file

@ -12,7 +12,7 @@ use deno_core::url::Url;
use deno_error::JsErrorBox;
use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm::registry::NpmPackageInfo;
use deno_runtime::ops::process::NpmProcessStateProviderRc;
use deno_runtime::deno_process::NpmProcessStateProviderRc;
use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq;
use http::HeaderName;

View file

@ -13,6 +13,7 @@ use deno_graph::Module;
use deno_graph::ModuleError;
use deno_graph::ModuleGraph;
use deno_graph::ModuleLoadError;
use deno_semver::npm::NpmPackageNvReference;
use deno_terminal::colors;
use once_cell::sync::Lazy;
use regex::Regex;
@ -261,6 +262,8 @@ impl TypeChecker {
maybe_check_hash,
} = get_tsc_roots(
&self.sys,
&self.npm_resolver,
&self.node_resolver,
&graph,
check_js,
check_state_hash(&self.npm_resolver),
@ -373,8 +376,11 @@ struct TscRoots {
/// redirects resolved. We need to include all the emittable files in
/// the roots, so they get type checked and optionally emitted,
/// otherwise they would be ignored if only imported into JavaScript.
#[allow(clippy::too_many_arguments)]
fn get_tsc_roots(
sys: &CliSys,
npm_resolver: &CliNpmResolver,
node_resolver: &CliNodeResolver,
graph: &ModuleGraph,
check_js: bool,
npm_cache_state_hash: Option<u64>,
@ -457,6 +463,7 @@ fn get_tsc_roots(
if let Some(hasher) = hasher {
hasher.write_str(module.specifier.as_str());
}
None
}
}
@ -493,17 +500,33 @@ fn get_tsc_roots(
let mut pending = VecDeque::new();
// put in the global types first so that they're resolved before anything else
let get_import_specifiers = || {
graph
.imports
for (referrer, import) in graph.imports.iter() {
for specifier in import
.dependencies
.values()
.flat_map(|i| i.dependencies.values())
.filter_map(|dep| dep.get_type().or_else(|| dep.get_code()))
};
for specifier in get_import_specifiers() {
let specifier = graph.resolve(specifier);
if seen.insert(specifier) {
pending.push_back((specifier, false));
{
let specifier = graph.resolve(specifier);
if seen.insert(specifier) {
if let Ok(nv_ref) = NpmPackageNvReference::from_specifier(specifier) {
let Some(resolved) =
resolve_npm_nv_ref(npm_resolver, node_resolver, &nv_ref, referrer)
else {
result.missing_diagnostics.push(
tsc::Diagnostic::from_missing_error(
specifier,
None,
maybe_additional_sloppy_imports_message(sys, specifier),
),
);
continue;
};
let mt = MediaType::from_specifier(&resolved);
result.roots.push((resolved, mt));
} else {
pending.push_back((specifier, false));
}
}
}
}
@ -624,6 +647,29 @@ fn get_tsc_roots(
result
}
fn resolve_npm_nv_ref(
npm_resolver: &CliNpmResolver,
node_resolver: &CliNodeResolver,
nv_ref: &NpmPackageNvReference,
referrer: &ModuleSpecifier,
) -> Option<ModuleSpecifier> {
let pkg_dir = npm_resolver
.as_managed()
.unwrap()
.resolve_pkg_folder_from_deno_module(nv_ref.nv())
.ok()?;
let resolved = node_resolver
.resolve_package_subpath_from_deno_module(
&pkg_dir,
nv_ref.sub_path(),
Some(referrer),
node_resolver::ResolutionMode::Import,
node_resolver::NodeResolutionKind::Types,
)
.ok()?;
Some(resolved)
}
/// Matches the `@ts-check` pragma.
static TS_CHECK_RE: Lazy<Regex> =
lazy_regex::lazy_regex!(r#"(?i)^\s*@ts-check(?:\s+|$)"#);

View file

@ -683,10 +683,21 @@ impl DepManager {
.and_then(|info| {
let latest_tag = info.dist_tags.get("latest")?;
let lower_bound = &semver_compatible.as_ref()?.version;
if latest_tag > lower_bound {
if latest_tag >= lower_bound {
Some(latest_tag.clone())
} else {
latest_version(Some(latest_tag), info.versions.keys())
latest_version(
Some(latest_tag),
info.versions.iter().filter_map(
|(version, version_info)| {
if version_info.deprecated.is_none() {
Some(version)
} else {
None
}
},
),
)
}
})
.map(|version| PackageNv {

View file

@ -280,9 +280,15 @@ fn choose_new_version_req(
if preferred.version <= resolved?.version {
return None;
}
let exact = if let Some(range) = dep.req.version_req.range() {
range.0[0].start == range.0[0].end
} else {
false
};
Some(
VersionReq::parse_from_specifier(
format!("^{}", preferred.version).as_str(),
format!("{}{}", if exact { "" } else { "^" }, preferred.version)
.as_str(),
)
.unwrap(),
)

View file

@ -500,6 +500,8 @@ delete Object.prototype.__proto__;
// Microsoft/TypeScript#26825 but that doesn't seem to be working here,
// so we will ignore complaints about this compiler setting.
5070,
// TS6053: File '{0}' not found.
6053,
// TS7016: Could not find a declaration file for module '...'. '...'
// implicitly has an 'any' type. This is due to `allowJs` being off by
// default but importing of a JavaScript module.
@ -705,15 +707,14 @@ delete Object.prototype.__proto__;
resolveTypeReferenceDirectiveReferences(
typeDirectiveReferences,
containingFilePath,
redirectedReference,
_redirectedReference,
options,
containingSourceFile,
_reusedNames,
) {
const isCjs =
containingSourceFile?.impliedNodeFormat === ts.ModuleKind.CommonJS;
/** @type {Array<ts.ResolvedTypeReferenceDirectiveWithFailedLookupLocations>} */
const result = typeDirectiveReferences.map((arg) => {
const toResolve = typeDirectiveReferences.map((arg) => {
/** @type {ts.FileReference} */
const fileReference = typeof arg === "string"
? {
@ -722,46 +723,50 @@ delete Object.prototype.__proto__;
fileName: arg,
}
: arg;
if (fileReference.fileName.startsWith("npm:")) {
/** @type {[string, ts.Extension | null] | undefined} */
const resolved = ops.op_resolve(
containingFilePath,
[
[
fileReference.resolutionMode == null
? isCjs
: fileReference.resolutionMode === ts.ModuleKind.CommonJS,
fileReference.fileName,
],
],
)?.[0];
if (resolved && resolved[1]) {
return {
resolvedTypeReferenceDirective: {
primary: true,
resolvedFileName: resolved[0],
// todo(dsherret): we should probably be setting this
isExternalLibraryImport: undefined,
},
};
} else {
return {
resolvedTypeReferenceDirective: undefined,
};
}
return [
fileReference.resolutionMode == null
? isCjs
: fileReference.resolutionMode === ts.ModuleKind.CommonJS,
fileReference.fileName,
];
});
/** @type {Array<[string, ts.Extension | null] | undefined>} */
const resolved = ops.op_resolve(
containingFilePath,
toResolve,
);
/** @type {Array<ts.ResolvedTypeReferenceDirectiveWithFailedLookupLocations>} */
const result = resolved.map((item) => {
if (item && item[1]) {
const [resolvedFileName, extension] = item;
return {
resolvedTypeReferenceDirective: {
primary: true,
resolvedFileName,
extension,
isExternalLibraryImport: false,
},
};
} else {
return ts.resolveTypeReferenceDirective(
fileReference.fileName,
containingFilePath,
options,
host,
redirectedReference,
undefined,
containingSourceFile?.impliedNodeFormat ??
fileReference.resolutionMode,
);
return {
resolvedTypeReferenceDirective: undefined,
};
}
});
if (logDebug) {
debug(
"resolveTypeReferenceDirectiveReferences ",
typeDirectiveReferences,
containingFilePath,
options,
containingSourceFile?.fileName,
" => ",
result,
);
}
return result;
},
resolveModuleNameLiterals(
@ -1116,6 +1121,36 @@ delete Object.prototype.__proto__;
if (IGNORED_DIAGNOSTICS.includes(diagnostic.code)) {
return false;
}
// ignore diagnostics resulting from the `ImportMeta` declaration in deno merging with
// the one in @types/node. the types of the filename and dirname properties are different,
// which causes tsc to error.
const importMetaFilenameDirnameModifiersRe =
/^All declarations of '(filename|dirname)'/;
const importMetaFilenameDirnameTypesRe =
/^Subsequent property declarations must have the same type.\s+Property '(filename|dirname)'/;
// Declarations of X must have identical modifiers.
if (diagnostic.code === 2687) {
if (
typeof diagnostic.messageText === "string" &&
(importMetaFilenameDirnameModifiersRe.test(diagnostic.messageText)) &&
(diagnostic.file?.fileName.startsWith("asset:///") ||
diagnostic.file?.fileName?.includes("@types/node"))
) {
return false;
}
}
// Subsequent property declarations must have the same type.
if (diagnostic.code === 2717) {
if (
typeof diagnostic.messageText === "string" &&
(importMetaFilenameDirnameTypesRe.test(diagnostic.messageText)) &&
(diagnostic.file?.fileName.startsWith("asset:///") ||
diagnostic.file?.fileName?.includes("@types/node"))
) {
return false;
}
}
// make the diagnostic for using an `export =` in an es module a warning
if (diagnostic.code === 1203) {
diagnostic.category = ts.DiagnosticCategory.Warning;
@ -1410,7 +1445,6 @@ delete Object.prototype.__proto__;
"ErrorConstructor",
"gc",
"Global",
"ImportMeta",
"localStorage",
"queueMicrotask",
"RequestInit",

View file

@ -119,9 +119,86 @@ declare var onunload: ((this: Window, ev: Event) => any) | null;
declare var onunhandledrejection:
| ((this: Window, ev: PromiseRejectionEvent) => any)
| null;
/** @category Storage */
/**
* Deno's `localStorage` API provides a way to store key-value pairs in a
* web-like environment, similar to the Web Storage API found in browsers.
* It allows developers to persist data across sessions in a Deno application.
* This API is particularly useful for applications that require a simple
* and effective way to store data locally.
*
* - Key-Value Storage: Stores data as key-value pairs.
* - Persistent: Data is retained even after the application is closed.
* - Synchronous API: Operations are performed synchronously.
*
* `localStorage` is similar to {@linkcode sessionStorage}, and shares the same
* API methods, visible in the {@linkcode Storage} type.
*
* When using the `--location` flag, the origin for the location is used to
* uniquely store the data. That means a location of http://example.com/a.ts
* and http://example.com/b.ts and http://example.com:80/ would all share the
* same storage, but https://example.com/ would be different.
*
* For more information, see the reference guide for
* [Web Storage](https://docs.deno.com/runtime/reference/web_platform_apis/#web-storage)
* and using
* [the `--location` flag](https://docs.deno.com/runtime/reference/web_platform_apis/#location-flag).
*
* @example
* ```ts
* // Set a value in localStorage
* localStorage.setItem("key", "value");
*
* // Get a value from localStorage
* const value = localStorage.getItem("key");
* console.log(value); // Output: "value"
*
* // Remove a value from localStorage
* localStorage.removeItem("key");
*
* // Clear all values from localStorage
* localStorage.clear();
* ```
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
* @category Storage */
declare var localStorage: Storage;
/** @category Storage */
/**
* Deno's `sessionStorage` API operates similarly to the {@linkcode localStorage} API,
* but it is intended for storing data temporarily for the duration of a session.
* Data stored in sessionStorage is cleared when the application session or
* process ends. This makes it suitable for temporary data that you do not need
* to persist across user sessions.
*
* - Key-Value Storage: Stores data as key-value pairs.
* - Session-Based: Data is only available for the duration of the page session.
* - Synchronous API: Operations are performed synchronously.
*
* `sessionStorage` is similar to {@linkcode localStorage}, and shares the same API
* methods, visible in the {@linkcode Storage} type.
*
* For more information, see the reference guide for
* [Web Storage](https://docs.deno.com/runtime/reference/web_platform_apis/#web-storage)
*
* @example
* ```ts
* // Set a value in sessionStorage
* sessionStorage.setItem("key", "value");
*
* // Get a value from sessionStorage
* const value = sessionStorage.getItem("key");
* console.log(value); // Output: "value"
*
* // Remove a value from sessionStorage
* sessionStorage.removeItem("key");
*
* // Clear all the values from sessionStorage
* sessionStorage.clear();
* ```
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage
* @category Storage
*/
declare var sessionStorage: Storage;
/** @category Cache */
declare var caches: CacheStorage;
@ -149,6 +226,12 @@ declare var navigator: Navigator;
*
* If the stdin is not interactive, it does nothing.
*
* @example
* ```ts
* // Displays the message "Acknowledge me! [Enter]" and waits for the enter key to be pressed before continuing.
* alert("Acknowledge me!");
* ```
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/alert
* @category Platform
*
* @param message
@ -162,6 +245,15 @@ declare function alert(message?: string): void;
*
* If the stdin is not interactive, it returns false.
*
* @example
* ```ts
* const shouldProceed = confirm("Do you want to proceed?");
*
* // If the user presses 'y' or 'Y', the result will be true
* // If the user presses 'n' or 'N', the result will be false
* console.log("Should proceed?", shouldProceed);
* ```
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm
* @category Platform
*
* @param message
@ -179,6 +271,15 @@ declare function confirm(message?: string): boolean;
*
* If the stdin is not interactive, it returns null.
*
* @example
* ```ts
* const pet = prompt("Cats or dogs?", "It's fine to love both!");
*
* // Displays the user's input or the default value of "It's fine to love both!"
* console.log("Best pet:", pet);
* ```
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt
*
* @category Platform
*
* @param message

View file

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

View file

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

View file

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

View file

@ -216,7 +216,7 @@ const styles = {
regexp: "red",
module: "underline",
internalError: "red",
temporal: "magenta",
temporal: "cyan",
};
const defaultFG = 39;

View file

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

View file

@ -6,33 +6,251 @@
/// <reference lib="esnext" />
/** @category I/O */
/**
* The Console interface provides methods for logging information to the console,
* as well as other utility methods for debugging and inspecting code.
* @see https://developer.mozilla.org/en-US/docs/Web/API/console
*/
/** Interface representing the console object that provides methods for logging, debugging, and timing */
interface Console {
/**
* Tests that an expression is true. If not, logs an error message
* @param condition The expression to test for truthiness
* @param data Additional arguments to be printed if the assertion fails
* @example
* ```ts
* console.assert(1 === 1, "This won't show");
* console.assert(1 === 2, "This will show an error");
* ```
*/
assert(condition?: boolean, ...data: any[]): void;
/**
* Clears the console if the environment allows it
* @example
* ```ts
* console.clear();
* ```
*/
clear(): void;
/**
* Maintains an internal counter for a given label, incrementing it each time the method is called
* @param label The label to count. Defaults to 'default'
* @example
* ```ts
* console.count('myCounter');
* console.count('myCounter'); // Will show: myCounter: 2
* ```
*/
count(label?: string): void;
/**
* Resets the counter for a given label
* @param label The label to reset. Defaults to 'default'
* @example
* ```ts
* console.count('myCounter');
* console.countReset('myCounter'); // Resets to 0
* ```
*/
countReset(label?: string): void;
/**
* Outputs a debugging message to the console
* @param data Values to be printed to the console
* @example
* ```ts
* console.debug('Debug message', { detail: 'some data' });
* ```
*/
debug(...data: any[]): void;
/**
* Displays a list of the properties of a specified object
* @param item Object to display
* @param options Formatting options
* @example
* ```ts
* console.dir({ name: 'object', value: 42 }, { depth: 1 });
* ```
*/
dir(item?: any, options?: any): void;
/**
* @ignore
*/
dirxml(...data: any[]): void;
/**
* Outputs an error message to the console.
* This method routes the output to stderr,
* unlike other console methods that route to stdout.
* @param data Values to be printed to the console
* @example
* ```ts
* console.error('Error occurred:', new Error('Something went wrong'));
* ```
*/
error(...data: any[]): void;
/**
* Creates a new inline group in the console, indenting subsequent console messages
* @param data Labels for the group
* @example
* ```ts
* console.group('Group 1');
* console.log('Inside group 1');
* console.groupEnd();
* ```
*/
group(...data: any[]): void;
/**
* Creates a new inline group in the console that is initially collapsed
* @param data Labels for the group
* @example
* ```ts
* console.groupCollapsed('Details');
* console.log('Hidden until expanded');
* console.groupEnd();
* ```
*/
groupCollapsed(...data: any[]): void;
/**
* Exits the current inline group in the console
* @example
* ```ts
* console.group('Group');
* console.log('Grouped message');
* console.groupEnd();
* ```
*/
groupEnd(): void;
/**
* Outputs an informational message to the console
* @param data Values to be printed to the console
* @example
* ```ts
* console.info('Application started', { version: '1.0.0' });
* ```
*/
info(...data: any[]): void;
/**
* Outputs a message to the console
* @param data Values to be printed to the console
* @example
* ```ts
* console.log('Hello', 'World', 123);
* ```
*/
log(...data: any[]): void;
/**
* Displays tabular data as a table
* @param tabularData Data to be displayed in table format
* @param properties Array of property names to be displayed
* @example
* ```ts
* console.table([
* { name: 'John', age: 30 },
* { name: 'Jane', age: 25 }
* ]);
* ```
*/
table(tabularData?: any, properties?: string[]): void;
/**
* Starts a timer you can use to track how long an operation takes
* @param label Timer label. Defaults to 'default'
* @example
* ```ts
* console.time('operation');
* // ... some code
* console.timeEnd('operation');
* ```
*/
time(label?: string): void;
/**
* Stops a timer that was previously started
* @param label Timer label to stop. Defaults to 'default'
* @example
* ```ts
* console.time('operation');
* // ... some code
* console.timeEnd('operation'); // Prints: operation: 1234ms
* ```
*/
timeEnd(label?: string): void;
/**
* Logs the current value of a timer that was previously started
* @param label Timer label
* @param data Additional data to log
* @example
* ```ts
* console.time('process');
* // ... some code
* console.timeLog('process', 'Checkpoint A');
* ```
*/
timeLog(label?: string, ...data: any[]): void;
/**
* Outputs a stack trace to the console
* @param data Values to be printed to the console
* @example
* ```ts
* console.trace('Trace message');
* ```
*/
trace(...data: any[]): void;
/**
* Outputs a warning message to the console
* @param data Values to be printed to the console
* @example
* ```ts
* console.warn('Deprecated feature used');
* ```
*/
warn(...data: any[]): void;
/** This method is a noop, unless used in inspector */
/**
* Adds a marker to the DevTools Performance panel
* @param label Label for the timestamp
* @example
* ```ts
* console.timeStamp('Navigation Start');
* ```
*/
timeStamp(label?: string): void;
/** This method is a noop, unless used in inspector */
/**
* Starts recording a performance profile
* @param label Profile label
* @example
* ```ts
* console.profile('Performance Profile');
* // ... code to profile
* console.profileEnd('Performance Profile');
* ```
*/
profile(label?: string): void;
/** This method is a noop, unless used in inspector */
/**
* Stops recording a performance profile
* @param label Profile label to stop
* @example
* ```ts
* console.profile('Performance Profile');
* // ... code to profile
* console.profileEnd('Performance Profile');
* ```
*/
profileEnd(label?: string): void;
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2,7 +2,7 @@
[package]
name = "deno_node"
version = "0.123.0"
version = "0.124.0"
authors.workspace = true
edition.workspace = true
license.workspace = true
@ -38,6 +38,7 @@ deno_net.workspace = true
deno_package_json.workspace = true
deno_path_util.workspace = true
deno_permissions.workspace = true
deno_process.workspace = true
deno_whoami = "0.1.0"
der = { version = "0.7.9", features = ["derive"] }
digest = { version = "0.10.5", features = ["core-api", "std"] }
@ -75,7 +76,6 @@ p256.workspace = true
p384.workspace = true
path-clean = "=0.1.0"
pbkdf2 = "0.12.1"
pin-project-lite = "0.2.13"
pkcs8 = { version = "0.10.2", features = ["std", "pkcs5", "encryption"] }
rand.workspace = true
regex.workspace = true

View file

@ -31,8 +31,6 @@ pub use deno_package_json::PackageJson;
use deno_permissions::PermissionCheckError;
pub use node_resolver::PathClean;
pub use ops::ipc::ChildPipeFd;
pub use ops::ipc::IpcJsonStreamResource;
pub use ops::ipc::IpcRefTracker;
use ops::vm;
pub use ops::vm::create_v8_context;
pub use ops::vm::init_global_template;

View file

@ -8,38 +8,24 @@ mod impl_ {
use std::cell::RefCell;
use std::future::Future;
use std::io;
use std::mem;
use std::pin::Pin;
use std::rc::Rc;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::AtomicUsize;
use std::task::ready;
use std::task::Context;
use std::task::Poll;
use deno_core::op2;
use deno_core::serde;
use deno_core::serde::Serializer;
use deno_core::serde_json;
use deno_core::v8;
use deno_core::AsyncRefCell;
use deno_core::CancelFuture;
use deno_core::CancelHandle;
use deno_core::ExternalOpsTracker;
use deno_core::OpState;
use deno_core::RcRef;
use deno_core::ResourceId;
use deno_core::ToV8;
use deno_error::JsErrorBox;
use deno_io::BiPipe;
use deno_io::BiPipeRead;
use deno_io::BiPipeWrite;
use memchr::memchr;
use pin_project_lite::pin_project;
use deno_process::ipc::IpcJsonStreamError;
pub use deno_process::ipc::IpcJsonStreamResource;
pub use deno_process::ipc::IpcRefTracker;
pub use deno_process::ipc::INITIAL_CAPACITY;
use serde::Serialize;
use tokio::io::AsyncRead;
use tokio::io::AsyncWriteExt;
use tokio::io::ReadBuf;
/// Wrapper around v8 value that implements Serialize.
struct SerializeWrapper<'a, 'b>(
@ -289,534 +275,12 @@ mod impl_ {
stream.ref_tracker.unref();
}
/// Tracks whether the IPC resources is currently
/// refed, and allows refing/unrefing it.
pub struct IpcRefTracker {
refed: AtomicBool,
tracker: OpsTracker,
}
/// A little wrapper so we don't have to get an
/// `ExternalOpsTracker` for tests. When we aren't
/// cfg(test), this will get optimized out.
enum OpsTracker {
External(ExternalOpsTracker),
#[cfg(test)]
Test,
}
impl OpsTracker {
fn ref_(&self) {
match self {
Self::External(tracker) => tracker.ref_op(),
#[cfg(test)]
Self::Test => {}
}
}
fn unref(&self) {
match self {
Self::External(tracker) => tracker.unref_op(),
#[cfg(test)]
Self::Test => {}
}
}
}
impl IpcRefTracker {
pub fn new(tracker: ExternalOpsTracker) -> Self {
Self {
refed: AtomicBool::new(false),
tracker: OpsTracker::External(tracker),
}
}
#[cfg(test)]
fn new_test() -> Self {
Self {
refed: AtomicBool::new(false),
tracker: OpsTracker::Test,
}
}
fn ref_(&self) {
if !self.refed.swap(true, std::sync::atomic::Ordering::AcqRel) {
self.tracker.ref_();
}
}
fn unref(&self) {
if self.refed.swap(false, std::sync::atomic::Ordering::AcqRel) {
self.tracker.unref();
}
}
}
pub struct IpcJsonStreamResource {
read_half: AsyncRefCell<IpcJsonStream>,
write_half: AsyncRefCell<BiPipeWrite>,
cancel: Rc<CancelHandle>,
queued_bytes: AtomicUsize,
ref_tracker: IpcRefTracker,
}
impl deno_core::Resource for IpcJsonStreamResource {
fn close(self: Rc<Self>) {
self.cancel.cancel();
}
}
impl IpcJsonStreamResource {
pub fn new(
stream: i64,
ref_tracker: IpcRefTracker,
) -> Result<Self, std::io::Error> {
let (read_half, write_half) = BiPipe::from_raw(stream as _)?.split();
Ok(Self {
read_half: AsyncRefCell::new(IpcJsonStream::new(read_half)),
write_half: AsyncRefCell::new(write_half),
cancel: Default::default(),
queued_bytes: Default::default(),
ref_tracker,
})
}
#[cfg(all(unix, test))]
fn from_stream(
stream: tokio::net::UnixStream,
ref_tracker: IpcRefTracker,
) -> Self {
let (read_half, write_half) = stream.into_split();
Self {
read_half: AsyncRefCell::new(IpcJsonStream::new(read_half.into())),
write_half: AsyncRefCell::new(write_half.into()),
cancel: Default::default(),
queued_bytes: Default::default(),
ref_tracker,
}
}
#[cfg(all(windows, test))]
fn from_stream(
pipe: tokio::net::windows::named_pipe::NamedPipeClient,
ref_tracker: IpcRefTracker,
) -> Self {
let (read_half, write_half) = tokio::io::split(pipe);
Self {
read_half: AsyncRefCell::new(IpcJsonStream::new(read_half.into())),
write_half: AsyncRefCell::new(write_half.into()),
cancel: Default::default(),
queued_bytes: Default::default(),
ref_tracker,
}
}
/// writes _newline terminated_ JSON message to the IPC pipe.
async fn write_msg_bytes(
self: Rc<Self>,
msg: &[u8],
) -> Result<(), io::Error> {
let mut write_half =
RcRef::map(self, |r| &r.write_half).borrow_mut().await;
write_half.write_all(msg).await?;
Ok(())
}
}
// Initial capacity of the buffered reader and the JSON backing buffer.
//
// This is a tradeoff between memory usage and performance on large messages.
//
// 64kb has been chosen after benchmarking 64 to 66536 << 6 - 1 bytes per message.
const INITIAL_CAPACITY: usize = 1024 * 64;
/// A buffer for reading from the IPC pipe.
/// Similar to the internal buffer of `tokio::io::BufReader`.
///
/// This exists to provide buffered reading while granting mutable access
/// to the internal buffer (which isn't exposed through `tokio::io::BufReader`
/// or the `AsyncBufRead` trait). `simd_json` requires mutable access to an input
/// buffer for parsing, so this allows us to use the read buffer directly as the
/// input buffer without a copy (provided the message fits).
struct ReadBuffer {
buffer: Box<[u8]>,
pos: usize,
cap: usize,
}
impl ReadBuffer {
fn new() -> Self {
Self {
buffer: vec![0; INITIAL_CAPACITY].into_boxed_slice(),
pos: 0,
cap: 0,
}
}
fn get_mut(&mut self) -> &mut [u8] {
&mut self.buffer
}
fn available_mut(&mut self) -> &mut [u8] {
&mut self.buffer[self.pos..self.cap]
}
fn consume(&mut self, n: usize) {
self.pos = std::cmp::min(self.pos + n, self.cap);
}
fn needs_fill(&self) -> bool {
self.pos >= self.cap
}
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum IpcJsonStreamError {
#[class(inherit)]
#[error("{0}")]
Io(#[source] std::io::Error),
#[class(generic)]
#[error("{0}")]
SimdJson(#[source] simd_json::Error),
}
// JSON serialization stream over IPC pipe.
//
// `\n` is used as a delimiter between messages.
struct IpcJsonStream {
pipe: BiPipeRead,
buffer: Vec<u8>,
read_buffer: ReadBuffer,
}
impl IpcJsonStream {
fn new(pipe: BiPipeRead) -> Self {
Self {
pipe,
buffer: Vec::with_capacity(INITIAL_CAPACITY),
read_buffer: ReadBuffer::new(),
}
}
async fn read_msg(
&mut self,
) -> Result<Option<serde_json::Value>, IpcJsonStreamError> {
let mut json = None;
let nread = read_msg_inner(
&mut self.pipe,
&mut self.buffer,
&mut json,
&mut self.read_buffer,
)
.await
.map_err(IpcJsonStreamError::Io)?;
if nread == 0 {
// EOF.
return Ok(None);
}
let json = match json {
Some(v) => v,
None => {
// Took more than a single read and some buffering.
simd_json::from_slice(&mut self.buffer[..nread])
.map_err(IpcJsonStreamError::SimdJson)?
}
};
// Safety: Same as `Vec::clear` but without the `drop_in_place` for
// each element (nop for u8). Capacity remains the same.
unsafe {
self.buffer.set_len(0);
}
Ok(Some(json))
}
}
pin_project! {
#[must_use = "futures do nothing unless you `.await` or poll them"]
struct ReadMsgInner<'a, R: ?Sized> {
reader: &'a mut R,
buf: &'a mut Vec<u8>,
json: &'a mut Option<serde_json::Value>,
// The number of bytes appended to buf. This can be less than buf.len() if
// the buffer was not empty when the operation was started.
read: usize,
read_buffer: &'a mut ReadBuffer,
}
}
fn read_msg_inner<'a, R>(
reader: &'a mut R,
buf: &'a mut Vec<u8>,
json: &'a mut Option<serde_json::Value>,
read_buffer: &'a mut ReadBuffer,
) -> ReadMsgInner<'a, R>
where
R: AsyncRead + ?Sized + Unpin,
{
ReadMsgInner {
reader,
buf,
json,
read: 0,
read_buffer,
}
}
fn read_msg_internal<R: AsyncRead + ?Sized>(
mut reader: Pin<&mut R>,
cx: &mut Context<'_>,
buf: &mut Vec<u8>,
read_buffer: &mut ReadBuffer,
json: &mut Option<serde_json::Value>,
read: &mut usize,
) -> Poll<io::Result<usize>> {
loop {
let (done, used) = {
// effectively a tiny `poll_fill_buf`, but allows us to get a mutable reference to the buffer.
if read_buffer.needs_fill() {
let mut read_buf = ReadBuf::new(read_buffer.get_mut());
ready!(reader.as_mut().poll_read(cx, &mut read_buf))?;
read_buffer.cap = read_buf.filled().len();
read_buffer.pos = 0;
}
let available = read_buffer.available_mut();
if let Some(i) = memchr(b'\n', available) {
if *read == 0 {
// Fast path: parse and put into the json slot directly.
json.replace(
simd_json::from_slice(&mut available[..i + 1])
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?,
);
} else {
// This is not the first read, so we have to copy the data
// to make it contiguous.
buf.extend_from_slice(&available[..=i]);
}
(true, i + 1)
} else {
buf.extend_from_slice(available);
(false, available.len())
}
};
read_buffer.consume(used);
*read += used;
if done || used == 0 {
return Poll::Ready(Ok(mem::replace(read, 0)));
}
}
}
impl<R: AsyncRead + ?Sized + Unpin> Future for ReadMsgInner<'_, R> {
type Output = io::Result<usize>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let me = self.project();
read_msg_internal(
Pin::new(*me.reader),
cx,
me.buf,
me.read_buffer,
me.json,
me.read,
)
}
}
#[cfg(test)]
mod tests {
use std::rc::Rc;
use deno_core::serde_json::json;
use deno_core::v8;
use deno_core::JsRuntime;
use deno_core::RcRef;
use deno_core::RuntimeOptions;
use super::IpcJsonStreamResource;
#[allow(clippy::unused_async)]
#[cfg(unix)]
pub async fn pair() -> (Rc<IpcJsonStreamResource>, tokio::net::UnixStream) {
let (a, b) = tokio::net::UnixStream::pair().unwrap();
/* Similar to how ops would use the resource */
let a = Rc::new(IpcJsonStreamResource::from_stream(
a,
super::IpcRefTracker::new_test(),
));
(a, b)
}
#[cfg(windows)]
pub async fn pair() -> (
Rc<IpcJsonStreamResource>,
tokio::net::windows::named_pipe::NamedPipeServer,
) {
use tokio::net::windows::named_pipe::ClientOptions;
use tokio::net::windows::named_pipe::ServerOptions;
let name =
format!(r"\\.\pipe\deno-named-pipe-test-{}", rand::random::<u32>());
let server = ServerOptions::new().create(name.clone()).unwrap();
let client = ClientOptions::new().open(name).unwrap();
server.connect().await.unwrap();
/* Similar to how ops would use the resource */
let client = Rc::new(IpcJsonStreamResource::from_stream(
client,
super::IpcRefTracker::new_test(),
));
(client, server)
}
#[allow(clippy::print_stdout)]
#[tokio::test]
async fn bench_ipc() -> Result<(), Box<dyn std::error::Error>> {
// A simple round trip benchmark for quick dev feedback.
//
// Only ran when the env var is set.
if std::env::var_os("BENCH_IPC_DENO").is_none() {
return Ok(());
}
let (ipc, mut fd2) = pair().await;
let child = tokio::spawn(async move {
use tokio::io::AsyncWriteExt;
let size = 1024 * 1024;
let stri = "x".repeat(size);
let data = format!("\"{}\"\n", stri);
for _ in 0..100 {
fd2.write_all(data.as_bytes()).await?;
}
Ok::<_, std::io::Error>(())
});
let start = std::time::Instant::now();
let mut bytes = 0;
let mut ipc = RcRef::map(ipc, |r| &r.read_half).borrow_mut().await;
loop {
let Some(msgs) = ipc.read_msg().await? else {
break;
};
bytes += msgs.as_str().unwrap().len();
if start.elapsed().as_secs() > 5 {
break;
}
}
let elapsed = start.elapsed();
let mb = bytes as f64 / 1024.0 / 1024.0;
println!("{} mb/s", mb / elapsed.as_secs_f64());
child.await??;
Ok(())
}
#[tokio::test]
async fn unix_ipc_json() -> Result<(), Box<dyn std::error::Error>> {
let (ipc, mut fd2) = pair().await;
let child = tokio::spawn(async move {
use tokio::io::AsyncReadExt;
use tokio::io::AsyncWriteExt;
const EXPECTED: &[u8] = b"\"hello\"\n";
let mut buf = [0u8; EXPECTED.len()];
let n = fd2.read_exact(&mut buf).await?;
assert_eq!(&buf[..n], EXPECTED);
fd2.write_all(b"\"world\"\n").await?;
Ok::<_, std::io::Error>(())
});
ipc
.clone()
.write_msg_bytes(&json_to_bytes(json!("hello")))
.await?;
let mut ipc = RcRef::map(ipc, |r| &r.read_half).borrow_mut().await;
let msgs = ipc.read_msg().await?.unwrap();
assert_eq!(msgs, json!("world"));
child.await??;
Ok(())
}
fn json_to_bytes(v: deno_core::serde_json::Value) -> Vec<u8> {
let mut buf = deno_core::serde_json::to_vec(&v).unwrap();
buf.push(b'\n');
buf
}
#[tokio::test]
async fn unix_ipc_json_multi() -> Result<(), Box<dyn std::error::Error>> {
let (ipc, mut fd2) = pair().await;
let child = tokio::spawn(async move {
use tokio::io::AsyncReadExt;
use tokio::io::AsyncWriteExt;
const EXPECTED: &[u8] = b"\"hello\"\n\"world\"\n";
let mut buf = [0u8; EXPECTED.len()];
let n = fd2.read_exact(&mut buf).await?;
assert_eq!(&buf[..n], EXPECTED);
fd2.write_all(b"\"foo\"\n\"bar\"\n").await?;
Ok::<_, std::io::Error>(())
});
ipc
.clone()
.write_msg_bytes(&json_to_bytes(json!("hello")))
.await?;
ipc
.clone()
.write_msg_bytes(&json_to_bytes(json!("world")))
.await?;
let mut ipc = RcRef::map(ipc, |r| &r.read_half).borrow_mut().await;
let msgs = ipc.read_msg().await?.unwrap();
assert_eq!(msgs, json!("foo"));
child.await??;
Ok(())
}
#[tokio::test]
async fn unix_ipc_json_invalid() -> Result<(), Box<dyn std::error::Error>> {
let (ipc, mut fd2) = pair().await;
let child = tokio::spawn(async move {
tokio::io::AsyncWriteExt::write_all(&mut fd2, b"\n\n").await?;
Ok::<_, std::io::Error>(())
});
let mut ipc = RcRef::map(ipc, |r| &r.read_half).borrow_mut().await;
let _err = ipc.read_msg().await.unwrap_err();
child.await??;
Ok(())
}
#[test]
fn memchr() {
let str = b"hello world";
assert_eq!(super::memchr(b'h', str), Some(0));
assert_eq!(super::memchr(b'w', str), Some(6));
assert_eq!(super::memchr(b'd', str), Some(10));
assert_eq!(super::memchr(b'x', str), None);
let empty = b"";
assert_eq!(super::memchr(b'\n', empty), None);
}
fn wrap_expr(s: &str) -> String {
format!("(function () {{ return {s}; }})()")
}

View file

@ -53,7 +53,7 @@ import {
convertToValidSignal,
kEmptyObject,
} from "ext:deno_node/internal/util.mjs";
import { kNeedsNpmProcessState } from "ext:runtime/40_process.js";
import { kNeedsNpmProcessState } from "ext:deno_process/40_process.js";
const MAX_BUFFER = 1024 * 1024;

View file

@ -455,8 +455,13 @@ class ClientRequest extends OutgoingMessage {
(async () => {
try {
const parsedUrl = new URL(url);
let baseConnRid =
this.socket._handle[kStreamBaseField][internalRidSymbol];
const handle = this.socket._handle;
if (!handle) {
// Using non-standard socket. There's no way to handle this type of socket.
// This should be only happening in artificial test cases
return;
}
let baseConnRid = handle[kStreamBaseField][internalRidSymbol];
if (this._encrypted) {
[baseConnRid] = op_tls_start({
rid: baseConnRid,
@ -637,6 +642,12 @@ class ClientRequest extends OutgoingMessage {
};
this.socket = socket;
this.emit("socket", socket);
socket.once("error", (err) => {
// This callback loosely follow `socketErrorListener` in Node.js
// https://github.com/nodejs/node/blob/f16cd10946ca9ad272f42b94f00cf960571c9181/lib/_http_client.js#L509
emitErrorEvent(this, err);
socket.destroy(err);
});
if (socket.readyState === "opening") {
socket.on("connect", onConnect);
} else {

View file

@ -61,7 +61,7 @@ import {
kExtraStdio,
kIpc,
kNeedsNpmProcessState,
} from "ext:runtime/40_process.js";
} from "ext:deno_process/40_process.js";
export function mapValues<T, O>(
record: Readonly<Record<string, T>>,

View file

@ -2,7 +2,7 @@
[package]
name = "deno_os"
version = "0.1.0"
version = "0.3.0"
authors.workspace = true
edition.workspace = true
license.workspace = true

41
ext/process/Cargo.toml Normal file
View file

@ -0,0 +1,41 @@
# Copyright 2018-2025 the Deno authors. MIT license.
[package]
name = "deno_process"
version = "0.1.0"
authors.workspace = true
edition.workspace = true
license.workspace = true
readme = "README.md"
repository.workspace = true
description = "Subprocess APIs for Deno"
[lib]
path = "lib.rs"
[dependencies]
deno_core.workspace = true
deno_error.workspace = true
deno_fs.workspace = true
deno_io.workspace = true
deno_os.workspace = true
deno_path_util.workspace = true
deno_permissions.workspace = true
libc.workspace = true
log.workspace = true
memchr = "2.7.4"
pin-project-lite = "0.2.13"
rand.workspace = true
serde.workspace = true
simd-json = "0.14.0"
tempfile.workspace = true
thiserror.workspace = true
tokio.workspace = true
which.workspace = true
[target.'cfg(unix)'.dependencies]
nix = { workspace = true, features = ["signal", "process"] }
[target.'cfg(windows)'.dependencies]
winapi = { workspace = true, features = [] }
windows-sys.workspace = true

3
ext/process/README.md Normal file
View file

@ -0,0 +1,3 @@
# deno_process
This crate implements subprocess APIs for Deno

558
ext/process/ipc.rs Normal file
View file

@ -0,0 +1,558 @@
// Copyright 2018-2025 the Deno authors. MIT license.
#![allow(unused)]
use std::cell::RefCell;
use std::future::Future;
use std::io;
use std::mem;
use std::pin::Pin;
use std::rc::Rc;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::AtomicUsize;
use std::task::ready;
use std::task::Context;
use std::task::Poll;
use deno_core::serde;
use deno_core::serde_json;
use deno_core::AsyncRefCell;
use deno_core::CancelHandle;
use deno_core::ExternalOpsTracker;
use deno_core::RcRef;
use deno_io::BiPipe;
use deno_io::BiPipeRead;
use deno_io::BiPipeWrite;
use memchr::memchr;
use pin_project_lite::pin_project;
use tokio::io::AsyncRead;
use tokio::io::AsyncWriteExt;
use tokio::io::ReadBuf;
/// Tracks whether the IPC resources is currently
/// refed, and allows refing/unrefing it.
pub struct IpcRefTracker {
refed: AtomicBool,
tracker: OpsTracker,
}
/// A little wrapper so we don't have to get an
/// `ExternalOpsTracker` for tests. When we aren't
/// cfg(test), this will get optimized out.
enum OpsTracker {
External(ExternalOpsTracker),
#[cfg(test)]
Test,
}
impl OpsTracker {
fn ref_(&self) {
match self {
Self::External(tracker) => tracker.ref_op(),
#[cfg(test)]
Self::Test => {}
}
}
fn unref(&self) {
match self {
Self::External(tracker) => tracker.unref_op(),
#[cfg(test)]
Self::Test => {}
}
}
}
impl IpcRefTracker {
pub fn new(tracker: ExternalOpsTracker) -> Self {
Self {
refed: AtomicBool::new(false),
tracker: OpsTracker::External(tracker),
}
}
#[cfg(test)]
fn new_test() -> Self {
Self {
refed: AtomicBool::new(false),
tracker: OpsTracker::Test,
}
}
pub fn ref_(&self) {
if !self.refed.swap(true, std::sync::atomic::Ordering::AcqRel) {
self.tracker.ref_();
}
}
pub fn unref(&self) {
if self.refed.swap(false, std::sync::atomic::Ordering::AcqRel) {
self.tracker.unref();
}
}
}
pub struct IpcJsonStreamResource {
pub read_half: AsyncRefCell<IpcJsonStream>,
pub write_half: AsyncRefCell<BiPipeWrite>,
pub cancel: Rc<CancelHandle>,
pub queued_bytes: AtomicUsize,
pub ref_tracker: IpcRefTracker,
}
impl deno_core::Resource for IpcJsonStreamResource {
fn close(self: Rc<Self>) {
self.cancel.cancel();
}
}
impl IpcJsonStreamResource {
pub fn new(
stream: i64,
ref_tracker: IpcRefTracker,
) -> Result<Self, std::io::Error> {
let (read_half, write_half) = BiPipe::from_raw(stream as _)?.split();
Ok(Self {
read_half: AsyncRefCell::new(IpcJsonStream::new(read_half)),
write_half: AsyncRefCell::new(write_half),
cancel: Default::default(),
queued_bytes: Default::default(),
ref_tracker,
})
}
#[cfg(all(unix, test))]
pub fn from_stream(
stream: tokio::net::UnixStream,
ref_tracker: IpcRefTracker,
) -> Self {
let (read_half, write_half) = stream.into_split();
Self {
read_half: AsyncRefCell::new(IpcJsonStream::new(read_half.into())),
write_half: AsyncRefCell::new(write_half.into()),
cancel: Default::default(),
queued_bytes: Default::default(),
ref_tracker,
}
}
#[cfg(all(windows, test))]
pub fn from_stream(
pipe: tokio::net::windows::named_pipe::NamedPipeClient,
ref_tracker: IpcRefTracker,
) -> Self {
let (read_half, write_half) = tokio::io::split(pipe);
Self {
read_half: AsyncRefCell::new(IpcJsonStream::new(read_half.into())),
write_half: AsyncRefCell::new(write_half.into()),
cancel: Default::default(),
queued_bytes: Default::default(),
ref_tracker,
}
}
/// writes _newline terminated_ JSON message to the IPC pipe.
pub async fn write_msg_bytes(
self: Rc<Self>,
msg: &[u8],
) -> Result<(), io::Error> {
let mut write_half = RcRef::map(self, |r| &r.write_half).borrow_mut().await;
write_half.write_all(msg).await?;
Ok(())
}
}
// Initial capacity of the buffered reader and the JSON backing buffer.
//
// This is a tradeoff between memory usage and performance on large messages.
//
// 64kb has been chosen after benchmarking 64 to 66536 << 6 - 1 bytes per message.
pub const INITIAL_CAPACITY: usize = 1024 * 64;
/// A buffer for reading from the IPC pipe.
/// Similar to the internal buffer of `tokio::io::BufReader`.
///
/// This exists to provide buffered reading while granting mutable access
/// to the internal buffer (which isn't exposed through `tokio::io::BufReader`
/// or the `AsyncBufRead` trait). `simd_json` requires mutable access to an input
/// buffer for parsing, so this allows us to use the read buffer directly as the
/// input buffer without a copy (provided the message fits).
struct ReadBuffer {
buffer: Box<[u8]>,
pos: usize,
cap: usize,
}
impl ReadBuffer {
fn new() -> Self {
Self {
buffer: vec![0; INITIAL_CAPACITY].into_boxed_slice(),
pos: 0,
cap: 0,
}
}
fn get_mut(&mut self) -> &mut [u8] {
&mut self.buffer
}
fn available_mut(&mut self) -> &mut [u8] {
&mut self.buffer[self.pos..self.cap]
}
fn consume(&mut self, n: usize) {
self.pos = std::cmp::min(self.pos + n, self.cap);
}
fn needs_fill(&self) -> bool {
self.pos >= self.cap
}
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum IpcJsonStreamError {
#[class(inherit)]
#[error("{0}")]
Io(#[source] std::io::Error),
#[class(generic)]
#[error("{0}")]
SimdJson(#[source] simd_json::Error),
}
// JSON serialization stream over IPC pipe.
//
// `\n` is used as a delimiter between messages.
pub struct IpcJsonStream {
pipe: BiPipeRead,
buffer: Vec<u8>,
read_buffer: ReadBuffer,
}
impl IpcJsonStream {
fn new(pipe: BiPipeRead) -> Self {
Self {
pipe,
buffer: Vec::with_capacity(INITIAL_CAPACITY),
read_buffer: ReadBuffer::new(),
}
}
pub async fn read_msg(
&mut self,
) -> Result<Option<serde_json::Value>, IpcJsonStreamError> {
let mut json = None;
let nread = read_msg_inner(
&mut self.pipe,
&mut self.buffer,
&mut json,
&mut self.read_buffer,
)
.await
.map_err(IpcJsonStreamError::Io)?;
if nread == 0 {
// EOF.
return Ok(None);
}
let json = match json {
Some(v) => v,
None => {
// Took more than a single read and some buffering.
simd_json::from_slice(&mut self.buffer[..nread])
.map_err(IpcJsonStreamError::SimdJson)?
}
};
// Safety: Same as `Vec::clear` but without the `drop_in_place` for
// each element (nop for u8). Capacity remains the same.
unsafe {
self.buffer.set_len(0);
}
Ok(Some(json))
}
}
pin_project! {
#[must_use = "futures do nothing unless you `.await` or poll them"]
struct ReadMsgInner<'a, R: ?Sized> {
reader: &'a mut R,
buf: &'a mut Vec<u8>,
json: &'a mut Option<serde_json::Value>,
// The number of bytes appended to buf. This can be less than buf.len() if
// the buffer was not empty when the operation was started.
read: usize,
read_buffer: &'a mut ReadBuffer,
}
}
fn read_msg_inner<'a, R>(
reader: &'a mut R,
buf: &'a mut Vec<u8>,
json: &'a mut Option<serde_json::Value>,
read_buffer: &'a mut ReadBuffer,
) -> ReadMsgInner<'a, R>
where
R: AsyncRead + ?Sized + Unpin,
{
ReadMsgInner {
reader,
buf,
json,
read: 0,
read_buffer,
}
}
fn read_msg_internal<R: AsyncRead + ?Sized>(
mut reader: Pin<&mut R>,
cx: &mut Context<'_>,
buf: &mut Vec<u8>,
read_buffer: &mut ReadBuffer,
json: &mut Option<serde_json::Value>,
read: &mut usize,
) -> Poll<io::Result<usize>> {
loop {
let (done, used) = {
// effectively a tiny `poll_fill_buf`, but allows us to get a mutable reference to the buffer.
if read_buffer.needs_fill() {
let mut read_buf = ReadBuf::new(read_buffer.get_mut());
ready!(reader.as_mut().poll_read(cx, &mut read_buf))?;
read_buffer.cap = read_buf.filled().len();
read_buffer.pos = 0;
}
let available = read_buffer.available_mut();
if let Some(i) = memchr(b'\n', available) {
if *read == 0 {
// Fast path: parse and put into the json slot directly.
json.replace(
simd_json::from_slice(&mut available[..i + 1])
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?,
);
} else {
// This is not the first read, so we have to copy the data
// to make it contiguous.
buf.extend_from_slice(&available[..=i]);
}
(true, i + 1)
} else {
buf.extend_from_slice(available);
(false, available.len())
}
};
read_buffer.consume(used);
*read += used;
if done || used == 0 {
return Poll::Ready(Ok(mem::replace(read, 0)));
}
}
}
impl<R: AsyncRead + ?Sized + Unpin> Future for ReadMsgInner<'_, R> {
type Output = io::Result<usize>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let me = self.project();
read_msg_internal(
Pin::new(*me.reader),
cx,
me.buf,
me.read_buffer,
me.json,
me.read,
)
}
}
#[cfg(test)]
mod tests {
use std::rc::Rc;
use deno_core::serde_json::json;
use deno_core::v8;
use deno_core::JsRuntime;
use deno_core::RcRef;
use deno_core::RuntimeOptions;
use super::IpcJsonStreamResource;
#[allow(clippy::unused_async)]
#[cfg(unix)]
pub async fn pair() -> (Rc<IpcJsonStreamResource>, tokio::net::UnixStream) {
let (a, b) = tokio::net::UnixStream::pair().unwrap();
/* Similar to how ops would use the resource */
let a = Rc::new(IpcJsonStreamResource::from_stream(
a,
super::IpcRefTracker::new_test(),
));
(a, b)
}
#[cfg(windows)]
pub async fn pair() -> (
Rc<IpcJsonStreamResource>,
tokio::net::windows::named_pipe::NamedPipeServer,
) {
use tokio::net::windows::named_pipe::ClientOptions;
use tokio::net::windows::named_pipe::ServerOptions;
let name =
format!(r"\\.\pipe\deno-named-pipe-test-{}", rand::random::<u32>());
let server = ServerOptions::new().create(name.clone()).unwrap();
let client = ClientOptions::new().open(name).unwrap();
server.connect().await.unwrap();
/* Similar to how ops would use the resource */
let client = Rc::new(IpcJsonStreamResource::from_stream(
client,
super::IpcRefTracker::new_test(),
));
(client, server)
}
#[allow(clippy::print_stdout)]
#[tokio::test]
async fn bench_ipc() -> Result<(), Box<dyn std::error::Error>> {
// A simple round trip benchmark for quick dev feedback.
//
// Only ran when the env var is set.
if std::env::var_os("BENCH_IPC_DENO").is_none() {
return Ok(());
}
let (ipc, mut fd2) = pair().await;
let child = tokio::spawn(async move {
use tokio::io::AsyncWriteExt;
let size = 1024 * 1024;
let stri = "x".repeat(size);
let data = format!("\"{}\"\n", stri);
for _ in 0..100 {
fd2.write_all(data.as_bytes()).await?;
}
Ok::<_, std::io::Error>(())
});
let start = std::time::Instant::now();
let mut bytes = 0;
let mut ipc = RcRef::map(ipc, |r| &r.read_half).borrow_mut().await;
loop {
let Some(msgs) = ipc.read_msg().await? else {
break;
};
bytes += msgs.as_str().unwrap().len();
if start.elapsed().as_secs() > 5 {
break;
}
}
let elapsed = start.elapsed();
let mb = bytes as f64 / 1024.0 / 1024.0;
println!("{} mb/s", mb / elapsed.as_secs_f64());
child.await??;
Ok(())
}
#[tokio::test]
async fn unix_ipc_json() -> Result<(), Box<dyn std::error::Error>> {
let (ipc, mut fd2) = pair().await;
let child = tokio::spawn(async move {
use tokio::io::AsyncReadExt;
use tokio::io::AsyncWriteExt;
const EXPECTED: &[u8] = b"\"hello\"\n";
let mut buf = [0u8; EXPECTED.len()];
let n = fd2.read_exact(&mut buf).await?;
assert_eq!(&buf[..n], EXPECTED);
fd2.write_all(b"\"world\"\n").await?;
Ok::<_, std::io::Error>(())
});
ipc
.clone()
.write_msg_bytes(&json_to_bytes(json!("hello")))
.await?;
let mut ipc = RcRef::map(ipc, |r| &r.read_half).borrow_mut().await;
let msgs = ipc.read_msg().await?.unwrap();
assert_eq!(msgs, json!("world"));
child.await??;
Ok(())
}
fn json_to_bytes(v: deno_core::serde_json::Value) -> Vec<u8> {
let mut buf = deno_core::serde_json::to_vec(&v).unwrap();
buf.push(b'\n');
buf
}
#[tokio::test]
async fn unix_ipc_json_multi() -> Result<(), Box<dyn std::error::Error>> {
let (ipc, mut fd2) = pair().await;
let child = tokio::spawn(async move {
use tokio::io::AsyncReadExt;
use tokio::io::AsyncWriteExt;
const EXPECTED: &[u8] = b"\"hello\"\n\"world\"\n";
let mut buf = [0u8; EXPECTED.len()];
let n = fd2.read_exact(&mut buf).await?;
assert_eq!(&buf[..n], EXPECTED);
fd2.write_all(b"\"foo\"\n\"bar\"\n").await?;
Ok::<_, std::io::Error>(())
});
ipc
.clone()
.write_msg_bytes(&json_to_bytes(json!("hello")))
.await?;
ipc
.clone()
.write_msg_bytes(&json_to_bytes(json!("world")))
.await?;
let mut ipc = RcRef::map(ipc, |r| &r.read_half).borrow_mut().await;
let msgs = ipc.read_msg().await?.unwrap();
assert_eq!(msgs, json!("foo"));
child.await??;
Ok(())
}
#[tokio::test]
async fn unix_ipc_json_invalid() -> Result<(), Box<dyn std::error::Error>> {
let (ipc, mut fd2) = pair().await;
let child = tokio::spawn(async move {
tokio::io::AsyncWriteExt::write_all(&mut fd2, b"\n\n").await?;
Ok::<_, std::io::Error>(())
});
let mut ipc = RcRef::map(ipc, |r| &r.read_half).borrow_mut().await;
let _err = ipc.read_msg().await.unwrap_err();
child.await??;
Ok(())
}
#[test]
fn memchr() {
let str = b"hello world";
assert_eq!(super::memchr(b'h', str), Some(0));
assert_eq!(super::memchr(b'w', str), Some(6));
assert_eq!(super::memchr(b'd', str), Some(10));
assert_eq!(super::memchr(b'x', str), None);
let empty = b"";
assert_eq!(super::memchr(b'\n', empty), None);
}
}

View file

@ -38,6 +38,10 @@ use serde::Deserialize;
use serde::Serialize;
use tokio::process::Command;
pub mod ipc;
use ipc::IpcJsonStreamResource;
use ipc::IpcRefTracker;
pub const UNSTABLE_FEATURE_NAME: &str = "process";
#[derive(Copy, Clone, Eq, PartialEq, Deserialize)]
@ -153,6 +157,7 @@ deno_core::extension!(
deprecated::op_run_status,
deprecated::op_kill,
],
esm = ["40_process.js"],
options = { get_npm_process_state: Option<NpmProcessStateProviderRc> },
state = |state, options| {
state.put::<NpmProcessStateProviderRc>(options.get_npm_process_state.unwrap_or(deno_fs::sync::MaybeArc::new(EmptyNpmProcessStateProvider)));
@ -462,13 +467,10 @@ fn create_command(
fds_to_dup.push((ipc_fd2, ipc));
fds_to_close.push(ipc_fd2);
/* One end returned to parent process (this) */
let pipe_rid =
state
.resource_table
.add(deno_node::IpcJsonStreamResource::new(
ipc_fd1 as _,
deno_node::IpcRefTracker::new(state.external_ops_tracker.clone()),
)?);
let pipe_rid = state.resource_table.add(IpcJsonStreamResource::new(
ipc_fd1 as _,
IpcRefTracker::new(state.external_ops_tracker.clone()),
)?);
/* The other end passed to child process via NODE_CHANNEL_FD */
command.env("NODE_CHANNEL_FD", format!("{}", ipc));
ipc_rid = Some(pipe_rid);
@ -532,12 +534,11 @@ fn create_command(
let (hd1, hd2) = deno_io::bi_pipe_pair_raw()?;
/* One end returned to parent process (this) */
let pipe_rid = Some(state.resource_table.add(
deno_node::IpcJsonStreamResource::new(
let pipe_rid =
Some(state.resource_table.add(IpcJsonStreamResource::new(
hd1 as i64,
deno_node::IpcRefTracker::new(state.external_ops_tracker.clone()),
)?,
));
IpcRefTracker::new(state.external_ops_tracker.clone()),
)?));
/* The other end passed to child process via NODE_CHANNEL_FD */
command.env("NODE_CHANNEL_FD", format!("{}", hd2 as i64));

View file

@ -2,7 +2,7 @@
[package]
name = "deno_telemetry"
version = "0.7.0"
version = "0.8.0"
authors.workspace = true
edition.workspace = true
license.workspace = true

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2,7 +2,7 @@
[package]
name = "deno_npm_cache"
version = "0.4.0"
version = "0.5.0"
authors.workspace = true
edition.workspace = true
license.workspace = true

View file

@ -2,7 +2,7 @@
[package]
name = "deno_runtime"
version = "0.193.0"
version = "0.194.0"
authors.workspace = true
edition.workspace = true
license.workspace = true
@ -60,6 +60,7 @@ deno_kv.workspace = true
deno_tls.workspace = true
deno_url.workspace = true
deno_web.workspace = true
deno_process.workspace = true
deno_webgpu.workspace = true
deno_webidl.workspace = true
deno_websocket.workspace = true
@ -93,6 +94,7 @@ deno_node.workspace = true
deno_os.workspace = true
deno_path_util.workspace = true
deno_permissions.workspace = true
deno_process.workspace = true
deno_resolver.workspace = true
deno_telemetry.workspace = true
deno_terminal.workspace = true

View file

@ -23,7 +23,7 @@ import * as io from "ext:deno_io/12_io.js";
import * as fs from "ext:deno_fs/30_fs.js";
import * as os from "ext:deno_os/30_os.js";
import * as fsEvents from "ext:runtime/40_fs_events.js";
import * as process from "ext:runtime/40_process.js";
import * as process from "ext:deno_process/40_process.js";
import * as signals from "ext:deno_os/40_signals.js";
import * as tty from "ext:runtime/40_tty.js";
import * as kv from "ext:deno_kv/01_db.ts";

View file

@ -18,6 +18,7 @@ pub use deno_net;
pub use deno_node;
pub use deno_os;
pub use deno_permissions;
pub use deno_process;
pub use deno_telemetry;
pub use deno_terminal::colors;
pub use deno_tls;
@ -115,7 +116,7 @@ pub static UNSTABLE_GRANULAR_FLAGS: &[UnstableGranularFlag] = &[
},
// TODO(bartlomieju): consider removing it
UnstableGranularFlag {
name: ops::process::UNSTABLE_FEATURE_NAME,
name: deno_process::UNSTABLE_FEATURE_NAME,
help_text: "Enable unstable process APIs",
show_in_help: false,
id: 10,

View file

@ -4,7 +4,6 @@ pub mod bootstrap;
pub mod fs_events;
pub mod http;
pub mod permissions;
pub mod process;
pub mod runtime;
pub mod tty;
pub mod web_worker;

View file

@ -50,14 +50,13 @@ impl TtyModeStore {
}
}
#[cfg(unix)]
use deno_process::JsNixError;
#[cfg(windows)]
use winapi::shared::minwindef::DWORD;
#[cfg(windows)]
use winapi::um::wincon;
#[cfg(unix)]
use crate::ops::process::JsNixError;
deno_core::extension!(
deno_tty,
ops = [op_set_raw, op_console_size, op_read_line_prompt],

View file

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

View file

@ -43,7 +43,6 @@ extension!(runtime,
"10_permissions.js",
"11_workers.js",
"40_fs_events.js",
"40_process.js",
"40_tty.js",
"41_prompt.js",
"90_deno_ns.js",

View file

@ -311,6 +311,7 @@ pub fn create_runtime_snapshot(
deno_io::deno_io::init_ops_and_esm(Default::default()),
deno_fs::deno_fs::init_ops_and_esm::<Permissions>(fs.clone()),
deno_os::deno_os::init_ops_and_esm(Default::default()),
deno_process::deno_process::init_ops_and_esm(Default::default()),
deno_node::deno_node::init_ops_and_esm::<
Permissions,
DenoInNpmPackageChecker,
@ -325,7 +326,6 @@ pub fn create_runtime_snapshot(
),
ops::fs_events::deno_fs_events::init_ops(),
ops::permissions::deno_permissions::init_ops(),
ops::process::deno_process::init_ops(None),
ops::tty::deno_tty::init_ops(),
ops::http::deno_http_runtime::init_ops(),
ops::bootstrap::deno_bootstrap::init_ops(Some(snapshot_options)),

View file

@ -44,6 +44,7 @@ use deno_kv::dynamic::MultiBackendDbHandler;
use deno_node::ExtNodeSys;
use deno_node::NodeExtInitServices;
use deno_permissions::PermissionsContainer;
use deno_process::NpmProcessStateProviderRc;
use deno_terminal::colors;
use deno_tls::RootCertStoreProvider;
use deno_tls::TlsKeys;
@ -59,7 +60,6 @@ use node_resolver::NpmPackageFolderResolver;
use crate::inspector_server::InspectorServer;
use crate::ops;
use crate::ops::process::NpmProcessStateProviderRc;
use crate::shared::maybe_transpile_source;
use crate::shared::runtime;
use crate::tokio_util::create_and_run_current_thread;
@ -548,6 +548,9 @@ impl WebWorker {
services.fs.clone(),
),
deno_os::deno_os_worker::init_ops_and_esm(),
deno_process::deno_process::init_ops_and_esm(
services.npm_process_state_provider,
),
deno_node::deno_node::init_ops_and_esm::<
PermissionsContainer,
TInNpmPackageChecker,
@ -562,9 +565,6 @@ impl WebWorker {
),
ops::fs_events::deno_fs_events::init_ops_and_esm(),
ops::permissions::deno_permissions::init_ops_and_esm(),
ops::process::deno_process::init_ops_and_esm(
services.npm_process_state_provider,
),
ops::tty::deno_tty::init_ops_and_esm(),
ops::http::deno_http_runtime::init_ops_and_esm(),
ops::bootstrap::deno_bootstrap::init_ops_and_esm(

View file

@ -40,6 +40,7 @@ use deno_node::ExtNodeSys;
use deno_node::NodeExtInitServices;
use deno_os::ExitCode;
use deno_permissions::PermissionsContainer;
use deno_process::NpmProcessStateProviderRc;
use deno_tls::RootCertStoreProvider;
use deno_tls::TlsKeys;
use deno_web::BlobStore;
@ -51,7 +52,6 @@ use crate::code_cache::CodeCache;
use crate::code_cache::CodeCacheType;
use crate::inspector_server::InspectorServer;
use crate::ops;
use crate::ops::process::NpmProcessStateProviderRc;
use crate::shared::maybe_transpile_source;
use crate::shared::runtime;
use crate::BootstrapOptions;
@ -428,6 +428,9 @@ impl MainWorker {
services.fs.clone(),
),
deno_os::deno_os::init_ops_and_esm(exit_code.clone()),
deno_process::deno_process::init_ops_and_esm(
services.npm_process_state_provider,
),
deno_node::deno_node::init_ops_and_esm::<
PermissionsContainer,
TInNpmPackageChecker,
@ -442,9 +445,6 @@ impl MainWorker {
),
ops::fs_events::deno_fs_events::init_ops_and_esm(),
ops::permissions::deno_permissions::init_ops_and_esm(),
ops::process::deno_process::init_ops_and_esm(
services.npm_process_state_provider,
),
ops::tty::deno_tty::init_ops_and_esm(),
ops::http::deno_http_runtime::init_ops_and_esm(),
ops::bootstrap::deno_bootstrap::init_ops_and_esm(

View file

@ -17296,3 +17296,119 @@ fn wildcard_augment() {
let diagnostics = client.did_open_file(&source);
assert_eq!(diagnostics.all().len(), 0);
}
#[test]
fn compiler_options_types() {
let context = TestContextBuilder::for_npm().use_temp_cwd().build();
let mut client = context.new_lsp_command().build();
let temp = context.temp_dir();
let temp_dir = temp.path();
let source = source_file(
temp_dir.join("index.ts"),
r#"
const foo = [1];
foo.augmented();
"#,
);
let deno_json = json!({
"imports": {
"@denotest/augments-global": "npm:@denotest/augments-global@1"
},
"compilerOptions": { "types": ["@denotest/augments-global"] },
});
temp.write("deno.json", deno_json.to_string());
client.initialize_default();
for node_modules_dir in ["none", "auto", "manual"] {
let mut deno_json = deno_json.clone();
deno_json["nodeModulesDir"] = json!(node_modules_dir);
temp.write("deno.json", deno_json.to_string());
context.run_deno("install");
client.did_change_watched_files(json!({
"changes": [{
"uri": temp.url().join("deno.json").unwrap(),
"type": 2,
}],
}));
let diagnostics = client.did_open_file(&source);
eprintln!("{:#?}", diagnostics.all());
assert_eq!(diagnostics.all().len(), 0);
client.did_close_file(&source);
}
}
#[test]
fn type_reference_import_meta() {
let context = TestContextBuilder::for_npm().use_temp_cwd().build();
let mut client = context.new_lsp_command().build();
let temp = context.temp_dir();
let temp_dir = temp.path();
let source = source_file(
temp_dir.join("index.ts"),
r#"
const test = import.meta.env.TEST;
const bar = import.meta.bar;
console.log(test, bar);
"#,
);
/*
tests type reference w/ bare specifier, type reference in an npm package,
and augmentation of `ImportMeta` (this combination modeled after the vanilla vite template,
which uses `vite/client`)
@denotest/augments-global/import-meta:
```dts
/// <reference types="./real-import-meta.d.ts" />
export type Foo = number;
```
real-import-meta.d.ts:
```dts
interface ImportMetaEnv {
TEST: string;
}
interface ImportMeta {
env: ImportMetaEnv;
bar: number;
}
```
*/
temp.write(
"types.d.ts",
r#"
/// <reference types="@denotest/augments-global/import-meta" />
"#,
);
let deno_json = json!({
"imports": {
"@denotest/augments-global": "npm:@denotest/augments-global@1"
}
});
temp.write("deno.json", deno_json.to_string());
client.initialize_default();
for node_modules_dir in ["none", "auto", "manual"] {
let mut deno_json = deno_json.clone();
deno_json["nodeModulesDir"] = json!(node_modules_dir);
temp.write("deno.json", deno_json.to_string());
context.run_deno("install");
client.did_change_watched_files(json!({
"changes": [{
"uri": temp.url().join("deno.json").unwrap(),
"type": 2,
}],
}));
let diagnostics = client.did_open_file(&source);
assert_eq!(diagnostics.all().len(), 0);
client.did_close_file(&source);
}
}

View file

@ -0,0 +1,3 @@
/// <reference types="./real-import-meta.d.ts" />
export type Foo = number;

View file

@ -0,0 +1 @@
import "./other.d.ts";

View file

@ -0,0 +1,6 @@
export {}
declare global {
interface Array<T> {
augmented(): void
}
}

View file

@ -0,0 +1,13 @@
{
"name": "@denotest/augments-global",
"version": "1.0.0",
"types": "./index.d.ts",
"exports": {
".": {
"types": "./index.d.ts"
},
"./import-meta": {
"types": "./import-meta.d.ts"
}
}
}

View file

@ -0,0 +1,8 @@
interface ImportMetaEnv {
TEST: string;
}
interface ImportMeta {
env: ImportMetaEnv;
bar: number;
}

View file

@ -0,0 +1,53 @@
{
"tempDir": true,
"tests": {
"node_modules_dir_none": {
"steps": [
{
"args": "run -A ./set_node_modules_dir.ts none",
"output": ""
},
{
"args": "install",
"output": "[WILDCARD]"
},
{
"args": "check ./main.ts",
"output": "Check [WILDCARD]main.ts\n"
}
]
},
"node_modules_dir_auto": {
"steps": [
{
"args": "run -A ./set_node_modules_dir.ts auto",
"output": ""
},
{
"args": "install",
"output": "[WILDCARD]"
},
{
"args": "check ./main.ts",
"output": "Check [WILDCARD]main.ts\n"
}
]
},
"node_modules_dir_manual": {
"steps": [
{
"args": "run -A ./set_node_modules_dir.ts auto",
"output": ""
},
{
"args": "install",
"output": "[WILDCARD]"
},
{
"args": "check ./main.ts",
"output": "Check [WILDCARD]main.ts\n"
}
]
}
}
}

View file

@ -0,0 +1,6 @@
{
"imports": {
"@denotest/augments-global": "npm:@denotest/augments-global@1"
},
"compilerOptions": { "types": ["@denotest/augments-global"] }
}

View file

@ -0,0 +1,2 @@
const foo = [1];
foo.augmented();

View file

@ -0,0 +1,8 @@
if (Deno.args.length !== 1) {
console.error("Usage: set_node_modules_dir.ts <setting>");
Deno.exit(1);
}
const setting = Deno.args[0].trim();
const denoJson = JSON.parse(Deno.readTextFileSync("./deno.json"));
denoJson["nodeModulesDir"] = setting;
Deno.writeTextFileSync("./deno.json", JSON.stringify(denoJson, null, 2));

View file

@ -0,0 +1,53 @@
{
"tempDir": true,
"tests": {
"node_modules_dir_none": {
"steps": [
{
"args": "run -A ./set_node_modules_dir.ts none",
"output": ""
},
{
"args": "install",
"output": "[WILDCARD]"
},
{
"args": "check --all ./main.ts",
"output": "Check [WILDCARD]main.ts\n"
}
]
},
"node_modules_dir_auto": {
"steps": [
{
"args": "run -A ./set_node_modules_dir.ts auto",
"output": ""
},
{
"args": "install",
"output": "[WILDCARD]"
},
{
"args": "check --all ./main.ts",
"output": "Check [WILDCARD]main.ts\n"
}
]
},
"node_modules_dir_manual": {
"steps": [
{
"args": "run -A ./set_node_modules_dir.ts auto",
"output": ""
},
{
"args": "install",
"output": "[WILDCARD]"
},
{
"args": "check --all ./main.ts",
"output": "Check [WILDCARD]main.ts\n"
}
]
}
}
}

View file

@ -0,0 +1,5 @@
{
"imports": {
"@types/node": "npm:@types/node@*"
}
}

View file

@ -0,0 +1,3 @@
/// <reference types="@types/node" />
const _foo = import.meta.dirname;

View file

@ -0,0 +1,8 @@
if (Deno.args.length !== 1) {
console.error("Usage: set_node_modules_dir.ts <setting>");
Deno.exit(1);
}
const setting = Deno.args[0].trim();
const denoJson = JSON.parse(Deno.readTextFileSync("./deno.json"));
denoJson["nodeModulesDir"] = setting;
Deno.writeTextFileSync("./deno.json", JSON.stringify(denoJson, null, 2));

View file

@ -0,0 +1,53 @@
{
"tempDir": true,
"tests": {
"node_modules_dir_none": {
"steps": [
{
"args": "run -A ./set_node_modules_dir.ts none",
"output": ""
},
{
"args": "install",
"output": "[WILDCARD]"
},
{
"args": "check ./main.ts",
"output": "Check [WILDCARD]main.ts\n"
}
]
},
"node_modules_dir_auto": {
"steps": [
{
"args": "run -A ./set_node_modules_dir.ts auto",
"output": ""
},
{
"args": "install",
"output": "[WILDCARD]"
},
{
"args": "check ./main.ts",
"output": "Check [WILDCARD]main.ts\n"
}
]
},
"node_modules_dir_manual": {
"steps": [
{
"args": "run -A ./set_node_modules_dir.ts auto",
"output": ""
},
{
"args": "install",
"output": "[WILDCARD]"
},
{
"args": "check ./main.ts",
"output": "Check [WILDCARD]main.ts\n"
}
]
}
}
}

View file

@ -0,0 +1,6 @@
{
"imports": {
"@denotest/augments-global": "npm:@denotest/augments-global@1"
},
"compilerOptions": { "types": ["./types.d.ts"] }
}

View file

@ -0,0 +1,3 @@
const test = import.meta.env.TEST;
const bar = import.meta.bar;
console.log(test, bar);

View file

@ -0,0 +1,8 @@
if (Deno.args.length !== 1) {
console.error("Usage: set_node_modules_dir.ts <setting>");
Deno.exit(1);
}
const setting = Deno.args[0].trim();
const denoJson = JSON.parse(Deno.readTextFileSync("./deno.json"));
denoJson["nodeModulesDir"] = setting;
Deno.writeTextFileSync("./deno.json", JSON.stringify(denoJson, null, 2));

View file

@ -0,0 +1 @@
/// <reference types="@denotest/augments-global/import-meta" />

View file

@ -5,7 +5,7 @@
"@denotest/subtract": "jsr:@denotest/subtract@^0.2.0",
"@denotest/with-subpath": "jsr:@denotest/multiple-exports@0.5.0/data-json",
"@denotest/breaking-change-between-versions": "npm:@denotest/breaking-change-between-versions@1.0.0",
"@denotest/bin": "npm:@denotest/bin@^1.0.0",
"@denotest/bin": "npm:@denotest/bin@1.0.0",
"@denotest/has-patch-versions": "npm:@denotest/has-patch-versions@^0.1.0"
},
"scopes": {

View file

@ -3,9 +3,9 @@
"@denotest/add": "jsr:@denotest/add@^1.0.0",
"@denotest/add/": "jsr:/@denotest/add@^1.0.0/",
"@denotest/subtract": "jsr:@denotest/subtract@^1.0.0",
"@denotest/with-subpath": "jsr:@denotest/multiple-exports@^1.0.0/data-json",
"@denotest/breaking-change-between-versions": "npm:@denotest/breaking-change-between-versions@^2.0.0",
"@denotest/bin": "npm:@denotest/bin@^1.0.0",
"@denotest/with-subpath": "jsr:@denotest/multiple-exports@1.0.0/data-json",
"@denotest/breaking-change-between-versions": "npm:@denotest/breaking-change-between-versions@2.0.0",
"@denotest/bin": "npm:@denotest/bin@1.0.0",
"@denotest/has-patch-versions": "npm:@denotest/has-patch-versions@^0.2.0"
},
"scopes": {
@ -13,7 +13,7 @@
"@denotest/add": "jsr:@denotest/add@^1.0.0",
"@denotest/add/": "jsr:/@denotest/add@^1.0.0/",
"@denotest/subtract": "jsr:@denotest/subtract@^1.0.0",
"@denotest/with-subpath": "jsr:@denotest/multiple-exports@^1.0.0/data-json"
"@denotest/with-subpath": "jsr:@denotest/multiple-exports@1.0.0/data-json"
}
}
}

View file

@ -2,10 +2,10 @@
"version": "4",
"specifiers": {
"jsr:@denotest/add@1": "1.0.0",
"jsr:@denotest/multiple-exports@1": "1.0.0",
"jsr:@denotest/multiple-exports@1.0.0": "1.0.0",
"jsr:@denotest/subtract@1": "1.0.0",
"npm:@denotest/bin@1": "1.0.0",
"npm:@denotest/breaking-change-between-versions@2": "2.0.0",
"npm:@denotest/bin@1.0.0": "1.0.0",
"npm:@denotest/breaking-change-between-versions@2.0.0": "2.0.0",
"npm:@denotest/has-patch-versions@0.2": "0.2.0"
},
"jsr": {
@ -33,10 +33,10 @@
"workspace": {
"dependencies": [
"jsr:@denotest/add@1",
"jsr:@denotest/multiple-exports@1",
"jsr:@denotest/multiple-exports@1.0.0",
"jsr:@denotest/subtract@1",
"npm:@denotest/bin@1",
"npm:@denotest/breaking-change-between-versions@2",
"npm:@denotest/bin@1.0.0",
"npm:@denotest/breaking-change-between-versions@2.0.0",
"npm:@denotest/has-patch-versions@0.2"
]
}

View file

@ -2,7 +2,7 @@
"imports": {
"@denotest/add": "jsr:@denotest/add@^1.0.0",
"@denotest/subtract": "jsr:@denotest/subtract@^1.0.0",
"@denotest/breaking-change-between-versions": "npm:@denotest/breaking-change-between-versions@^2.0.0",
"@denotest/breaking-change-between-versions": "npm:@denotest/breaking-change-between-versions@2.0.0",
"@denotest/has-patch-versions": "npm:@denotest/has-patch-versions@^0.2.0"
}
}

View file

@ -0,0 +1,13 @@
{
"tempDir": true,
"steps": [
{
"args": "install",
"output": "[WILDCARD]"
},
{
"args": "outdated",
"output": ""
}
]
}

View file

@ -0,0 +1,5 @@
{
"dependencies": {
"@denotest/has-pre-release": "1.0.0"
}
}

View file

@ -3,6 +3,6 @@
"version": "0.1.0",
"dependencies": {
"@denotest/has-patch-versions": "0.1.0",
"aliased": "npm:@denotest/bin@^1.0.0"
"aliased": "npm:@denotest/bin@1.0.0"
}
}

View file

@ -4,7 +4,7 @@
"imports": {
"@denotest/add": "jsr:@denotest/add@^1.0.0",
"@denotest/add/": "jsr:/@denotest/add@^1.0.0/",
"@denotest/with-subpath": "jsr:@denotest/multiple-exports@^1.0.0/data-json",
"@denotest/breaking-change-between-versions": "npm:@denotest/breaking-change-between-versions@^2.0.0"
"@denotest/with-subpath": "jsr:@denotest/multiple-exports@1.0.0/data-json",
"@denotest/breaking-change-between-versions": "npm:@denotest/breaking-change-between-versions@2.0.0"
}
}

View file

@ -2,7 +2,7 @@
"name": "@denotest/member-b",
"version": "0.1.0",
"dependencies": {
"@denotest/has-patch-versions": "^0.2.0",
"aliased": "npm:@denotest/bin@^1.0.0"
"@denotest/has-patch-versions": "0.2.0",
"aliased": "npm:@denotest/bin@1.0.0"
}
}

View file

@ -2,7 +2,7 @@
"version": "4",
"specifiers": {
"npm:@denotest/bin@1": "1.0.0",
"npm:@denotest/breaking-change-between-versions@2": "2.0.0",
"npm:@denotest/breaking-change-between-versions@2.0.0": "2.0.0",
"npm:@denotest/has-patch-versions@0.2": "0.2.0"
},
"npm": {
@ -20,7 +20,7 @@
"packageJson": {
"dependencies": [
"npm:@denotest/bin@1",
"npm:@denotest/breaking-change-between-versions@2",
"npm:@denotest/breaking-change-between-versions@2.0.0",
"npm:@denotest/has-patch-versions@0.2"
]
}

View file

@ -1,7 +1,7 @@
{
"dependencies": {
"@denotest/has-patch-versions": "^0.2.0",
"@denotest/breaking-change-between-versions": "^2.0.0"
"@denotest/breaking-change-between-versions": "2.0.0"
},
"devDependencies": {
"aliased": "npm:@denotest/bin@^1.0.0"

Some files were not shown because too many files have changed in this diff Show more