1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-21 05:42:25 -05:00

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));
```
This commit is contained in:
David Sherret 2024-11-19 18:59:23 -05:00 committed by GitHub
parent 6b478cd0a3
commit 8be2bbf074
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
60 changed files with 401 additions and 46 deletions

14
Cargo.lock generated
View file

@ -1466,9 +1466,9 @@ dependencies = [
[[package]] [[package]]
name = "deno_core" name = "deno_core"
version = "0.320.0" version = "0.321.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f285eed7b072749f9c3a9c4cf2c9ebb06462a2c22afec94892a6684c38f32696" checksum = "cd2a54cda74cdc187d5fc2d23370a45cf09f912caf566dd1cd24a50157d809c7"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -1480,6 +1480,7 @@ dependencies = [
"deno_ops", "deno_ops",
"deno_unsync", "deno_unsync",
"futures", "futures",
"indexmap 2.3.0",
"libc", "libc",
"memoffset", "memoffset",
"parking_lot", "parking_lot",
@ -1494,6 +1495,7 @@ dependencies = [
"tokio", "tokio",
"url", "url",
"v8", "v8",
"wasm_dep_analyzer",
] ]
[[package]] [[package]]
@ -1981,9 +1983,9 @@ dependencies = [
[[package]] [[package]]
name = "deno_ops" name = "deno_ops"
version = "0.196.0" version = "0.197.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d35c75ae05062f37ec2ae5fd1d99b2dcdfa0aef70844d3706759b8775056c5f6" checksum = "37a8825d92301cf445727c43f17fee2a20fcdf4370004339965156ae7c56c97e"
dependencies = [ dependencies = [
"proc-macro-rules", "proc-macro-rules",
"proc-macro2", "proc-macro2",
@ -6517,9 +6519,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_v8" name = "serde_v8"
version = "0.229.0" version = "0.230.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e1dbbda82d67a393ea96f75d8383bc41fcd0bba43164aeaab599e1c2c2d46d7" checksum = "b5a783242d2af51d6955cc04bf2b64adb643ab588b61e9573c908a69dabf8c2f"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"serde", "serde",

View file

@ -46,7 +46,7 @@ repository = "https://github.com/denoland/deno"
[workspace.dependencies] [workspace.dependencies]
deno_ast = { version = "=0.43.3", features = ["transpiling"] } deno_ast = { version = "=0.43.3", features = ["transpiling"] }
deno_core = { version = "0.320.0" } deno_core = { version = "0.321.0" }
deno_bench_util = { version = "0.171.0", path = "./bench_util" } deno_bench_util = { version = "0.171.0", path = "./bench_util" }
deno_config = { version = "=0.39.1", features = ["workspace", "sync"] } deno_config = { version = "=0.39.1", features = ["workspace", "sync"] }

View file

@ -1548,6 +1548,10 @@ impl CliOptions {
}) => Url::parse(&flags.module_url) }) => Url::parse(&flags.module_url)
.ok() .ok()
.map(|url| vec![Cow::Owned(url)]), .map(|url| vec![Cow::Owned(url)]),
DenoSubcommand::Doc(DocFlags {
source_files: DocSourceFileFlag::Paths(paths),
..
}) => Some(files_to_urls(paths)),
_ => None, _ => None,
}) })
.unwrap_or_default(); .unwrap_or_default();

View file

@ -38,6 +38,7 @@ fn get_module_graph_error_class(err: &ModuleGraphError) -> &'static str {
ModuleGraphError::ModuleError(err) => match err { ModuleGraphError::ModuleError(err) => match err {
ModuleError::InvalidTypeAssertion { .. } => "SyntaxError", ModuleError::InvalidTypeAssertion { .. } => "SyntaxError",
ModuleError::ParseErr(_, diagnostic) => get_diagnostic_class(diagnostic), ModuleError::ParseErr(_, diagnostic) => get_diagnostic_class(diagnostic),
ModuleError::WasmParseErr(..) => "SyntaxError",
ModuleError::UnsupportedMediaType { .. } ModuleError::UnsupportedMediaType { .. }
| ModuleError::UnsupportedImportAttributeType { .. } => "TypeError", | ModuleError::UnsupportedImportAttributeType { .. } => "TypeError",
ModuleError::Missing(_, _) | ModuleError::MissingDynamic(_, _) => { ModuleError::Missing(_, _) | ModuleError::MissingDynamic(_, _) => {
@ -71,7 +72,6 @@ fn get_module_graph_error_class(err: &ModuleGraphError) -> &'static str {
| JsrLoadError::UnknownExport { .. } => "NotFound", | JsrLoadError::UnknownExport { .. } => "NotFound",
}, },
}, },
ModuleError::WasmParseErr(_, _) => "SyntaxError",
}, },
} }
} }

View file

@ -883,8 +883,13 @@ impl FileSystemDocuments {
let doc = if specifier.scheme() == "file" { let doc = if specifier.scheme() == "file" {
let path = url_to_file_path(specifier).ok()?; let path = url_to_file_path(specifier).ok()?;
let bytes = fs::read(path).ok()?; let bytes = fs::read(path).ok()?;
let content = let content = bytes_to_content(
deno_graph::source::decode_owned_source(specifier, bytes, None).ok()?; specifier,
MediaType::from_specifier(specifier),
bytes,
None,
)
.ok()?;
Document::new( Document::new(
specifier.clone(), specifier.clone(),
content.into(), content.into(),
@ -923,19 +928,24 @@ impl FileSystemDocuments {
specifier, specifier,
Some(&cached_file.metadata.headers), Some(&cached_file.metadata.headers),
); );
let content = deno_graph::source::decode_owned_source( let media_type = resolve_media_type(
specifier, specifier,
Some(&cached_file.metadata.headers),
None,
);
let content = bytes_to_content(
specifier,
media_type,
cached_file.content, cached_file.content,
maybe_charset, maybe_charset,
) )
.ok()?; .ok()?;
let maybe_headers = Some(cached_file.metadata.headers);
Document::new( Document::new(
specifier.clone(), specifier.clone(),
content.into(), content.into(),
None, None,
None, None,
maybe_headers, Some(cached_file.metadata.headers),
is_cjs_resolver, is_cjs_resolver,
resolver.clone(), resolver.clone(),
config.clone(), config.clone(),
@ -1706,6 +1716,24 @@ fn analyze_module(
} }
} }
fn bytes_to_content(
specifier: &ModuleSpecifier,
media_type: MediaType,
bytes: Vec<u8>,
maybe_charset: Option<&str>,
) -> Result<String, AnyError> {
if media_type == MediaType::Wasm {
// we use the dts representation for Wasm modules
Ok(deno_graph::source::wasm::wasm_module_to_dts(&bytes)?)
} else {
Ok(deno_graph::source::decode_owned_source(
specifier,
bytes,
maybe_charset,
)?)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View file

@ -5609,7 +5609,7 @@ mod tests {
let (_tx, rx) = mpsc::unbounded_channel(); let (_tx, rx) = mpsc::unbounded_channel();
let state = let state =
State::new(state_snapshot, Default::default(), Default::default(), rx); State::new(state_snapshot, Default::default(), Default::default(), rx);
let mut op_state = OpState::new(None); let mut op_state = OpState::new(None, None);
op_state.put(state); op_state.put(state);
op_state op_state
} }

View file

@ -66,6 +66,7 @@ use deno_graph::JsonModule;
use deno_graph::Module; use deno_graph::Module;
use deno_graph::ModuleGraph; use deno_graph::ModuleGraph;
use deno_graph::Resolution; use deno_graph::Resolution;
use deno_graph::WasmModule;
use deno_runtime::code_cache; use deno_runtime::code_cache;
use deno_runtime::deno_fs::FileSystem; use deno_runtime::deno_fs::FileSystem;
use deno_runtime::deno_node::create_host_defined_options; use deno_runtime::deno_node::create_host_defined_options;
@ -368,7 +369,9 @@ impl<TGraphContainer: ModuleGraphContainer>
requested_module_type: RequestedModuleType, requested_module_type: RequestedModuleType,
) -> Result<ModuleSource, AnyError> { ) -> Result<ModuleSource, AnyError> {
let code_source = self.load_code_source(specifier, maybe_referrer).await?; let code_source = self.load_code_source(specifier, maybe_referrer).await?;
let code = if self.shared.is_inspecting { let code = if self.shared.is_inspecting
|| code_source.media_type == MediaType::Wasm
{
// we need the code with the source map in order for // we need the code with the source map in order for
// it to work with --inspect or --inspect-brk // it to work with --inspect or --inspect-brk
code_source.code code_source.code
@ -378,6 +381,7 @@ impl<TGraphContainer: ModuleGraphContainer>
}; };
let module_type = match code_source.media_type { let module_type = match code_source.media_type {
MediaType::Json => ModuleType::Json, MediaType::Json => ModuleType::Json,
MediaType::Wasm => ModuleType::Wasm,
_ => ModuleType::JavaScript, _ => ModuleType::JavaScript,
}; };
@ -545,6 +549,7 @@ impl<TGraphContainer: ModuleGraphContainer>
Some(Module::Node(module)) => module.specifier.clone(), Some(Module::Node(module)) => module.specifier.clone(),
Some(Module::Js(module)) => module.specifier.clone(), Some(Module::Js(module)) => module.specifier.clone(),
Some(Module::Json(module)) => module.specifier.clone(), Some(Module::Json(module)) => module.specifier.clone(),
Some(Module::Wasm(module)) => module.specifier.clone(),
Some(Module::External(module)) => { Some(Module::External(module)) => {
node::resolve_specifier_into_node_modules( node::resolve_specifier_into_node_modules(
&module.specifier, &module.specifier,
@ -552,7 +557,6 @@ impl<TGraphContainer: ModuleGraphContainer>
) )
} }
None => specifier.into_owned(), None => specifier.into_owned(),
Some(Module::Wasm(_)) => todo!("@dsherret"),
}; };
Ok(specifier) Ok(specifier)
} }
@ -717,13 +721,19 @@ impl<TGraphContainer: ModuleGraphContainer>
media_type: *media_type, media_type: *media_type,
}))) })))
} }
Some(deno_graph::Module::Wasm(WasmModule {
source, specifier, ..
})) => Ok(Some(CodeOrDeferredEmit::Code(ModuleCodeStringSource {
code: ModuleSourceCode::Bytes(source.clone().into()),
found_url: specifier.clone(),
media_type: MediaType::Wasm,
}))),
Some( Some(
deno_graph::Module::External(_) deno_graph::Module::External(_)
| deno_graph::Module::Node(_) | deno_graph::Module::Node(_)
| deno_graph::Module::Npm(_), | deno_graph::Module::Npm(_),
) )
| None => Ok(None), | None => Ok(None),
Some(deno_graph::Module::Wasm(_)) => todo!("@dsherret"),
} }
} }

View file

@ -675,10 +675,12 @@ impl<'a> DenoCompileBinaryWriter<'a> {
deno_graph::Module::Json(m) => { deno_graph::Module::Json(m) => {
(Some(m.source.as_bytes().to_vec()), m.media_type) (Some(m.source.as_bytes().to_vec()), m.media_type)
} }
deno_graph::Module::Wasm(m) => {
(Some(m.source.to_vec()), MediaType::Wasm)
}
deno_graph::Module::Npm(_) deno_graph::Module::Npm(_)
| deno_graph::Module::Node(_) | deno_graph::Module::Node(_)
| deno_graph::Module::External(_) => (None, MediaType::Unknown), | deno_graph::Module::External(_) => (None, MediaType::Unknown),
deno_graph::Module::Wasm(_) => todo!("@dsherret"),
}; };
if module.specifier().scheme() == "file" { if module.specifier().scheme() == "file" {
let file_path = deno_path_util::url_to_file_path(module.specifier())?; let file_path = deno_path_util::url_to_file_path(module.specifier())?;

View file

@ -380,10 +380,14 @@ fn get_check_hash(
hasher.write_str(module.specifier.as_str()); hasher.write_str(module.specifier.as_str());
hasher.write_str(&module.source); hasher.write_str(&module.source);
} }
Module::Wasm(module) => {
has_file_to_type_check = true;
hasher.write_str(module.specifier.as_str());
hasher.write_str(&module.source_dts);
}
Module::External(module) => { Module::External(module) => {
hasher.write_str(module.specifier.as_str()); hasher.write_str(module.specifier.as_str());
} }
Module::Wasm(_) => todo!("@dsherret"),
} }
} }
@ -438,11 +442,11 @@ fn get_tsc_roots(
| MediaType::SourceMap | MediaType::SourceMap
| MediaType::Unknown => None, | MediaType::Unknown => None,
}, },
Module::Wasm(module) => Some((module.specifier.clone(), MediaType::Dmts)),
Module::External(_) Module::External(_)
| Module::Node(_) | Module::Node(_)
| Module::Npm(_) | Module::Npm(_)
| Module::Json(_) => None, | Module::Json(_) => None,
Module::Wasm(_) => todo!("@dsherret"),
} }
} }

View file

@ -446,8 +446,8 @@ impl<'a> GraphDisplayContext<'a> {
let maybe_cache_info = match root { let maybe_cache_info = match root {
Module::Js(module) => module.maybe_cache_info.as_ref(), Module::Js(module) => module.maybe_cache_info.as_ref(),
Module::Json(module) => module.maybe_cache_info.as_ref(), Module::Json(module) => module.maybe_cache_info.as_ref(),
Module::Wasm(module) => module.maybe_cache_info.as_ref(),
Module::Node(_) | Module::Npm(_) | Module::External(_) => None, Module::Node(_) | Module::Npm(_) | Module::External(_) => None,
Module::Wasm(_) => todo!("@dsherret"),
}; };
if let Some(cache_info) = maybe_cache_info { if let Some(cache_info) = maybe_cache_info {
if let Some(local) = &cache_info.local { if let Some(local) = &cache_info.local {
@ -469,8 +469,8 @@ impl<'a> GraphDisplayContext<'a> {
let size = match m { let size = match m {
Module::Js(module) => module.size(), Module::Js(module) => module.size(),
Module::Json(module) => module.size(), Module::Json(module) => module.size(),
Module::Wasm(module) => module.size(),
Module::Node(_) | Module::Npm(_) | Module::External(_) => 0, Module::Node(_) | Module::Npm(_) | Module::External(_) => 0,
Module::Wasm(_) => todo!("@dsherret"),
}; };
size as f64 size as f64
}) })
@ -569,8 +569,8 @@ impl<'a> GraphDisplayContext<'a> {
Specifier(_) => match module { Specifier(_) => match module {
Module::Js(module) => Some(module.size() as u64), Module::Js(module) => Some(module.size() as u64),
Module::Json(module) => Some(module.size() as u64), Module::Json(module) => Some(module.size() as u64),
Module::Wasm(module) => Some(module.size() as u64),
Module::Node(_) | Module::Npm(_) | Module::External(_) => None, Module::Node(_) | Module::Npm(_) | Module::External(_) => None,
Module::Wasm(_) => todo!("@dsherret"),
}, },
}; };
format!("{} {}", header_text, maybe_size_to_text(maybe_size)) format!("{} {}", header_text, maybe_size_to_text(maybe_size))
@ -583,8 +583,8 @@ impl<'a> GraphDisplayContext<'a> {
Package(package) => { Package(package) => {
tree_node.children.extend(self.build_npm_deps(package)); tree_node.children.extend(self.build_npm_deps(package));
} }
Specifier(_) => { Specifier(_) => match module {
if let Some(module) = module.js() { Module::Js(module) => {
if let Some(types_dep) = &module.maybe_types_dependency { if let Some(types_dep) = &module.maybe_types_dependency {
if let Some(child) = if let Some(child) =
self.build_resolved_info(&types_dep.dependency, true) self.build_resolved_info(&types_dep.dependency, true)
@ -596,7 +596,16 @@ impl<'a> GraphDisplayContext<'a> {
tree_node.children.extend(self.build_dep_info(dep)); tree_node.children.extend(self.build_dep_info(dep));
} }
} }
} Module::Wasm(module) => {
for dep in module.dependencies.values() {
tree_node.children.extend(self.build_dep_info(dep));
}
}
Module::Json(_)
| Module::Npm(_)
| Module::Node(_)
| Module::External(_) => {}
},
} }
} }
tree_node tree_node
@ -661,7 +670,7 @@ impl<'a> GraphDisplayContext<'a> {
}; };
self.build_error_msg(specifier, message.as_ref()) self.build_error_msg(specifier, message.as_ref())
} }
ModuleError::ParseErr(_, _) => { ModuleError::ParseErr(_, _) | ModuleError::WasmParseErr(_, _) => {
self.build_error_msg(specifier, "(parsing error)") self.build_error_msg(specifier, "(parsing error)")
} }
ModuleError::UnsupportedImportAttributeType { .. } => { ModuleError::UnsupportedImportAttributeType { .. } => {
@ -673,7 +682,6 @@ impl<'a> GraphDisplayContext<'a> {
ModuleError::Missing(_, _) | ModuleError::MissingDynamic(_, _) => { ModuleError::Missing(_, _) | ModuleError::MissingDynamic(_, _) => {
self.build_error_msg(specifier, "(missing)") self.build_error_msg(specifier, "(missing)")
} }
ModuleError::WasmParseErr(_, _) => todo!("@dsherret"),
} }
} }

View file

@ -26,7 +26,6 @@ use deno_core::serde_json;
use deno_core::serde_json::json; use deno_core::serde_json::json;
use deno_core::serde_json::Value; use deno_core::serde_json::Value;
use deno_core::url::Url; use deno_core::url::Url;
use deno_graph::Module;
use deno_terminal::colors; use deno_terminal::colors;
use http_body_util::BodyExt; use http_body_util::BodyExt;
use serde::Deserialize; use serde::Deserialize;
@ -1108,13 +1107,12 @@ fn collect_excluded_module_diagnostics(
let graph_specifiers = graph let graph_specifiers = graph
.modules() .modules()
.filter_map(|m| match m { .filter_map(|m| match m {
deno_graph::Module::Js(_) | deno_graph::Module::Json(_) => { deno_graph::Module::Js(_)
Some(m.specifier()) | deno_graph::Module::Json(_)
} | deno_graph::Module::Wasm(_) => Some(m.specifier()),
deno_graph::Module::Npm(_) deno_graph::Module::Npm(_)
| deno_graph::Module::Node(_) | deno_graph::Module::Node(_)
| deno_graph::Module::External(_) => None, | deno_graph::Module::External(_) => None,
Module::Wasm(_) => todo!("@dsherret"),
}) })
.filter(|s| s.as_str().starts_with(root.as_str())); .filter(|s| s.as_str().starts_with(root.as_str()));
for specifier in graph_specifiers { for specifier in graph_specifiers {

View file

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

View file

@ -650,6 +650,10 @@ fn op_load_inner(
media_type = MediaType::Json; media_type = MediaType::Json;
Some(Cow::Borrowed(&*module.source)) Some(Cow::Borrowed(&*module.source))
} }
Module::Wasm(module) => {
media_type = MediaType::Dts;
Some(Cow::Borrowed(&*module.source_dts))
}
Module::Npm(_) | Module::Node(_) => None, Module::Npm(_) | Module::Node(_) => None,
Module::External(module) => { Module::External(module) => {
// means it's Deno code importing an npm module // means it's Deno code importing an npm module
@ -664,7 +668,6 @@ fn op_load_inner(
&mut is_cjs, &mut is_cjs,
)?)) )?))
} }
Module::Wasm(_) => todo!("@dsherret"),
} }
} else if let Some(npm) = state } else if let Some(npm) = state
.maybe_npm .maybe_npm
@ -890,6 +893,9 @@ fn resolve_graph_specifier_types(
Some(Module::Json(module)) => { Some(Module::Json(module)) => {
Ok(Some((module.specifier.clone(), module.media_type))) Ok(Some((module.specifier.clone(), module.media_type)))
} }
Some(Module::Wasm(module)) => {
Ok(Some((module.specifier.clone(), MediaType::Dmts)))
}
Some(Module::Npm(module)) => { Some(Module::Npm(module)) => {
if let Some(npm) = &state.maybe_npm.as_ref() { if let Some(npm) = &state.maybe_npm.as_ref() {
let package_folder = npm let package_folder = npm
@ -929,7 +935,6 @@ fn resolve_graph_specifier_types(
})) }))
} }
Some(Module::Node(_)) | None => Ok(None), Some(Module::Node(_)) | None => Ok(None),
Some(Module::Wasm(_)) => todo!("@dsherret"),
} }
} }
@ -1198,7 +1203,7 @@ mod tests {
.context("Unable to get CWD") .context("Unable to get CWD")
.unwrap(), .unwrap(),
); );
let mut op_state = OpState::new(None); let mut op_state = OpState::new(None, None);
op_state.put(state); op_state.put(state);
op_state op_state
} }

View file

@ -1086,12 +1086,10 @@ function loadESMFromCJS(module, filename, code) {
module.exports = namespace; module.exports = namespace;
} }
Module._extensions[".mjs"] = Module._extensions[".mts"] = function ( Module._extensions[".mjs"] =
module, Module._extensions[".mts"] =
filename, Module._extensions[".wasm"] =
) { loadESMFromCJS;
loadESMFromCJS(module, filename);
};
function stripBOM(content) { function stripBOM(content) {
if (StringPrototypeCharCodeAt(content, 0) === 0xfeff) { if (StringPrototypeCharCodeAt(content, 0) === 0xfeff) {

View file

@ -78,7 +78,7 @@ pub fn validate_import_attributes_callback(
for (key, value) in attributes { for (key, value) in attributes {
let msg = if key != "type" { let msg = if key != "type" {
Some(format!("\"{key}\" attribute is not supported.")) Some(format!("\"{key}\" attribute is not supported."))
} else if value != "json" { } else if value != "json" && value != "$$deno-core-internal-wasm-module" {
Some(format!("\"{value}\" is not a valid module type.")) Some(format!("\"{value}\" is not a valid module type."))
} else { } else {
None None

View file

@ -5427,7 +5427,8 @@ fn lsp_code_actions_deno_cache() {
let res = let res =
client client
.write_request( "textDocument/codeAction", .write_request(
"textDocument/codeAction",
json!({ json!({
"textDocument": { "textDocument": {
"uri": "file:///a/file.ts" "uri": "file:///a/file.ts"
@ -5453,8 +5454,7 @@ fn lsp_code_actions_deno_cache() {
"only": ["quickfix"] "only": ["quickfix"]
} }
}), }),
) );
;
assert_eq!( assert_eq!(
res, res,
json!([{ json!([{
@ -16516,3 +16516,47 @@ fn lsp_jsdoc_named_example() {
}), }),
); );
} }
#[test]
fn lsp_wasm_module() {
let context = TestContextBuilder::new()
.use_temp_cwd()
.use_http_server()
.build();
let mut client = context.new_lsp_command().build();
client.initialize_default();
client.did_open(json!({
"textDocument": {
"uri": "file:///a/file.ts",
"languageId": "typescript",
"version": 1,
"text": "import { add } from \"http://localhost:4545/wasm/math.wasm\";\nadd(1, '');\n"
}
}));
client.write_request(
"workspace/executeCommand",
json!({
"command": "deno.cache",
"arguments": [[], "file:///a/file.ts"],
}),
);
let diagnostics = client.read_diagnostics();
assert_eq!(
json!(diagnostics.all()),
json!([
{
"range": {
"start": { "line": 1, "character": 7 },
"end": { "line": 1, "character": 9 }
},
"severity": 1,
"code": 2345,
"source": "deno-ts",
"message": "Argument of type 'string' is not assignable to parameter of type 'number'."
}
])
);
client.shutdown();
}

View file

@ -0,0 +1,5 @@
{
"args": "check --allow-import main.ts",
"output": "check.out",
"exitCode": 1
}

View file

@ -0,0 +1,6 @@
Download http://localhost:4545/wasm/math.wasm
Check file:///[WILDLINE]/main.ts
error: TS2345 [ERROR]: Argument of type 'string' is not assignable to parameter of type 'number'.
console.log(add(1, ""));
~~
at file:///[WILDLINE]/main.ts:3:20

View file

@ -0,0 +1,3 @@
import { add } from "http://localhost:4545/wasm/math.wasm";
console.log(add(1, ""));

View file

@ -0,0 +1,4 @@
{
"args": "doc http://localhost:4545/wasm/math.wasm",
"output": "doc.out"
}

View file

@ -0,0 +1,21 @@
Download http://localhost:4545/wasm/math.wasm
Defined in http://localhost:4545/wasm/math.wasm:2:1
function add(arg0: number, arg1: number): number
Defined in http://localhost:4545/wasm/math.wasm:3:1
function subtract(arg0: number, arg1: number): number
Defined in http://localhost:4545/wasm/math.wasm:4:22
const __data_end: number
Defined in http://localhost:4545/wasm/math.wasm:5:22
const __heap_base: number
Defined in http://localhost:4545/wasm/math.wasm:1:22
const memory: WebAssembly.Memory

View file

@ -0,0 +1,4 @@
{
"args": "info --allow-import main.js",
"output": "main.out"
}

View file

@ -0,0 +1,7 @@
import {
add,
subtract,
} from "http://localhost:4545/wasm/math_with_import.wasm";
console.log(add(1, 2));
console.log(subtract(100, 50));

View file

@ -0,0 +1,10 @@
Download http://localhost:4545/wasm/math_with_import.wasm
Download http://localhost:4545/wasm/math.ts
local: [WILDLINE]main.js
type: JavaScript
dependencies: 2 unique
size: [WILDLINE]
file:///[WILDLINE]/main.js ([WILDLINE])
└─┬ http://localhost:4545/wasm/math_with_import.wasm ([WILDLINE])
└── http://localhost:4545/wasm/math.ts ([WILDLINE])

View file

@ -0,0 +1,12 @@
{
"steps": [{
"args": "run -A setup.ts",
"output": "[WILDCARD]"
}, {
"args": "run -A --check main.cts",
"output": "main.out"
}, {
"args": "run -A --check main.cjs",
"output": "main.out"
}]
}

View file

@ -0,0 +1,5 @@
// @ts-check
const { add, subtract } = require("./math.wasm");
console.log(add(1, 2));
console.log(subtract(9, 3));

View file

@ -0,0 +1,4 @@
import WasmModule = require("./math.wasm");
console.log(WasmModule.add(1, 2));
console.log(WasmModule.subtract(9, 3));

View file

@ -0,0 +1,3 @@
Check file:///[WILDLINE]
3
6

Binary file not shown.

View file

@ -0,0 +1,4 @@
{
"args": "run -A main.cjs",
"output": "main.out"
}

View file

@ -0,0 +1,7 @@
fetch("http://localhost:4545/wasm/math.wasm").then(async (response) => {
if (!response.ok) {
throw new Error(`Failed to fetch WASM module: ${response.statusText}`);
}
using file = Deno.openSync("math.wasm", { write: true, create: true });
await response.body!.pipeTo(file.writable);
});

View file

@ -0,0 +1,5 @@
{
"args": "--allow-import main.js",
"output": "main.out",
"exitCode": 1
}

View file

@ -0,0 +1,9 @@
{
"lock": false,
"scopes": {
"http://localhost:4545/wasm/": {
// file won't exist
"http://localhost:4545/wasm/math.ts": "./local_math.ts"
}
}
}

View file

@ -0,0 +1,7 @@
import {
add,
subtract,
} from "http://localhost:4545/wasm/math_with_import.wasm";
console.log(add(1, 2));
console.log(subtract(100, 50));

View file

@ -0,0 +1,3 @@
Download http://localhost:4545/wasm/math_with_import.wasm
error: Module not found "file:///[WILDLINE]/local_math.ts".
at http://localhost:4545/wasm/math_with_import.wasm:1:8

View file

@ -0,0 +1,5 @@
{
"args": "--allow-import main.js",
"output": "main.out",
"exitCode": 1
}

View file

@ -0,0 +1,8 @@
{
"lock": false,
"scopes": {
"http://localhost:4545/wasm/": {
"http://localhost:4545/wasm/math.ts": "./local_math.ts"
}
}
}

View file

@ -0,0 +1,7 @@
export function addTest(a: number, b: number) {
return (a + b) * 2;
}
export function subtractTest(a: number, b: number) {
return (a - b) / 2;
}

View file

@ -0,0 +1,7 @@
import {
add,
subtract,
} from "http://localhost:4545/wasm/math_with_import.wasm";
console.log(add(1, 2));
console.log(subtract(100, 50));

View file

@ -0,0 +1,3 @@
Download http://localhost:4545/wasm/math_with_import.wasm
error: Uncaught SyntaxError: The requested module './math.ts' does not provide an export named 'add'
at <anonymous> (http://localhost:4545/wasm/math_with_import.wasm:[WILDLINE])

View file

@ -0,0 +1,4 @@
{
"args": "--allow-import main.js",
"output": "main.out"
}

View file

@ -0,0 +1,7 @@
import {
add,
subtract,
} from "http://localhost:4545/wasm/math_with_import.wasm";
console.log(add(1, 2));
console.log(subtract(100, 50));

View file

@ -0,0 +1,4 @@
Download http://localhost:4545/wasm/math_with_import.wasm
Download http://localhost:4545/wasm/math.ts
3
50

View file

@ -0,0 +1,5 @@
{
"args": "--allow-import main.js",
"output": "main.out",
"exitCode": 10
}

View file

@ -0,0 +1,2 @@
{
}

View file

@ -0,0 +1,6 @@
{
"version": "4",
"remote": {
"http://localhost:4545/wasm/math.wasm": "c4fdd49432f1517835b93274447890007947f9d30674ab7f1474091860113d95"
}
}

View file

@ -0,0 +1,4 @@
import { add, subtract } from "http://localhost:4545/wasm/math.wasm";
console.log(add(1, 2));
console.log(subtract(100, 50));

View file

@ -0,0 +1,12 @@
Download http://localhost:4545/wasm/math.wasm
error: Integrity check failed for remote specifier. The source code is invalid, as it does not match the expected hash in the lock file.
Specifier: http://localhost:4545/wasm/math.wasm
Actual: d1643d9d4ba8f34ee5198717860cbc629013179addba6d4e347b68eb721c73b4
Expected: c4fdd49432f1517835b93274447890007947f9d30674ab7f1474091860113d95
This could be caused by:
* the lock file may be corrupt
* the source itself may be corrupt
Investigate the lockfile; delete it to regenerate the lockfile or --reload to reload the source code from the server.

View file

@ -0,0 +1,4 @@
{
"args": "--allow-import main.js",
"output": "main.out"
}

View file

@ -0,0 +1,8 @@
{
"lock": false,
"scopes": {
"http://localhost:4545/wasm/": {
"http://localhost:4545/wasm/math.ts": "./local_math.ts"
}
}
}

View file

@ -0,0 +1,7 @@
export function add(a: number, b: number) {
return (a + b) * 2;
}
export function subtract(a: number, b: number) {
return (a - b) / 2;
}

View file

@ -0,0 +1,7 @@
import {
add,
subtract,
} from "http://localhost:4545/wasm/math_with_import.wasm";
console.log(add(1, 2));
console.log(subtract(100, 50));

View file

@ -0,0 +1,3 @@
Download http://localhost:4545/wasm/math_with_import.wasm
6
25

View file

@ -0,0 +1,4 @@
{
"args": "run --allow-import main.ts",
"output": "main.out"
}

View file

@ -0,0 +1,3 @@
Download http://localhost:4545/wasm/math.wasm
3
6

View file

@ -0,0 +1,4 @@
import { add, subtract } from "http://localhost:4545/wasm/math.wasm";
console.log(add(1, 2));
console.log(subtract(8, 2));

8
tests/testdata/wasm/math.ts vendored Normal file
View file

@ -0,0 +1,8 @@
// this file is imported by math_with_import.wasm
export function add(a: number, b: number) {
return a + b;
}
export function subtract(a: number, b: number) {
return a - b;
}

BIN
tests/testdata/wasm/math.wasm vendored Normal file

Binary file not shown.

Binary file not shown.

View file

@ -919,6 +919,11 @@ pub fn wildcard_match_detailed(
if was_last_wildcard || was_last_wildline || current_text.is_empty() { if was_last_wildcard || was_last_wildline || current_text.is_empty() {
WildcardMatchResult::Success WildcardMatchResult::Success
} else if current_text == "\n" {
WildcardMatchResult::Fail(
"<matched everything>\n!!!! PROBLEM: Missing final newline at end of expected output !!!!"
.to_string(),
)
} else { } else {
output_lines.push("==== HAD TEXT AT END OF FILE ====".to_string()); output_lines.push("==== HAD TEXT AT END OF FILE ====".to_string());
output_lines.push(colors::red(annotate_whitespace(current_text))); output_lines.push(colors::red(annotate_whitespace(current_text)));