Skip to content

Commit e1d6d3c

Browse files
Merge branch 'main' into f_cache_env_file
2 parents 083f823 + fc74cfe commit e1d6d3c

File tree

23 files changed

+292
-69
lines changed

23 files changed

+292
-69
lines changed

cli/lsp/diagnostics.rs

+24-13
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use deno_core::unsync::spawn_blocking;
2525
use deno_core::unsync::JoinHandle;
2626
use deno_core::url::Url;
2727
use deno_core::ModuleSpecifier;
28+
use deno_graph::source::ResolutionKind;
2829
use deno_graph::source::ResolveError;
2930
use deno_graph::Resolution;
3031
use deno_graph::ResolutionError;
@@ -40,6 +41,7 @@ use import_map::ImportMap;
4041
use import_map::ImportMapErrorKind;
4142
use log::error;
4243
use lsp_types::Uri;
44+
use node_resolver::NodeResolutionKind;
4345
use tokio::sync::mpsc;
4446
use tokio::sync::Mutex as AsyncMutex;
4547
use tokio::time::Duration;
@@ -1577,10 +1579,12 @@ fn maybe_ambient_specifier_resolution_err(
15771579
}
15781580
}
15791581

1582+
#[allow(clippy::too_many_arguments)]
15801583
fn diagnose_resolution(
15811584
snapshot: &language_server::StateSnapshot,
15821585
dependency_key: &str,
15831586
resolution: &Resolution,
1587+
resolution_kind: ResolutionKind,
15841588
is_dynamic: bool,
15851589
maybe_assert_type: Option<&str>,
15861590
referrer_module: &DocumentModule,
@@ -1647,6 +1651,7 @@ fn diagnose_resolution(
16471651
.npm_to_file_url(
16481652
&pkg_ref,
16491653
&referrer_module.specifier,
1654+
NodeResolutionKind::from_deno_graph(resolution_kind),
16501655
referrer_module.resolution_mode,
16511656
)
16521657
.is_none()
@@ -1774,22 +1779,27 @@ fn diagnose_dependency(
17741779
.includes(i.specifier_range.range.start)
17751780
.is_some()
17761781
});
1777-
1782+
let resolution;
1783+
let resolution_kind;
1784+
if dependency.maybe_code.is_none()
1785+
// If not @ts-types, diagnose the types if the code errored because
1786+
// it's likely resolving into the node_modules folder, which might be
1787+
// erroring correctly due to resolution only being for bundlers. Let this
1788+
// fail at runtime if necessary, but don't bother erroring in the editor
1789+
|| !is_types_deno_types && matches!(dependency.maybe_type, Resolution::Ok(_))
1790+
&& matches!(dependency.maybe_code, Resolution::Err(_))
1791+
{
1792+
resolution = &dependency.maybe_type;
1793+
resolution_kind = ResolutionKind::Types;
1794+
} else {
1795+
resolution = &dependency.maybe_code;
1796+
resolution_kind = ResolutionKind::Execution;
1797+
};
17781798
let (resolution_diagnostics, deferred) = diagnose_resolution(
17791799
snapshot,
17801800
dependency_key,
1781-
if dependency.maybe_code.is_none()
1782-
// If not @ts-types, diagnose the types if the code errored because
1783-
// it's likely resolving into the node_modules folder, which might be
1784-
// erroring correctly due to resolution only being for bundlers. Let this
1785-
// fail at runtime if necessary, but don't bother erroring in the editor
1786-
|| !is_types_deno_types && matches!(dependency.maybe_type, Resolution::Ok(_))
1787-
&& matches!(dependency.maybe_code, Resolution::Err(_))
1788-
{
1789-
&dependency.maybe_type
1790-
} else {
1791-
&dependency.maybe_code
1792-
},
1801+
resolution,
1802+
resolution_kind,
17931803
dependency.is_dynamic,
17941804
dependency.maybe_attribute_type.as_deref(),
17951805
referrer_module,
@@ -1825,6 +1835,7 @@ fn diagnose_dependency(
18251835
snapshot,
18261836
dependency_key,
18271837
&dependency.maybe_type,
1838+
ResolutionKind::Types,
18281839
dependency.is_dynamic,
18291840
dependency.maybe_attribute_type.as_deref(),
18301841
referrer_module,

cli/lsp/documents.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1633,8 +1633,12 @@ impl DocumentModules {
16331633
let mut media_type = None;
16341634
if let Ok(npm_ref) = NpmPackageReqReference::from_specifier(&specifier) {
16351635
let scoped_resolver = self.resolver.get_scoped_resolver(scope);
1636-
let (s, mt) =
1637-
scoped_resolver.npm_to_file_url(&npm_ref, referrer, resolution_mode)?;
1636+
let (s, mt) = scoped_resolver.npm_to_file_url(
1637+
&npm_ref,
1638+
referrer,
1639+
NodeResolutionKind::Types,
1640+
resolution_mode,
1641+
)?;
16381642
specifier = s;
16391643
media_type = Some(mt);
16401644
}

cli/lsp/resolver.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ impl LspScopedResolver {
353353
&self,
354354
req_ref: &NpmPackageReqReference,
355355
referrer: &ModuleSpecifier,
356+
resolution_kind: NodeResolutionKind,
356357
resolution_mode: ResolutionMode,
357358
) -> Option<(ModuleSpecifier, MediaType)> {
358359
let npm_pkg_req_resolver = self.npm_pkg_req_resolver.as_ref()?;
@@ -363,7 +364,7 @@ impl LspScopedResolver {
363364
req_ref,
364365
referrer,
365366
resolution_mode,
366-
NodeResolutionKind::Types,
367+
resolution_kind,
367368
)
368369
.ok()?
369370
.into_url()

cli/lsp/tsc.rs

+2
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ use lazy_regex::lazy_regex;
5252
use log::error;
5353
use lsp_types::Uri;
5454
use node_resolver::cache::NodeResolutionThreadLocalCache;
55+
use node_resolver::NodeResolutionKind;
5556
use node_resolver::ResolutionMode;
5657
use once_cell::sync::Lazy;
5758
use regex::Captures;
@@ -4875,6 +4876,7 @@ fn op_script_names(state: &mut OpState) -> ScriptNames {
48754876
let Some((resolved, _)) = scoped_resolver.npm_to_file_url(
48764877
&req_ref,
48774878
scope,
4879+
NodeResolutionKind::Types,
48784880
ResolutionMode::Import,
48794881
) else {
48804882
lsp_log!("failed to resolve {req_ref} to file URL");

ext/canvas/01_image.js

+3-12
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,9 @@ function createImageBitmap(
250250
if (isBlob) {
251251
imageBitmapSource = 0;
252252
buf = new Uint8Array(await image.arrayBuffer());
253-
const mimeTypeString = sniffImage(image.type);
253+
// NOTE: The MIME type of image/svg+xml can't support
254+
// https://github.com/whatwg/html/pull/10172
255+
const mimeTypeString = sniffImage(null, buf);
254256

255257
if (mimeTypeString === "image/png") {
256258
mimeType = 1;
@@ -280,17 +282,6 @@ function createImageBitmap(
280282
"InvalidStateError",
281283
),
282284
);
283-
} else if (mimeTypeString === "") {
284-
return PromiseReject(
285-
new DOMException(
286-
`The MIME type of source image is not specified\n
287-
hint: When you want to get a "Blob" from "fetch", make sure to go through a file server that returns the appropriate content-type response header,
288-
and specify the URL to the file server like "await(await fetch('http://localhost:8000/sample.png').blob()".
289-
Alternatively, if you are reading a local file using 'Deno.readFile' etc.,
290-
set the appropriate MIME type like "new Blob([await Deno.readFile('sample.png')], { type: 'image/png' })".\n`,
291-
"InvalidStateError",
292-
),
293-
);
294285
} else {
295286
return PromiseReject(
296287
new DOMException(

ext/fetch/dns.rs

+55
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::future::Future;
33
use std::io;
44
use std::net::SocketAddr;
55
use std::pin::Pin;
6+
use std::sync::Arc;
67
use std::task::Poll;
78
use std::task::{self};
89
use std::vec;
@@ -19,6 +20,24 @@ pub enum Resolver {
1920
Gai(GaiResolver),
2021
/// hickory-resolver's userspace resolver.
2122
Hickory(hickory_resolver::Resolver<TokioConnectionProvider>),
23+
/// A custom resolver that implements `Resolve`.
24+
Custom(Arc<dyn Resolve>),
25+
}
26+
27+
/// Alias for the `Future` type returned by a custom DNS resolver.
28+
// The future has to be `Send` as `tokio::spawn` is used to execute the future.
29+
pub type Resolving =
30+
Pin<Box<dyn Future<Output = Result<SocketAddrs, io::Error>> + Send>>;
31+
32+
/// A trait for customizing DNS resolution in ext/fetch.
33+
// The resolver needs to be `Send` and `Sync` for two reasons. One is it is
34+
// wrapped inside an `Arc` and will be cloned and moved to an async block to
35+
// perfrom DNS resolution. That async block will be executed by `tokio::spawn`,
36+
// so to make that async block `Send`, `Arc<dyn Resolve>` needs to be
37+
// `Send`. The other is `Resolver` needs to be `Send` to make the wrapping
38+
// `HttpConnector` `Send`.
39+
pub trait Resolve: Send + Sync + std::fmt::Debug {
40+
fn resolve(&self, name: Name) -> Resolving;
2241
}
2342

2443
impl Default for Resolver {
@@ -107,7 +126,43 @@ impl Service<Name> for Resolver {
107126
Ok(iter)
108127
})
109128
}
129+
Resolver::Custom(resolver) => {
130+
let resolver = resolver.clone();
131+
tokio::spawn(async move { resolver.resolve(name).await })
132+
}
110133
};
111134
ResolveFut { inner: task }
112135
}
113136
}
137+
138+
#[cfg(test)]
139+
mod tests {
140+
use std::str::FromStr;
141+
142+
use super::*;
143+
144+
// A resolver that resolves any name into the same address.
145+
#[derive(Debug)]
146+
struct DebugResolver(SocketAddr);
147+
148+
impl Resolve for DebugResolver {
149+
fn resolve(&self, _name: Name) -> Resolving {
150+
let addr = self.0;
151+
Box::pin(async move { Ok(vec![addr].into_iter()) })
152+
}
153+
}
154+
155+
#[tokio::test]
156+
async fn custom_dns_resolver() {
157+
let mut resolver = Resolver::Custom(Arc::new(DebugResolver(
158+
"127.0.0.1:8080".parse().unwrap(),
159+
)));
160+
let mut addr = resolver
161+
.call(Name::from_str("foo.com").unwrap())
162+
.await
163+
.unwrap();
164+
165+
let addr = addr.next().unwrap();
166+
assert_eq!(addr, "127.0.0.1:8080".parse().unwrap());
167+
}
168+
}

ext/net/01_net.js

+12
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
op_net_recv_unixpacket,
2828
op_net_send_udp,
2929
op_net_send_unixpacket,
30+
op_net_set_broadcast_udp,
3031
op_net_set_multi_loopback_udp,
3132
op_net_set_multi_ttl_udp,
3233
op_set_keepalive,
@@ -377,6 +378,12 @@ class Listener {
377378
}
378379
}
379380

381+
const _setBroadcast = Symbol("setBroadcast");
382+
383+
function setDatagramBroadcast(conn, broadcast) {
384+
return conn[_setBroadcast](broadcast);
385+
}
386+
380387
class DatagramConn {
381388
#rid = 0;
382389
#addr = null;
@@ -393,6 +400,10 @@ class DatagramConn {
393400
return this.#addr;
394401
}
395402

403+
[_setBroadcast](broadcast) {
404+
op_net_set_broadcast_udp(this.#rid, broadcast);
405+
}
406+
396407
async joinMulticastV4(addr, multiInterface) {
397408
await op_net_join_multi_v4_udp(
398409
this.#rid,
@@ -688,6 +699,7 @@ export {
688699
Listener,
689700
listenOptionApiName,
690701
resolveDns,
702+
setDatagramBroadcast,
691703
TcpConn,
692704
UnixConn,
693705
UpgradedConn,

ext/net/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ deno_core::extension!(deno_net,
156156
ops::op_net_leave_multi_v6_udp,
157157
ops::op_net_set_multi_loopback_udp,
158158
ops::op_net_set_multi_ttl_udp,
159+
ops::op_net_set_broadcast_udp,
159160
ops::op_dns_resolve<P>,
160161
ops::op_set_nodelay,
161162
ops::op_set_keepalive,

ext/net/ops.rs

+17
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,23 @@ pub async fn op_net_set_multi_ttl_udp(
390390
Ok(())
391391
}
392392

393+
#[op2(async)]
394+
pub async fn op_net_set_broadcast_udp(
395+
state: Rc<RefCell<OpState>>,
396+
#[smi] rid: ResourceId,
397+
broadcast: bool,
398+
) -> Result<(), NetError> {
399+
let resource = state
400+
.borrow_mut()
401+
.resource_table
402+
.get::<UdpSocketResource>(rid)
403+
.map_err(|_| NetError::SocketClosed)?;
404+
let socket = RcRef::map(&resource, |r| &r.socket).borrow().await;
405+
socket.set_broadcast(broadcast)?;
406+
407+
Ok(())
408+
}
409+
393410
/// If this token is present in op_net_connect_tcp call and
394411
/// the hostname matches with one of the resolved IPs, then
395412
/// the permission check is performed against the original hostname.

ext/node/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,7 @@ deno_core::extension!(deno_node,
458458
ops::require::op_require_package_imports_resolve<P, TInNpmPackageChecker, TNpmPackageFolderResolver, TSys>,
459459
ops::require::op_require_break_on_next_statement,
460460
ops::util::op_node_guess_handle_type,
461+
ops::util::op_node_view_has_buffer,
461462
ops::worker_threads::op_worker_threads_filename<P, TSys>,
462463
ops::ipc::op_node_child_ipc_pipe,
463464
ops::ipc::op_node_ipc_write,

ext/node/ops/util.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright 2018-2025 the Deno authors. MIT license.
22

33
use deno_core::op2;
4+
use deno_core::v8;
45
use deno_core::OpState;
56
use deno_core::ResourceHandle;
67
use deno_core::ResourceHandleFd;
@@ -80,3 +81,8 @@ fn guess_handle_type(handle: ResourceHandleFd) -> HandleType {
8081
_ => HandleType::Unknown,
8182
}
8283
}
84+
85+
#[op2(fast)]
86+
pub fn op_node_view_has_buffer(buffer: v8::Local<v8::ArrayBufferView>) -> bool {
87+
buffer.has_buffer()
88+
}

ext/node/polyfills/internal/dgram.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@
2020
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
2121
// USE OR OTHER DEALINGS IN THE SOFTWARE.
2222

23-
// TODO(petamoriken): enable prefer-primordials for node polyfills
24-
// deno-lint-ignore-file prefer-primordials
25-
2623
import { lookup as defaultLookup } from "node:dns";
2724
import {
2825
isInt32,
@@ -33,6 +30,8 @@ import { ERR_SOCKET_BAD_TYPE } from "ext:deno_node/internal/errors.ts";
3330
import { UDP } from "ext:deno_node/internal_binding/udp_wrap.ts";
3431
import { guessHandleType } from "ext:deno_node/internal_binding/util.ts";
3532
import { codeMap } from "ext:deno_node/internal_binding/uv.ts";
33+
import { primordials } from "ext:core/mod.js";
34+
const { FunctionPrototypeBind, MapPrototypeGet, Symbol } = primordials;
3635

3736
export type SocketType = "udp4" | "udp6";
3837

@@ -75,15 +74,15 @@ export function newHandle(
7574
if (type === "udp4") {
7675
const handle = new UDP();
7776

78-
handle.lookup = lookup4.bind(handle, lookup);
77+
handle.lookup = FunctionPrototypeBind(lookup4, handle, lookup);
7978

8079
return handle;
8180
}
8281

8382
if (type === "udp6") {
8483
const handle = new UDP();
8584

86-
handle.lookup = lookup6.bind(handle, lookup);
85+
handle.lookup = FunctionPrototypeBind(lookup6, handle, lookup);
8786
handle.bind = handle.bind6;
8887
handle.connect = handle.connect6;
8988
handle.send = handle.send6;
@@ -108,11 +107,12 @@ export function _createSocketHandle(
108107
const type = guessHandleType(fd);
109108

110109
if (type !== "UDP") {
111-
err = codeMap.get("EINVAL")!;
110+
err = MapPrototypeGet(codeMap, "EINVAL")!;
112111
} else {
113112
err = handle.open(fd);
114113
}
115114
} else if (port || address) {
115+
// deno-lint-ignore prefer-primordials
116116
err = handle.bind(address, port || 0, flags);
117117
}
118118

0 commit comments

Comments
 (0)