Skip to content

Commit 8be2bbf

Browse files
authored
feat: Wasm module support (#26668)
Support for Wasm modules. Note this implements the standard where the default export is the instance (not the module). The module will come later with source phase imports. ```ts import { add } from "./math.wasm"; console.log(add(1, 2)); ```
1 parent 6b478cd commit 8be2bbf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+401
-46
lines changed

Cargo.lock

+8-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ repository = "https://github.com/denoland/deno"
4646

4747
[workspace.dependencies]
4848
deno_ast = { version = "=0.43.3", features = ["transpiling"] }
49-
deno_core = { version = "0.320.0" }
49+
deno_core = { version = "0.321.0" }
5050

5151
deno_bench_util = { version = "0.171.0", path = "./bench_util" }
5252
deno_config = { version = "=0.39.1", features = ["workspace", "sync"] }

cli/args/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1548,6 +1548,10 @@ impl CliOptions {
15481548
}) => Url::parse(&flags.module_url)
15491549
.ok()
15501550
.map(|url| vec![Cow::Owned(url)]),
1551+
DenoSubcommand::Doc(DocFlags {
1552+
source_files: DocSourceFileFlag::Paths(paths),
1553+
..
1554+
}) => Some(files_to_urls(paths)),
15511555
_ => None,
15521556
})
15531557
.unwrap_or_default();

cli/errors.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ fn get_module_graph_error_class(err: &ModuleGraphError) -> &'static str {
3838
ModuleGraphError::ModuleError(err) => match err {
3939
ModuleError::InvalidTypeAssertion { .. } => "SyntaxError",
4040
ModuleError::ParseErr(_, diagnostic) => get_diagnostic_class(diagnostic),
41+
ModuleError::WasmParseErr(..) => "SyntaxError",
4142
ModuleError::UnsupportedMediaType { .. }
4243
| ModuleError::UnsupportedImportAttributeType { .. } => "TypeError",
4344
ModuleError::Missing(_, _) | ModuleError::MissingDynamic(_, _) => {
@@ -71,7 +72,6 @@ fn get_module_graph_error_class(err: &ModuleGraphError) -> &'static str {
7172
| JsrLoadError::UnknownExport { .. } => "NotFound",
7273
},
7374
},
74-
ModuleError::WasmParseErr(_, _) => "SyntaxError",
7575
},
7676
}
7777
}

cli/lsp/documents.rs

+33-5
Original file line numberDiff line numberDiff line change
@@ -883,8 +883,13 @@ impl FileSystemDocuments {
883883
let doc = if specifier.scheme() == "file" {
884884
let path = url_to_file_path(specifier).ok()?;
885885
let bytes = fs::read(path).ok()?;
886-
let content =
887-
deno_graph::source::decode_owned_source(specifier, bytes, None).ok()?;
886+
let content = bytes_to_content(
887+
specifier,
888+
MediaType::from_specifier(specifier),
889+
bytes,
890+
None,
891+
)
892+
.ok()?;
888893
Document::new(
889894
specifier.clone(),
890895
content.into(),
@@ -923,19 +928,24 @@ impl FileSystemDocuments {
923928
specifier,
924929
Some(&cached_file.metadata.headers),
925930
);
926-
let content = deno_graph::source::decode_owned_source(
931+
let media_type = resolve_media_type(
932+
specifier,
933+
Some(&cached_file.metadata.headers),
934+
None,
935+
);
936+
let content = bytes_to_content(
927937
specifier,
938+
media_type,
928939
cached_file.content,
929940
maybe_charset,
930941
)
931942
.ok()?;
932-
let maybe_headers = Some(cached_file.metadata.headers);
933943
Document::new(
934944
specifier.clone(),
935945
content.into(),
936946
None,
937947
None,
938-
maybe_headers,
948+
Some(cached_file.metadata.headers),
939949
is_cjs_resolver,
940950
resolver.clone(),
941951
config.clone(),
@@ -1706,6 +1716,24 @@ fn analyze_module(
17061716
}
17071717
}
17081718

1719+
fn bytes_to_content(
1720+
specifier: &ModuleSpecifier,
1721+
media_type: MediaType,
1722+
bytes: Vec<u8>,
1723+
maybe_charset: Option<&str>,
1724+
) -> Result<String, AnyError> {
1725+
if media_type == MediaType::Wasm {
1726+
// we use the dts representation for Wasm modules
1727+
Ok(deno_graph::source::wasm::wasm_module_to_dts(&bytes)?)
1728+
} else {
1729+
Ok(deno_graph::source::decode_owned_source(
1730+
specifier,
1731+
bytes,
1732+
maybe_charset,
1733+
)?)
1734+
}
1735+
}
1736+
17091737
#[cfg(test)]
17101738
mod tests {
17111739
use super::*;

cli/lsp/tsc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5609,7 +5609,7 @@ mod tests {
56095609
let (_tx, rx) = mpsc::unbounded_channel();
56105610
let state =
56115611
State::new(state_snapshot, Default::default(), Default::default(), rx);
5612-
let mut op_state = OpState::new(None);
5612+
let mut op_state = OpState::new(None, None);
56135613
op_state.put(state);
56145614
op_state
56155615
}

cli/module_loader.rs

+13-3
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ use deno_graph::JsonModule;
6666
use deno_graph::Module;
6767
use deno_graph::ModuleGraph;
6868
use deno_graph::Resolution;
69+
use deno_graph::WasmModule;
6970
use deno_runtime::code_cache;
7071
use deno_runtime::deno_fs::FileSystem;
7172
use deno_runtime::deno_node::create_host_defined_options;
@@ -368,7 +369,9 @@ impl<TGraphContainer: ModuleGraphContainer>
368369
requested_module_type: RequestedModuleType,
369370
) -> Result<ModuleSource, AnyError> {
370371
let code_source = self.load_code_source(specifier, maybe_referrer).await?;
371-
let code = if self.shared.is_inspecting {
372+
let code = if self.shared.is_inspecting
373+
|| code_source.media_type == MediaType::Wasm
374+
{
372375
// we need the code with the source map in order for
373376
// it to work with --inspect or --inspect-brk
374377
code_source.code
@@ -378,6 +381,7 @@ impl<TGraphContainer: ModuleGraphContainer>
378381
};
379382
let module_type = match code_source.media_type {
380383
MediaType::Json => ModuleType::Json,
384+
MediaType::Wasm => ModuleType::Wasm,
381385
_ => ModuleType::JavaScript,
382386
};
383387

@@ -545,14 +549,14 @@ impl<TGraphContainer: ModuleGraphContainer>
545549
Some(Module::Node(module)) => module.specifier.clone(),
546550
Some(Module::Js(module)) => module.specifier.clone(),
547551
Some(Module::Json(module)) => module.specifier.clone(),
552+
Some(Module::Wasm(module)) => module.specifier.clone(),
548553
Some(Module::External(module)) => {
549554
node::resolve_specifier_into_node_modules(
550555
&module.specifier,
551556
self.shared.fs.as_ref(),
552557
)
553558
}
554559
None => specifier.into_owned(),
555-
Some(Module::Wasm(_)) => todo!("@dsherret"),
556560
};
557561
Ok(specifier)
558562
}
@@ -717,13 +721,19 @@ impl<TGraphContainer: ModuleGraphContainer>
717721
media_type: *media_type,
718722
})))
719723
}
724+
Some(deno_graph::Module::Wasm(WasmModule {
725+
source, specifier, ..
726+
})) => Ok(Some(CodeOrDeferredEmit::Code(ModuleCodeStringSource {
727+
code: ModuleSourceCode::Bytes(source.clone().into()),
728+
found_url: specifier.clone(),
729+
media_type: MediaType::Wasm,
730+
}))),
720731
Some(
721732
deno_graph::Module::External(_)
722733
| deno_graph::Module::Node(_)
723734
| deno_graph::Module::Npm(_),
724735
)
725736
| None => Ok(None),
726-
Some(deno_graph::Module::Wasm(_)) => todo!("@dsherret"),
727737
}
728738
}
729739

cli/standalone/binary.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -675,10 +675,12 @@ impl<'a> DenoCompileBinaryWriter<'a> {
675675
deno_graph::Module::Json(m) => {
676676
(Some(m.source.as_bytes().to_vec()), m.media_type)
677677
}
678+
deno_graph::Module::Wasm(m) => {
679+
(Some(m.source.to_vec()), MediaType::Wasm)
680+
}
678681
deno_graph::Module::Npm(_)
679682
| deno_graph::Module::Node(_)
680683
| deno_graph::Module::External(_) => (None, MediaType::Unknown),
681-
deno_graph::Module::Wasm(_) => todo!("@dsherret"),
682684
};
683685
if module.specifier().scheme() == "file" {
684686
let file_path = deno_path_util::url_to_file_path(module.specifier())?;

cli/tools/check.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -380,10 +380,14 @@ fn get_check_hash(
380380
hasher.write_str(module.specifier.as_str());
381381
hasher.write_str(&module.source);
382382
}
383+
Module::Wasm(module) => {
384+
has_file_to_type_check = true;
385+
hasher.write_str(module.specifier.as_str());
386+
hasher.write_str(&module.source_dts);
387+
}
383388
Module::External(module) => {
384389
hasher.write_str(module.specifier.as_str());
385390
}
386-
Module::Wasm(_) => todo!("@dsherret"),
387391
}
388392
}
389393

@@ -438,11 +442,11 @@ fn get_tsc_roots(
438442
| MediaType::SourceMap
439443
| MediaType::Unknown => None,
440444
},
445+
Module::Wasm(module) => Some((module.specifier.clone(), MediaType::Dmts)),
441446
Module::External(_)
442447
| Module::Node(_)
443448
| Module::Npm(_)
444449
| Module::Json(_) => None,
445-
Module::Wasm(_) => todo!("@dsherret"),
446450
}
447451
}
448452

cli/tools/info.rs

+16-8
Original file line numberDiff line numberDiff line change
@@ -446,8 +446,8 @@ impl<'a> GraphDisplayContext<'a> {
446446
let maybe_cache_info = match root {
447447
Module::Js(module) => module.maybe_cache_info.as_ref(),
448448
Module::Json(module) => module.maybe_cache_info.as_ref(),
449+
Module::Wasm(module) => module.maybe_cache_info.as_ref(),
449450
Module::Node(_) | Module::Npm(_) | Module::External(_) => None,
450-
Module::Wasm(_) => todo!("@dsherret"),
451451
};
452452
if let Some(cache_info) = maybe_cache_info {
453453
if let Some(local) = &cache_info.local {
@@ -469,8 +469,8 @@ impl<'a> GraphDisplayContext<'a> {
469469
let size = match m {
470470
Module::Js(module) => module.size(),
471471
Module::Json(module) => module.size(),
472+
Module::Wasm(module) => module.size(),
472473
Module::Node(_) | Module::Npm(_) | Module::External(_) => 0,
473-
Module::Wasm(_) => todo!("@dsherret"),
474474
};
475475
size as f64
476476
})
@@ -569,8 +569,8 @@ impl<'a> GraphDisplayContext<'a> {
569569
Specifier(_) => match module {
570570
Module::Js(module) => Some(module.size() as u64),
571571
Module::Json(module) => Some(module.size() as u64),
572+
Module::Wasm(module) => Some(module.size() as u64),
572573
Module::Node(_) | Module::Npm(_) | Module::External(_) => None,
573-
Module::Wasm(_) => todo!("@dsherret"),
574574
},
575575
};
576576
format!("{} {}", header_text, maybe_size_to_text(maybe_size))
@@ -583,8 +583,8 @@ impl<'a> GraphDisplayContext<'a> {
583583
Package(package) => {
584584
tree_node.children.extend(self.build_npm_deps(package));
585585
}
586-
Specifier(_) => {
587-
if let Some(module) = module.js() {
586+
Specifier(_) => match module {
587+
Module::Js(module) => {
588588
if let Some(types_dep) = &module.maybe_types_dependency {
589589
if let Some(child) =
590590
self.build_resolved_info(&types_dep.dependency, true)
@@ -596,7 +596,16 @@ impl<'a> GraphDisplayContext<'a> {
596596
tree_node.children.extend(self.build_dep_info(dep));
597597
}
598598
}
599-
}
599+
Module::Wasm(module) => {
600+
for dep in module.dependencies.values() {
601+
tree_node.children.extend(self.build_dep_info(dep));
602+
}
603+
}
604+
Module::Json(_)
605+
| Module::Npm(_)
606+
| Module::Node(_)
607+
| Module::External(_) => {}
608+
},
600609
}
601610
}
602611
tree_node
@@ -661,7 +670,7 @@ impl<'a> GraphDisplayContext<'a> {
661670
};
662671
self.build_error_msg(specifier, message.as_ref())
663672
}
664-
ModuleError::ParseErr(_, _) => {
673+
ModuleError::ParseErr(_, _) | ModuleError::WasmParseErr(_, _) => {
665674
self.build_error_msg(specifier, "(parsing error)")
666675
}
667676
ModuleError::UnsupportedImportAttributeType { .. } => {
@@ -673,7 +682,6 @@ impl<'a> GraphDisplayContext<'a> {
673682
ModuleError::Missing(_, _) | ModuleError::MissingDynamic(_, _) => {
674683
self.build_error_msg(specifier, "(missing)")
675684
}
676-
ModuleError::WasmParseErr(_, _) => todo!("@dsherret"),
677685
}
678686
}
679687

cli/tools/registry/mod.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ use deno_core::serde_json;
2626
use deno_core::serde_json::json;
2727
use deno_core::serde_json::Value;
2828
use deno_core::url::Url;
29-
use deno_graph::Module;
3029
use deno_terminal::colors;
3130
use http_body_util::BodyExt;
3231
use serde::Deserialize;
@@ -1108,13 +1107,12 @@ fn collect_excluded_module_diagnostics(
11081107
let graph_specifiers = graph
11091108
.modules()
11101109
.filter_map(|m| match m {
1111-
deno_graph::Module::Js(_) | deno_graph::Module::Json(_) => {
1112-
Some(m.specifier())
1113-
}
1110+
deno_graph::Module::Js(_)
1111+
| deno_graph::Module::Json(_)
1112+
| deno_graph::Module::Wasm(_) => Some(m.specifier()),
11141113
deno_graph::Module::Npm(_)
11151114
| deno_graph::Module::Node(_)
11161115
| deno_graph::Module::External(_) => None,
1117-
Module::Wasm(_) => todo!("@dsherret"),
11181116
})
11191117
.filter(|s| s.as_str().starts_with(root.as_str()));
11201118
for specifier in graph_specifiers {

cli/tsc/99_main_compiler.js

+6
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,12 @@ delete Object.prototype.__proto__;
450450
// We specify the resolution mode to be CommonJS for some npm files and this
451451
// diagnostic gets generated even though we're using custom module resolution.
452452
1452,
453+
// Module '...' cannot be imported using this construct. The specifier only resolves to an
454+
// ES module, which cannot be imported with 'require'.
455+
1471,
456+
// TS1479: The current file is a CommonJS module whose imports will produce 'require' calls;
457+
// however, the referenced file is an ECMAScript module and cannot be imported with 'require'.
458+
1479,
453459
// TS2306: File '.../index.d.ts' is not a module.
454460
// We get this for `x-typescript-types` declaration files which don't export
455461
// anything. We prefer to treat these as modules with no exports.

0 commit comments

Comments
 (0)