0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-03-08 04:07:41 -05:00

Merge remote-tracking branch 'upstream/main' into lsp-jupyter-cell-continuity

This commit is contained in:
Nayeem Rahman 2024-09-11 23:43:28 +01:00
commit 3f3fb886f3
490 changed files with 5263 additions and 6203 deletions

View file

@ -649,7 +649,7 @@ const ci = {
name: "test_format.js",
if: "matrix.job == 'lint' && matrix.os == 'linux'",
run:
"deno run --unstable --allow-write --allow-read --allow-run --allow-net ./tools/format.js --check",
"deno run --allow-write --allow-read --allow-run --allow-net ./tools/format.js --check",
},
{
name: "Lint PR title",
@ -664,7 +664,7 @@ const ci = {
name: "lint.js",
if: "matrix.job == 'lint'",
run:
"deno run --unstable --allow-write --allow-read --allow-run --allow-net ./tools/lint.js",
"deno run --allow-write --allow-read --allow-run --allow-net ./tools/lint.js",
},
{
name: "jsdoc_checker.js",
@ -826,7 +826,7 @@ const ci = {
"!startsWith(github.ref, 'refs/tags/')",
].join("\n"),
run:
"target/release/deno run -A --unstable --config tests/config/deno.json ext/websocket/autobahn/fuzzingclient.js",
"target/release/deno run -A --config tests/config/deno.json ext/websocket/autobahn/fuzzingclient.js",
},
{
name: "Test (full, debug)",
@ -879,9 +879,9 @@ const ci = {
DENO_BIN: "./target/debug/deno",
},
run: [
"deno run -A --unstable --lock=tools/deno.lock.json --config tests/config/deno.json\\",
"deno run -A --lock=tools/deno.lock.json --config tests/config/deno.json\\",
" ./tests/wpt/wpt.ts setup",
"deno run -A --unstable --lock=tools/deno.lock.json --config tests/config/deno.json\\",
"deno run -A --lock=tools/deno.lock.json --config tests/config/deno.json\\",
' ./tests/wpt/wpt.ts run --quiet --binary="$DENO_BIN"',
].join("\n"),
},
@ -892,9 +892,9 @@ const ci = {
DENO_BIN: "./target/release/deno",
},
run: [
"deno run -A --unstable --lock=tools/deno.lock.json --config tests/config/deno.json\\",
"deno run -A --lock=tools/deno.lock.json --config tests/config/deno.json\\",
" ./tests/wpt/wpt.ts setup",
"deno run -A --unstable --lock=tools/deno.lock.json --config tests/config/deno.json\\",
"deno run -A --lock=tools/deno.lock.json --config tests/config/deno.json\\",
" ./tests/wpt/wpt.ts run --quiet --release \\",
' --binary="$DENO_BIN" \\',
" --json=wpt.json \\",
@ -958,8 +958,7 @@ const ci = {
"git clone --depth 1 --branch gh-pages \\",
" https://${DENOBOT_PAT}@github.com/denoland/benchmark_data.git \\",
" gh-pages",
"./target/release/deno run --allow-all --unstable \\",
" ./tools/build_benchmark_jsons.js --release",
"./target/release/deno run --allow-all ./tools/build_benchmark_jsons.js --release",
"cd gh-pages",
'git config user.email "propelml@gmail.com"',
'git config user.name "denobot"',

View file

@ -389,7 +389,7 @@ jobs:
cache-path: ./target
- name: test_format.js
if: '!(matrix.skip) && (matrix.job == ''lint'' && matrix.os == ''linux'')'
run: deno run --unstable --allow-write --allow-read --allow-run --allow-net ./tools/format.js --check
run: deno run --allow-write --allow-read --allow-run --allow-net ./tools/format.js --check
- name: Lint PR title
if: '!(matrix.skip) && (matrix.job == ''lint'' && github.event_name == ''pull_request'' && matrix.os == ''linux'')'
env:
@ -397,7 +397,7 @@ jobs:
run: deno run ./tools/verify_pr_title.js "$PR_TITLE"
- name: lint.js
if: '!(matrix.skip) && (matrix.job == ''lint'')'
run: deno run --unstable --allow-write --allow-read --allow-run --allow-net ./tools/lint.js
run: deno run --allow-write --allow-read --allow-run --allow-net ./tools/lint.js
- name: jsdoc_checker.js
if: '!(matrix.skip) && (matrix.job == ''lint'')'
run: deno run --allow-read --allow-env --allow-sys ./tools/jsdoc_checker.js
@ -494,7 +494,7 @@ jobs:
matrix.job == 'test' &&
matrix.profile == 'release' &&
!startsWith(github.ref, 'refs/tags/'))
run: target/release/deno run -A --unstable --config tests/config/deno.json ext/websocket/autobahn/fuzzingclient.js
run: target/release/deno run -A --config tests/config/deno.json ext/websocket/autobahn/fuzzingclient.js
- name: 'Test (full, debug)'
if: |-
!(matrix.skip) && (matrix.job == 'test' &&
@ -531,18 +531,18 @@ jobs:
env:
DENO_BIN: ./target/debug/deno
run: |-
deno run -A --unstable --lock=tools/deno.lock.json --config tests/config/deno.json\
deno run -A --lock=tools/deno.lock.json --config tests/config/deno.json\
./tests/wpt/wpt.ts setup
deno run -A --unstable --lock=tools/deno.lock.json --config tests/config/deno.json\
deno run -A --lock=tools/deno.lock.json --config tests/config/deno.json\
./tests/wpt/wpt.ts run --quiet --binary="$DENO_BIN"
- name: Run web platform tests (release)
if: '!(matrix.skip) && (matrix.wpt && matrix.profile == ''release'')'
env:
DENO_BIN: ./target/release/deno
run: |-
deno run -A --unstable --lock=tools/deno.lock.json --config tests/config/deno.json\
deno run -A --lock=tools/deno.lock.json --config tests/config/deno.json\
./tests/wpt/wpt.ts setup
deno run -A --unstable --lock=tools/deno.lock.json --config tests/config/deno.json\
deno run -A --lock=tools/deno.lock.json --config tests/config/deno.json\
./tests/wpt/wpt.ts run --quiet --release \
--binary="$DENO_BIN" \
--json=wpt.json \
@ -590,8 +590,7 @@ jobs:
git clone --depth 1 --branch gh-pages \
https://${DENOBOT_PAT}@github.com/denoland/benchmark_data.git \
gh-pages
./target/release/deno run --allow-all --unstable \
./tools/build_benchmark_jsons.js --release
./target/release/deno run --allow-all ./tools/build_benchmark_jsons.js --release
cd gh-pages
git config user.email "propelml@gmail.com"
git config user.name "denobot"

View file

@ -66,9 +66,9 @@ jobs:
- name: Run web platform tests
shell: bash
run: |
deno run --unstable -A --lock=tools/deno.lock.json --config=tests/config/deno.json \
deno run -A --lock=tools/deno.lock.json --config=tests/config/deno.json \
./tests/wpt/wpt.ts setup
deno run --unstable -A --lock=tools/deno.lock.json --config=tests/config/deno.json \
deno run -A --lock=tools/deno.lock.json --config=tests/config/deno.json \
./tests/wpt/wpt.ts run \ \
--binary=$(which deno) --quiet --release --no-ignore --json=wpt.json --wptreport=wptreport.json --exit-zero

33
Cargo.lock generated
View file

@ -1253,6 +1253,7 @@ dependencies = [
"which 4.4.2",
"winapi",
"winres",
"yoke",
"zeromq",
"zip",
"zstd",
@ -1374,9 +1375,9 @@ dependencies = [
[[package]]
name = "deno_config"
version = "0.33.2"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84d90b5eacfd6ee4ec978a11739c71eaeb19a575889f8c2b473430df84078fe2"
checksum = "353595ebd9d19602f4cc0bb5613ae8bf036fb23ce1e6638eec594a63b1f8d48a"
dependencies = [
"anyhow",
"deno_package_json",
@ -1404,9 +1405,9 @@ dependencies = [
[[package]]
name = "deno_core"
version = "0.307.0"
version = "0.308.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "154b0902402807a043579102f949e6dd6f3a09d2d5049929fd710fc3192bf109"
checksum = "62fc8250fa9da059cc05b18328319a9048c73e4889ca929cc60877a8a1bfc4d4"
dependencies = [
"anyhow",
"bincode",
@ -1700,9 +1701,9 @@ dependencies = [
[[package]]
name = "deno_lint"
version = "0.64.0"
version = "0.65.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b47f5f65369a3f188b5fa7c1263d9f96cdaa688e417b8852a3c8de0389e1c985"
checksum = "90a58ed695d2a04c43ff6f5fb03d1597f86e3748861c872ea5a9443da7512fc7"
dependencies = [
"anyhow",
"deno_ast",
@ -1886,9 +1887,9 @@ dependencies = [
[[package]]
name = "deno_ops"
version = "0.183.0"
version = "0.184.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9114f9eb6419839f1ab9668f91c463238945bb974e1998629a703f72b4608daf"
checksum = "24a465b7d691ad7cae41e8f51bd954b1e3ffd201b84dc30de2c16cf91034946e"
dependencies = [
"proc-macro-rules",
"proc-macro2",
@ -4305,9 +4306,9 @@ dependencies = [
[[package]]
name = "malva"
version = "0.9.0"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e6e9f16e424a6672f6726daf965333952dece79ef3d17aac712b92b3b72d0a8"
checksum = "484beda6e5d775ed06a8ec0fce79e51d39f49d834ed2a29da3f437079321804f"
dependencies = [
"aho-corasick",
"itertools 0.13.0",
@ -5241,9 +5242,9 @@ dependencies = [
[[package]]
name = "pretty_yaml"
version = "0.4.0"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ba50511591c8e1d84125f7e2e6d17ccb06865c484b812f5ee3af61f42a66be"
checksum = "dda9a64ee7296e82d1e0f4389383e6a7d8e6e2487d8391f7d028c131395fd376"
dependencies = [
"rowan",
"tiny_pretty",
@ -6256,9 +6257,9 @@ dependencies = [
[[package]]
name = "serde_v8"
version = "0.216.0"
version = "0.217.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1733b8192f123beedd2fc7998efeaf2a0b8bfa35c01537f50b690e786db8024c"
checksum = "467c0a7bfc67cd918f1f7ab7a5ab70a9e744e466ff428cd728ff2c03bc77874c"
dependencies = [
"num-bigint",
"serde",
@ -7911,9 +7912,9 @@ dependencies = [
[[package]]
name = "v8"
version = "0.105.0"
version = "0.106.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692624c4fd58ff50aa6d690c159df18e7881c13970005b9b2bff77dc425fd370"
checksum = "a381badc47c6f15acb5fe0b5b40234162349ed9d4e4fd7c83a7f5547c0fc69c5"
dependencies = [
"bindgen",
"bitflags 2.6.0",

View file

@ -45,7 +45,7 @@ repository = "https://github.com/denoland/deno"
[workspace.dependencies]
deno_ast = { version = "=0.42.0", features = ["transpiling"] }
deno_core = { version = "0.307.0" }
deno_core = { version = "0.308.0" }
deno_bench_util = { version = "0.162.0", path = "./bench_util" }
deno_lockfile = "=0.23.0"
@ -193,6 +193,7 @@ url = { version = "< 2.5.0", features = ["serde", "expose_internals"] }
uuid = { version = "1.3.0", features = ["v4"] }
webpki-roots = "0.26"
which = "4.2.5"
yoke = { version = "0.7.4", features = ["derive"] }
zeromq = { version = "=0.4.0", default-features = false, features = ["tcp-transport", "tokio-runtime"] }
zstd = "=0.12.4"

View file

@ -65,11 +65,11 @@ winres.workspace = true
[dependencies]
deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "proposal", "react", "sourcemap", "transforms", "typescript", "view", "visit"] }
deno_cache_dir = { workspace = true }
deno_config = { version = "=0.33.2", features = ["workspace", "sync"] }
deno_config = { version = "=0.34.0", features = ["workspace", "sync"] }
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] }
deno_doc = { version = "0.148.0", features = ["html", "syntect"] }
deno_graph = { version = "=0.82.1" }
deno_lint = { version = "=0.64.0", features = ["docs"] }
deno_lint = { version = "=0.65.0", features = ["docs"] }
deno_lockfile.workspace = true
deno_npm = "=0.25.0"
deno_package_json.workspace = true
@ -123,7 +123,7 @@ libc.workspace = true
libz-sys.workspace = true
log = { workspace = true, features = ["serde"] }
lsp-types.workspace = true
malva = "=0.9.0"
malva = "=0.10.1"
markup_fmt = "=0.12.0"
memmem.workspace = true
monch.workspace = true
@ -134,7 +134,7 @@ p256.workspace = true
pathdiff = "0.2.1"
percent-encoding.workspace = true
phf.workspace = true
pretty_yaml = "=0.4.0"
pretty_yaml = "=0.5.0"
quick-junit = "^0.3.5"
rand = { workspace = true, features = ["small_rng"] }
regex.workspace = true
@ -161,6 +161,7 @@ typed-arena = "=2.0.2"
uuid = { workspace = true, features = ["serde"] }
walkdir = "=2.3.2"
which.workspace = true
yoke.workspace = true
zeromq.workspace = true
zip = { version = "2.1.6", default-features = false, features = ["deflate-flate2"] }
zstd.workspace = true

View file

@ -85,6 +85,7 @@ impl FileFlags {
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct AddFlags {
pub packages: Vec<String>,
pub dev: bool,
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
@ -569,6 +570,7 @@ fn parse_packages_allowed_scripts(s: &str) -> Result<String, AnyError> {
Clone, Default, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize,
)]
pub struct UnstableConfig {
// TODO(bartlomieju): remove in Deno 2.5
pub legacy_flag_enabled: bool, // --unstable
pub bare_node_builtins: bool, // --unstable-bare-node-builts
pub sloppy_imports: bool,
@ -1120,6 +1122,8 @@ impl Flags {
static ENV_VARIABLES_HELP: &str = cstr!(
r#"<y>Environment variables:</>
<y>Docs:</> <c>https://docs.deno.com/go/env-vars</>
<g>DENO_AUTH_TOKENS</> A semi-colon separated list of bearer tokens and hostnames
to use when fetching remote modules from private repositories
<p(245)>(e.g. "abcde12345@deno.land;54321edcba@github.com")</>
@ -1585,6 +1589,15 @@ fn help_subcommand(app: &Command) -> Command {
}))
}
fn add_dev_arg() -> Arg {
Arg::new("dev")
.long("dev")
.short('D')
.help("Add as a dev dependency")
.long_help("Add the package as a dev dependency. Note: This only applies when adding to a `package.json` file.")
.action(ArgAction::SetTrue)
}
fn add_subcommand() -> Command {
command(
"add",
@ -1598,13 +1611,15 @@ You can add multiple dependencies at once:
UnstableArgsConfig::None,
)
.defer(|cmd| {
cmd.arg(
Arg::new("packages")
.help("List of packages to add")
.required_unless_present("help")
.num_args(1..)
.action(ArgAction::Append),
)
cmd
.arg(
Arg::new("packages")
.help("List of packages to add")
.required_unless_present("help")
.num_args(1..)
.action(ArgAction::Append),
)
.arg(add_dev_arg())
})
}
@ -2453,6 +2468,7 @@ These must be added to the path manually if required."), UnstableArgsConfig::Res
.help("Install dependents of the specified entrypoint(s)"),
)
.arg(env_file_arg())
.arg(add_dev_arg().conflicts_with("entrypoint").conflicts_with("global"))
})
}
@ -2461,7 +2477,7 @@ fn json_reference_subcommand() -> Command {
}
fn jupyter_subcommand() -> Command {
Command::new("jupyter")
command("jupyter", "Deno kernel for Jupyter notebooks", UnstableArgsConfig::ResolutionAndRuntime)
.arg(
Arg::new("install")
.long("install")
@ -2484,7 +2500,6 @@ fn jupyter_subcommand() -> Command {
.value_parser(value_parser!(String))
.value_hint(ValueHint::FilePath)
.conflicts_with("install"))
.about("Deno kernel for Jupyter notebooks")
}
fn uninstall_subcommand() -> Command {
@ -2971,12 +2986,8 @@ The declaration file could be saved and used for typing information.",
)
}
fn upgrade_subcommand() -> Command {
command(
"upgrade",
cstr!("Upgrade deno executable to the given version.
<g>Latest</>
pub static UPGRADE_USAGE: &str = cstr!(
"<g>Latest</>
<bold>deno upgrade</>
<g>Specific version</>
@ -2987,7 +2998,15 @@ fn upgrade_subcommand() -> Command {
<g>Channel</>
<bold>deno upgrade</> <p(245)>stable</>
<bold>deno upgrade</> <p(245)>rc</>
<bold>deno upgrade</> <p(245)>canary</>
<bold>deno upgrade</> <p(245)>canary</>"
);
fn upgrade_subcommand() -> Command {
command(
"upgrade",
color_print::cformat!("Upgrade deno executable to the given version.
{}
The version is downloaded from <p(245)>https://dl.deno.land</> and is used to replace the current executable.
@ -2995,7 +3014,7 @@ If you want to not replace the current Deno executable but instead download an u
different location, use the <c>--output</> flag:
<p(245)>deno upgrade --output $HOME/my_deno</>
<y>Read more:</> <c>https://docs.deno.com/go/cmd/upgrade</>"),
<y>Read more:</> <c>https://docs.deno.com/go/cmd/upgrade</>", UPGRADE_USAGE),
UnstableArgsConfig::None,
)
.hide(cfg!(not(feature = "upgrade")))
@ -3139,7 +3158,7 @@ fn compile_args_without_check_args(app: Command) -> Command {
fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
app
.after_help(cstr!(r#"<y>Permission options:</>
Docs: <c>https://docs.deno.com/go/permissions</>
<y>Docs</>: <c>https://docs.deno.com/go/permissions</>
<g>-A, --allow-all</> Allow all permissions.
<g>--no-prompt</> Always throw if required permission wasn't passed.
@ -4092,7 +4111,8 @@ fn add_parse_inner(
let packages = packages
.unwrap_or_else(|| matches.remove_many::<String>("packages").unwrap())
.collect();
AddFlags { packages }
let dev = matches.get_flag("dev");
AddFlags { packages, dev }
}
fn remove_parse(flags: &mut Flags, matches: &mut ArgMatches) {
@ -4584,6 +4604,8 @@ fn json_reference_parse(
}
fn jupyter_parse(flags: &mut Flags, matches: &mut ArgMatches) {
unstable_args_parse(flags, matches, UnstableArgsConfig::ResolutionAndRuntime);
let conn_file = matches.remove_one::<String>("conn");
let kernel = matches.get_flag("kernel");
let install = matches.get_flag("install");
@ -5461,6 +5483,7 @@ fn unstable_args_parse(
matches: &mut ArgMatches,
cfg: UnstableArgsConfig,
) {
// TODO(bartlomieju): remove in Deno 2.5
if matches.get_flag("unstable") {
flags.unstable_config.legacy_flag_enabled = true;
}
@ -8750,7 +8773,7 @@ mod tests {
#[test]
fn test_with_flags() {
#[rustfmt::skip]
let r = flags_from_vec(svec!["deno", "test", "--unstable", "--no-npm", "--no-remote", "--trace-leaks", "--no-run", "--filter", "- foo", "--coverage=cov", "--clean", "--location", "https:foo", "--allow-net", "--permit-no-files", "dir1/", "dir2/", "--", "arg1", "arg2"]);
let r = flags_from_vec(svec!["deno", "test", "--no-npm", "--no-remote", "--trace-leaks", "--no-run", "--filter", "- foo", "--coverage=cov", "--clean", "--location", "https:foo", "--allow-net", "--permit-no-files", "dir1/", "dir2/", "--", "arg1", "arg2"]);
assert_eq!(
r.unwrap(),
Flags {
@ -8774,10 +8797,6 @@ mod tests {
junit_path: None,
hide_stacktraces: false,
}),
unstable_config: UnstableConfig {
legacy_flag_enabled: true,
..Default::default()
},
no_npm: true,
no_remote: true,
location: Some(Url::parse("https://foo/").unwrap()),
@ -10185,7 +10204,6 @@ mod tests {
"deno",
"bench",
"--json",
"--unstable",
"--no-npm",
"--no-remote",
"--no-run",
@ -10213,10 +10231,6 @@ mod tests {
},
watch: Default::default(),
}),
unstable_config: UnstableConfig {
legacy_flag_enabled: true,
..Default::default()
},
no_npm: true,
no_remote: true,
type_check_mode: TypeCheckMode::Local,
@ -10508,31 +10522,53 @@ mod tests {
}
#[test]
fn add_subcommand() {
fn add_or_install_subcommand() {
let r = flags_from_vec(svec!["deno", "add"]);
r.unwrap_err();
for cmd in ["add", "install"] {
let mk_flags = |flags: AddFlags| -> Flags {
match cmd {
"add" => Flags {
subcommand: DenoSubcommand::Add(flags),
..Flags::default()
},
"install" => Flags {
subcommand: DenoSubcommand::Install(InstallFlags {
kind: InstallKind::Local(InstallFlagsLocal::Add(flags)),
}),
..Flags::default()
},
_ => unreachable!(),
}
};
let r = flags_from_vec(svec!["deno", "add", "@david/which"]);
assert_eq!(
r.unwrap(),
Flags {
subcommand: DenoSubcommand::Add(AddFlags {
let r = flags_from_vec(svec!["deno", cmd, "@david/which"]);
assert_eq!(
r.unwrap(),
mk_flags(AddFlags {
packages: svec!["@david/which"],
}),
..Flags::default()
}
);
dev: false,
}) // default is false
);
let r = flags_from_vec(svec!["deno", "add", "@david/which", "@luca/hello"]);
assert_eq!(
r.unwrap(),
Flags {
subcommand: DenoSubcommand::Add(AddFlags {
let r = flags_from_vec(svec!["deno", cmd, "@david/which", "@luca/hello"]);
assert_eq!(
r.unwrap(),
mk_flags(AddFlags {
packages: svec!["@david/which", "@luca/hello"],
dev: false,
})
);
let r = flags_from_vec(svec!["deno", cmd, "--dev", "npm:chalk"]);
assert_eq!(
r.unwrap(),
mk_flags(AddFlags {
packages: svec!["npm:chalk"],
dev: true,
}),
..Flags::default()
}
);
);
}
}
#[test]
@ -10746,6 +10782,35 @@ mod tests {
.contains("Note: Permission flags can only be used in a global setting"));
}
#[test]
fn jupyter_unstable_flags() {
let r = flags_from_vec(svec![
"deno",
"jupyter",
"--unstable-ffi",
"--unstable-bare-node-builtins",
"--unstable-worker-options"
]);
assert_eq!(
r.unwrap(),
Flags {
subcommand: DenoSubcommand::Jupyter(JupyterFlags {
install: false,
kernel: false,
conn_file: None,
}),
unstable_config: UnstableConfig {
bare_node_builtins: true,
sloppy_imports: false,
features: svec!["ffi", "worker-options"],
..Default::default()
},
..Flags::default()
}
);
}
#[test]
fn escape_and_split_commas_test() {
assert_eq!(escape_and_split_commas("foo".to_string()).unwrap(), ["foo"]);

View file

@ -50,7 +50,7 @@ pub fn parse(paths: Vec<String>) -> clap::error::Result<Vec<String>> {
out.push(format!("{}:{}", host, port.0));
}
} else {
host_and_port.parse::<NetDescriptor>().map_err(|e| {
NetDescriptor::parse(&host_and_port).map_err(|e| {
clap::Error::raw(clap::error::ErrorKind::InvalidValue, format!("{e:?}"))
})?;
out.push(host_and_port)

View file

@ -1548,10 +1548,6 @@ impl CliOptions {
&self.flags.unsafely_ignore_certificate_errors
}
pub fn legacy_unstable_flag(&self) -> bool {
self.flags.unstable_config.legacy_flag_enabled
}
pub fn unstable_bare_node_builtins(&self) -> bool {
self.flags.unstable_config.bare_node_builtins
|| self.workspace().has_unstable("bare-node-builtins")

View file

@ -1,6 +1,5 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use std::collections::HashSet;
use std::path::PathBuf;
use std::sync::Arc;
@ -10,18 +9,16 @@ use deno_package_json::PackageJsonDepValue;
use deno_semver::npm::NpmPackageReqReference;
use deno_semver::package::PackageReq;
use crate::util::path::is_banned_path_char;
#[derive(Debug)]
pub struct InstallNpmRemotePkg {
pub alias: String,
pub alias: Option<String>,
pub base_dir: PathBuf,
pub req: PackageReq,
}
#[derive(Debug)]
pub struct InstallNpmWorkspacePkg {
pub alias: String,
pub alias: Option<String>,
pub target_dir: PathBuf,
}
@ -43,16 +40,13 @@ impl NpmInstallDepsProvider {
let workspace_npm_pkgs = workspace.npm_packages();
for (_, folder) in workspace.config_folders() {
let mut deno_json_aliases = HashSet::new();
// deal with the deno.json first because it takes precedence during resolution
if let Some(deno_json) = &folder.deno_json {
// don't bother with externally referenced import maps as users
// should inline their import map to get this behaviour
if let Some(serde_json::Value::Object(obj)) = &deno_json.json.imports {
deno_json_aliases.reserve(obj.len());
let mut pkg_pkgs = Vec::with_capacity(obj.len());
for (alias, value) in obj {
for (_alias, value) in obj {
let serde_json::Value::String(specifier) = value else {
continue;
};
@ -60,11 +54,6 @@ impl NpmInstallDepsProvider {
else {
continue;
};
// skip any aliases with banned characters
if alias.chars().any(|c| c == '\\' || is_banned_path_char(c)) {
continue;
}
deno_json_aliases.insert(alias.to_lowercase());
let pkg_req = npm_req_ref.into_inner().req;
let workspace_pkg = workspace_npm_pkgs
.iter()
@ -72,12 +61,12 @@ impl NpmInstallDepsProvider {
if let Some(pkg) = workspace_pkg {
workspace_pkgs.push(InstallNpmWorkspacePkg {
alias: alias.to_string(),
alias: None,
target_dir: pkg.pkg_json.dir_path().to_path_buf(),
});
} else {
pkg_pkgs.push(InstallNpmRemotePkg {
alias: alias.to_string(),
alias: None,
base_dir: deno_json.dir_path(),
req: pkg_req,
});
@ -85,7 +74,7 @@ impl NpmInstallDepsProvider {
}
// sort within each package (more like npm resolution)
pkg_pkgs.sort_by(|a, b| a.alias.cmp(&b.alias));
pkg_pkgs.sort_by(|a, b| a.req.cmp(&b.req));
remote_pkgs.extend(pkg_pkgs);
}
}
@ -97,11 +86,6 @@ impl NpmInstallDepsProvider {
let Ok(dep) = dep else {
continue;
};
if deno_json_aliases.contains(&alias.to_lowercase()) {
// aliases in deno.json take precedence over package.json, so
// since this can't be resolved don't bother installing it
continue;
}
match dep {
PackageJsonDepValue::Req(pkg_req) => {
let workspace_pkg = workspace_npm_pkgs.iter().find(|pkg| {
@ -112,12 +96,12 @@ impl NpmInstallDepsProvider {
if let Some(pkg) = workspace_pkg {
workspace_pkgs.push(InstallNpmWorkspacePkg {
alias,
alias: Some(alias),
target_dir: pkg.pkg_json.dir_path().to_path_buf(),
});
} else {
pkg_pkgs.push(InstallNpmRemotePkg {
alias,
alias: Some(alias),
base_dir: pkg_json.dir_path().to_path_buf(),
req: pkg_req,
});
@ -128,7 +112,7 @@ impl NpmInstallDepsProvider {
pkg.matches_name_and_version_req(&alias, &version_req)
}) {
workspace_pkgs.push(InstallNpmWorkspacePkg {
alias,
alias: Some(alias),
target_dir: pkg.pkg_json.dir_path().to_path_buf(),
});
}

View file

@ -49,7 +49,7 @@ pub fn benchmark(
}
let port = get_port();
// deno run -A --unstable <path> <addr>
// deno run -A --unstable-net <path> <addr>
res.insert(
file_stem.to_string(),
run(
@ -57,7 +57,7 @@ pub fn benchmark(
deno_exe.as_str(),
"run",
"--allow-all",
"--unstable",
"--unstable-net",
"--enable-testing-features-do-not-use",
path,
&server_addr(port),

View file

@ -80,10 +80,6 @@ impl CodeCache {
data,
));
}
pub fn remove_code_cache(&self, specifier: &str) {
Self::ensure_ok(self.inner.remove_code_cache(specifier))
}
}
impl code_cache::CodeCache for CodeCache {
@ -162,15 +158,6 @@ impl CodeCacheInner {
self.conn.execute(sql, params)?;
Ok(())
}
pub fn remove_code_cache(&self, specifier: &str) -> Result<(), AnyError> {
let sql = "
DELETE FROM codecache
WHERE specifier=$1;";
let params = params![specifier];
self.conn.execute(sql, params)?;
Ok(())
}
}
fn serialize_code_cache_type(

View file

@ -714,10 +714,6 @@ impl CliFactory {
let mut checker = FeatureChecker::default();
checker.set_exit_cb(Box::new(crate::unstable_exit_cb));
checker.set_warn_cb(Box::new(crate::unstable_warn_cb));
if cli_options.legacy_unstable_flag() {
checker.enable_legacy_unstable();
checker.warn_on_legacy_unstable();
}
let unstable_features = cli_options.unstable_features();
for granular_flag in crate::UNSTABLE_GRANULAR_FLAGS {
if unstable_features.contains(&granular_flag.name.to_string()) {
@ -856,7 +852,6 @@ impl CliFactory {
unsafely_ignore_certificate_errors: cli_options
.unsafely_ignore_certificate_errors()
.clone(),
unstable: cli_options.legacy_unstable_flag(),
create_hmr_runner,
create_coverage_collector,
node_ipc: cli_options.node_ipc_fd(),

View file

@ -43,6 +43,8 @@ use indexmap::IndexSet;
use lsp_types::ClientCapabilities;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::ops::Deref;
use std::ops::DerefMut;
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
@ -70,6 +72,54 @@ fn is_true() -> bool {
true
}
/// Wrapper that defaults if it fails to deserialize. Good for individual
/// settings.
#[derive(Debug, Default, Clone, Eq, PartialEq)]
pub struct SafeValue<T> {
inner: T,
}
impl<'de, T: Default + for<'de2> Deserialize<'de2>> Deserialize<'de>
for SafeValue<T>
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Ok(Self {
inner: Deserialize::deserialize(deserializer).unwrap_or_default(),
})
}
}
impl<T: Serialize> Serialize for SafeValue<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.inner.serialize(serializer)
}
}
impl<T> Deref for SafeValue<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T> DerefMut for SafeValue<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.inner
}
}
impl<T> SafeValue<T> {
pub fn as_deref(&self) -> &T {
&self.inner
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct CodeLensSettings {
@ -538,7 +588,7 @@ pub struct WorkspaceSettings {
pub unsafely_ignore_certificate_errors: Option<Vec<String>>,
#[serde(default)]
pub unstable: bool,
pub unstable: SafeValue<Vec<String>>,
#[serde(default)]
pub javascript: LanguageWorkspaceSettings,
@ -568,7 +618,7 @@ impl Default for WorkspaceSettings {
testing: Default::default(),
tls_certificate: None,
unsafely_ignore_certificate_errors: None,
unstable: false,
unstable: Default::default(),
javascript: Default::default(),
typescript: Default::default(),
}
@ -1084,7 +1134,6 @@ impl Default for LspTsConfig {
"strict": true,
"target": "esnext",
"useDefineForClassFields": true,
"useUnknownInCatchVariables": false,
"jsx": "react",
"jsxFactory": "React.createElement",
"jsxFragmentFactory": "React.Fragment",
@ -2142,7 +2191,7 @@ mod tests {
},
tls_certificate: None,
unsafely_ignore_certificate_errors: None,
unstable: false,
unstable: Default::default(),
javascript: LanguageWorkspaceSettings {
inlay_hints: InlayHintsSettings {
parameter_names: InlayHintsParamNamesOptions {

View file

@ -12,6 +12,7 @@ use super::language_server::StateSnapshot;
use super::performance::Performance;
use super::tsc;
use super::tsc::TsServer;
use super::urls::uri_parse_unencoded;
use super::urls::url_to_uri;
use super::urls::LspUrlMap;
@ -53,11 +54,9 @@ use deno_semver::package::PackageReq;
use import_map::ImportMap;
use import_map::ImportMapError;
use log::error;
use lsp_types::Uri;
use std::collections::HashMap;
use std::collections::HashSet;
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::atomic::AtomicUsize;
use std::sync::Arc;
use std::thread;
@ -738,7 +737,7 @@ fn to_lsp_related_information(
if let (Some(file_name), Some(start), Some(end)) =
(&ri.file_name, &ri.start, &ri.end)
{
let uri = Uri::from_str(file_name).unwrap();
let uri = uri_parse_unencoded(file_name).unwrap();
Some(lsp::DiagnosticRelatedInformation {
location: lsp::Location {
uri,

View file

@ -4042,7 +4042,11 @@ impl Inner {
</details>
"#,
serde_json::to_string_pretty(&workspace_settings).unwrap(),
serde_json::to_string_pretty(&workspace_settings)
.inspect_err(|e| {
dbg!(e);
})
.unwrap(),
documents_specifiers.len(),
documents_specifiers
.into_iter()

View file

@ -1,7 +1,6 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use std::collections::HashMap;
use std::str::FromStr;
use deno_ast::LineAndColumnIndex;
use deno_ast::ModuleSpecifier;
@ -42,6 +41,7 @@ use super::config::LanguageWorkspaceSettings;
use super::config::ObjectLiteralMethodSnippets;
use super::config::TestingSettings;
use super::config::WorkspaceSettings;
use super::urls::uri_parse_unencoded;
use super::urls::url_to_uri;
#[derive(Debug)]
@ -263,7 +263,8 @@ impl ReplLanguageServer {
}
fn get_document_uri(&self) -> Uri {
Uri::from_str(self.cwd_uri.join("$deno$repl.ts").unwrap().as_str()).unwrap()
uri_parse_unencoded(self.cwd_uri.join("$deno$repl.ts").unwrap().as_str())
.unwrap()
}
}
@ -311,7 +312,7 @@ pub fn get_repl_workspace_settings() -> WorkspaceSettings {
document_preload_limit: 0, // don't pre-load any modules as it's expensive and not useful for the repl
tls_certificate: None,
unsafely_ignore_certificate_errors: None,
unstable: false,
unstable: Default::default(),
suggest: DenoCompletionSettings {
imports: ImportCompletionSettings {
auto_discover: false,

View file

@ -12,6 +12,7 @@ use crate::lsp::client::Client;
use crate::lsp::client::TestingNotification;
use crate::lsp::config;
use crate::lsp::logging::lsp_log;
use crate::lsp::urls::uri_parse_unencoded;
use crate::lsp::urls::uri_to_url;
use crate::lsp::urls::url_to_uri;
use crate::tools::test;
@ -32,11 +33,10 @@ use deno_core::ModuleSpecifier;
use deno_runtime::deno_permissions::Permissions;
use deno_runtime::tokio_util::create_and_run_current_thread;
use indexmap::IndexMap;
use lsp_types::Uri;
use std::borrow::Cow;
use std::collections::HashMap;
use std::collections::HashSet;
use std::num::NonZeroUsize;
use std::str::FromStr;
use std::sync::Arc;
use std::time::Duration;
use std::time::Instant;
@ -219,8 +219,9 @@ impl TestRun {
) -> Result<(), AnyError> {
let args = self.get_args();
lsp_log!("Executing test run with arguments: {}", args.join(" "));
let flags =
Arc::new(flags_from_vec(args.into_iter().map(From::from).collect())?);
let flags = Arc::new(flags_from_vec(
args.into_iter().map(|s| From::from(s.as_ref())).collect(),
)?);
let factory = CliFactory::from_flags(flags);
let cli_options = factory.cli_options()?;
// Various test files should not share the same permissions in terms of
@ -452,37 +453,42 @@ impl TestRun {
Ok(())
}
fn get_args(&self) -> Vec<&str> {
let mut args = vec!["deno", "test"];
fn get_args(&self) -> Vec<Cow<str>> {
let mut args = vec![Cow::Borrowed("deno"), Cow::Borrowed("test")];
args.extend(
self
.workspace_settings
.testing
.args
.iter()
.map(|s| s.as_str()),
.map(|s| Cow::Borrowed(s.as_str())),
);
args.push("--trace-leaks");
if self.workspace_settings.unstable && !args.contains(&"--unstable") {
args.push("--unstable");
args.push(Cow::Borrowed("--trace-leaks"));
for unstable_feature in self.workspace_settings.unstable.as_deref() {
let flag = format!("--unstable-{unstable_feature}");
if !args.contains(&Cow::Borrowed(&flag)) {
args.push(Cow::Owned(flag));
}
}
if let Some(config) = &self.workspace_settings.config {
if !args.contains(&"--config") && !args.contains(&"-c") {
args.push("--config");
args.push(config.as_str());
if !args.contains(&Cow::Borrowed("--config"))
&& !args.contains(&Cow::Borrowed("-c"))
{
args.push(Cow::Borrowed("--config"));
args.push(Cow::Borrowed(config.as_str()));
}
}
if let Some(import_map) = &self.workspace_settings.import_map {
if !args.contains(&"--import-map") {
args.push("--import-map");
args.push(import_map.as_str());
if !args.contains(&Cow::Borrowed("--import-map")) {
args.push(Cow::Borrowed("--import-map"));
args.push(Cow::Borrowed(import_map.as_str()));
}
}
if self.kind == lsp_custom::TestRunKind::Debug
&& !args.contains(&"--inspect")
&& !args.contains(&"--inspect-brk")
&& !args.contains(&Cow::Borrowed("--inspect"))
&& !args.contains(&Cow::Borrowed("--inspect-brk"))
{
args.push("--inspect");
args.push(Cow::Borrowed("--inspect"));
}
args
}
@ -529,7 +535,7 @@ impl LspTestDescription {
&self,
tests: &IndexMap<usize, LspTestDescription>,
) -> lsp_custom::TestIdentifier {
let uri = Uri::from_str(&self.location().file_name).unwrap();
let uri = uri_parse_unencoded(&self.location().file_name).unwrap();
let static_id = self.static_id();
let mut root_desc = self;
while let Some(parent_id) = root_desc.parent_id() {

View file

@ -61,6 +61,25 @@ const COMPONENT: &percent_encoding::AsciiSet = &percent_encoding::CONTROLS
.add(b'+')
.add(b',');
/// Characters that may be left unencoded in a `Url` path but not valid in a
/// `Uri` path.
const URL_TO_URI_PATH: &percent_encoding::AsciiSet =
&percent_encoding::CONTROLS
.add(b'[')
.add(b']')
.add(b'^')
.add(b'|');
/// Characters that may be left unencoded in a `Url` query but not valid in a
/// `Uri` query.
const URL_TO_URI_QUERY: &percent_encoding::AsciiSet =
&URL_TO_URI_PATH.add(b'\\').add(b'`').add(b'{').add(b'}');
/// Characters that may be left unencoded in a `Url` fragment but not valid in
/// a `Uri` fragment.
const URL_TO_URI_FRAGMENT: &percent_encoding::AsciiSet =
&URL_TO_URI_PATH.add(b'#').add(b'\\').add(b'{').add(b'}');
fn hash_data_specifier(specifier: &ModuleSpecifier) -> String {
let mut file_name_str = specifier.path().to_string();
if let Some(query) = specifier.query() {
@ -259,8 +278,33 @@ impl LspUrlMapInner {
}
}
pub fn uri_parse_unencoded(s: &str) -> Result<Uri, AnyError> {
url_to_uri(&Url::parse(s)?)
}
pub fn url_to_uri(url: &Url) -> Result<Uri, AnyError> {
Ok(Uri::from_str(url.as_str()).inspect_err(|err| {
let components = deno_core::url::quirks::internal_components(url);
let mut input = String::with_capacity(url.as_str().len());
input.push_str(&url.as_str()[..components.path_start as usize]);
input.push_str(
&percent_encoding::utf8_percent_encode(url.path(), URL_TO_URI_PATH)
.to_string(),
);
if let Some(query) = url.query() {
input.push('?');
input.push_str(
&percent_encoding::utf8_percent_encode(query, URL_TO_URI_QUERY)
.to_string(),
);
}
if let Some(fragment) = url.fragment() {
input.push('#');
input.push_str(
&percent_encoding::utf8_percent_encode(fragment, URL_TO_URI_FRAGMENT)
.to_string(),
);
}
Ok(Uri::from_str(&input).inspect_err(|err| {
lsp_warn!("Could not convert URL \"{url}\" to URI: {err}")
})?)
}
@ -373,7 +417,7 @@ impl LspUrlMap {
} else {
to_deno_uri(specifier)
};
let uri = Uri::from_str(&uri_str)?;
let uri = uri_parse_unencoded(&uri_str)?;
inner.put(specifier.clone(), uri.clone());
uri
};

View file

@ -337,17 +337,61 @@ fn exit_with_message(message: &str, code: i32) -> ! {
std::process::exit(code);
}
fn get_suggestions_for_commonjs_error(e: &JsError) -> Vec<FixSuggestion> {
if e.name.as_deref() == Some("ReferenceError") {
if let Some(msg) = &e.message {
if msg.contains("module is not defined")
|| msg.contains("exports is not defined")
{
return vec![
FixSuggestion::info("Deno does not support CommonJS modules without `.cjs` extension."),
FixSuggestion::hint("Rewrite this module to ESM or change the file extension to `.cjs`."),
];
}
fn get_suggestions_for_terminal_errors(e: &JsError) -> Vec<FixSuggestion> {
if let Some(msg) = &e.message {
if msg.contains("module is not defined")
|| msg.contains("exports is not defined")
{
return vec![
FixSuggestion::info(
"Deno does not support CommonJS modules without `.cjs` extension.",
),
FixSuggestion::hint(
"Rewrite this module to ESM or change the file extension to `.cjs`.",
),
];
} else if msg.contains("openKv is not a function") {
return vec![
FixSuggestion::info("Deno.openKv() is an unstable API."),
FixSuggestion::hint(
"Run again with `--unstable-kv` flag to enable this API.",
),
];
} else if msg.contains("cron is not a function") {
return vec![
FixSuggestion::info("Deno.cron() is an unstable API."),
FixSuggestion::hint(
"Run again with `--unstable-cron` flag to enable this API.",
),
];
} else if msg.contains("createHttpClient is not a function") {
return vec![
FixSuggestion::info("Deno.createHttpClient() is an unstable API."),
FixSuggestion::hint(
"Run again with `--unstable-http` flag to enable this API.",
),
];
} else if msg.contains("WebSocketStream is not defined") {
return vec![
FixSuggestion::info("new WebSocketStream() is an unstable API."),
FixSuggestion::hint(
"Run again with `--unstable-net` flag to enable this API.",
),
];
} else if msg.contains("Temporal is not defined") {
return vec![
FixSuggestion::info("Temporal is an unstable API."),
FixSuggestion::hint(
"Run again with `--unstable-temporal` flag to enable this API.",
),
];
} else if msg.contains("BroadcastChannel is not defined") {
return vec![
FixSuggestion::info("BroadcastChannel is an unstable API."),
FixSuggestion::hint(
"Run again with `--unstable-broadcast-channel` flag to enable this API.",
),
];
}
}
@ -359,7 +403,7 @@ fn exit_for_error(error: AnyError) -> ! {
let mut error_code = 1;
if let Some(e) = error.downcast_ref::<JsError>() {
let suggestions = get_suggestions_for_commonjs_error(e);
let suggestions = get_suggestions_for_terminal_errors(e);
error_string = format_js_error_with_suggestions(e, suggestions);
} else if let Some(SnapshotFromLockfileError::IntegrityCheckFailed(e)) =
error.downcast_ref::<SnapshotFromLockfileError>()
@ -434,25 +478,14 @@ fn resolve_flags_and_init(
Err(err) => exit_for_error(AnyError::from(err)),
};
// TODO(bartlomieju): remove when `--unstable` flag is removed.
// TODO(bartlomieju): remove in Deno v2.5 and hard error then.
if flags.unstable_config.legacy_flag_enabled {
#[allow(clippy::print_stderr)]
if matches!(flags.subcommand, DenoSubcommand::Check(_)) {
// can't use log crate because that's not setup yet
eprintln!(
"⚠️ {}",
colors::yellow(
"The `--unstable` flag is not needed for `deno check` anymore."
)
);
} else {
eprintln!(
"⚠️ {}",
colors::yellow(
"The `--unstable` flag is deprecated and will be removed in Deno 2.0. Use granular `--unstable-*` flags instead.\nLearn more at: https://docs.deno.com/runtime/manual/tools/unstable_flags"
)
);
}
log::warn!(
"⚠️ {}",
colors::yellow(
"The `--unstable` flag has been removed in Deno 2.0. Use granular `--unstable-*` flags instead.\nLearn more at: https://docs.deno.com/runtime/manual/tools/unstable_flags"
)
);
}
let default_v8_flags = match flags.subcommand {

View file

@ -2,7 +2,6 @@
use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::HashSet;
use std::path::PathBuf;
use std::pin::Pin;
use std::rc::Rc;
@ -44,7 +43,6 @@ use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::futures::future::FutureExt;
use deno_core::futures::Future;
use deno_core::parking_lot::Mutex;
use deno_core::resolve_url;
use deno_core::ModuleCodeString;
use deno_core::ModuleLoader;
@ -244,7 +242,6 @@ impl CliModuleLoaderFactory {
emitter: self.shared.emitter.clone(),
parsed_source_cache: self.shared.parsed_source_cache.clone(),
shared: self.shared.clone(),
prevent_v8_code_cache: Default::default(),
})));
ModuleLoaderAndSourceMapGetter {
module_loader: loader,
@ -296,10 +293,6 @@ struct CliModuleLoaderInner<TGraphContainer: ModuleGraphContainer> {
emitter: Arc<Emitter>,
parsed_source_cache: Arc<ParsedSourceCache>,
graph_container: TGraphContainer,
// NOTE(bartlomieju): this is temporary, for deprecated import assertions.
// Should be removed in Deno 2.
// Modules stored here should not be V8 code-cached.
prevent_v8_code_cache: Arc<Mutex<HashSet<String>>>,
}
impl<TGraphContainer: ModuleGraphContainer>
@ -785,14 +778,6 @@ impl<TGraphContainer: ModuleGraphContainer> ModuleLoader
code_cache: &[u8],
) -> Pin<Box<dyn Future<Output = ()>>> {
if let Some(cache) = self.0.shared.code_cache.as_ref() {
if self
.0
.prevent_v8_code_cache
.lock()
.contains(specifier.as_str())
{
return std::future::ready(()).boxed_local();
}
// This log line is also used by tests.
log::debug!(
"Updating V8 code cache for ES module: {specifier}, [{source_hash:?}]"
@ -807,19 +792,6 @@ impl<TGraphContainer: ModuleGraphContainer> ModuleLoader
std::future::ready(()).boxed_local()
}
fn purge_and_prevent_code_cache(&self, specifier: &str) {
if let Some(cache) = self.0.shared.code_cache.as_ref() {
// This log line is also used by tests.
log::debug!("Remove V8 code cache for ES module: {specifier}");
cache.remove_code_cache(specifier);
self
.0
.prevent_v8_code_cache
.lock()
.insert(specifier.to_string());
}
}
fn get_source_map(&self, file_name: &str) -> Option<Vec<u8>> {
let specifier = resolve_url(file_name).ok()?;
match specifier.scheme() {

View file

@ -10,6 +10,7 @@ use std::cmp::Ordering;
use std::collections::hash_map::Entry;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::collections::HashSet;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
@ -620,6 +621,9 @@ async fn sync_resolution_with_fs(
let mut found_names: HashMap<&String, &PackageNv> = HashMap::new();
// set of node_modules in workspace packages that we've already ensured exist
let mut existing_child_node_modules_dirs: HashSet<PathBuf> = HashSet::new();
// 4. Create symlinks for package json dependencies
{
for remote in npm_install_deps_provider.remote_pkgs() {
@ -638,13 +642,16 @@ async fn sync_resolution_with_fs(
} else {
continue; // skip, package not found
};
let alias_clashes = remote.req.name != remote.alias
&& newest_packages_by_name.contains_key(&remote.alias);
let Some(remote_alias) = &remote.alias else {
continue;
};
let alias_clashes = remote.req.name != *remote_alias
&& newest_packages_by_name.contains_key(remote_alias);
let install_in_child = {
// we'll install in the child if the alias is taken by another package, or
// if there's already a package with the same name but different version
// linked into the root
match found_names.entry(&remote.alias) {
match found_names.entry(remote_alias) {
Entry::Occupied(nv) => {
alias_clashes
|| remote.req.name != nv.get().name // alias to a different package (in case of duplicate aliases)
@ -667,8 +674,15 @@ async fn sync_resolution_with_fs(
);
if install_in_child {
// symlink the dep into the package's child node_modules folder
let dest_path =
remote.base_dir.join("node_modules").join(&remote.alias);
let dest_node_modules = remote.base_dir.join("node_modules");
if !existing_child_node_modules_dirs.contains(&dest_node_modules) {
fs::create_dir_all(&dest_node_modules).with_context(|| {
format!("Creating '{}'", dest_node_modules.display())
})?;
existing_child_node_modules_dirs.insert(dest_node_modules.clone());
}
let mut dest_path = dest_node_modules;
dest_path.push(remote_alias);
symlink_package_dir(&local_registry_package_path, &dest_path)?;
} else {
@ -678,7 +692,7 @@ async fn sync_resolution_with_fs(
{
symlink_package_dir(
&local_registry_package_path,
&join_package_name(root_node_modules_dir_path, &remote.alias),
&join_package_name(root_node_modules_dir_path, remote_alias),
)?;
}
}
@ -763,9 +777,12 @@ async fn sync_resolution_with_fs(
// install correctly for a workspace (potentially in sub directories),
// but this is good enough for a first pass
for workspace in npm_install_deps_provider.workspace_pkgs() {
let Some(workspace_alias) = &workspace.alias else {
continue;
};
symlink_package_dir(
&workspace.target_dir,
&root_node_modules_dir_path.join(&workspace.alias),
&root_node_modules_dir_path.join(workspace_alias),
)?;
}
}

View file

@ -707,7 +707,14 @@ impl Resolver for CliGraphResolver {
.resolve_if_for_npm_pkg(raw_specifier, referrer, to_node_mode(mode))
.map_err(ResolveError::Other)?;
if let Some(res) = maybe_resolution {
return Ok(res.into_url());
match res {
NodeResolution::Esm(url) | NodeResolution::CommonJs(url) => {
return Ok(url)
}
NodeResolution::BuiltIn(_) => {
// don't resolve bare specifiers for built-in modules via node resolution
}
}
}
}

View file

@ -223,7 +223,7 @@
"useUnknownInCatchVariables": {
"description": "Default catch clause variables as `unknown` instead of `any`.",
"type": "boolean",
"default": false,
"default": true,
"markdownDescription": "Default catch clause variables as `unknown` instead of `any`.\n\nSee more: https://www.typescriptlang.org/tsconfig#useUnknownInCatchVariables"
}
}
@ -279,25 +279,6 @@
"type": "string"
}
},
"files": {
"type": "object",
"properties": {
"include": {
"type": "array",
"description": "List of files, directories or globs that will be linted.",
"items": {
"type": "string"
}
},
"exclude": {
"type": "array",
"description": "List of files, directories or globs that will not be linted.",
"items": {
"type": "string"
}
}
}
},
"rules": {
"type": "object",
"properties": {
@ -355,25 +336,6 @@
"type": "string"
}
},
"files": {
"type": "object",
"properties": {
"include": {
"type": "array",
"description": "List of files, directories or globs that will be formatted.",
"items": {
"type": "string"
}
},
"exclude": {
"type": "array",
"description": "List of files, directories or globs that will not be formatted.",
"items": {
"type": "string"
}
}
}
},
"useTabs": {
"description": "Whether to use tabs (true) or spaces (false) for indentation.",
"type": "boolean",
@ -477,25 +439,6 @@
"items": {
"type": "string"
}
},
"files": {
"type": "object",
"properties": {
"include": {
"type": "array",
"description": "List of files, directories or globs that will be searched for tests.",
"items": {
"type": "string"
}
},
"exclude": {
"type": "array",
"description": "List of files, directories or globs that will not be searched for tests.",
"items": {
"type": "string"
}
}
}
}
}
},
@ -536,25 +479,6 @@
"items": {
"type": "string"
}
},
"files": {
"type": "object",
"properties": {
"include": {
"type": "array",
"description": "List of files, directories or globs that will be searched for benchmarks.",
"items": {
"type": "string"
}
},
"exclude": {
"type": "array",
"description": "List of files, directories or globs that will not be searched for benchmarks.",
"items": {
"type": "string"
}
}
}
}
}
},

View file

@ -624,7 +624,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
},
node_modules,
unstable_config: UnstableConfig {
legacy_flag_enabled: cli_options.legacy_unstable_flag(),
legacy_flag_enabled: false,
bare_node_builtins: cli_options.unstable_bare_node_builtins(),
sloppy_imports: cli_options.unstable_sloppy_imports(),
features: cli_options.unstable_features(),

View file

@ -682,12 +682,6 @@ pub async fn run(
let feature_checker = Arc::new({
let mut checker = FeatureChecker::default();
checker.set_exit_cb(Box::new(crate::unstable_exit_cb));
// TODO(bartlomieju): enable, once we deprecate `--unstable` in favor
// of granular --unstable-* flags.
// feature_checker.set_warn_cb(Box::new(crate::unstable_warn_cb));
if metadata.unstable_config.legacy_flag_enabled {
checker.enable_legacy_unstable();
}
for feature in metadata.unstable_config.features {
// `metadata` is valid for the whole lifetime of the program, so we
// can leak the string here.
@ -733,7 +727,6 @@ pub async fn run(
seed: metadata.seed,
unsafely_ignore_certificate_errors: metadata
.unsafely_ignore_certificate_errors,
unstable: metadata.unstable_config.legacy_flag_enabled,
create_hmr_runner: None,
create_coverage_collector: None,
node_ipc: None,

View file

@ -907,6 +907,7 @@ fn get_resolved_malva_config(
};
let language_options = LanguageOptions {
align_comments: true,
hex_case: HexCase::Lower,
hex_color_length: None,
quotes: if let Some(true) = options.single_quote {
@ -1011,7 +1012,6 @@ fn get_resolved_yaml_config(
let layout_options = LayoutOptions {
print_width: options.line_width.unwrap_or(80) as usize,
use_tabs: options.use_tabs.unwrap_or_default(),
indent_width: options.indent_width.unwrap_or(2) as usize,
line_break: LineBreak::Lf,
};
@ -1028,6 +1028,9 @@ fn get_resolved_yaml_config(
brace_spacing: true,
bracket_spacing: false,
dash_spacing: DashSpacing::OneSpace,
prefer_single_line: false,
flow_sequence_prefer_single_line: None,
flow_map_prefer_single_line: None,
trim_trailing_whitespaces: true,
trim_trailing_zero: false,
ignore_comment_directive: "deno-fmt-ignore".into(),

View file

@ -490,10 +490,6 @@ async fn resolve_shim_data(
TypeCheckMode::Local => executable_args.push("--check".to_string()),
}
if flags.unstable_config.legacy_flag_enabled {
executable_args.push("--unstable".to_string());
}
for feature in &flags.unstable_config.features {
executable_args.push(format!("--unstable-{}", feature));
}
@ -822,13 +818,7 @@ mod tests {
create_install_shim(
&HttpClientProvider::new(None, None),
&Flags {
unstable_config: UnstableConfig {
legacy_flag_enabled: true,
..Default::default()
},
..Flags::default()
},
&Flags::default(),
InstallFlagsGlobal {
module_url: "http://localhost:4545/echo_server.ts".to_string(),
args: vec![],
@ -850,12 +840,11 @@ mod tests {
let content = fs::read_to_string(file_path).unwrap();
if cfg!(windows) {
assert!(content.contains(
r#""run" "--unstable" "--no-config" "http://localhost:4545/echo_server.ts""#
r#""run" "--no-config" "http://localhost:4545/echo_server.ts""#
));
} else {
assert!(content.contains(
r#"run --unstable --no-config 'http://localhost:4545/echo_server.ts'"#
));
assert!(content
.contains(r#"run --no-config 'http://localhost:4545/echo_server.ts'"#));
}
}
@ -886,13 +875,7 @@ mod tests {
async fn install_unstable_legacy() {
let shim_data = resolve_shim_data(
&HttpClientProvider::new(None, None),
&Flags {
unstable_config: UnstableConfig {
legacy_flag_enabled: true,
..Default::default()
},
..Default::default()
},
&Default::default(),
&InstallFlagsGlobal {
module_url: "http://localhost:4545/echo_server.ts".to_string(),
args: vec![],
@ -907,12 +890,7 @@ mod tests {
assert_eq!(shim_data.name, "echo_server");
assert_eq!(
shim_data.args,
vec![
"run",
"--unstable",
"--no-config",
"http://localhost:4545/echo_server.ts",
]
vec!["run", "--no-config", "http://localhost:4545/echo_server.ts",]
);
}

View file

@ -7,7 +7,6 @@ use deno_semver::jsr::JsrPackageReqReference;
use deno_semver::npm::NpmPackageReqReference;
use std::borrow::Cow;
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
@ -26,9 +25,11 @@ use deno_semver::package::PackageReq;
use indexmap::IndexMap;
use jsonc_parser::ast::ObjectProp;
use jsonc_parser::ast::Value;
use yoke::Yoke;
use crate::args::AddFlags;
use crate::args::CacheSetting;
use crate::args::CliOptions;
use crate::args::Flags;
use crate::args::RemoveFlags;
use crate::factory::CliFactory;
@ -56,115 +57,303 @@ impl DenoConfigFormat {
}
}
struct DenoConfig {
config: Arc<deno_config::deno_json::ConfigFile>,
format: DenoConfigFormat,
imports: IndexMap<String, String>,
}
fn deno_json_imports(
config: &deno_config::deno_json::ConfigFile,
) -> Result<IndexMap<String, String>, AnyError> {
Ok(
config
.json
.imports
.clone()
.map(|imports| {
serde_json::from_value(imports)
.map_err(|err| anyhow!("Malformed \"imports\" configuration: {err}"))
})
.transpose()?
.unwrap_or_default(),
)
}
impl DenoConfig {
fn from_options(options: &CliOptions) -> Result<Option<Self>, AnyError> {
let start_dir = &options.start_dir;
if let Some(config) = start_dir.maybe_deno_json() {
Ok(Some(Self {
imports: deno_json_imports(config)?,
config: config.clone(),
format: DenoConfigFormat::from_specifier(&config.specifier)?,
}))
} else {
Ok(None)
}
}
fn add(&mut self, selected: SelectedPackage) {
self.imports.insert(
selected.import_name,
format!("{}@{}", selected.package_name, selected.version_req),
);
}
fn remove(&mut self, package: &str) -> bool {
self.imports.shift_remove(package).is_some()
}
fn take_import_fields(
&mut self,
) -> Vec<(&'static str, IndexMap<String, String>)> {
vec![("imports", std::mem::take(&mut self.imports))]
}
}
impl NpmConfig {
fn from_options(options: &CliOptions) -> Result<Option<Self>, AnyError> {
let start_dir = &options.start_dir;
if let Some(pkg_json) = start_dir.maybe_pkg_json() {
Ok(Some(Self {
dependencies: pkg_json.dependencies.clone().unwrap_or_default(),
dev_dependencies: pkg_json.dev_dependencies.clone().unwrap_or_default(),
config: pkg_json.clone(),
fmt_options: None,
}))
} else {
Ok(None)
}
}
fn add(&mut self, selected: SelectedPackage, dev: bool) {
let (name, version) = package_json_dependency_entry(selected);
if dev {
self.dev_dependencies.insert(name, version);
} else {
self.dependencies.insert(name, version);
}
}
fn remove(&mut self, package: &str) -> bool {
let in_deps = self.dependencies.shift_remove(package).is_some();
let in_dev_deps = self.dev_dependencies.shift_remove(package).is_some();
in_deps || in_dev_deps
}
fn take_import_fields(
&mut self,
) -> Vec<(&'static str, IndexMap<String, String>)> {
vec![
("dependencies", std::mem::take(&mut self.dependencies)),
(
"devDependencies",
std::mem::take(&mut self.dev_dependencies),
),
]
}
}
struct NpmConfig {
config: Arc<deno_node::PackageJson>,
fmt_options: Option<FmtOptionsConfig>,
dependencies: IndexMap<String, String>,
dev_dependencies: IndexMap<String, String>,
}
enum DenoOrPackageJson {
Deno(Arc<deno_config::deno_json::ConfigFile>, DenoConfigFormat),
Npm(Arc<deno_node::PackageJson>, Option<FmtOptionsConfig>),
Deno(DenoConfig),
Npm(NpmConfig),
}
impl From<DenoConfig> for DenoOrPackageJson {
fn from(config: DenoConfig) -> Self {
Self::Deno(config)
}
}
impl From<NpmConfig> for DenoOrPackageJson {
fn from(config: NpmConfig) -> Self {
Self::Npm(config)
}
}
/// Wrapper around `jsonc_parser::ast::Object` that can be stored in a `Yoke`
#[derive(yoke::Yokeable)]
struct JsoncObjectView<'a>(jsonc_parser::ast::Object<'a>);
struct ConfigUpdater {
config: DenoOrPackageJson,
// the `Yoke` is so we can carry the parsed object (which borrows from
// the source) along with the source itself
ast: Yoke<JsoncObjectView<'static>, String>,
path: PathBuf,
modified: bool,
}
impl ConfigUpdater {
fn obj(&self) -> &jsonc_parser::ast::Object<'_> {
&self.ast.get().0
}
fn contents(&self) -> &str {
self.ast.backing_cart()
}
async fn maybe_new(
config: Option<impl Into<DenoOrPackageJson>>,
) -> Result<Option<Self>, AnyError> {
if let Some(config) = config {
Ok(Some(Self::new(config.into()).await?))
} else {
Ok(None)
}
}
async fn new(config: DenoOrPackageJson) -> Result<Self, AnyError> {
let specifier = config.specifier();
if specifier.scheme() != "file" {
bail!("Can't update a remote configuration file");
}
let config_file_path = specifier.to_file_path().map_err(|_| {
anyhow!("Specifier {specifier:?} is an invalid file path")
})?;
let config_file_contents = {
let contents = tokio::fs::read_to_string(&config_file_path)
.await
.with_context(|| {
format!("Reading config file at: {}", config_file_path.display())
})?;
if contents.trim().is_empty() {
"{}\n".into()
} else {
contents
}
};
let ast = Yoke::try_attach_to_cart(config_file_contents, |contents| {
let ast = jsonc_parser::parse_to_ast(
contents,
&Default::default(),
&Default::default(),
)
.with_context(|| {
format!("Failed to parse config file at {}", specifier)
})?;
let obj = match ast.value {
Some(Value::Object(obj)) => obj,
_ => bail!(
"Failed to update config file at {}, expected an object",
specifier
),
};
Ok(JsoncObjectView(obj))
})?;
Ok(Self {
config,
ast,
path: config_file_path,
modified: false,
})
}
fn add(&mut self, selected: SelectedPackage, dev: bool) {
match &mut self.config {
DenoOrPackageJson::Deno(deno) => deno.add(selected),
DenoOrPackageJson::Npm(npm) => npm.add(selected, dev),
}
self.modified = true;
}
fn remove(&mut self, package: &str) -> bool {
let removed = match &mut self.config {
DenoOrPackageJson::Deno(deno) => deno.remove(package),
DenoOrPackageJson::Npm(npm) => npm.remove(package),
};
if removed {
self.modified = true;
}
removed
}
async fn commit(mut self) -> Result<(), AnyError> {
if !self.modified {
return Ok(());
}
let import_fields = self.config.take_import_fields();
let fmt_config_options = self.config.fmt_options();
let new_text = update_config_file_content(
self.obj(),
self.contents(),
fmt_config_options,
import_fields.into_iter().map(|(k, v)| {
(
k,
if v.is_empty() {
None
} else {
Some(generate_imports(v.into_iter().collect()))
},
)
}),
self.config.file_name(),
);
tokio::fs::write(&self.path, new_text).await?;
Ok(())
}
}
impl DenoOrPackageJson {
fn specifier(&self) -> Cow<ModuleSpecifier> {
match self {
Self::Deno(d, ..) => Cow::Borrowed(&d.specifier),
Self::Npm(n, ..) => Cow::Owned(n.specifier()),
}
}
/// Returns the existing imports/dependencies from the config.
fn existing_imports(&self) -> Result<IndexMap<String, String>, AnyError> {
match self {
DenoOrPackageJson::Deno(deno, ..) => {
if let Some(imports) = deno.json.imports.clone() {
match serde_json::from_value(imports) {
Ok(map) => Ok(map),
Err(err) => {
bail!("Malformed \"imports\" configuration: {err}")
}
}
} else {
Ok(Default::default())
}
}
DenoOrPackageJson::Npm(npm, ..) => {
Ok(npm.dependencies.clone().unwrap_or_default())
}
Self::Deno(d, ..) => Cow::Borrowed(&d.config.specifier),
Self::Npm(n, ..) => Cow::Owned(n.config.specifier()),
}
}
fn fmt_options(&self) -> FmtOptionsConfig {
match self {
DenoOrPackageJson::Deno(deno, ..) => deno
.config
.to_fmt_config()
.ok()
.map(|f| f.options)
.unwrap_or_default(),
DenoOrPackageJson::Npm(_, config) => config.clone().unwrap_or_default(),
DenoOrPackageJson::Npm(config) => {
config.fmt_options.clone().unwrap_or_default()
}
}
}
fn imports_key(&self) -> &'static str {
fn take_import_fields(
&mut self,
) -> Vec<(&'static str, IndexMap<String, String>)> {
match self {
DenoOrPackageJson::Deno(..) => "imports",
DenoOrPackageJson::Npm(..) => "dependencies",
Self::Deno(d) => d.take_import_fields(),
Self::Npm(n) => n.take_import_fields(),
}
}
fn file_name(&self) -> &'static str {
match self {
DenoOrPackageJson::Deno(_, format) => match format {
DenoOrPackageJson::Deno(config) => match config.format {
DenoConfigFormat::Json => "deno.json",
DenoConfigFormat::Jsonc => "deno.jsonc",
},
DenoOrPackageJson::Npm(..) => "package.json",
}
}
}
fn is_npm(&self) -> bool {
matches!(self, Self::Npm(..))
}
/// Get the preferred config file to operate on
/// given the flags. If no config file is present,
/// creates a `deno.json` file - in this case
/// we also return a new `CliFactory` that knows about
/// the new config
fn from_flags(flags: Arc<Flags>) -> Result<(Self, CliFactory), AnyError> {
let factory = CliFactory::from_flags(flags.clone());
let options = factory.cli_options()?;
let start_dir = &options.start_dir;
match (start_dir.maybe_deno_json(), start_dir.maybe_pkg_json()) {
// when both are present, for now,
// default to deno.json
(Some(deno), Some(_) | None) => Ok((
DenoOrPackageJson::Deno(
deno.clone(),
DenoConfigFormat::from_specifier(&deno.specifier)?,
),
factory,
)),
(None, Some(package_json)) => {
Ok((DenoOrPackageJson::Npm(package_json.clone(), None), factory))
}
(None, None) => {
std::fs::write(options.initial_cwd().join("deno.json"), "{}\n")
.context("Failed to create deno.json file")?;
drop(factory); // drop to prevent use
log::info!("Created deno.json configuration file.");
let factory = CliFactory::from_flags(flags.clone());
let options = factory.cli_options()?.clone();
let start_dir = &options.start_dir;
Ok((
DenoOrPackageJson::Deno(
start_dir.maybe_deno_json().cloned().ok_or_else(|| {
anyhow!("config not found, but it was just created")
})?,
DenoConfigFormat::Json,
),
factory,
))
}
}
}
fn create_deno_json(
flags: &Arc<Flags>,
options: &CliOptions,
) -> Result<CliFactory, AnyError> {
std::fs::write(options.initial_cwd().join("deno.json"), "{}\n")
.context("Failed to create deno.json file")?;
log::info!("Created deno.json configuration file.");
let factory = CliFactory::from_flags(flags.clone());
Ok(factory)
}
fn package_json_dependency_entry(
@ -199,19 +388,53 @@ impl std::fmt::Display for AddCommandName {
}
}
fn load_configs(
flags: &Arc<Flags>,
) -> Result<(CliFactory, Option<NpmConfig>, Option<DenoConfig>), AnyError> {
let cli_factory = CliFactory::from_flags(flags.clone());
let options = cli_factory.cli_options()?;
let npm_config = NpmConfig::from_options(options)?;
let (cli_factory, deno_config) = match DenoConfig::from_options(options)? {
Some(config) => (cli_factory, Some(config)),
None if npm_config.is_some() => (cli_factory, None),
None => {
let factory = create_deno_json(flags, options)?;
let options = factory.cli_options()?.clone();
(
factory,
Some(
DenoConfig::from_options(&options)?.expect("Just created deno.json"),
),
)
}
};
assert!(deno_config.is_some() || npm_config.is_some());
Ok((cli_factory, npm_config, deno_config))
}
pub async fn add(
flags: Arc<Flags>,
add_flags: AddFlags,
cmd_name: AddCommandName,
) -> Result<(), AnyError> {
let (config_file, cli_factory) =
DenoOrPackageJson::from_flags(flags.clone())?;
let (cli_factory, npm_config, deno_config) = load_configs(&flags)?;
let mut npm_config = ConfigUpdater::maybe_new(npm_config).await?;
let mut deno_config = ConfigUpdater::maybe_new(deno_config).await?;
let config_specifier = config_file.specifier();
if config_specifier.scheme() != "file" {
bail!("Can't add dependencies to a remote configuration file");
if let Some(deno) = &deno_config {
let specifier = deno.config.specifier();
if deno.obj().get_string("importMap").is_some() {
bail!(
concat!(
"`deno {}` is not supported when configuration file contains an \"importMap\" field. ",
"Inline the import map into the Deno configuration file.\n",
" at {}",
),
cmd_name,
specifier
);
}
}
let config_file_path = config_specifier.to_file_path().unwrap();
let http_client = cli_factory.http_client_provider();
@ -279,39 +502,7 @@ pub async fn add(
}
}
let config_file_contents = {
let contents = tokio::fs::read_to_string(&config_file_path).await.unwrap();
if contents.trim().is_empty() {
"{}\n".into()
} else {
contents
}
};
let ast = jsonc_parser::parse_to_ast(
&config_file_contents,
&Default::default(),
&Default::default(),
)?;
let obj = match ast.value {
Some(Value::Object(obj)) => obj,
_ => bail!("Failed updating config file due to no object."),
};
if obj.get_string("importMap").is_some() {
bail!(
concat!(
"`deno add` is not supported when configuration file contains an \"importMap\" field. ",
"Inline the import map into the Deno configuration file.\n",
" at {}",
),
config_specifier
);
}
let mut existing_imports = config_file.existing_imports()?;
let is_npm = config_file.is_npm();
let dev = add_flags.dev;
for selected_package in selected_packages {
log::info!(
"Add {}{}{}",
@ -320,39 +511,32 @@ pub async fn add(
selected_package.selected_version
);
if is_npm {
let (name, version) = package_json_dependency_entry(selected_package);
existing_imports.insert(name, version)
if selected_package.package_name.starts_with("npm:") {
if let Some(npm) = &mut npm_config {
npm.add(selected_package, dev);
} else {
deno_config.as_mut().unwrap().add(selected_package, dev);
}
} else if let Some(deno) = &mut deno_config {
deno.add(selected_package, dev);
} else {
existing_imports.insert(
selected_package.import_name,
format!(
"{}@{}",
selected_package.package_name, selected_package.version_req
),
)
};
npm_config.as_mut().unwrap().add(selected_package, dev);
}
}
let mut import_list: Vec<(String, String)> =
existing_imports.into_iter().collect();
import_list.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
let generated_imports = generate_imports(import_list);
let mut commit_futures = vec![];
if let Some(npm) = npm_config {
commit_futures.push(npm.commit());
}
if let Some(deno) = deno_config {
commit_futures.push(deno.commit());
}
let commit_futures =
deno_core::futures::future::join_all(commit_futures).await;
let fmt_config_options = config_file.fmt_options();
let new_text = update_config_file_content(
obj,
&config_file_contents,
generated_imports,
fmt_config_options,
config_file.imports_key(),
config_file.file_name(),
);
tokio::fs::write(&config_file_path, new_text)
.await
.context("Failed to update configuration file")?;
for result in commit_futures {
result.context("Failed to update configuration file")?;
}
// clear the previously cached package.json from memory before reloading it
node_resolver::PackageJsonThreadLocalCache::clear();
@ -524,7 +708,8 @@ impl AddPackageReq {
}
}
fn generate_imports(packages_to_version: Vec<(String, String)>) -> String {
fn generate_imports(mut packages_to_version: Vec<(String, String)>) -> String {
packages_to_version.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
let mut contents = vec![];
let len = packages_to_version.len();
for (index, (package, version)) in packages_to_version.iter().enumerate() {
@ -537,68 +722,27 @@ fn generate_imports(packages_to_version: Vec<(String, String)>) -> String {
contents.join("\n")
}
fn remove_from_config(
config_path: &Path,
keys: &[&'static str],
packages_to_remove: &[String],
removed_packages: &mut Vec<String>,
fmt_options: &FmtOptionsConfig,
) -> Result<(), AnyError> {
let mut json: serde_json::Value =
serde_json::from_slice(&std::fs::read(config_path)?)?;
for key in keys {
let Some(obj) = json.get_mut(*key).and_then(|v| v.as_object_mut()) else {
continue;
};
for package in packages_to_remove {
if obj.shift_remove(package).is_some() {
removed_packages.push(package.clone());
}
}
}
let config = serde_json::to_string_pretty(&json)?;
let config =
crate::tools::fmt::format_json(config_path, &config, fmt_options)
.ok()
.flatten()
.unwrap_or(config);
std::fs::write(config_path, config)
.context("Failed to update configuration file")?;
Ok(())
}
pub async fn remove(
flags: Arc<Flags>,
remove_flags: RemoveFlags,
) -> Result<(), AnyError> {
let (config_file, factory) = DenoOrPackageJson::from_flags(flags.clone())?;
let options = factory.cli_options()?;
let start_dir = &options.start_dir;
let fmt_config_options = config_file.fmt_options();
let (_, npm_config, deno_config) = load_configs(&flags)?;
let mut removed_packages = Vec::new();
let mut configs = [
ConfigUpdater::maybe_new(npm_config).await?,
ConfigUpdater::maybe_new(deno_config).await?,
];
if let Some(deno_json) = start_dir.maybe_deno_json() {
remove_from_config(
&deno_json.specifier.to_file_path().unwrap(),
&["imports"],
&remove_flags.packages,
&mut removed_packages,
&fmt_config_options,
)?;
}
let mut removed_packages = vec![];
if let Some(pkg_json) = start_dir.maybe_pkg_json() {
remove_from_config(
&pkg_json.path,
&["dependencies", "devDependencies"],
&remove_flags.packages,
&mut removed_packages,
&fmt_config_options,
)?;
for package in &remove_flags.packages {
let mut removed = false;
for config in configs.iter_mut().flatten() {
removed |= config.remove(package);
}
if removed {
removed_packages.push(package.clone());
}
}
if removed_packages.is_empty() {
@ -607,6 +751,10 @@ pub async fn remove(
for package in &removed_packages {
log::info!("Removed {}", crate::colors::green(package));
}
for config in configs.into_iter().flatten() {
config.commit().await?;
}
// Update deno.lock
node_resolver::PackageJsonThreadLocalCache::clear();
let cli_factory = CliFactory::from_flags(flags);
@ -616,41 +764,72 @@ pub async fn remove(
Ok(())
}
fn update_config_file_content(
obj: jsonc_parser::ast::Object,
fn update_config_file_content<
I: IntoIterator<Item = (&'static str, Option<String>)>,
>(
obj: &jsonc_parser::ast::Object,
config_file_contents: &str,
generated_imports: String,
fmt_options: FmtOptionsConfig,
imports_key: &str,
entries: I,
file_name: &str,
) -> String {
let mut text_changes = vec![];
for (key, value) in entries {
match obj.properties.iter().enumerate().find_map(|(idx, k)| {
if k.name.as_str() == key {
Some((idx, k))
} else {
None
}
}) {
Some((
idx,
ObjectProp {
value: Value::Object(lit),
range,
..
},
)) => {
if let Some(value) = value {
text_changes.push(TextChange {
range: (lit.range.start + 1)..(lit.range.end - 1),
new_text: value,
})
} else {
text_changes.push(TextChange {
// remove field entirely, making sure to
// remove the comma if it's not the last field
range: range.start..(if idx == obj.properties.len() - 1 {
range.end
} else {
obj.properties[idx + 1].range.start
}),
new_text: "".to_string(),
})
}
}
match obj.get(imports_key) {
Some(ObjectProp {
value: Value::Object(lit),
..
}) => text_changes.push(TextChange {
range: (lit.range.start + 1)..(lit.range.end - 1),
new_text: generated_imports,
}),
None => {
let insert_position = obj.range.end - 1;
text_changes.push(TextChange {
range: insert_position..insert_position,
// NOTE(bartlomieju): adding `\n` here to force the formatter to always
// produce a config file that is multiline, like so:
// ```
// {
// "imports": {
// "<package_name>": "<registry>:<package_name>@<semver>"
// }
// }
new_text: format!("\"{imports_key}\": {{\n {generated_imports} }}"),
})
// need to add field
None => {
if let Some(value) = value {
let insert_position = obj.range.end - 1;
text_changes.push(TextChange {
range: insert_position..insert_position,
// NOTE(bartlomieju): adding `\n` here to force the formatter to always
// produce a config file that is multiline, like so:
// ```
// {
// "imports": {
// "<package_name>": "<registry>:<package_name>@<semver>"
// }
// }
new_text: format!("\"{key}\": {{\n {value} }}"),
})
}
}
// we verified the shape of `imports`/`dependencies` above
Some(_) => unreachable!(),
}
// we verified the shape of `imports`/`dependencies` above
Some(_) => unreachable!(),
}
let new_text =

View file

@ -318,10 +318,10 @@ pub const OP_DETAILS: phf::Map<&'static str, [&'static str; 2]> = phf_map! {
"op_fs_chown_async" => ["change the owner of a file", "awaiting the result of a `Deno.chown` call"],
"op_fs_copy_file_async" => ["copy a file", "awaiting the result of a `Deno.copyFile` call"],
"op_fs_events_poll" => ["get the next file system event", "breaking out of a for await loop looping over `Deno.FsEvents`"],
"op_fs_fdatasync_async" => ["flush pending data operations for a file to disk", "awaiting the result of a `Deno.fdatasync` or `Deno.FsFile.syncData` call"],
"op_fs_file_sync_data_async" => ["flush pending data operations for a file to disk", "awaiting the result of a `Deno.FsFile.prototype.syncData` call"],
"op_fs_file_stat_async" => ["get file metadata", "awaiting the result of a `Deno.FsFile.prototype.stat` call"],
"op_fs_flock_async" => ["lock a file", "awaiting the result of a `Deno.FsFile.lock` call"],
"op_fs_fsync_async" => ["flush pending data operations for a file to disk", "awaiting the result of a `Deno.fsync` or `Deno.FsFile.sync` call"],
"op_fs_file_sync_async" => ["flush pending data operations for a file to disk", "awaiting the result of a `Deno.FsFile.sync` call"],
"op_fs_file_truncate_async" => ["truncate a file", "awaiting the result of a `Deno.FsFile.prototype.truncate` call"],
"op_fs_funlock_async" => ["unlock a file", "awaiting the result of a `Deno.FsFile.unlock` call"],
"op_fs_link_async" => ["create a hard link", "awaiting the result of a `Deno.link` call"],

View file

@ -4,6 +4,7 @@
use crate::args::Flags;
use crate::args::UpgradeFlags;
use crate::args::UPGRADE_USAGE;
use crate::colors;
use crate::factory::CliFactory;
use crate::http_util::HttpClient;
@ -15,7 +16,6 @@ use crate::util::progress_bar::ProgressBarStyle;
use crate::version;
use async_trait::async_trait;
use color_print::cstr;
use deno_core::anyhow::bail;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
@ -38,8 +38,6 @@ const RELEASE_URL: &str = "https://github.com/denoland/deno/releases";
const CANARY_URL: &str = "https://dl.deno.land/canary";
const RC_URL: &str = "https://dl.deno.land/release";
static EXAMPLE_USAGE: &str = cstr!("Example usage:\n <p(245)>deno upgrade | deno upgrade 1.46 | deno upgrade canary</>");
pub static ARCHIVE_NAME: Lazy<String> =
Lazy::new(|| format!("deno-{}.zip", env!("TARGET")));
@ -625,6 +623,7 @@ impl RequestedVersion {
};
let mut maybe_passed_version = upgrade_flags.version.clone();
// TODO(bartlomieju): prefer flags first? This whole logic could be cleaned up...
if let Some(val) = &upgrade_flags.version_or_hash_or_channel {
if let Ok(channel) = ReleaseChannel::deserialize(&val.to_lowercase()) {
// TODO(bartlomieju): print error if any other flags passed?
@ -651,18 +650,19 @@ impl RequestedVersion {
let (channel, passed_version) = if is_canary {
if !re_hash.is_match(&passed_version) {
bail!(
"Invalid commit hash passed ({})\n\n{}",
"Invalid commit hash passed ({})\n\nPass a semver, or a full 40 character git commit hash, or a release channel name.\n\nUsage:\n{}",
colors::gray(passed_version),
EXAMPLE_USAGE
UPGRADE_USAGE
);
}
(ReleaseChannel::Canary, passed_version)
} else {
let Ok(semver) = Version::parse_standard(&passed_version) else {
bail!(
"Invalid version passed ({})\n\n{}",
"Invalid version passed ({})\n\nPass a semver, or a full 40 character git commit hash, or a release channel name.\n\nUsage:\n{}",
colors::gray(passed_version),
EXAMPLE_USAGE
UPGRADE_USAGE
);
};
@ -1123,6 +1123,8 @@ mod test {
use std::cell::RefCell;
use std::rc::Rc;
use test_util::assert_contains;
use super::*;
#[test]
@ -1221,6 +1223,27 @@ mod test {
"5c69b4861b52ab406e73b9cd85c254f0505cb20f".to_string()
)
);
upgrade_flags.version_or_hash_or_channel =
Some("5c69b4861b52a".to_string());
let err = RequestedVersion::from_upgrade_flags(upgrade_flags.clone())
.unwrap_err()
.to_string();
assert_contains!(err, "Invalid version passed");
assert_contains!(
err,
"Pass a semver, or a full 40 character git commit hash, or a release channel name."
);
upgrade_flags.version_or_hash_or_channel = Some("11.asd.1324".to_string());
let err = RequestedVersion::from_upgrade_flags(upgrade_flags.clone())
.unwrap_err()
.to_string();
assert_contains!(err, "Invalid version passed");
assert_contains!(
err,
"Pass a semver, or a full 40 character git commit hash, or a release channel name."
);
}
#[test]

View file

@ -1152,7 +1152,6 @@ delete Object.prototype.__proto__;
"strict": true,
"target": "esnext",
"useDefineForClassFields": true,
"useUnknownInCatchVariables": false,
"jsx": "react",
"jsxFactory": "React.createElement",
"jsxFragmentFactory": "React.Fragment",

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -112,7 +112,6 @@ pub struct CliMainWorkerOptions {
pub origin_data_folder_path: Option<PathBuf>,
pub seed: Option<u64>,
pub unsafely_ignore_certificate_errors: Option<Vec<String>>,
pub unstable: bool,
pub skip_op_registration: bool,
pub create_hmr_runner: Option<CreateHmrRunnerCb>,
pub create_coverage_collector: Option<CreateCoverageCollectorCb>,
@ -580,7 +579,6 @@ impl CliMainWorkerFactory {
is_stdout_tty: deno_terminal::is_stdout_tty(),
is_stderr_tty: deno_terminal::is_stderr_tty(),
color_level: colors::get_color_level(),
unstable: shared.options.unstable,
unstable_features,
user_agent: version::DENO_VERSION_INFO.user_agent.to_string(),
inspect: shared.options.is_inspecting,
@ -775,7 +773,6 @@ fn create_web_worker_callback(
color_level: colors::get_color_level(),
is_stdout_tty: deno_terminal::is_stdout_tty(),
is_stderr_tty: deno_terminal::is_stderr_tty(),
unstable: shared.options.unstable,
unstable_features,
user_agent: version::DENO_VERSION_INFO.user_agent.to_string(),
inspect: shared.options.is_inspecting,

View file

@ -260,6 +260,7 @@ const colors = {
function defineColorAlias(target, alias) {
ObjectDefineProperty(colors, alias, {
__proto__: null,
get() {
return this[target];
},
@ -843,14 +844,6 @@ function formatRaw(ctx, value, recurseTimes, typedArray, proxyDetails) {
ObjectPrototypeIsPrototypeOf(
globalThis.Temporal.Duration.prototype,
value,
) ||
ObjectPrototypeIsPrototypeOf(
globalThis.Temporal.TimeZone.prototype,
value,
) ||
ObjectPrototypeIsPrototypeOf(
globalThis.Temporal.Calendar.prototype,
value,
)
)
) {
@ -3447,7 +3440,10 @@ function inspect(
function createFilteredInspectProxy({ object, keys, evaluate }) {
const obj = class {};
if (object.constructor?.name) {
ObjectDefineProperty(obj, "name", { value: object.constructor.name });
ObjectDefineProperty(obj, "name", {
__proto__: null,
value: object.constructor.name,
});
}
return new Proxy(new obj(), {

View file

@ -263,6 +263,7 @@ function mixinBody(prototype, bodySymbol, mimeTypeSymbol) {
/** @type {PropertyDescriptorMap} */
const mixin = {
body: {
__proto__: null,
/**
* @returns {ReadableStream<Uint8Array> | null}
*/
@ -278,6 +279,7 @@ function mixinBody(prototype, bodySymbol, mimeTypeSymbol) {
enumerable: true,
},
bodyUsed: {
__proto__: null,
/**
* @returns {boolean}
*/
@ -292,6 +294,7 @@ function mixinBody(prototype, bodySymbol, mimeTypeSymbol) {
enumerable: true,
},
arrayBuffer: {
__proto__: null,
/** @returns {Promise<ArrayBuffer>} */
value: function arrayBuffer() {
return consumeBody(this, "ArrayBuffer");
@ -301,6 +304,7 @@ function mixinBody(prototype, bodySymbol, mimeTypeSymbol) {
enumerable: true,
},
blob: {
__proto__: null,
/** @returns {Promise<Blob>} */
value: function blob() {
return consumeBody(this, "Blob");
@ -310,6 +314,7 @@ function mixinBody(prototype, bodySymbol, mimeTypeSymbol) {
enumerable: true,
},
bytes: {
__proto__: null,
/** @returns {Promise<Uint8Array>} */
value: function bytes() {
return consumeBody(this, "bytes");
@ -319,6 +324,7 @@ function mixinBody(prototype, bodySymbol, mimeTypeSymbol) {
enumerable: true,
},
formData: {
__proto__: null,
/** @returns {Promise<FormData>} */
value: function formData() {
return consumeBody(this, "FormData");
@ -328,6 +334,7 @@ function mixinBody(prototype, bodySymbol, mimeTypeSymbol) {
enumerable: true,
},
json: {
__proto__: null,
/** @returns {Promise<any>} */
value: function json() {
return consumeBody(this, "JSON");
@ -337,6 +344,7 @@ function mixinBody(prototype, bodySymbol, mimeTypeSymbol) {
enumerable: true,
},
text: {
__proto__: null,
/** @returns {Promise<string>} */
value: function text() {
return consumeBody(this, "text");

View file

@ -42,6 +42,7 @@ class HttpClient {
*/
constructor(rid) {
ObjectDefineProperty(this, internalRidSymbol, {
__proto__: null,
enumerable: false,
value: rid,
});

View file

@ -432,9 +432,9 @@ class Response {
webidl.configureInterface(Response);
ObjectDefineProperties(Response, {
json: { enumerable: true },
redirect: { enumerable: true },
error: { enumerable: true },
json: { __proto__: null, enumerable: true },
redirect: { __proto__: null, enumerable: true },
error: { __proto__: null, enumerable: true },
});
const ResponsePrototype = Response.prototype;
mixinBody(ResponsePrototype, _body, _mimeType);

View file

@ -355,12 +355,15 @@ const EventSourcePrototype = EventSource.prototype;
ObjectDefineProperties(EventSource, {
CONNECTING: {
__proto__: null,
value: 0,
},
OPEN: {
__proto__: null,
value: 1,
},
CLOSED: {
__proto__: null,
value: 2,
},
});

View file

@ -484,10 +484,11 @@ class DynamicLibrary {
this.symbols,
symbol,
{
__proto__: null,
configurable: false,
enumerable: true,
value,
writable: false,
value,
},
);
continue;
@ -504,8 +505,10 @@ class DynamicLibrary {
this.symbols,
symbol,
{
__proto__: null,
configurable: false,
enumerable: true,
writable: false,
value: (...parameters) => {
if (isStructResult) {
const buffer = new Uint8Array(structSize);
@ -527,7 +530,6 @@ class DynamicLibrary {
);
}
},
writable: false,
},
);
}

View file

@ -1,6 +1,6 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { core, internals, primordials } from "ext:core/mod.js";
import { core, primordials } from "ext:core/mod.js";
const {
isDate,
internalRidSymbol,
@ -15,15 +15,15 @@ import {
op_fs_copy_file_async,
op_fs_copy_file_sync,
op_fs_cwd,
op_fs_fdatasync_async,
op_fs_fdatasync_sync,
op_fs_file_stat_async,
op_fs_file_stat_sync,
op_fs_file_sync_async,
op_fs_file_sync_data_async,
op_fs_file_sync_data_sync,
op_fs_file_sync_sync,
op_fs_file_truncate_async,
op_fs_flock_async,
op_fs_flock_sync,
op_fs_fsync_async,
op_fs_fsync_sync,
op_fs_ftruncate_sync,
op_fs_funlock_async,
op_fs_funlock_sync,
@ -517,22 +517,6 @@ async function symlink(
);
}
function fdatasyncSync(rid) {
op_fs_fdatasync_sync(rid);
}
async function fdatasync(rid) {
await op_fs_fdatasync_async(rid);
}
function fsyncSync(rid) {
op_fs_fsync_sync(rid);
}
async function fsync(rid) {
await op_fs_fsync_async(rid);
}
function openSync(
path,
options,
@ -585,33 +569,18 @@ class FsFile {
constructor(rid, symbol) {
ObjectDefineProperty(this, internalRidSymbol, {
__proto__: null,
enumerable: false,
value: rid,
});
this.#rid = rid;
if (!symbol || symbol !== SymbolFor("Deno.internal.FsFile")) {
internals.warnOnDeprecatedApi(
"new Deno.FsFile()",
new Error().stack,
"Use `Deno.open` or `Deno.openSync` instead.",
throw new TypeError(
"`Deno.FsFile` cannot be constructed, use `Deno.open()` or `Deno.openSync()` instead.",
);
if (internals.future) {
throw new TypeError(
"`Deno.FsFile` cannot be constructed, use `Deno.open()` or `Deno.openSync()` instead.",
);
}
}
}
get rid() {
internals.warnOnDeprecatedApi(
"Deno.FsFile.rid",
new Error().stack,
"Use `Deno.FsFile` methods directly instead.",
);
return this.#rid;
}
write(p) {
return write(this.#rid, p);
}
@ -654,11 +623,11 @@ class FsFile {
}
async syncData() {
await op_fs_fdatasync_async(this.#rid);
await op_fs_file_sync_data_async(this.#rid);
}
syncDataSync() {
op_fs_fdatasync_sync(this.#rid);
op_fs_file_sync_data_sync(this.#rid);
}
close() {
@ -680,11 +649,11 @@ class FsFile {
}
async sync() {
await op_fs_fsync_async(this.#rid);
await op_fs_file_sync_async(this.#rid);
}
syncSync() {
op_fs_fsync_sync(this.#rid);
op_fs_file_sync_sync(this.#rid);
}
async utime(atime, mtime) {
@ -920,11 +889,7 @@ export {
create,
createSync,
cwd,
fdatasync,
fdatasyncSync,
FsFile,
fsync,
fsyncSync,
link,
linkSync,
lstat,

View file

@ -91,7 +91,7 @@ impl FsPermissions for deno_permissions::PermissionsContainer {
if resolved {
self
.check_special_file(path, api_name)
.map_err(FsError::PermissionDenied)?;
.map_err(FsError::NotCapable)?;
return Ok(Cow::Borrowed(path));
}
@ -99,11 +99,11 @@ impl FsPermissions for deno_permissions::PermissionsContainer {
let read = read || !write;
if read {
FsPermissions::check_read(self, path, api_name)
.map_err(|_| FsError::PermissionDenied("read"))?;
.map_err(|_| FsError::NotCapable("read"))?;
}
if write {
FsPermissions::check_write(self, path, api_name)
.map_err(|_| FsError::PermissionDenied("write"))?;
.map_err(|_| FsError::NotCapable("write"))?;
}
Ok(Cow::Borrowed(path))
}
@ -229,10 +229,10 @@ deno_core::extension!(deno_fs,
op_fs_seek_sync,
op_fs_seek_async,
op_fs_fdatasync_sync,
op_fs_fdatasync_async,
op_fs_fsync_sync,
op_fs_fsync_async,
op_fs_file_sync_data_sync,
op_fs_file_sync_data_async,
op_fs_file_sync_sync,
op_fs_file_sync_async,
op_fs_file_stat_sync,
op_fs_file_stat_async,
op_fs_flock_async,

View file

@ -60,7 +60,7 @@ fn map_permission_error(
path: &Path,
) -> AnyError {
match error {
FsError::PermissionDenied(err) => {
FsError::NotCapable(err) => {
let path = format!("{path:?}");
let (path, truncated) = if path.len() > 1024 {
(&path[0..1024], "...(truncated)")
@ -74,7 +74,7 @@ fn map_permission_error(
format!(
"Requires {err} access to {path}{truncated}, run again with the --allow-{err} flag")
};
custom_error("PermissionDenied", msg)
custom_error("NotCapable", msg)
}
err => Err::<(), _>(err)
.context_path(operation, path)
@ -1430,7 +1430,7 @@ pub async fn op_fs_seek_async(
}
#[op2(fast)]
pub fn op_fs_fdatasync_sync(
pub fn op_fs_file_sync_data_sync(
state: &mut OpState,
#[smi] rid: ResourceId,
) -> Result<(), AnyError> {
@ -1440,7 +1440,7 @@ pub fn op_fs_fdatasync_sync(
}
#[op2(async)]
pub async fn op_fs_fdatasync_async(
pub async fn op_fs_file_sync_data_async(
state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId,
) -> Result<(), AnyError> {
@ -1450,7 +1450,7 @@ pub async fn op_fs_fdatasync_async(
}
#[op2(fast)]
pub fn op_fs_fsync_sync(
pub fn op_fs_file_sync_sync(
state: &mut OpState,
#[smi] rid: ResourceId,
) -> Result<(), AnyError> {
@ -1460,7 +1460,7 @@ pub fn op_fs_fsync_sync(
}
#[op2(async)]
pub async fn op_fs_fsync_async(
pub async fn op_fs_file_sync_async(
state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId,
) -> Result<(), AnyError> {

View file

@ -1069,8 +1069,10 @@ fn open_with_access_check(
};
(*access_check)(false, &path, &options)?;
// On Linux, /proc may contain magic links that we don't want to resolve
let needs_canonicalization = !is_windows_device_path
&& (!cfg!(target_os = "linux") || path.starts_with("/proc"));
let is_linux_special_path = cfg!(target_os = "linux")
&& (path.starts_with("/proc") || path.starts_with("/dev"));
let needs_canonicalization =
!is_windows_device_path && !is_linux_special_path;
let path = if needs_canonicalization {
match path.canonicalize() {
Ok(path) => path,

View file

@ -583,7 +583,7 @@ type RawServeOptions = {
const kLoadBalanced = Symbol("kLoadBalanced");
function mapAnyAddrToLocalhostForWindows(hostname: string) {
function formatHostName(hostname: string): string {
// If the hostname is "0.0.0.0", we display "localhost" in console
// because browsers in Windows don't resolve "0.0.0.0".
// See the discussion in https://github.com/denoland/deno_std/issues/1165
@ -593,7 +593,9 @@ function mapAnyAddrToLocalhostForWindows(hostname: string) {
) {
return "localhost";
}
return hostname;
// Add brackets around ipv6 hostname
return StringPrototypeIncludes(hostname, ":") ? `[${hostname}]` : hostname;
}
function serve(arg1, arg2) {
@ -690,10 +692,8 @@ function serve(arg1, arg2) {
if (options.onListen) {
options.onListen(addr);
} else {
const hostname = mapAnyAddrToLocalhostForWindows(addr.hostname);
const host = StringPrototypeIncludes(hostname, ":")
? `[${hostname}]`
: hostname;
const host = formatHostName(addr.hostname);
// deno-lint-ignore no-console
console.log(`Listening on ${scheme}${host}:${addr.port}/`);
}
@ -868,10 +868,11 @@ function registerDeclarativeServer(exports) {
const nThreads = serveWorkerCount > 1
? ` with ${serveWorkerCount} threads`
: "";
const hostname_ = mapAnyAddrToLocalhostForWindows(hostname);
const host = formatHostName(hostname);
// deno-lint-ignore no-console
console.debug(
`%cdeno serve%c: Listening on %chttp://${hostname_}:${port}/%c${nThreads}`,
`%cdeno serve%c: Listening on %chttp://${host}:${port}/%c${nThreads}`,
"color: green",
"color: inherit",
"color: yellow",

View file

@ -4,7 +4,7 @@
// Documentation liberally lifted from them too.
// Thank you! We love Go! <3
import { core, internals, primordials } from "ext:core/mod.js";
import { core, primordials } from "ext:core/mod.js";
import { op_set_raw } from "ext:core/ops";
const {
Uint8Array,
@ -121,11 +121,6 @@ class Stdin {
}
get rid() {
internals.warnOnDeprecatedApi(
"Deno.stdin.rid",
new Error().stack,
"Use `Deno.stdin` instance methods instead.",
);
return this.#rid;
}
@ -186,11 +181,6 @@ class Stdout {
}
get rid() {
internals.warnOnDeprecatedApi(
"Deno.stdout.rid",
new Error().stack,
"Use `Deno.stdout` instance methods instead.",
);
return this.#rid;
}
@ -226,11 +216,6 @@ class Stderr {
}
get rid() {
internals.warnOnDeprecatedApi(
"Deno.stderr.rid",
new Error().stack,
"Use `Deno.stderr` instance methods instead.",
);
return this.#rid;
}

View file

@ -22,7 +22,7 @@ pub enum FsError {
Io(io::Error),
FileBusy,
NotSupported,
PermissionDenied(&'static str),
NotCapable(&'static str),
}
impl FsError {
@ -31,7 +31,7 @@ impl FsError {
Self::Io(err) => err.kind(),
Self::FileBusy => io::ErrorKind::Other,
Self::NotSupported => io::ErrorKind::Other,
Self::PermissionDenied(_) => io::ErrorKind::PermissionDenied,
Self::NotCapable(_) => io::ErrorKind::Other,
}
}
@ -40,7 +40,7 @@ impl FsError {
FsError::Io(err) => err,
FsError::FileBusy => io::Error::new(self.kind(), "file busy"),
FsError::NotSupported => io::Error::new(self.kind(), "not supported"),
FsError::PermissionDenied(err) => {
FsError::NotCapable(err) => {
io::Error::new(self.kind(), format!("requires {err} access"))
}
}
@ -65,8 +65,8 @@ impl From<FsError> for AnyError {
FsError::Io(err) => AnyError::from(err),
FsError::FileBusy => resource_unavailable(),
FsError::NotSupported => not_supported(),
FsError::PermissionDenied(err) => {
custom_error("PermissionDenied", format!("permission denied: {err}"))
FsError::NotCapable(err) => {
custom_error("NotCapable", format!("permission denied: {err}"))
}
}
}

View file

@ -1,6 +1,6 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { core, internals, primordials } from "ext:core/mod.js";
import { core, primordials } from "ext:core/mod.js";
const {
BadResourcePrototype,
InterruptedPrototype,
@ -101,13 +101,8 @@ class Conn {
#writable;
constructor(rid, remoteAddr, localAddr) {
if (internals.future) {
ObjectDefineProperty(this, "rid", {
enumerable: false,
value: undefined,
});
}
ObjectDefineProperty(this, internalRidSymbol, {
__proto__: null,
enumerable: false,
value: rid,
});
@ -116,15 +111,6 @@ class Conn {
this.#localAddr = localAddr;
}
get rid() {
internals.warnOnDeprecatedApi(
"Deno.Conn.rid",
new Error().stack,
"Use `Deno.Conn` instance methods instead.",
);
return this.#rid;
}
get remoteAddr() {
return this.#remoteAddr;
}
@ -214,21 +200,13 @@ class TcpConn extends Conn {
constructor(rid, remoteAddr, localAddr) {
super(rid, remoteAddr, localAddr);
ObjectDefineProperty(this, internalRidSymbol, {
__proto__: null,
enumerable: false,
value: rid,
});
this.#rid = rid;
}
get rid() {
internals.warnOnDeprecatedApi(
"Deno.TcpConn.rid",
new Error().stack,
"Use `Deno.TcpConn` instance methods instead.",
);
return this.#rid;
}
setNoDelay(noDelay = true) {
return op_set_nodelay(this.#rid, noDelay);
}
@ -244,20 +222,12 @@ class UnixConn extends Conn {
constructor(rid, remoteAddr, localAddr) {
super(rid, remoteAddr, localAddr);
ObjectDefineProperty(this, internalRidSymbol, {
__proto__: null,
enumerable: false,
value: rid,
});
this.#rid = rid;
}
get rid() {
internals.warnOnDeprecatedApi(
"Deno.UnixConn.rid",
new Error().stack,
"Use `Deno.UnixConn` instance methods instead.",
);
return this.#rid;
}
}
class Listener {
@ -267,13 +237,8 @@ class Listener {
#promise = null;
constructor(rid, addr) {
if (internals.future) {
ObjectDefineProperty(this, "rid", {
enumerable: false,
value: undefined,
});
}
ObjectDefineProperty(this, internalRidSymbol, {
__proto__: null,
enumerable: false,
value: rid,
});
@ -281,15 +246,6 @@ class Listener {
this.#addr = addr;
}
get rid() {
internals.warnOnDeprecatedApi(
"Deno.Listener.rid",
new Error().stack,
"Use `Deno.Listener` instance methods instead.",
);
return this.#rid;
}
get addr() {
return this.#addr;
}

View file

@ -13,7 +13,6 @@ import {
op_tls_handshake,
op_tls_key_null,
op_tls_key_static,
op_tls_key_static_from_file,
op_tls_start,
} from "ext:core/ops";
const {
@ -30,21 +29,13 @@ class TlsConn extends Conn {
constructor(rid, remoteAddr, localAddr) {
super(rid, remoteAddr, localAddr);
ObjectDefineProperty(this, internalRidSymbol, {
__proto__: null,
enumerable: false,
value: rid,
});
this.#rid = rid;
}
get rid() {
internals.warnOnDeprecatedApi(
"Deno.TlsConn.rid",
new Error().stack,
"Use `Deno.TlsConn` instance methods instead.",
);
return this.#rid;
}
handshake() {
return op_tls_handshake(this.#rid);
}
@ -58,45 +49,23 @@ async function connectTls({
alpnProtocols = undefined,
keyFormat = undefined,
cert = undefined,
certFile = undefined,
certChain = undefined,
key = undefined,
keyFile = undefined,
privateKey = undefined,
}) {
if (transport !== "tcp") {
throw new TypeError(`Unsupported transport: '${transport}'`);
}
let deprecatedCertFile = undefined;
// Deno.connectTls has an irregular option where you can just pass `certFile` and
// not `keyFile`. In this case it's used for `caCerts` rather than the client key.
if (certFile !== undefined && keyFile === undefined) {
internals.warnOnDeprecatedApi(
"Deno.ConnectTlsOptions.certFile",
new Error().stack,
"Pass the cert file's contents to the `Deno.ConnectTlsOptions.caCerts` option instead.",
);
deprecatedCertFile = certFile;
certFile = undefined;
}
const keyPair = loadTlsKeyPair("Deno.connectTls", {
keyFormat,
cert,
certFile,
certChain,
key,
keyFile,
privateKey,
});
// TODO(mmastrac): We only expose this feature via symbol for now. This should actually be a feature
// in Deno.connectTls, however.
const serverName = arguments[0][serverNameSymbol] ?? null;
const { 0: rid, 1: localAddr, 2: remoteAddr } = await op_net_connect_tls(
{ hostname, port },
{ certFile: deprecatedCertFile, caCerts, alpnProtocols, serverName },
{ caCerts, alpnProtocols, serverName },
keyPair,
);
localAddr.transport = "tcp";
@ -110,21 +79,13 @@ class TlsListener extends Listener {
constructor(rid, addr) {
super(rid, addr);
ObjectDefineProperty(this, internalRidSymbol, {
__proto__: null,
enumerable: false,
value: rid,
});
this.#rid = rid;
}
get rid() {
internals.warnOnDeprecatedApi(
"Deno.TlsListener.rid",
new Error().stack,
"Use `Deno.TlsListener` instance methods instead.",
);
return this.#rid;
}
async accept() {
const { 0: rid, 1: localAddr, 2: remoteAddr } = await op_net_accept_tls(
this.#rid,
@ -144,10 +105,7 @@ function hasTlsKeyPairOptions(options) {
if (options[resolverSymbol] !== undefined) {
return true;
}
return (options.cert !== undefined || options.key !== undefined ||
options.certFile !== undefined ||
options.keyFile !== undefined || options.privateKey !== undefined ||
options.certChain !== undefined);
return (options.cert !== undefined || options.key !== undefined);
}
/**
@ -157,19 +115,8 @@ function hasTlsKeyPairOptions(options) {
function loadTlsKeyPair(api, {
keyFormat,
cert,
certFile,
certChain,
key,
keyFile,
privateKey,
}) {
if (internals.future) {
certFile = undefined;
certChain = undefined;
keyFile = undefined;
privateKey = undefined;
}
// TODO(mmastrac): remove this temporary symbol when the API lands
if (arguments[1][resolverSymbol] !== undefined) {
return createTlsKeyResolver(arguments[1][resolverSymbol]);
@ -180,68 +127,18 @@ function loadTlsKeyPair(api, {
throw new TypeError('If `keyFormat` is specified, it must be "pem"');
}
function exclusive(a1, a1v, a2, a2v) {
if (a1v !== undefined && a2v !== undefined) {
throw new TypeError(
`Cannot specify both \`${a1}\` and \`${a2}\` for \`${api}\`.`,
);
}
if (cert !== undefined && key === undefined) {
throw new TypeError(
`If \`cert\` is specified, \`key\` must be specified as well for \`${api}\`.`,
);
}
if (cert === undefined && key !== undefined) {
throw new TypeError(
`If \`key\` is specified, \`cert\` must be specified as well for \`${api}\`.`,
);
}
// Ensure that only one pair is valid
exclusive("certChain", certChain, "cert", cert);
exclusive("certChain", certChain, "certFile", certFile);
exclusive("key", key, "keyFile", keyFile);
exclusive("key", key, "privateKey", privateKey);
function both(a1, a1v, a2, a2v) {
if (a1v !== undefined && a2v === undefined) {
throw new TypeError(
`If \`${a1}\` is specified, \`${a2}\` must be specified as well for \`${api}\`.`,
);
}
if (a1v === undefined && a2v !== undefined) {
throw new TypeError(
`If \`${a2}\` is specified, \`${a1}\` must be specified as well for \`${api}\`.`,
);
}
}
// Pick one pair of cert/key, certFile/keyFile or certChain/privateKey
both("cert", cert, "key", key);
both("certFile", certFile, "keyFile", keyFile);
both("certChain", certChain, "privateKey", privateKey);
if (certFile !== undefined) {
internals.warnOnDeprecatedApi(
"Deno.TlsCertifiedKeyOptions.keyFile",
new Error().stack,
"Pass the key file's contents to the `Deno.TlsCertifiedKeyPem.key` option instead.",
);
internals.warnOnDeprecatedApi(
"Deno.TlsCertifiedKeyOptions.certFile",
new Error().stack,
"Pass the cert file's contents to the `Deno.TlsCertifiedKeyPem.cert` option instead.",
);
return op_tls_key_static_from_file(api, certFile, keyFile);
} else if (certChain !== undefined) {
if (api !== "Deno.connectTls") {
throw new TypeError(
`Invalid options 'certChain' and 'privateKey' for ${api}`,
);
}
internals.warnOnDeprecatedApi(
"Deno.TlsCertifiedKeyOptions.privateKey",
new Error().stack,
"Use the `Deno.TlsCertifiedKeyPem.key` option instead.",
);
internals.warnOnDeprecatedApi(
"Deno.TlsCertifiedKeyOptions.certChain",
new Error().stack,
"Use the `Deno.TlsCertifiedKeyPem.cert` option instead.",
);
return op_tls_key_static(certChain, privateKey);
} else if (cert !== undefined) {
if (cert !== undefined) {
return op_tls_key_static(cert, key);
} else {
return op_tls_key_null();

View file

@ -35,15 +35,6 @@ declare namespace Deno {
/** Return the address of the `Listener`. */
readonly addr: A;
/**
* Return the rid of the `Listener`.
*
* @deprecated This will be removed in Deno 2.0. See the
* {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide}
* for migration instructions.
*/
readonly rid: number;
[Symbol.asyncIterator](): AsyncIterableIterator<T>;
/**
@ -77,20 +68,61 @@ declare namespace Deno {
export type UnixListener = Listener<UnixConn, UnixAddr>;
/** @category Network */
export interface Conn<A extends Addr = Addr>
extends Reader, Writer, Closer, Disposable {
export interface Conn<A extends Addr = Addr> extends Disposable {
/** Read the incoming data from the connection into an array buffer (`p`).
*
* Resolves to either the number of bytes read during the operation or EOF
* (`null`) if there was nothing more to read.
*
* It is possible for a read to successfully return with `0` bytes. This
* does not indicate EOF.
*
* **It is not guaranteed that the full buffer will be read in a single
* call.**
*
* ```ts
* // If the text "hello world" is received by the client:
* const conn = await Deno.connect({ hostname: "example.com", port: 80 });
* const buf = new Uint8Array(100);
* const numberOfBytesRead = await conn.read(buf); // 11 bytes
* const text = new TextDecoder().decode(buf); // "hello world"
* ```
*
* @category I/O
*/
read(p: Uint8Array): Promise<number | null>;
/** Write the contents of the array buffer (`p`) to the connection.
*
* Resolves to the number of bytes written.
*
* **It is not guaranteed that the full buffer will be written in a single
* call.**
*
* ```ts
* const conn = await Deno.connect({ hostname: "example.com", port: 80 });
* const encoder = new TextEncoder();
* const data = encoder.encode("Hello world");
* const bytesWritten = await conn.write(data); // 11
* ```
*
* @category I/O
*/
write(p: Uint8Array): Promise<number>;
/** Closes the connection, freeing the resource.
*
* ```ts
* const conn = await Deno.connect({ hostname: "example.com", port: 80 });
*
* // ...
*
* conn.close();
* ```
*/
close(): void;
/** The local address of the connection. */
readonly localAddr: A;
/** The remote address of the connection. */
readonly remoteAddr: A;
/**
* The resource ID of the connection.
*
* @deprecated This will be removed in Deno 2.0. See the
* {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide}
* for migration instructions.
*/
readonly rid: number;
/** Shuts down (`shutdown(2)`) the write side of the connection. Most
* callers should just use `close()`. */
closeWrite(): Promise<void>;
@ -123,14 +155,6 @@ declare namespace Deno {
* not happened yet. Calling this method is optional; the TLS handshake
* will be completed automatically as soon as data is sent or received. */
handshake(): Promise<TlsHandshakeInfo>;
/**
* The resource ID of the connection.
*
* @deprecated This will be removed in Deno 2.0. See the
* {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide}
* for migration instructions.
*/
readonly rid: number;
}
/** @category Network */
@ -199,16 +223,6 @@ declare namespace Deno {
options: UnixListenOptions & { transport: "unix" },
): UnixListener;
/** Provides TLS certified keys, ie: a key that has been certified by a trusted certificate authority.
* A certified key generally consists of a private key and certificate part.
*
* @category Network
*/
export type TlsCertifiedKeyOptions =
| TlsCertifiedKeyPem
| TlsCertifiedKeyFromFile
| TlsCertifiedKeyConnectTls;
/**
* Provides certified key material from strings. The key material is provided in
* `PEM`-format (Privacy Enhanced Mail, https://www.rfc-editor.org/rfc/rfc1422) which can be identified by having
@ -235,59 +249,6 @@ declare namespace Deno {
cert: string;
}
/**
* @deprecated This will be removed in Deno 2.0. See the
* {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide}
* for migration instructions.
*
* @category Network
*/
export interface TlsCertifiedKeyFromFile {
/** Path to a file containing a PEM formatted CA certificate. Requires
* `--allow-read`.
*
* @tags allow-read
* @deprecated This will be removed in Deno 2.0. See the
* {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide}
* for migration instructions.
*/
certFile: string;
/** Path to a file containing a private key file. Requires `--allow-read`.
*
* @tags allow-read
* @deprecated This will be removed in Deno 2.0. See the
* {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide}
* for migration instructions.
*/
keyFile: string;
}
/**
* @deprecated This will be removed in Deno 2.0. See the
* {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide}
* for migration instructions.
*
* @category Network
*/
export interface TlsCertifiedKeyConnectTls {
/**
* Certificate chain in `PEM` format.
*
* @deprecated This will be removed in Deno 2.0. See the
* {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide}
* for migration instructions.
*/
certChain: string;
/**
* Private key in `PEM` format. RSA, EC, and PKCS8-format keys are supported.
*
* @deprecated This will be removed in Deno 2.0. See the
* {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide}
* for migration instructions.
*/
privateKey: string;
}
/** @category Network */
export interface ListenTlsOptions extends TcpListenOptions {
transport?: "tcp";
@ -316,7 +277,7 @@ declare namespace Deno {
* @category Network
*/
export function listenTls(
options: ListenTlsOptions & TlsCertifiedKeyOptions,
options: ListenTlsOptions & TlsCertifiedKeyPem,
): TlsListener;
/** @category Network */
@ -359,14 +320,6 @@ declare namespace Deno {
setNoDelay(noDelay?: boolean): void;
/** Enable/disable keep-alive functionality. */
setKeepAlive(keepAlive?: boolean): void;
/**
* The resource ID of the connection.
*
* @deprecated This will be removed in Deno 2.0. See the
* {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide}
* for migration instructions.
*/
readonly rid: number;
}
/** @category Network */
@ -376,16 +329,7 @@ declare namespace Deno {
}
/** @category Network */
export interface UnixConn extends Conn<UnixAddr> {
/**
* The resource ID of the connection.
*
* @deprecated This will be removed in Deno 2.0. See the
* {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide}
* for migration instructions.
*/
readonly rid: number;
}
export interface UnixConn extends Conn<UnixAddr> {}
/** Connects to the hostname (default is "127.0.0.1") and port on the named
* transport (default is "tcp"), and resolves to the connection (`Conn`).
@ -414,16 +358,6 @@ declare namespace Deno {
*
* @default {"127.0.0.1"} */
hostname?: string;
/** Path to a file containing a PEM formatted list of root certificates that will
* be used in addition to the default root certificates to verify the peer's certificate. Requires
* `--allow-read`.
*
* @tags allow-read
* @deprecated This will be removed in Deno 2.0. See the
* {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide}
* for migration instructions.
*/
certFile?: string;
/** A list of root certificates that will be used in addition to the
* default root certificates to verify the peer's certificate.
*
@ -477,7 +411,7 @@ declare namespace Deno {
* @category Network
*/
export function connectTls(
options: ConnectTlsOptions & TlsCertifiedKeyOptions,
options: ConnectTlsOptions & TlsCertifiedKeyPem,
): Promise<TlsConn>;
/** @category Network */

View file

@ -115,7 +115,6 @@ deno_core::extension!(deno_net,
ops_tls::op_tls_key_null,
ops_tls::op_tls_key_static,
ops_tls::op_tls_key_static_from_file<P>,
ops_tls::op_tls_cert_resolver_create,
ops_tls::op_tls_cert_resolver_poll,
ops_tls::op_tls_cert_resolver_resolve,

View file

@ -34,8 +34,6 @@ use deno_tls::new_resolver;
use deno_tls::rustls::pki_types::ServerName;
use deno_tls::rustls::ClientConnection;
use deno_tls::rustls::ServerConfig;
use deno_tls::webpki::types::CertificateDer;
use deno_tls::webpki::types::PrivateKeyDer;
use deno_tls::ServerConfigProvider;
use deno_tls::SocketUse;
use deno_tls::TlsKey;
@ -213,32 +211,6 @@ pub fn op_tls_key_static(
Ok(TlsKeysHolder::from(TlsKeys::Static(TlsKey(cert, key))))
}
/// Legacy op -- will be removed in Deno 2.0.
#[op2]
#[cppgc]
pub fn op_tls_key_static_from_file<NP>(
state: &mut OpState,
#[string] api: String,
#[string] cert_file: String,
#[string] key_file: String,
) -> Result<TlsKeysHolder, AnyError>
where
NP: NetPermissions + 'static,
{
{
let permissions = state.borrow_mut::<NP>();
permissions.check_read(Path::new(&cert_file), &api)?;
permissions.check_read(Path::new(&key_file), &api)?;
}
let cert = load_certs_from_file(&cert_file)?;
let key = load_private_keys_from_file(&key_file)?
.into_iter()
.next()
.unwrap();
Ok(TlsKeysHolder::from(TlsKeys::Static(TlsKey(cert, key))))
}
#[op2]
pub fn op_tls_cert_resolver_create<'s>(
scope: &mut v8::HandleScope<'s>,
@ -455,21 +427,6 @@ where
Ok((rid, IpAddr::from(local_addr), IpAddr::from(remote_addr)))
}
fn load_certs_from_file(
path: &str,
) -> Result<Vec<CertificateDer<'static>>, AnyError> {
let cert_file = File::open(path)?;
let reader = &mut BufReader::new(cert_file);
load_certs(reader)
}
fn load_private_keys_from_file(
path: &str,
) -> Result<Vec<PrivateKeyDer<'static>>, AnyError> {
let key_bytes = std::fs::read(path)?;
load_private_keys(&key_bytes)
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ListenTlsArgs {

View file

@ -97,7 +97,7 @@ url.workspace = true
winapi.workspace = true
x25519-dalek = { version = "2.0.0", features = ["static_secrets"] }
x509-parser = "0.15.0"
yoke = { version = "0.7.4", features = ["derive"] }
yoke.workspace = true
[target.'cfg(windows)'.dependencies]
windows-sys.workspace = true

View file

@ -29,6 +29,7 @@ if (process.env.CHILD) {
const start = performance.now();
const options = {
__proto__: null,
"stdio": ["inherit", "inherit", "inherit", "ipc"],
"env": { "CHILD": len.toString() },
};

View file

@ -286,6 +286,25 @@ deno_core::extension!(deno_node,
ops::winerror::op_node_sys_to_uv_error,
ops::v8::op_v8_cached_data_version_tag,
ops::v8::op_v8_get_heap_statistics,
ops::v8::op_v8_get_wire_format_version,
ops::v8::op_v8_new_deserializer,
ops::v8::op_v8_new_serializer,
ops::v8::op_v8_read_double,
ops::v8::op_v8_read_header,
ops::v8::op_v8_read_raw_bytes,
ops::v8::op_v8_read_uint32,
ops::v8::op_v8_read_uint64,
ops::v8::op_v8_read_value,
ops::v8::op_v8_release_buffer,
ops::v8::op_v8_set_treat_array_buffer_views_as_host_objects,
ops::v8::op_v8_transfer_array_buffer,
ops::v8::op_v8_transfer_array_buffer_de,
ops::v8::op_v8_write_double,
ops::v8::op_v8_write_header,
ops::v8::op_v8_write_raw_bytes,
ops::v8::op_v8_write_uint32,
ops::v8::op_v8_write_uint64,
ops::v8::op_v8_write_value,
ops::vm::op_vm_create_script,
ops::vm::op_vm_create_context,
ops::vm::op_vm_script_run_in_context,
@ -339,6 +358,7 @@ deno_core::extension!(deno_node,
ops::os::op_homedir<P>,
op_node_build_os,
op_npm_process_state,
ops::require::op_require_can_parse_as_esm,
ops::require::op_require_init_paths,
ops::require::op_require_node_module_paths<P>,
ops::require::op_require_proxy_path,

View file

@ -4,6 +4,7 @@ use aes::cipher::block_padding::Pkcs7;
use aes::cipher::BlockDecryptMut;
use aes::cipher::BlockEncryptMut;
use aes::cipher::KeyIvInit;
use deno_core::error::range_error;
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::Resource;
@ -157,6 +158,13 @@ impl Cipher {
Aes256Gcm(Box::new(cipher))
}
"aes256" | "aes-256-cbc" => {
if key.len() != 32 {
return Err(range_error("Invalid key length"));
}
if iv.len() != 16 {
return Err(type_error("Invalid initialization vector"));
}
Aes256Cbc(Box::new(cbc::Encryptor::new(key.into(), iv.into())))
}
_ => return Err(type_error(format!("Unknown cipher {algorithm_name}"))),
@ -346,6 +354,13 @@ impl Decipher {
Aes256Gcm(Box::new(decipher))
}
"aes256" | "aes-256-cbc" => {
if key.len() != 32 {
return Err(range_error("Invalid key length"));
}
if iv.len() != 16 {
return Err(type_error("Invalid initialization vector"));
}
Aes256Cbc(Box::new(cbc::Decryptor::new(key.into(), iv.into())))
}
_ => return Err(type_error(format!("Unknown cipher {algorithm_name}"))),

View file

@ -220,13 +220,9 @@ pub fn op_node_create_cipheriv(
#[string] algorithm: &str,
#[buffer] key: &[u8],
#[buffer] iv: &[u8],
) -> u32 {
state.resource_table.add(
match cipher::CipherContext::new(algorithm, key, iv) {
Ok(context) => context,
Err(_) => return 0,
},
)
) -> Result<u32, AnyError> {
let context = cipher::CipherContext::new(algorithm, key, iv)?;
Ok(state.resource_table.add(context))
}
#[op2(fast)]
@ -292,13 +288,9 @@ pub fn op_node_create_decipheriv(
#[string] algorithm: &str,
#[buffer] key: &[u8],
#[buffer] iv: &[u8],
) -> u32 {
state.resource_table.add(
match cipher::DecipherContext::new(algorithm, key, iv) {
Ok(context) => context,
Err(_) => return 0,
},
)
) -> Result<u32, AnyError> {
let context = cipher::DecipherContext::new(algorithm, key, iv)?;
Ok(state.resource_table.add(context))
}
#[op2(fast)]

View file

@ -6,6 +6,7 @@ use deno_core::error::AnyError;
use deno_core::normalize_path;
use deno_core::op2;
use deno_core::url::Url;
use deno_core::v8;
use deno_core::JsRuntimeInspector;
use deno_core::ModuleSpecifier;
use deno_core::OpState;
@ -591,12 +592,14 @@ where
}
}
#[op2(fast)]
pub fn op_require_break_on_next_statement(state: &mut OpState) {
let inspector = state.borrow::<Rc<RefCell<JsRuntimeInspector>>>();
inspector
.borrow_mut()
.wait_for_session_and_break_on_next_statement()
#[op2(fast, reentrant)]
pub fn op_require_break_on_next_statement(state: Rc<RefCell<OpState>>) {
let inspector_rc = {
let state = state.borrow();
state.borrow::<Rc<RefCell<JsRuntimeInspector>>>().clone()
};
let mut inspector = inspector_rc.borrow_mut();
inspector.wait_for_session_and_break_on_next_statement()
}
fn url_to_file_path_string(url: &Url) -> Result<String, AnyError> {
@ -612,3 +615,29 @@ fn url_to_file_path(url: &Url) -> Result<PathBuf, AnyError> {
}
}
}
#[op2(fast)]
pub fn op_require_can_parse_as_esm(
scope: &mut v8::HandleScope,
#[string] source: &str,
) -> bool {
let scope = &mut v8::TryCatch::new(scope);
let Some(source) = v8::String::new(scope, source) else {
return false;
};
let origin = v8::ScriptOrigin::new(
scope,
source.into(),
0,
0,
false,
0,
None,
true,
false,
true,
None,
);
let mut source = v8::script_compiler::Source::new(source, Some(&origin));
v8::script_compiler::compile_module(scope, &mut source).is_some()
}

View file

@ -1,6 +1,15 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use deno_core::error::generic_error;
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::op2;
use deno_core::v8;
use deno_core::FastString;
use deno_core::GarbageCollected;
use deno_core::ToJsBuffer;
use std::ptr::NonNull;
use v8::ValueDeserializerHelper;
use v8::ValueSerializerHelper;
#[op2(fast)]
pub fn op_v8_cached_data_version_tag() -> u32 {
@ -30,3 +39,355 @@ pub fn op_v8_get_heap_statistics(
buffer[12] = stats.used_global_handles_size() as f64;
buffer[13] = stats.external_memory() as f64;
}
pub struct Serializer<'a> {
inner: v8::ValueSerializer<'a>,
}
pub struct SerializerDelegate {
obj: v8::Global<v8::Object>,
}
impl<'a> v8::cppgc::GarbageCollected for Serializer<'a> {
fn trace(&self, _visitor: &v8::cppgc::Visitor) {}
}
impl SerializerDelegate {
fn obj<'s>(
&self,
scope: &mut v8::HandleScope<'s>,
) -> v8::Local<'s, v8::Object> {
v8::Local::new(scope, &self.obj)
}
}
impl v8::ValueSerializerImpl for SerializerDelegate {
fn get_shared_array_buffer_id<'s>(
&self,
scope: &mut v8::HandleScope<'s>,
shared_array_buffer: v8::Local<'s, v8::SharedArrayBuffer>,
) -> Option<u32> {
let obj = self.obj(scope);
let key = FastString::from_static("_getSharedArrayBufferId")
.v8_string(scope)
.into();
if let Some(v) = obj.get(scope, key) {
if let Ok(fun) = v.try_cast::<v8::Function>() {
return fun
.call(scope, obj.into(), &[shared_array_buffer.into()])
.and_then(|ret| ret.uint32_value(scope));
}
}
None
}
fn has_custom_host_object(&self, _isolate: &mut v8::Isolate) -> bool {
false
}
fn throw_data_clone_error<'s>(
&self,
scope: &mut v8::HandleScope<'s>,
message: v8::Local<'s, v8::String>,
) {
let obj = self.obj(scope);
let key = FastString::from_static("_getDataCloneError")
.v8_string(scope)
.into();
if let Some(v) = obj.get(scope, key) {
let fun = v
.try_cast::<v8::Function>()
.expect("_getDataCloneError should be a function");
if let Some(error) = fun.call(scope, obj.into(), &[message.into()]) {
scope.throw_exception(error);
return;
}
}
let error = v8::Exception::type_error(scope, message);
scope.throw_exception(error);
}
fn write_host_object<'s>(
&self,
scope: &mut v8::HandleScope<'s>,
object: v8::Local<'s, v8::Object>,
_value_serializer: &dyn ValueSerializerHelper,
) -> Option<bool> {
let obj = self.obj(scope);
let key = FastString::from_static("_writeHostObject")
.v8_string(scope)
.into();
if let Some(v) = obj.get(scope, key) {
if let Ok(v) = v.try_cast::<v8::Function>() {
v.call(scope, obj.into(), &[object.into()])?;
return Some(true);
}
}
None
}
fn is_host_object<'s>(
&self,
_scope: &mut v8::HandleScope<'s>,
_object: v8::Local<'s, v8::Object>,
) -> Option<bool> {
// should never be called because has_custom_host_object returns false
None
}
}
#[op2]
#[cppgc]
pub fn op_v8_new_serializer(
scope: &mut v8::HandleScope,
obj: v8::Local<v8::Object>,
) -> Serializer<'static> {
let obj = v8::Global::new(scope, obj);
let inner =
v8::ValueSerializer::new(scope, Box::new(SerializerDelegate { obj }));
Serializer { inner }
}
#[op2(fast)]
pub fn op_v8_set_treat_array_buffer_views_as_host_objects(
#[cppgc] ser: &Serializer,
value: bool,
) {
ser
.inner
.set_treat_array_buffer_views_as_host_objects(value);
}
#[op2]
#[serde]
pub fn op_v8_release_buffer(#[cppgc] ser: &Serializer) -> ToJsBuffer {
ser.inner.release().into()
}
#[op2(fast)]
pub fn op_v8_transfer_array_buffer(
#[cppgc] ser: &Serializer,
#[smi] id: u32,
array_buffer: v8::Local<v8::ArrayBuffer>,
) {
ser.inner.transfer_array_buffer(id, array_buffer);
}
#[op2(fast)]
pub fn op_v8_write_double(#[cppgc] ser: &Serializer, double: f64) {
ser.inner.write_double(double);
}
#[op2(fast)]
pub fn op_v8_write_header(#[cppgc] ser: &Serializer) {
ser.inner.write_header();
}
#[op2]
pub fn op_v8_write_raw_bytes(
#[cppgc] ser: &Serializer,
#[anybuffer] source: &[u8],
) {
ser.inner.write_raw_bytes(source);
}
#[op2(fast)]
pub fn op_v8_write_uint32(#[cppgc] ser: &Serializer, num: u32) {
ser.inner.write_uint32(num);
}
#[op2(fast)]
pub fn op_v8_write_uint64(#[cppgc] ser: &Serializer, hi: u32, lo: u32) {
let num = ((hi as u64) << 32) | (lo as u64);
ser.inner.write_uint64(num);
}
#[op2(nofast, reentrant)]
pub fn op_v8_write_value(
scope: &mut v8::HandleScope,
#[cppgc] ser: &Serializer,
value: v8::Local<v8::Value>,
) -> Result<(), AnyError> {
let context = scope.get_current_context();
ser.inner.write_value(context, value);
Ok(())
}
struct DeserBuffer {
ptr: Option<NonNull<u8>>,
// Hold onto backing store to keep the underlying buffer
// alive while we hold a reference to it.
_backing_store: v8::SharedRef<v8::BackingStore>,
}
pub struct Deserializer<'a> {
buf: DeserBuffer,
inner: v8::ValueDeserializer<'a>,
}
impl<'a> deno_core::GarbageCollected for Deserializer<'a> {}
pub struct DeserializerDelegate {
obj: v8::Global<v8::Object>,
}
impl GarbageCollected for DeserializerDelegate {
fn trace(&self, _visitor: &v8::cppgc::Visitor) {}
}
impl v8::ValueDeserializerImpl for DeserializerDelegate {
fn read_host_object<'s>(
&self,
scope: &mut v8::HandleScope<'s>,
_value_deserializer: &dyn v8::ValueDeserializerHelper,
) -> Option<v8::Local<'s, v8::Object>> {
let obj = v8::Local::new(scope, &self.obj);
let key = FastString::from_static("_readHostObject")
.v8_string(scope)
.into();
let scope = &mut v8::AllowJavascriptExecutionScope::new(scope);
if let Some(v) = obj.get(scope, key) {
if let Ok(v) = v.try_cast::<v8::Function>() {
let result = v.call(scope, obj.into(), &[])?;
match result.try_cast() {
Ok(res) => return Some(res),
Err(_) => {
let msg =
FastString::from_static("readHostObject must return an object")
.v8_string(scope);
let error = v8::Exception::type_error(scope, msg);
scope.throw_exception(error);
return None;
}
}
}
}
None
}
}
#[op2]
#[cppgc]
pub fn op_v8_new_deserializer(
scope: &mut v8::HandleScope,
obj: v8::Local<v8::Object>,
buffer: v8::Local<v8::ArrayBufferView>,
) -> Result<Deserializer<'static>, AnyError> {
let offset = buffer.byte_offset();
let len = buffer.byte_length();
let backing_store = buffer.get_backing_store().ok_or_else(|| {
generic_error("deserialization buffer has no backing store")
})?;
let (buf_slice, buf_ptr) = if let Some(data) = backing_store.data() {
// SAFETY: the offset is valid for the underlying buffer because we're getting it directly from v8
let data_ptr = unsafe { data.as_ptr().cast::<u8>().add(offset) };
(
// SAFETY: the len is valid, from v8, and the data_ptr is valid (as above)
unsafe { std::slice::from_raw_parts(data_ptr.cast_const().cast(), len) },
Some(data.cast()),
)
} else {
(&[] as &[u8], None::<NonNull<u8>>)
};
let obj = v8::Global::new(scope, obj);
let inner = v8::ValueDeserializer::new(
scope,
Box::new(DeserializerDelegate { obj }),
buf_slice,
);
Ok(Deserializer {
inner,
buf: DeserBuffer {
_backing_store: backing_store,
ptr: buf_ptr,
},
})
}
#[op2(fast)]
pub fn op_v8_transfer_array_buffer_de(
#[cppgc] deser: &Deserializer,
#[smi] id: u32,
array_buffer: v8::Local<v8::ArrayBuffer>,
) {
// TODO(nathanwhit): also need binding for TransferSharedArrayBuffer, then call that if
// array_buffer is shared
deser.inner.transfer_array_buffer(id, array_buffer);
}
#[op2(fast)]
pub fn op_v8_read_double(
#[cppgc] deser: &Deserializer,
) -> Result<f64, AnyError> {
let mut double = 0f64;
if !deser.inner.read_double(&mut double) {
return Err(type_error("ReadDouble() failed"));
}
Ok(double)
}
#[op2(nofast)]
pub fn op_v8_read_header(
scope: &mut v8::HandleScope,
#[cppgc] deser: &Deserializer,
) -> bool {
let context = scope.get_current_context();
let res = deser.inner.read_header(context);
res.unwrap_or_default()
}
#[op2(fast)]
#[number]
pub fn op_v8_read_raw_bytes(
#[cppgc] deser: &Deserializer,
#[number] length: usize,
) -> usize {
let Some(buf_ptr) = deser.buf.ptr else {
return 0;
};
if let Some(buf) = deser.inner.read_raw_bytes(length) {
let ptr = buf.as_ptr();
(ptr as usize) - (buf_ptr.as_ptr() as usize)
} else {
0
}
}
#[op2(fast)]
pub fn op_v8_read_uint32(
#[cppgc] deser: &Deserializer,
) -> Result<u32, AnyError> {
let mut value = 0;
if !deser.inner.read_uint32(&mut value) {
return Err(type_error("ReadUint32() failed"));
}
Ok(value)
}
#[op2]
#[serde]
pub fn op_v8_read_uint64(
#[cppgc] deser: &Deserializer,
) -> Result<(u32, u32), AnyError> {
let mut val = 0;
if !deser.inner.read_uint64(&mut val) {
return Err(type_error("ReadUint64() failed"));
}
Ok(((val >> 32) as u32, val as u32))
}
#[op2(fast)]
pub fn op_v8_get_wire_format_version(#[cppgc] deser: &Deserializer) -> u32 {
deser.inner.get_wire_format_version()
}
#[op2(reentrant)]
pub fn op_v8_read_value<'s>(
scope: &mut v8::HandleScope<'s>,
#[cppgc] deser: &Deserializer,
) -> v8::Local<'s, v8::Value> {
let context = scope.get_current_context();
let val = deser.inner.read_value(context);
val.unwrap_or_else(|| v8::null(scope).into())
}

View file

@ -4,9 +4,11 @@
import { core, internals, primordials } from "ext:core/mod.js";
import {
op_import_sync,
op_napi_open,
op_require_as_file_path,
op_require_break_on_next_statement,
op_require_can_parse_as_esm,
op_require_init_paths,
op_require_is_deno_dir_package,
op_require_is_request_relative,
@ -900,16 +902,6 @@ Module.prototype.load = function (filename) {
pathDirname(this.filename),
);
const extension = findLongestRegisteredExtension(filename);
// allow .mjs to be overridden
if (
StringPrototypeEndsWith(filename, ".mjs") && !Module._extensions[".mjs"]
) {
throw createRequireEsmError(
filename,
moduleParentCache.get(this)?.filename,
);
}
Module._extensions[extension](this, this.filename);
this.loaded = true;
@ -987,27 +979,24 @@ function wrapSafe(
if (process.mainModule === cjsModuleInstance) {
enrichCJSError(err.thrown);
}
if (isEsmSyntaxError(err.thrown)) {
throw createRequireEsmError(
filename,
moduleParentCache.get(cjsModuleInstance)?.filename,
);
} else {
throw err.thrown;
}
throw err.thrown;
}
return f;
}
Module.prototype._compile = function (content, filename, format) {
const compiledWrapper = wrapSafe(filename, content, this, format);
if (format === "module") {
// TODO(https://github.com/denoland/deno/issues/24822): implement require esm
throw createRequireEsmError(
filename,
moduleParentCache.get(module)?.filename,
);
return loadESMFromCJS(this, filename, content);
}
let compiledWrapper;
try {
compiledWrapper = wrapSafe(filename, content, this, format);
} catch (err) {
if (err instanceof SyntaxError && op_require_can_parse_as_esm(content)) {
return loadESMFromCJS(this, filename, content);
}
throw err;
}
const dirname = pathDirname(filename);
@ -1065,12 +1054,7 @@ Module._extensions[".js"] = function (module, filename) {
if (StringPrototypeEndsWith(filename, ".js")) {
const pkg = op_require_read_closest_package_json(filename);
if (pkg?.typ === "module") {
// TODO(https://github.com/denoland/deno/issues/24822): implement require esm
format = "module";
throw createRequireEsmError(
filename,
moduleParentCache.get(module)?.filename,
);
} else if (pkg?.type === "commonjs") {
format = "commonjs";
}
@ -1081,20 +1065,19 @@ Module._extensions[".js"] = function (module, filename) {
module._compile(content, filename, format);
};
function createRequireEsmError(filename, parent) {
let message = `require() of ES Module ${filename}`;
function loadESMFromCJS(module, filename, code) {
const namespace = op_import_sync(
url.pathToFileURL(filename).toString(),
code,
);
if (parent) {
message += ` from ${parent}`;
}
message +=
` not supported. Instead change the require to a dynamic import() which is available in all CommonJS modules.`;
const err = new Error(message);
err.code = "ERR_REQUIRE_ESM";
return err;
module.exports = namespace;
}
Module._extensions[".mjs"] = function (module, filename) {
loadESMFromCJS(module, filename);
};
function stripBOM(content) {
if (StringPrototypeCharCodeAt(content, 0) === 0xfeff) {
content = StringPrototypeSlice(content, 1);

View file

@ -60,7 +60,7 @@ export class BrotliDecompress extends Transform {
#context;
// TODO(littledivy): use `options` argument
constructor(_options = {}) {
constructor(_options = { __proto__: null }) {
super({
// TODO(littledivy): use `encoding` argument
transform(chunk, _encoding, callback) {
@ -91,7 +91,7 @@ export class BrotliDecompress extends Transform {
export class BrotliCompress extends Transform {
#context;
constructor(options = {}) {
constructor(options = { __proto__: null }) {
super({
// TODO(littledivy): use `encoding` argument
transform(chunk, _encoding, callback) {

View file

@ -12,6 +12,28 @@ export const {
S_IXUSR,
S_IRGRP,
S_IWGRP,
S_IFBLK,
S_IFCHR,
S_IFDIR,
S_IFIFO,
S_IFLNK,
S_IFMT,
S_IFREG,
S_IFSOCK,
S_IRWXG,
S_IRWXO,
S_IRWXU,
UV_DIRENT_BLOCK,
UV_DIRENT_CHAR,
UV_DIRENT_DIR,
UV_DIRENT_FIFO,
UV_DIRENT_FILE,
UV_DIRENT_LINK,
UV_DIRENT_SOCKET,
UV_DIRENT_UNKNOWN,
UV_FS_O_FILEMAP,
UV_FS_SYMLINK_DIR,
UV_FS_SYMLINK_JUNCTION,
S_IXGRP,
S_IROTH,
S_IWOTH,

View file

@ -23,6 +23,7 @@ import {
validateStringAfterArrayBufferView,
} from "ext:deno_node/internal/fs/utils.mjs";
import { promisify } from "ext:deno_node/internal/util.mjs";
import { FileHandle } from "ext:deno_node/internal/fs/handle.ts";
import { FsFile } from "ext:deno_fs/30_fs.js";
interface Writer {
@ -30,7 +31,7 @@ interface Writer {
}
export function writeFile(
pathOrRid: string | number | URL,
pathOrRid: string | number | URL | FileHandle,
data: string | Uint8Array,
optOrCallback: Encodings | CallbackWithError | WriteFileOptions | undefined,
callback?: CallbackWithError,
@ -45,6 +46,7 @@ export function writeFile(
}
pathOrRid = pathOrRid instanceof URL ? pathFromURL(pathOrRid) : pathOrRid;
pathOrRid = pathOrRid instanceof FileHandle ? pathOrRid.fd : pathOrRid;
const flag: string | undefined = isFileOptions(options)
? options.flag

View file

@ -53,8 +53,8 @@ function denoEnvGet(name: string) {
} catch (e) {
if (
ObjectPrototypeIsPrototypeOf(TypeErrorPrototype, e) ||
// TODO(iuioiua): Use `PermissionDeniedPrototype` when it's available
ObjectPrototypeIsPrototypeOf(Deno.errors.PermissionDenied.prototype, e)
// TODO(iuioiua): Use `NotCapablePrototype` when it's available
ObjectPrototypeIsPrototypeOf(Deno.errors.NotCapable.prototype, e)
) {
return undefined;
}

View file

@ -65,22 +65,26 @@ export function createWritableStdioStream(writer, name, warmup = false) {
stream.once("close", () => writer?.close());
ObjectDefineProperties(stream, {
columns: {
__proto__: null,
enumerable: true,
configurable: true,
get: () =>
writer?.isTerminal() ? Deno.consoleSize?.().columns : undefined,
},
rows: {
__proto__: null,
enumerable: true,
configurable: true,
get: () => writer?.isTerminal() ? Deno.consoleSize?.().rows : undefined,
},
isTTY: {
__proto__: null,
enumerable: true,
configurable: true,
get: () => writer?.isTerminal(),
},
getWindowSize: {
__proto__: null,
enumerable: true,
configurable: true,
value: () =>
@ -203,6 +207,7 @@ export const initStdin = (warmup = false) => {
stdin.on("close", () => io.stdin?.close());
stdin.fd = io.stdin ? io.STDIN_RID : -1;
ObjectDefineProperty(stdin, "isTTY", {
__proto__: null,
enumerable: true,
configurable: true,
get() {
@ -216,6 +221,7 @@ export const initStdin = (warmup = false) => {
return stdin;
};
ObjectDefineProperty(stdin, "isRaw", {
__proto__: null,
enumerable: true,
configurable: true,
get() {

View file

@ -3,6 +3,7 @@
// deno-fmt-ignore-file
// deno-lint-ignore-file
import { nextTick } from "ext:deno_node/_next_tick.ts";
import { EventEmitter as EE } from "ext:deno_node/_events.mjs";
import { AbortController } from "ext:deno_web/03_abort_signal.js";
import { Blob } from "ext:deno_web/09_file.js";
import { StringDecoder } from "node:string_decoder";
@ -1723,446 +1724,11 @@ var require_destroy = __commonJS({
},
});
// node_modules/events/events.js
var require_events = __commonJS({
"node_modules/events/events.js"(exports, module) {
"use strict";
var R = typeof Reflect === "object" ? Reflect : null;
var ReflectApply = R && typeof R.apply === "function"
? R.apply
: function ReflectApply2(target, receiver, args) {
return Function.prototype.apply.call(target, receiver, args);
};
var ReflectOwnKeys;
if (R && typeof R.ownKeys === "function") {
ReflectOwnKeys = R.ownKeys;
} else if (Object.getOwnPropertySymbols) {
ReflectOwnKeys = function ReflectOwnKeys2(target) {
return Object.getOwnPropertyNames(target).concat(
Object.getOwnPropertySymbols(target),
);
};
} else {
ReflectOwnKeys = function ReflectOwnKeys2(target) {
return Object.getOwnPropertyNames(target);
};
}
function ProcessEmitWarning(warning) {
if (console && console.warn) {
console.warn(warning);
}
}
var NumberIsNaN = Number.isNaN || function NumberIsNaN2(value) {
return value !== value;
};
function EventEmitter() {
EventEmitter.init.call(this);
}
module.exports = EventEmitter;
module.exports.once = once;
EventEmitter.EventEmitter = EventEmitter;
EventEmitter.prototype._events = void 0;
EventEmitter.prototype._eventsCount = 0;
EventEmitter.prototype._maxListeners = void 0;
var defaultMaxListeners = 10;
function checkListener(listener) {
if (typeof listener !== "function") {
throw new TypeError(
'The "listener" argument must be of type Function. Received type ' +
typeof listener,
);
}
}
Object.defineProperty(EventEmitter, "defaultMaxListeners", {
enumerable: true,
get: function () {
return defaultMaxListeners;
},
set: function (arg) {
if (typeof arg !== "number" || arg < 0 || NumberIsNaN(arg)) {
throw new RangeError(
'The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' +
arg + ".",
);
}
defaultMaxListeners = arg;
},
});
EventEmitter.init = function () {
if (
this._events === void 0 ||
this._events === Object.getPrototypeOf(this)._events
) {
this._events = /* @__PURE__ */ Object.create(null);
this._eventsCount = 0;
}
this._maxListeners = this._maxListeners || void 0;
};
EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
if (typeof n !== "number" || n < 0 || NumberIsNaN(n)) {
throw new RangeError(
'The value of "n" is out of range. It must be a non-negative number. Received ' +
n + ".",
);
}
this._maxListeners = n;
return this;
};
function _getMaxListeners(that) {
if (that._maxListeners === void 0) {
return EventEmitter.defaultMaxListeners;
}
return that._maxListeners;
}
EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
return _getMaxListeners(this);
};
EventEmitter.prototype.emit = function emit(type) {
var args = [];
for (var i = 1; i < arguments.length; i++) {
args.push(arguments[i]);
}
var doError = type === "error";
var events = this._events;
if (events !== void 0) {
doError = doError && events.error === void 0;
} else if (!doError) {
return false;
}
if (doError) {
var er;
if (args.length > 0) {
er = args[0];
}
if (er instanceof Error) {
throw er;
}
var err = new Error(
"Unhandled error." + (er ? " (" + er.message + ")" : ""),
);
err.context = er;
throw err;
}
var handler = events[type];
if (handler === void 0) {
return false;
}
if (typeof handler === "function") {
ReflectApply(handler, this, args);
} else {
var len = handler.length;
var listeners = arrayClone(handler, len);
for (var i = 0; i < len; ++i) {
ReflectApply(listeners[i], this, args);
}
}
return true;
};
function _addListener(target, type, listener, prepend) {
var m;
var events;
var existing;
checkListener(listener);
events = target._events;
if (events === void 0) {
events = target._events = /* @__PURE__ */ Object.create(null);
target._eventsCount = 0;
} else {
if (events.newListener !== void 0) {
target.emit(
"newListener",
type,
listener.listener ? listener.listener : listener,
);
events = target._events;
}
existing = events[type];
}
if (existing === void 0) {
existing = events[type] = listener;
++target._eventsCount;
} else {
if (typeof existing === "function") {
existing = events[type] = prepend
? [listener, existing]
: [existing, listener];
} else if (prepend) {
existing.unshift(listener);
} else {
existing.push(listener);
}
m = _getMaxListeners(target);
if (m > 0 && existing.length > m && !existing.warned) {
existing.warned = true;
var w = new Error(
"Possible EventEmitter memory leak detected. " + existing.length +
" " + String(type) +
" listeners added. Use emitter.setMaxListeners() to increase limit",
);
w.name = "MaxListenersExceededWarning";
w.emitter = target;
w.type = type;
w.count = existing.length;
ProcessEmitWarning(w);
}
}
return target;
}
EventEmitter.prototype.addListener = function addListener(type, listener) {
return _addListener(this, type, listener, false);
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.prependListener = function prependListener(
type,
listener,
) {
return _addListener(this, type, listener, true);
};
function onceWrapper() {
if (!this.fired) {
this.target.removeListener(this.type, this.wrapFn);
this.fired = true;
if (arguments.length === 0) {
return this.listener.call(this.target);
}
return this.listener.apply(this.target, arguments);
}
}
function _onceWrap(target, type, listener) {
var state = { fired: false, wrapFn: void 0, target, type, listener };
var wrapped = onceWrapper.bind(state);
wrapped.listener = listener;
state.wrapFn = wrapped;
return wrapped;
}
EventEmitter.prototype.once = function once2(type, listener) {
checkListener(listener);
this.on(type, _onceWrap(this, type, listener));
return this;
};
EventEmitter.prototype.prependOnceListener = function prependOnceListener(
type,
listener,
) {
checkListener(listener);
this.prependListener(type, _onceWrap(this, type, listener));
return this;
};
EventEmitter.prototype.removeListener = function removeListener(
type,
listener,
) {
var list, events, position, i, originalListener;
checkListener(listener);
events = this._events;
if (events === void 0) {
return this;
}
list = events[type];
if (list === void 0) {
return this;
}
if (list === listener || list.listener === listener) {
if (--this._eventsCount === 0) {
this._events = /* @__PURE__ */ Object.create(null);
} else {
delete events[type];
if (events.removeListener) {
this.emit("removeListener", type, list.listener || listener);
}
}
} else if (typeof list !== "function") {
position = -1;
for (i = list.length - 1; i >= 0; i--) {
if (list[i] === listener || list[i].listener === listener) {
originalListener = list[i].listener;
position = i;
break;
}
}
if (position < 0) {
return this;
}
if (position === 0) {
list.shift();
} else {
spliceOne(list, position);
}
if (list.length === 1) {
events[type] = list[0];
}
if (events.removeListener !== void 0) {
this.emit("removeListener", type, originalListener || listener);
}
}
return this;
};
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
EventEmitter.prototype.removeAllListeners = function removeAllListeners(
type,
) {
var listeners, events, i;
events = this._events;
if (events === void 0) {
return this;
}
if (events.removeListener === void 0) {
if (arguments.length === 0) {
this._events = /* @__PURE__ */ Object.create(null);
this._eventsCount = 0;
} else if (events[type] !== void 0) {
if (--this._eventsCount === 0) {
this._events = /* @__PURE__ */ Object.create(null);
} else {
delete events[type];
}
}
return this;
}
if (arguments.length === 0) {
var keys = Object.keys(events);
var key;
for (i = 0; i < keys.length; ++i) {
key = keys[i];
if (key === "removeListener") {
continue;
}
this.removeAllListeners(key);
}
this.removeAllListeners("removeListener");
this._events = /* @__PURE__ */ Object.create(null);
this._eventsCount = 0;
return this;
}
listeners = events[type];
if (typeof listeners === "function") {
this.removeListener(type, listeners);
} else if (listeners !== void 0) {
for (i = listeners.length - 1; i >= 0; i--) {
this.removeListener(type, listeners[i]);
}
}
return this;
};
function _listeners(target, type, unwrap) {
var events = target._events;
if (events === void 0) {
return [];
}
var evlistener = events[type];
if (evlistener === void 0) {
return [];
}
if (typeof evlistener === "function") {
return unwrap ? [evlistener.listener || evlistener] : [evlistener];
}
return unwrap
? unwrapListeners(evlistener)
: arrayClone(evlistener, evlistener.length);
}
EventEmitter.prototype.listeners = function listeners(type) {
return _listeners(this, type, true);
};
EventEmitter.prototype.rawListeners = function rawListeners(type) {
return _listeners(this, type, false);
};
EventEmitter.listenerCount = function (emitter, type) {
if (typeof emitter.listenerCount === "function") {
return emitter.listenerCount(type);
} else {
return listenerCount.call(emitter, type);
}
};
EventEmitter.prototype.listenerCount = listenerCount;
function listenerCount(type) {
var events = this._events;
if (events !== void 0) {
var evlistener = events[type];
if (typeof evlistener === "function") {
return 1;
} else if (evlistener !== void 0) {
return evlistener.length;
}
}
return 0;
}
EventEmitter.prototype.eventNames = function eventNames() {
return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
};
function arrayClone(arr, n) {
var copy = new Array(n);
for (var i = 0; i < n; ++i) {
copy[i] = arr[i];
}
return copy;
}
function spliceOne(list, index) {
for (; index + 1 < list.length; index++) {
list[index] = list[index + 1];
}
list.pop();
}
function unwrapListeners(arr) {
var ret = new Array(arr.length);
for (var i = 0; i < ret.length; ++i) {
ret[i] = arr[i].listener || arr[i];
}
return ret;
}
function once(emitter, name) {
return new Promise(function (resolve, reject) {
function errorListener(err) {
emitter.removeListener(name, resolver);
reject(err);
}
function resolver() {
if (typeof emitter.removeListener === "function") {
emitter.removeListener("error", errorListener);
}
resolve([].slice.call(arguments));
}
eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });
if (name !== "error") {
addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });
}
});
}
function addErrorHandlerIfEventEmitter(emitter, handler, flags) {
if (typeof emitter.on === "function") {
eventTargetAgnosticAddListener(emitter, "error", handler, flags);
}
}
function eventTargetAgnosticAddListener(emitter, name, listener, flags) {
if (typeof emitter.on === "function") {
if (flags.once) {
emitter.once(name, listener);
} else {
emitter.on(name, listener);
}
} else if (typeof emitter.addEventListener === "function") {
emitter.addEventListener(name, function wrapListener(arg) {
if (flags.once) {
emitter.removeEventListener(name, wrapListener);
}
listener(arg);
});
} else {
throw new TypeError(
'The "emitter" argument must be of type EventEmitter. Received type ' +
typeof emitter,
);
}
}
},
});
// lib/internal/streams/legacy.js
var require_legacy = __commonJS({
"lib/internal/streams/legacy.js"(exports, module) {
"use strict";
var { ArrayIsArray, ObjectSetPrototypeOf } = require_primordials();
var { EventEmitter: EE } = require_events();
function Stream(opts) {
EE.call(this, opts);
}
@ -2688,7 +2254,6 @@ var require_readable = __commonJS({
} = require_primordials();
module.exports = Readable;
Readable.ReadableState = ReadableState;
var { EventEmitter: EE } = require_events();
var { Stream, prependListener } = require_legacy();
var { Buffer: Buffer2 } = require_buffer();
var { addAbortSignal } = require_add_abort_signal();
@ -3722,7 +3287,6 @@ var require_writable = __commonJS({
} = require_primordials();
module.exports = Writable;
Writable.WritableState = WritableState;
var { EventEmitter: EE } = require_events();
var Stream = require_legacy().Stream;
var { Buffer: Buffer2 } = require_buffer();
var destroyImpl = require_destroy();

View file

@ -13,7 +13,7 @@ import { clearTimeout, setTimeout } from "ext:deno_web/02_timers.js";
/** Resolve a Promise after a given amount of milliseconds. */
export function delay(
ms: number,
options: { signal?: AbortSignal } = {},
options: { signal?: AbortSignal } = { __proto__: null },
): Promise<void> {
const { signal } = options;
if (signal?.aborted) {

View file

@ -325,7 +325,10 @@ export function diffstr(A: string, B: string) {
);
}
function tokenize(string: string, { wordDiff = false } = {}): string[] {
function tokenize(
string: string,
{ wordDiff = false } = { __proto__: null },
): string[] {
if (wordDiff) {
// Split string on whitespace symbols
const tokens = StringPrototypeSplit(string, WHITESPACE_SYMBOL_PATTERN);
@ -450,7 +453,7 @@ export function diffstr(A: string, B: string) {
*/
function createColor(
diffType: DiffType,
{ background = false } = {},
{ background = false } = { __proto__: null },
): (s: string) => string {
// TODO(@littledivy): Remove this when we can detect
// true color terminals.
@ -484,7 +487,7 @@ function createSign(diffType: DiffType): string {
export function buildMessage(
diffResult: ReadonlyArray<DiffResult<string>>,
{ stringDiff = false } = {},
{ stringDiff = false } = { __proto__: null },
): string[] {
const messages: string[] = [], diffMessages: string[] = [];
ArrayPrototypePush(messages, "");

View file

@ -1,15 +1,15 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// TODO(petamoriken): enable prefer-primordials for node polyfills
// deno-lint-ignore-file prefer-primordials
import { primordials } from "ext:core/mod.js";
import { Console } from "ext:deno_node/internal/console/constructor.mjs";
import { windowOrWorkerGlobalScope } from "ext:runtime/98_global_scope_shared.js";
// Don't rely on global `console` because during bootstrapping, it is pointing
// to native `console` object provided by V8.
const console = windowOrWorkerGlobalScope.console.value;
Object.assign(console, { Console });
const { ObjectAssign } = primordials;
ObjectAssign(console, { Console });
export default console;

View file

@ -51,6 +51,28 @@ export const {
UV_FS_COPYFILE_EXCL,
UV_FS_COPYFILE_FICLONE,
UV_FS_COPYFILE_FICLONE_FORCE,
S_IFBLK,
S_IFCHR,
S_IFDIR,
S_IFIFO,
S_IFLNK,
S_IFMT,
S_IFREG,
S_IFSOCK,
S_IRWXG,
S_IRWXO,
S_IRWXU,
UV_DIRENT_BLOCK,
UV_DIRENT_CHAR,
UV_DIRENT_DIR,
UV_DIRENT_FIFO,
UV_DIRENT_FILE,
UV_DIRENT_LINK,
UV_DIRENT_SOCKET,
UV_DIRENT_UNKNOWN,
UV_FS_O_FILEMAP,
UV_FS_SYMLINK_DIR,
UV_FS_SYMLINK_JUNCTION,
} = fsConstants;
export const {
RTLD_DEEPBIND,

View file

@ -242,7 +242,7 @@ export class Cipheriv extends Transform implements Cipher {
): Buffer | string {
// TODO(kt3k): throw ERR_INVALID_ARG_TYPE if data is not string, Buffer, or ArrayBufferView
let buf = data;
if (typeof data === "string" && typeof inputEncoding === "string") {
if (typeof data === "string") {
buf = Buffer.from(data, inputEncoding);
}
@ -396,7 +396,7 @@ export class Decipheriv extends Transform implements Cipher {
): Buffer | string {
// TODO(kt3k): throw ERR_INVALID_ARG_TYPE if data is not string, Buffer, or ArrayBufferView
let buf = data;
if (typeof data === "string" && typeof inputEncoding === "string") {
if (typeof data === "string") {
buf = Buffer.from(data, inputEncoding);
}

View file

@ -133,12 +133,28 @@ export class FileHandle extends EventEmitter {
}
}
writeFile(data, options): Promise<void> {
return fsCall(promises.writeFile, this, data, options);
}
close(): Promise<void> {
// Note that Deno.close is not async
return Promise.resolve(core.close(this.fd));
}
}
function fsCall(fn, handle, ...args) {
if (handle.fd === -1) {
const err = new Error("file closed");
throw Object.assign(err, {
code: "EBADF",
syscall: fn.name,
});
}
return fn(handle, ...args);
}
export default {
FileHandle,
};

View file

@ -160,16 +160,8 @@ export class Pipe extends ConnectionWrap {
}
},
(e) => {
// TODO(cmorten): correct mapping of connection error to status code.
let code: number;
if (e instanceof Deno.errors.NotFound) {
code = codeMap.get("ENOENT")!;
} else if (e instanceof Deno.errors.PermissionDenied) {
code = codeMap.get("EACCES")!;
} else {
code = codeMap.get("ECONNREFUSED")!;
}
const code = codeMap.get(e.code ?? "UNKNOWN") ??
codeMap.get("UNKNOWN")!;
try {
this.afterConnect(req, code);
@ -207,16 +199,10 @@ export class Pipe extends ConnectionWrap {
try {
listener = Deno.listen(listenOptions);
} catch (e) {
if (e instanceof Deno.errors.AddrInUse) {
return codeMap.get("EADDRINUSE")!;
} else if (e instanceof Deno.errors.AddrNotAvailable) {
return codeMap.get("EADDRNOTAVAIL")!;
} else if (e instanceof Deno.errors.PermissionDenied) {
if (e instanceof Deno.errors.NotCapable) {
throw e;
}
// TODO(cmorten): map errors to appropriate error codes.
return codeMap.get("UNKNOWN")!;
return codeMap.get(e.code ?? "UNKNOWN") ?? codeMap.get("UNKNOWN")!;
}
const address = listener.addr as Deno.UnixAddr;

View file

@ -38,6 +38,7 @@ import { TextEncoder } from "ext:deno_web/08_text_encoding.js";
import { Buffer } from "node:buffer";
import { notImplemented } from "ext:deno_node/_utils.ts";
import { HandleWrap } from "ext:deno_node/internal_binding/handle_wrap.ts";
import { ownerSymbol } from "ext:deno_node/internal/async_hooks.ts";
import {
AsyncWrap,
providerType,
@ -343,7 +344,8 @@ export class LibuvStreamWrap extends HandleWrap {
) {
nread = codeMap.get("ECONNRESET")!;
} else {
nread = codeMap.get("UNKNOWN")!;
this[ownerSymbol].destroy(e);
return;
}
}

View file

@ -45,6 +45,7 @@ import {
INITIAL_ACCEPT_BACKOFF_DELAY,
MAX_ACCEPT_BACKOFF_DELAY,
} from "ext:deno_node/internal_binding/_listen.ts";
import { nextTick } from "ext:deno_node/_next_tick.ts";
/** The type of TCP socket. */
enum socketType {
@ -211,16 +212,10 @@ export class TCP extends ConnectionWrap {
try {
listener = Deno.listen(listenOptions);
} catch (e) {
if (e instanceof Deno.errors.AddrInUse) {
return codeMap.get("EADDRINUSE")!;
} else if (e instanceof Deno.errors.AddrNotAvailable) {
return codeMap.get("EADDRNOTAVAIL")!;
} else if (e instanceof Deno.errors.PermissionDenied) {
if (e instanceof Deno.errors.NotCapable) {
throw e;
}
// TODO(cmorten): map errors to appropriate error codes.
return codeMap.get("UNKNOWN")!;
return codeMap.get(e.code ?? "UNKNOWN") ?? codeMap.get("UNKNOWN")!;
}
const address = listener.addr as Deno.NetAddr;
@ -228,7 +223,14 @@ export class TCP extends ConnectionWrap {
this.#port = address.port;
this.#listener = listener;
this.#accept();
// TODO(kt3k): Delays the accept() call 2 ticks. Deno.Listener can't be closed
// synchronously when accept() is called. By delaying the accept() call,
// the user can close the server synchronously in the callback of listen().
// This workaround enables `npm:detect-port` to work correctly.
// Remove these nextTick calls when the below issue resolved:
// https://github.com/denoland/deno/issues/25480
nextTick(nextTick, () => this.#accept());
return 0;
}

View file

@ -337,16 +337,10 @@ export class UDP extends HandleWrap {
try {
listener = DenoListenDatagram(listenOptions);
} catch (e) {
if (e instanceof Deno.errors.AddrInUse) {
return codeMap.get("EADDRINUSE")!;
} else if (e instanceof Deno.errors.AddrNotAvailable) {
return codeMap.get("EADDRNOTAVAIL")!;
} else if (e instanceof Deno.errors.PermissionDenied) {
if (e instanceof Deno.errors.NotCapable) {
throw e;
}
// TODO(cmorten): map errors to appropriate error codes.
return codeMap.get("UNKNOWN")!;
return codeMap.get(e.code ?? "UNKNOWN") ?? codeMap.get("UNKNOWN")!;
}
const address = listener.addr as Deno.NetAddr;

View file

@ -478,6 +478,9 @@ export function parse(path: string): ParsedPath {
return ret;
}
export const _makeLong = toNamespacedPath;
export default {
basename,
delimiter,
@ -492,4 +495,5 @@ export default {
resolve,
sep,
toNamespacedPath,
_makeLong,
};

View file

@ -953,6 +953,8 @@ export function parse(path: string): ParsedPath {
return ret;
}
export const _makeLong = toNamespacedPath;
export default {
basename,
delimiter,
@ -967,4 +969,5 @@ export default {
resolve,
sep,
toNamespacedPath,
_makeLong,
};

View file

@ -36,6 +36,7 @@ export const {
resolve,
sep,
toNamespacedPath,
_makeLong,
} = path;
export default path;
export * from "ext:deno_node/path/common.ts";

View file

@ -18,6 +18,9 @@ export const {
resolve,
sep,
toNamespacedPath,
_makeLong,
} = path.posix;
export const posix = path.posix;
export const win32 = path.win32;
export default path.posix;

View file

@ -18,6 +18,9 @@ export const {
resolve,
sep,
toNamespacedPath,
_makeLong,
} = path.win32;
export const posix = path.posix;
export const win32 = path.win32;
export default path.win32;

View file

@ -403,6 +403,7 @@ StringDecoder.prototype.text = function text(
ObjectDefineProperties(StringDecoder.prototype, {
lastNeed: {
__proto__: null,
configurable: true,
enumerable: true,
get(this: StringDecoder): number {
@ -410,6 +411,7 @@ ObjectDefineProperties(StringDecoder.prototype, {
},
},
lastTotal: {
__proto__: null,
configurable: true,
enumerable: true,
get(this: StringDecoder): number {

View file

@ -33,6 +33,7 @@ export function setTimeout(
}
ObjectDefineProperty(setTimeout, promisify.custom, {
__proto__: null,
value: (timeout: number, ...args: unknown[]) => {
return new Promise((cb) =>
setTimeout(cb, timeout, ...new SafeArrayIterator(args))

View file

@ -177,6 +177,7 @@ export function inherits<T, U>(
);
}
ObjectDefineProperty(ctor, "super_", {
__proto__: null,
value: superCtor,
writable: true,
configurable: true,

View file

@ -6,15 +6,36 @@
// TODO(petamoriken): enable prefer-primordials for node polyfills
// deno-lint-ignore-file prefer-primordials
import { core } from "ext:core/mod.js";
import { primordials } from "ext:core/mod.js";
const { ObjectPrototypeToString } = primordials;
import {
op_v8_cached_data_version_tag,
op_v8_get_heap_statistics,
op_v8_get_wire_format_version,
op_v8_new_deserializer,
op_v8_new_serializer,
op_v8_read_double,
op_v8_read_header,
op_v8_read_raw_bytes,
op_v8_read_uint32,
op_v8_read_uint64,
op_v8_read_value,
op_v8_release_buffer,
op_v8_set_treat_array_buffer_views_as_host_objects,
op_v8_transfer_array_buffer,
op_v8_transfer_array_buffer_de,
op_v8_write_double,
op_v8_write_header,
op_v8_write_raw_bytes,
op_v8_write_uint32,
op_v8_write_uint64,
op_v8_write_value,
} from "ext:core/ops";
import { Buffer } from "node:buffer";
import { notImplemented, warnNotImplemented } from "ext:deno_node/_utils.ts";
import { notImplemented } from "ext:deno_node/_utils.ts";
import { isArrayBufferView } from "ext:deno_node/internal/util/types.ts";
export function cachedDataVersionTag() {
return op_v8_cached_data_version_tag();
@ -71,65 +92,225 @@ export function takeCoverage() {
export function writeHeapSnapshot() {
notImplemented("v8.writeHeapSnapshot");
}
export function serialize(value) {
return Buffer.from(core.serialize(value));
// deno-lint-ignore no-explicit-any
export function serialize(value: any) {
const ser = new DefaultSerializer();
ser.writeHeader();
ser.writeValue(value);
return ser.releaseBuffer();
}
export function deserialize(data) {
return core.deserialize(data);
export function deserialize(buffer: Buffer | ArrayBufferView | DataView) {
if (!isArrayBufferView(buffer)) {
throw new TypeError(
"buffer must be a TypedArray or a DataView",
);
}
const der = new DefaultDeserializer(buffer);
der.readHeader();
return der.readValue();
}
const kHandle = Symbol("kHandle");
export class Serializer {
[kHandle]: object;
constructor() {
warnNotImplemented("v8.Serializer.prototype.constructor");
this[kHandle] = op_v8_new_serializer(this);
}
_setTreatArrayBufferViewsAsHostObjects(value: boolean): void {
op_v8_set_treat_array_buffer_views_as_host_objects(this[kHandle], value);
}
releaseBuffer(): Buffer {
warnNotImplemented("v8.DefaultSerializer.prototype.releaseBuffer");
return Buffer.from("");
return Buffer.from(op_v8_release_buffer(this[kHandle]));
}
transferArrayBuffer(_id: number, _arrayBuffer: ArrayBuffer): void {
warnNotImplemented("v8.DefaultSerializer.prototype.transferArrayBuffer");
op_v8_transfer_array_buffer(this[kHandle], _id, _arrayBuffer);
}
writeDouble(_value: number): void {
warnNotImplemented("v8.DefaultSerializer.prototype.writeDouble");
writeDouble(value: number): void {
op_v8_write_double(this[kHandle], value);
}
writeHeader(): void {
warnNotImplemented("v8.DefaultSerializer.prototype.writeHeader");
op_v8_write_header(this[kHandle]);
}
writeRawBytes(_value: ArrayBufferView): void {
warnNotImplemented("v8.DefaultSerializer.prototype.writeRawBytes");
writeRawBytes(source: ArrayBufferView): void {
if (!isArrayBufferView(source)) {
throw new TypeError(
"source must be a TypedArray or a DataView",
);
}
op_v8_write_raw_bytes(this[kHandle], source);
}
writeUint32(_value: number): void {
warnNotImplemented("v8.DefaultSerializer.prototype.writeUint32");
writeUint32(value: number): void {
op_v8_write_uint32(this[kHandle], value);
}
writeUint64(_hi: number, _lo: number): void {
warnNotImplemented("v8.DefaultSerializer.prototype.writeUint64");
writeUint64(hi: number, lo: number): void {
op_v8_write_uint64(this[kHandle], hi, lo);
}
// deno-lint-ignore no-explicit-any
writeValue(_value: any): void {
warnNotImplemented("v8.DefaultSerializer.prototype.writeValue");
writeValue(value: any): void {
op_v8_write_value(this[kHandle], value);
}
_getDataCloneError = Error;
}
export class Deserializer {
buffer: ArrayBufferView;
[kHandle]: object;
constructor(buffer: ArrayBufferView) {
if (!isArrayBufferView(buffer)) {
throw new TypeError(
"buffer must be a TypedArray or a DataView",
);
}
this.buffer = buffer;
this[kHandle] = op_v8_new_deserializer(this, buffer);
}
readRawBytes(length: number): Buffer {
const offset = this._readRawBytes(length);
return Buffer.from(
this.buffer.buffer,
this.buffer.byteOffset + offset,
length,
);
}
_readRawBytes(length: number): number {
return op_v8_read_raw_bytes(this[kHandle], length);
}
getWireFormatVersion(): number {
return op_v8_get_wire_format_version(this[kHandle]);
}
readDouble(): number {
return op_v8_read_double(this[kHandle]);
}
readHeader(): boolean {
return op_v8_read_header(this[kHandle]);
}
readUint32(): number {
return op_v8_read_uint32(this[kHandle]);
}
readUint64(): [hi: number, lo: number] {
return op_v8_read_uint64(this[kHandle]);
}
readValue(): unknown {
return op_v8_read_value(this[kHandle]);
}
transferArrayBuffer(
id: number,
arrayBuffer: ArrayBuffer | SharedArrayBuffer,
): void {
return op_v8_transfer_array_buffer_de(this[kHandle], id, arrayBuffer);
}
}
export class Deserializer {
constructor() {
notImplemented("v8.Deserializer.prototype.constructor");
}
function arrayBufferViewTypeToIndex(abView: ArrayBufferView) {
const type = ObjectPrototypeToString(abView);
if (type === "[object Int8Array]") return 0;
if (type === "[object Uint8Array]") return 1;
if (type === "[object Uint8ClampedArray]") return 2;
if (type === "[object Int16Array]") return 3;
if (type === "[object Uint16Array]") return 4;
if (type === "[object Int32Array]") return 5;
if (type === "[object Uint32Array]") return 6;
if (type === "[object Float32Array]") return 7;
if (type === "[object Float64Array]") return 8;
if (type === "[object DataView]") return 9;
// Index 10 is FastBuffer.
if (type === "[object BigInt64Array]") return 11;
if (type === "[object BigUint64Array]") return 12;
return -1;
}
export class DefaultSerializer extends Serializer {
constructor() {
warnNotImplemented("v8.DefaultSerializer.prototype.constructor");
super();
this._setTreatArrayBufferViewsAsHostObjects(true);
}
// deno-lint-ignore no-explicit-any
_writeHostObject(abView: any) {
// Keep track of how to handle different ArrayBufferViews. The default
// Serializer for Node does not use the V8 methods for serializing those
// objects because Node's `Buffer` objects use pooled allocation in many
// cases, and their underlying `ArrayBuffer`s would show up in the
// serialization. Because a) those may contain sensitive data and the user
// may not be aware of that and b) they are often much larger than the
// `Buffer` itself, custom serialization is applied.
let i = 10; // FastBuffer
if (abView.constructor !== Buffer) {
i = arrayBufferViewTypeToIndex(abView);
if (i === -1) {
throw new this._getDataCloneError(
`Unserializable host object: ${abView}`,
);
}
}
this.writeUint32(i);
this.writeUint32(abView.byteLength);
this.writeRawBytes(
new Uint8Array(abView.buffer, abView.byteOffset, abView.byteLength),
);
}
}
export class DefaultDeserializer {
constructor() {
notImplemented("v8.DefaultDeserializer.prototype.constructor");
// deno-lint-ignore no-explicit-any
function arrayBufferViewIndexToType(index: number): any {
if (index === 0) return Int8Array;
if (index === 1) return Uint8Array;
if (index === 2) return Uint8ClampedArray;
if (index === 3) return Int16Array;
if (index === 4) return Uint16Array;
if (index === 5) return Int32Array;
if (index === 6) return Uint32Array;
if (index === 7) return Float32Array;
if (index === 8) return Float64Array;
if (index === 9) return DataView;
if (index === 10) return Buffer;
if (index === 11) return BigInt64Array;
if (index === 12) return BigUint64Array;
return undefined;
}
export class DefaultDeserializer extends Deserializer {
constructor(buffer: ArrayBufferView) {
super(buffer);
}
_readHostObject() {
const typeIndex = this.readUint32();
const ctor = arrayBufferViewIndexToType(typeIndex);
const byteLength = this.readUint32();
const byteOffset = this._readRawBytes(byteLength);
const BYTES_PER_ELEMENT = ctor?.BYTES_PER_ELEMENT ?? 1;
const offset = this.buffer.byteOffset + byteOffset;
if (offset % BYTES_PER_ELEMENT === 0) {
return new ctor(
this.buffer.buffer,
offset,
byteLength / BYTES_PER_ELEMENT,
);
}
// Copy to an aligned buffer first.
const bufferCopy = Buffer.allocUnsafe(byteLength);
Buffer.from(
this.buffer.buffer,
byteOffset,
byteLength,
).copy(bufferCopy);
return new ctor(
bufferCopy.buffer,
bufferCopy.byteOffset,
byteLength / BYTES_PER_ELEMENT,
);
}
}
export const promiseHooks = {

View file

@ -34,7 +34,7 @@ const kParsingContext = Symbol("script parsing context");
export class Script {
#inner;
constructor(code, options = {}) {
constructor(code, options = { __proto__: null }) {
code = `${code}`;
if (typeof options === "string") {
options = { filename: options };
@ -80,7 +80,7 @@ export class Script {
: undefined;
}
#runInContext(contextifiedObject, options = {}) {
#runInContext(contextifiedObject, options = { __proto__: null }) {
validateObject(options, "options");
let timeout = options.timeout;
@ -181,7 +181,10 @@ function getContextOptions(options) {
}
let defaultContextNameIndex = 1;
export function createContext(contextObject = {}, options = {}) {
export function createContext(
contextObject = {},
options = { __proto__: null },
) {
if (isContext(contextObject)) {
return contextObject;
}
@ -276,7 +279,7 @@ export function isContext(object) {
return op_vm_is_context(object);
}
export function compileFunction(code, params, options = {}) {
export function compileFunction(code, params, options = { __proto__: null }) {
validateString(code, "code");
if (params !== undefined) {
validateStringArray(params, "params");

View file

@ -267,7 +267,7 @@ class NodeWorker extends EventEmitter {
}
};
postMessage(message, transferOrOptions = {}) {
postMessage(message, transferOrOptions = { __proto__: null }) {
const prefix = "Failed to execute 'postMessage' on 'MessagePort'";
webidl.requiredArguments(arguments.length, 1, prefix);
message = webidl.converters.any(message);

View file

@ -186,7 +186,7 @@ const entries = ObjectEntries({
});
for (let i = 0; i < entries.length; ++i) {
const { 0: key, 1: value } = entries[i];
const desc = { value, enumerable: true };
const desc = { __proto__: null, value, enumerable: true };
ObjectDefineProperty(DOMException, key, desc);
ObjectDefineProperty(DOMException.prototype, key, desc);
}

View file

@ -392,6 +392,7 @@ const EventPrototype = Event.prototype;
// Not spec compliant. The spec defines it as [LegacyUnforgeable]
// but doing so has a big performance hit
ReflectDefineProperty(Event.prototype, "isTrusted", {
__proto__: null,
enumerable: true,
get: isTrusted,
});
@ -402,7 +403,10 @@ function defineEnumerableProps(
) {
for (let i = 0; i < props.length; ++i) {
const prop = props[i];
ReflectDefineProperty(Ctor.prototype, prop, { enumerable: true });
ReflectDefineProperty(Ctor.prototype, prop, {
__proto__: null,
enumerable: true,
});
}
}
@ -1274,6 +1278,7 @@ class CustomEvent extends Event {
const CustomEventPrototype = CustomEvent.prototype;
ReflectDefineProperty(CustomEvent.prototype, "detail", {
__proto__: null,
enumerable: true,
});
@ -1417,6 +1422,7 @@ function defineEventHandler(
) {
// HTML specification section 8.1.7.1
ObjectDefineProperty(emitter, `on${name}`, {
__proto__: null,
get() {
if (!this[_eventHandlers]) {
return null;

View file

@ -5420,6 +5420,7 @@ class ReadableStream {
// TODO(lucacasonato): should be moved to webidl crate
ReadableStream.prototype[SymbolAsyncIterator] = ReadableStream.prototype.values;
ObjectDefineProperty(ReadableStream.prototype, SymbolAsyncIterator, {
__proto__: null,
writable: true,
enumerable: false,
configurable: true,

View file

@ -454,36 +454,42 @@ webidl.configureInterface(FileReader);
const FileReaderPrototype = FileReader.prototype;
ObjectDefineProperty(FileReader, "EMPTY", {
__proto__: null,
writable: false,
enumerable: true,
configurable: false,
value: 0,
});
ObjectDefineProperty(FileReader, "LOADING", {
__proto__: null,
writable: false,
enumerable: true,
configurable: false,
value: 1,
});
ObjectDefineProperty(FileReader, "DONE", {
__proto__: null,
writable: false,
enumerable: true,
configurable: false,
value: 2,
});
ObjectDefineProperty(FileReader.prototype, "EMPTY", {
__proto__: null,
writable: false,
enumerable: true,
configurable: false,
value: 0,
});
ObjectDefineProperty(FileReader.prototype, "LOADING", {
__proto__: null,
writable: false,
enumerable: true,
configurable: false,
value: 1,
});
ObjectDefineProperty(FileReader.prototype, "DONE", {
__proto__: null,
writable: false,
enumerable: true,
configurable: false,

View file

@ -35,6 +35,7 @@ class Location {
url.password = "";
ObjectDefineProperties(this, {
hash: {
__proto__: null,
get() {
return url.hash;
},
@ -47,6 +48,7 @@ class Location {
enumerable: true,
},
host: {
__proto__: null,
get() {
return url.host;
},
@ -59,6 +61,7 @@ class Location {
enumerable: true,
},
hostname: {
__proto__: null,
get() {
return url.hostname;
},
@ -71,6 +74,7 @@ class Location {
enumerable: true,
},
href: {
__proto__: null,
get() {
return url.href;
},
@ -83,12 +87,14 @@ class Location {
enumerable: true,
},
origin: {
__proto__: null,
get() {
return url.origin;
},
enumerable: true,
},
pathname: {
__proto__: null,
get() {
return url.pathname;
},
@ -101,6 +107,7 @@ class Location {
enumerable: true,
},
port: {
__proto__: null,
get() {
return url.port;
},
@ -113,6 +120,7 @@ class Location {
enumerable: true,
},
protocol: {
__proto__: null,
get() {
return url.protocol;
},
@ -125,6 +133,7 @@ class Location {
enumerable: true,
},
search: {
__proto__: null,
get() {
return url.search;
},
@ -137,6 +146,7 @@ class Location {
enumerable: true,
},
ancestorOrigins: {
__proto__: null,
get() {
// TODO(nayeemrmn): Replace with a `DOMStringList` instance.
return {
@ -148,6 +158,7 @@ class Location {
enumerable: true,
},
assign: {
__proto__: null,
value: function assign() {
throw new DOMException(
`Cannot call "location.assign()".`,
@ -157,6 +168,7 @@ class Location {
enumerable: true,
},
reload: {
__proto__: null,
value: function reload() {
throw new DOMException(
`Cannot call "location.reload()".`,
@ -166,6 +178,7 @@ class Location {
enumerable: true,
},
replace: {
__proto__: null,
value: function replace() {
throw new DOMException(
`Cannot call "location.replace()".`,
@ -175,12 +188,14 @@ class Location {
enumerable: true,
},
toString: {
__proto__: null,
value: function toString() {
return url.href;
},
enumerable: true,
},
[SymbolFor("Deno.privateCustomInspect")]: {
__proto__: null,
value: function (inspect, inspectOptions) {
return `${this.constructor.name} ${
inspect({
@ -203,6 +218,7 @@ class Location {
ObjectDefineProperties(Location.prototype, {
[SymbolToStringTag]: {
__proto__: null,
value: "Location",
configurable: true,
},
@ -224,6 +240,7 @@ class WorkerLocation {
ObjectDefineProperties(WorkerLocation.prototype, {
hash: {
__proto__: null,
get() {
const url = WeakMapPrototypeGet(workerLocationUrls, this);
if (url == null) {
@ -235,6 +252,7 @@ ObjectDefineProperties(WorkerLocation.prototype, {
enumerable: true,
},
host: {
__proto__: null,
get() {
const url = WeakMapPrototypeGet(workerLocationUrls, this);
if (url == null) {
@ -246,6 +264,7 @@ ObjectDefineProperties(WorkerLocation.prototype, {
enumerable: true,
},
hostname: {
__proto__: null,
get() {
const url = WeakMapPrototypeGet(workerLocationUrls, this);
if (url == null) {
@ -257,6 +276,7 @@ ObjectDefineProperties(WorkerLocation.prototype, {
enumerable: true,
},
href: {
__proto__: null,
get() {
const url = WeakMapPrototypeGet(workerLocationUrls, this);
if (url == null) {
@ -268,6 +288,7 @@ ObjectDefineProperties(WorkerLocation.prototype, {
enumerable: true,
},
origin: {
__proto__: null,
get() {
const url = WeakMapPrototypeGet(workerLocationUrls, this);
if (url == null) {
@ -279,6 +300,7 @@ ObjectDefineProperties(WorkerLocation.prototype, {
enumerable: true,
},
pathname: {
__proto__: null,
get() {
const url = WeakMapPrototypeGet(workerLocationUrls, this);
if (url == null) {
@ -290,6 +312,7 @@ ObjectDefineProperties(WorkerLocation.prototype, {
enumerable: true,
},
port: {
__proto__: null,
get() {
const url = WeakMapPrototypeGet(workerLocationUrls, this);
if (url == null) {
@ -301,6 +324,7 @@ ObjectDefineProperties(WorkerLocation.prototype, {
enumerable: true,
},
protocol: {
__proto__: null,
get() {
const url = WeakMapPrototypeGet(workerLocationUrls, this);
if (url == null) {
@ -312,6 +336,7 @@ ObjectDefineProperties(WorkerLocation.prototype, {
enumerable: true,
},
search: {
__proto__: null,
get() {
const url = WeakMapPrototypeGet(workerLocationUrls, this);
if (url == null) {
@ -323,6 +348,7 @@ ObjectDefineProperties(WorkerLocation.prototype, {
enumerable: true,
},
toString: {
__proto__: null,
value: function toString() {
const url = WeakMapPrototypeGet(workerLocationUrls, this);
if (url == null) {
@ -335,10 +361,12 @@ ObjectDefineProperties(WorkerLocation.prototype, {
writable: true,
},
[SymbolToStringTag]: {
__proto__: null,
value: "WorkerLocation",
configurable: true,
},
[SymbolFor("Deno.privateCustomInspect")]: {
__proto__: null,
value: function (inspect, inspectOptions) {
return `${this.constructor.name} ${
inspect({

View file

@ -132,14 +132,17 @@ class MessagePort extends EventTarget {
constructor() {
super();
ObjectDefineProperty(this, MessagePortReceiveMessageOnPortSymbol, {
__proto__: null,
value: false,
enumerable: false,
});
ObjectDefineProperty(this, nodeWorkerThreadCloseCb, {
__proto__: null,
value: null,
enumerable: false,
});
ObjectDefineProperty(this, nodeWorkerThreadCloseCbInvoked, {
__proto__: null,
value: false,
enumerable: false,
});

View file

@ -907,6 +907,7 @@ const GPUDeviceLostInfoPrototype = GPUDeviceLostInfo.prototype;
function GPUObjectBaseMixin(name, type) {
type.prototype[_label] = null;
ObjectDefineProperty(type.prototype, "label", {
__proto__: null,
/**
* @return {string | null}
*/

View file

@ -753,6 +753,7 @@ function createDictionaryConverter(name, ...dictionaries) {
defaultValues[member.key] = member.converter(idlMemberValue, {});
} else {
ObjectDefineProperty(defaultValues, member.key, {
__proto__: null,
get() {
return member.converter(idlMemberValue, member.defaultValue);
},
@ -1076,6 +1077,7 @@ function mixinPairIterable(name, prototype, dataSymbol, keyKey, valueKey) {
function createDefaultIterator(target, kind) {
const iterator = ObjectCreate(iteratorPrototype);
ObjectDefineProperty(iterator, _iteratorInternal, {
__proto__: null,
value: { target, kind, index: 0 },
configurable: true,
});
@ -1149,6 +1151,7 @@ function configureInterface(interface_) {
configureProperties(interface_);
configureProperties(interface_.prototype);
ObjectDefineProperty(interface_.prototype, SymbolToStringTag, {
__proto__: null,
value: interface_.name,
enumerable: false,
configurable: true,
@ -1170,12 +1173,14 @@ function configureProperties(obj) {
typeof descriptor.value === "function"
) {
ObjectDefineProperty(obj, key, {
__proto__: null,
enumerable: true,
writable: true,
configurable: true,
});
} else if (ReflectHas(descriptor, "get")) {
ObjectDefineProperty(obj, key, {
__proto__: null,
enumerable: true,
configurable: true,
});
@ -1189,6 +1194,7 @@ const setlikeInner = Symbol("[[set]]");
function setlike(obj, objPrototype, readonly) {
ObjectDefineProperties(obj, {
size: {
__proto__: null,
configurable: true,
enumerable: true,
get() {
@ -1197,6 +1203,7 @@ function setlike(obj, objPrototype, readonly) {
},
},
[SymbolIterator]: {
__proto__: null,
configurable: true,
enumerable: false,
writable: true,
@ -1206,6 +1213,7 @@ function setlike(obj, objPrototype, readonly) {
},
},
entries: {
__proto__: null,
configurable: true,
enumerable: true,
writable: true,
@ -1215,6 +1223,7 @@ function setlike(obj, objPrototype, readonly) {
},
},
keys: {
__proto__: null,
configurable: true,
enumerable: true,
writable: true,
@ -1224,6 +1233,7 @@ function setlike(obj, objPrototype, readonly) {
},
},
values: {
__proto__: null,
configurable: true,
enumerable: true,
writable: true,
@ -1233,6 +1243,7 @@ function setlike(obj, objPrototype, readonly) {
},
},
forEach: {
__proto__: null,
configurable: true,
enumerable: true,
writable: true,
@ -1242,6 +1253,7 @@ function setlike(obj, objPrototype, readonly) {
},
},
has: {
__proto__: null,
configurable: true,
enumerable: true,
writable: true,
@ -1255,6 +1267,7 @@ function setlike(obj, objPrototype, readonly) {
if (!readonly) {
ObjectDefineProperties(obj, {
add: {
__proto__: null,
configurable: true,
enumerable: true,
writable: true,
@ -1264,6 +1277,7 @@ function setlike(obj, objPrototype, readonly) {
},
},
delete: {
__proto__: null,
configurable: true,
enumerable: true,
writable: true,
@ -1273,6 +1287,7 @@ function setlike(obj, objPrototype, readonly) {
},
},
clear: {
__proto__: null,
configurable: true,
enumerable: true,
writable: true,

View file

@ -627,15 +627,19 @@ class WebSocket extends EventTarget {
ObjectDefineProperties(WebSocket, {
CONNECTING: {
__proto__: null,
value: 0,
},
OPEN: {
__proto__: null,
value: 1,
},
CLOSING: {
__proto__: null,
value: 2,
},
CLOSED: {
__proto__: null,
value: 3,
},
});

View file

@ -11,7 +11,7 @@ const AUTOBAHN_TESTSUITE_DOCKER =
"crossbario/autobahn-testsuite:0.8.2@sha256:5d4ba3aa7d6ab2fdbf6606f3f4ecbe4b66f205ce1cbc176d6cdf650157e52242";
const self = Deno.execPath();
$`${self} run -A --unstable --config ${pwd}/../../../tests/config/deno.json ${pwd}/autobahn_server.js`
$`${self} run -A --config ${pwd}/../../../tests/config/deno.json ${pwd}/autobahn_server.js`
.spawn();
for (let i = 0; i < 6; i++) {

View file

@ -119,6 +119,7 @@ function createStorage(persistent) {
set(target, key, value) {
if (typeof key === "symbol") {
return ReflectDefineProperty(target, key, {
__proto__: null,
value,
configurable: true,
});

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