mirror of
https://github.com/denoland/deno.git
synced 2024-11-22 04:51:22 +00:00
Loader: support .wasm imports (#3328)
* loader: support .wasm imports * http_server: true * Support named exports * Clippy
This commit is contained in:
parent
fdf0ede2ac
commit
4189cc1ab5
@ -1,3 +1,4 @@
|
||||
cli/compilers/wasm_wrap.js
|
||||
cli/tests/error_syntax.js
|
||||
std/deno.d.ts
|
||||
std/prettier/vendor
|
||||
|
@ -1,3 +1,4 @@
|
||||
cli/compilers/wasm_wrap.js
|
||||
cli/tests/error_syntax.js
|
||||
cli/tests/badly_formatted.js
|
||||
cli/tests/top_level_for_await.js
|
||||
|
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -91,6 +91,11 @@ dependencies = [
|
||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
@ -282,6 +287,7 @@ version = "0.23.0"
|
||||
dependencies = [
|
||||
"ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"deno 0.23.0",
|
||||
@ -1944,6 +1950,7 @@ dependencies = [
|
||||
"checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea"
|
||||
"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491"
|
||||
"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
|
||||
"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
|
||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
"checksum blake2b_simd 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b83b7baab1e671718d78204225800d6b170e648188ac7dc992e9d6bddf87d0c0"
|
||||
"checksum bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad807f2fc2bf185eeb98ff3a901bd46dc5ad58163d0fa4577ba0d25674d71708"
|
||||
|
@ -27,6 +27,7 @@ deno_typescript = { path = "../deno_typescript", version = "0.23.0" }
|
||||
|
||||
ansi_term = "0.12.1"
|
||||
atty = "0.2.13"
|
||||
base64 = "0.11.0"
|
||||
byteorder = "1.3.2"
|
||||
clap = "2.33.0"
|
||||
dirs = "2.0.2"
|
||||
|
@ -5,10 +5,12 @@ use futures::Future;
|
||||
mod js;
|
||||
mod json;
|
||||
mod ts;
|
||||
mod wasm;
|
||||
|
||||
pub use js::JsCompiler;
|
||||
pub use json::JsonCompiler;
|
||||
pub use ts::TsCompiler;
|
||||
pub use wasm::WasmCompiler;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CompiledModule {
|
||||
|
174
cli/compilers/wasm.rs
Normal file
174
cli/compilers/wasm.rs
Normal file
@ -0,0 +1,174 @@
|
||||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::compilers::CompiledModule;
|
||||
use crate::compilers::CompiledModuleFuture;
|
||||
use crate::file_fetcher::SourceFile;
|
||||
use crate::global_state::ThreadSafeGlobalState;
|
||||
use crate::startup_data;
|
||||
use crate::state::*;
|
||||
use crate::worker::Worker;
|
||||
use deno::Buf;
|
||||
use futures::Future;
|
||||
use futures::IntoFuture;
|
||||
use serde_derive::Deserialize;
|
||||
use serde_json;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use url::Url;
|
||||
|
||||
// TODO(kevinkassimo): This is a hack to encode/decode data as base64 string.
|
||||
// (Since Deno namespace might not be available, Deno.read can fail).
|
||||
// Binary data is already available through source_file.source_code.
|
||||
// If this is proven too wasteful in practice, refactor this.
|
||||
|
||||
// Ref: https://webassembly.github.io/esm-integration/js-api/index.html#esm-integration
|
||||
// https://github.com/nodejs/node/blob/35ec01097b2a397ad0a22aac536fe07514876e21/lib/internal/modules/esm/translators.js#L190-L210
|
||||
|
||||
// Dynamically construct JS wrapper with custom static imports and named exports.
|
||||
// Boots up an internal worker to resolve imports/exports through query from V8.
|
||||
|
||||
static WASM_WRAP: &str = include_str!("./wasm_wrap.js");
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct WasmModuleInfo {
|
||||
import_list: Vec<String>,
|
||||
export_list: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct WasmCompiler {
|
||||
cache: Arc<Mutex<HashMap<Url, CompiledModule>>>,
|
||||
}
|
||||
|
||||
impl WasmCompiler {
|
||||
/// Create a new V8 worker with snapshot of WASM compiler and setup compiler's runtime.
|
||||
fn setup_worker(global_state: ThreadSafeGlobalState) -> Worker {
|
||||
let (int, ext) = ThreadSafeState::create_channels();
|
||||
let worker_state =
|
||||
ThreadSafeState::new(global_state.clone(), None, true, int)
|
||||
.expect("Unable to create worker state");
|
||||
|
||||
// Count how many times we start the compiler worker.
|
||||
global_state
|
||||
.metrics
|
||||
.compiler_starts
|
||||
.fetch_add(1, Ordering::SeqCst);
|
||||
|
||||
let mut worker = Worker::new(
|
||||
"WASM".to_string(),
|
||||
startup_data::compiler_isolate_init(),
|
||||
worker_state,
|
||||
ext,
|
||||
);
|
||||
worker.execute("denoMain('WASM')").unwrap();
|
||||
worker.execute("workerMain()").unwrap();
|
||||
worker.execute("wasmCompilerMain()").unwrap();
|
||||
worker
|
||||
}
|
||||
|
||||
pub fn compile_async(
|
||||
self: &Self,
|
||||
global_state: ThreadSafeGlobalState,
|
||||
source_file: &SourceFile,
|
||||
) -> Box<CompiledModuleFuture> {
|
||||
let cache = self.cache.clone();
|
||||
let maybe_cached = { cache.lock().unwrap().get(&source_file.url).cloned() };
|
||||
if let Some(m) = maybe_cached {
|
||||
return Box::new(futures::future::ok(m.clone()));
|
||||
}
|
||||
let cache_ = self.cache.clone();
|
||||
|
||||
debug!(">>>>> wasm_compile_async START");
|
||||
let base64_data = base64::encode(&source_file.source_code);
|
||||
let worker = WasmCompiler::setup_worker(global_state.clone());
|
||||
let worker_ = worker.clone();
|
||||
let url = source_file.url.clone();
|
||||
|
||||
let fut = worker
|
||||
.post_message(
|
||||
serde_json::to_string(&base64_data)
|
||||
.unwrap()
|
||||
.into_boxed_str()
|
||||
.into_boxed_bytes(),
|
||||
)
|
||||
.into_future()
|
||||
.then(move |_| worker)
|
||||
.then(move |result| {
|
||||
if let Err(err) = result {
|
||||
// TODO(ry) Need to forward the error instead of exiting.
|
||||
eprintln!("{}", err.to_string());
|
||||
std::process::exit(1);
|
||||
}
|
||||
debug!("Sent message to worker");
|
||||
worker_.get_message()
|
||||
})
|
||||
.map_err(|_| panic!("not handled"))
|
||||
.and_then(move |maybe_msg: Option<Buf>| {
|
||||
debug!("Received message from worker");
|
||||
let json_msg = maybe_msg.unwrap();
|
||||
let module_info: WasmModuleInfo =
|
||||
serde_json::from_slice(&json_msg).unwrap();
|
||||
debug!("WASM module info: {:#?}", &module_info);
|
||||
let code = wrap_wasm_code(
|
||||
&base64_data,
|
||||
&module_info.import_list,
|
||||
&module_info.export_list,
|
||||
);
|
||||
debug!("Generated code: {}", &code);
|
||||
let module = CompiledModule {
|
||||
code,
|
||||
name: url.to_string(),
|
||||
};
|
||||
{
|
||||
cache_.lock().unwrap().insert(url.clone(), module.clone());
|
||||
}
|
||||
debug!("<<<<< wasm_compile_async END");
|
||||
Ok(module)
|
||||
});
|
||||
Box::new(fut)
|
||||
}
|
||||
}
|
||||
|
||||
fn build_single_import(index: usize, origin: &str) -> String {
|
||||
let origin_json = serde_json::to_string(origin).unwrap();
|
||||
format!(
|
||||
r#"import * as m{} from {};
|
||||
importObject[{}] = m{};
|
||||
"#,
|
||||
index, &origin_json, &origin_json, index
|
||||
)
|
||||
}
|
||||
|
||||
fn build_imports(imports: &[String]) -> String {
|
||||
let mut code = String::from("");
|
||||
for (index, origin) in imports.iter().enumerate() {
|
||||
code.push_str(&build_single_import(index, origin));
|
||||
}
|
||||
code
|
||||
}
|
||||
|
||||
fn build_single_export(name: &str) -> String {
|
||||
format!("export const {} = instance.exports.{};\n", name, name)
|
||||
}
|
||||
|
||||
fn build_exports(exports: &[String]) -> String {
|
||||
let mut code = String::from("");
|
||||
for e in exports {
|
||||
code.push_str(&build_single_export(e));
|
||||
}
|
||||
code
|
||||
}
|
||||
|
||||
fn wrap_wasm_code(
|
||||
base64_data: &str,
|
||||
imports: &[String],
|
||||
exports: &[String],
|
||||
) -> String {
|
||||
let imports_code = build_imports(imports);
|
||||
let exports_code = build_exports(exports);
|
||||
String::from(WASM_WRAP)
|
||||
.replace("//IMPORTS\n", &imports_code)
|
||||
.replace("//EXPORTS\n", &exports_code)
|
||||
.replace("BASE64_DATA", base64_data)
|
||||
}
|
19
cli/compilers/wasm_wrap.js
Normal file
19
cli/compilers/wasm_wrap.js
Normal file
@ -0,0 +1,19 @@
|
||||
const importObject = Object.create(null);
|
||||
//IMPORTS
|
||||
|
||||
function base64ToUint8Array(data) {
|
||||
const binString = window.atob(data);
|
||||
const size = binString.length;
|
||||
const bytes = new Uint8Array(size);
|
||||
for (let i = 0; i < size; i++) {
|
||||
bytes[i] = binString.charCodeAt(i);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
const buffer = base64ToUint8Array("BASE64_DATA");
|
||||
const compiled = await WebAssembly.compile(buffer);
|
||||
|
||||
const instance = new WebAssembly.Instance(compiled, importObject);
|
||||
|
||||
//EXPORTS
|
@ -491,6 +491,7 @@ fn map_file_extension(path: &Path) -> msg::MediaType {
|
||||
Some("jsx") => msg::MediaType::JSX,
|
||||
Some("mjs") => msg::MediaType::JavaScript,
|
||||
Some("json") => msg::MediaType::Json,
|
||||
Some("wasm") => msg::MediaType::Wasm,
|
||||
_ => msg::MediaType::Unknown,
|
||||
},
|
||||
}
|
||||
@ -1503,6 +1504,10 @@ mod tests {
|
||||
map_file_extension(Path::new("foo/bar.json")),
|
||||
msg::MediaType::Json
|
||||
);
|
||||
assert_eq!(
|
||||
map_file_extension(Path::new("foo/bar.wasm")),
|
||||
msg::MediaType::Wasm
|
||||
);
|
||||
assert_eq!(
|
||||
map_file_extension(Path::new("foo/bar.txt")),
|
||||
msg::MediaType::Unknown
|
||||
@ -1544,6 +1549,10 @@ mod tests {
|
||||
map_content_type(Path::new("foo/bar.json"), None),
|
||||
msg::MediaType::Json
|
||||
);
|
||||
assert_eq!(
|
||||
map_content_type(Path::new("foo/bar.wasm"), None),
|
||||
msg::MediaType::Wasm
|
||||
);
|
||||
assert_eq!(
|
||||
map_content_type(Path::new("foo/bar"), None),
|
||||
msg::MediaType::Unknown
|
||||
|
@ -3,6 +3,7 @@ use crate::compilers::CompiledModule;
|
||||
use crate::compilers::JsCompiler;
|
||||
use crate::compilers::JsonCompiler;
|
||||
use crate::compilers::TsCompiler;
|
||||
use crate::compilers::WasmCompiler;
|
||||
use crate::deno_dir;
|
||||
use crate::deno_error::permission_denied;
|
||||
use crate::file_fetcher::SourceFileFetcher;
|
||||
@ -45,6 +46,7 @@ pub struct GlobalState {
|
||||
pub js_compiler: JsCompiler,
|
||||
pub json_compiler: JsonCompiler,
|
||||
pub ts_compiler: TsCompiler,
|
||||
pub wasm_compiler: WasmCompiler,
|
||||
pub lockfile: Option<Mutex<Lockfile>>,
|
||||
}
|
||||
|
||||
@ -111,6 +113,7 @@ impl ThreadSafeGlobalState {
|
||||
ts_compiler,
|
||||
js_compiler: JsCompiler {},
|
||||
json_compiler: JsonCompiler {},
|
||||
wasm_compiler: WasmCompiler::default(),
|
||||
lockfile,
|
||||
};
|
||||
|
||||
@ -130,6 +133,9 @@ impl ThreadSafeGlobalState {
|
||||
.and_then(move |out| match out.media_type {
|
||||
msg::MediaType::Unknown => state1.js_compiler.compile_async(&out),
|
||||
msg::MediaType::Json => state1.json_compiler.compile_async(&out),
|
||||
msg::MediaType::Wasm => {
|
||||
state1.wasm_compiler.compile_async(state1.clone(), &out)
|
||||
}
|
||||
msg::MediaType::TypeScript
|
||||
| msg::MediaType::TSX
|
||||
| msg::MediaType::JSX => {
|
||||
|
@ -28,7 +28,8 @@ enum MediaType {
|
||||
TypeScript = 2,
|
||||
TSX = 3,
|
||||
Json = 4,
|
||||
Unknown = 5
|
||||
Wasm = 5,
|
||||
Unknown = 6
|
||||
}
|
||||
|
||||
// Warning! The values in this enum are duplicated in cli/msg.rs
|
||||
@ -44,8 +45,8 @@ enum CompilerRequestType {
|
||||
const console = new Console(core.print);
|
||||
window.console = console;
|
||||
window.workerMain = workerMain;
|
||||
function denoMain(): void {
|
||||
os.start(true, "TS");
|
||||
function denoMain(compilerType?: string): void {
|
||||
os.start(true, compilerType || "TS");
|
||||
}
|
||||
window["denoMain"] = denoMain;
|
||||
|
||||
@ -371,6 +372,9 @@ function getExtension(fileName: string, mediaType: MediaType): ts.Extension {
|
||||
return ts.Extension.Tsx;
|
||||
case MediaType.Json:
|
||||
return ts.Extension.Json;
|
||||
case MediaType.Wasm:
|
||||
// Custom marker for Wasm type.
|
||||
return ts.Extension.Js;
|
||||
case MediaType.Unknown:
|
||||
default:
|
||||
throw TypeError("Cannot resolve extension.");
|
||||
@ -724,3 +728,47 @@ window.compilerMain = function compilerMain(): void {
|
||||
workerClose();
|
||||
};
|
||||
};
|
||||
|
||||
function base64ToUint8Array(data: string): Uint8Array {
|
||||
const binString = window.atob(data);
|
||||
const size = binString.length;
|
||||
const bytes = new Uint8Array(size);
|
||||
for (let i = 0; i < size; i++) {
|
||||
bytes[i] = binString.charCodeAt(i);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
window.wasmCompilerMain = function wasmCompilerMain(): void {
|
||||
// workerMain should have already been called since a compiler is a worker.
|
||||
window.onmessage = async ({
|
||||
data: binary
|
||||
}: {
|
||||
data: string;
|
||||
}): Promise<void> => {
|
||||
const buffer = base64ToUint8Array(binary);
|
||||
// @ts-ignore
|
||||
const compiled = await WebAssembly.compile(buffer);
|
||||
|
||||
util.log(">>> WASM compile start");
|
||||
|
||||
const importList = Array.from(
|
||||
// @ts-ignore
|
||||
new Set(WebAssembly.Module.imports(compiled).map(({ module }) => module))
|
||||
);
|
||||
const exportList = Array.from(
|
||||
// @ts-ignore
|
||||
new Set(WebAssembly.Module.exports(compiled).map(({ name }) => name))
|
||||
);
|
||||
|
||||
postMessage({
|
||||
importList,
|
||||
exportList
|
||||
});
|
||||
|
||||
util.log("<<< WASM compile end");
|
||||
|
||||
// The compiler isolate exits after a single message.
|
||||
workerClose();
|
||||
};
|
||||
};
|
||||
|
@ -74,7 +74,8 @@ pub enum MediaType {
|
||||
TypeScript = 2,
|
||||
TSX = 3,
|
||||
Json = 4,
|
||||
Unknown = 5,
|
||||
Wasm = 5,
|
||||
Unknown = 6,
|
||||
}
|
||||
|
||||
pub fn enum_name_media_type(mt: MediaType) -> &'static str {
|
||||
@ -84,6 +85,7 @@ pub fn enum_name_media_type(mt: MediaType) -> &'static str {
|
||||
MediaType::TypeScript => "TypeScript",
|
||||
MediaType::TSX => "TSX",
|
||||
MediaType::Json => "Json",
|
||||
MediaType::Wasm => "Wasm",
|
||||
MediaType::Unknown => "Unknown",
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
use super::dispatch_json::{Deserialize, JsonOp, Value};
|
||||
use crate::futures::future::join_all;
|
||||
use crate::futures::Future;
|
||||
use crate::msg;
|
||||
use crate::ops::json_op;
|
||||
use crate::state::ThreadSafeState;
|
||||
use deno::Loader;
|
||||
@ -74,17 +75,44 @@ fn op_fetch_source_files(
|
||||
futures.push(fut);
|
||||
}
|
||||
|
||||
let global_state = state.global_state.clone();
|
||||
|
||||
let future = join_all(futures)
|
||||
.map_err(ErrBox::from)
|
||||
.and_then(move |files| {
|
||||
let res = files
|
||||
// We want to get an array of futures that resolves to
|
||||
let v: Vec<_> = files
|
||||
.into_iter()
|
||||
.map(|file| {
|
||||
// Special handling of Wasm files:
|
||||
// compile them into JS first!
|
||||
// This allows TS to do correct export types.
|
||||
if file.media_type == msg::MediaType::Wasm {
|
||||
return futures::future::Either::A(
|
||||
global_state
|
||||
.wasm_compiler
|
||||
.compile_async(global_state.clone(), &file)
|
||||
.and_then(|compiled_mod| Ok((file, Some(compiled_mod.code)))),
|
||||
);
|
||||
}
|
||||
futures::future::Either::B(futures::future::ok((file, None)))
|
||||
})
|
||||
.collect();
|
||||
join_all(v)
|
||||
})
|
||||
.and_then(move |files_with_code| {
|
||||
let res = files_with_code
|
||||
.into_iter()
|
||||
.map(|(file, maybe_code)| {
|
||||
json!({
|
||||
"url": file.url.to_string(),
|
||||
"filename": file.filename.to_str().unwrap(),
|
||||
"mediaType": file.media_type as i32,
|
||||
"sourceCode": String::from_utf8(file.source_code).unwrap(),
|
||||
"sourceCode": if let Some(code) = maybe_code {
|
||||
code
|
||||
} else {
|
||||
String::from_utf8(file.source_code).unwrap()
|
||||
},
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
22
cli/tests/051_wasm_import.ts
Normal file
22
cli/tests/051_wasm_import.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { add, addImported, addRemote } from "./051_wasm_import/simple.wasm";
|
||||
import { state } from "./051_wasm_import/wasm-dep.js";
|
||||
|
||||
function assertEquals(actual: unknown, expected: unknown, msg?: string): void {
|
||||
if (actual !== expected) {
|
||||
throw new Error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(state, "WASM Start Executed", "Incorrect state");
|
||||
|
||||
assertEquals(add(10, 20), 30, "Incorrect add");
|
||||
|
||||
assertEquals(addImported(0), 42, "Incorrect addImported");
|
||||
|
||||
assertEquals(state, "WASM JS Function Executed", "Incorrect state");
|
||||
|
||||
assertEquals(addImported(1), 43, "Incorrect addImported");
|
||||
|
||||
assertEquals(addRemote(1), 2020, "Incorrect addRemote");
|
||||
|
||||
console.log("Passed");
|
1
cli/tests/051_wasm_import.ts.out
Normal file
1
cli/tests/051_wasm_import.ts.out
Normal file
@ -0,0 +1 @@
|
||||
Passed
|
3
cli/tests/051_wasm_import/remote.ts
Normal file
3
cli/tests/051_wasm_import/remote.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export function jsRemoteFn(): number {
|
||||
return 2019;
|
||||
}
|
BIN
cli/tests/051_wasm_import/simple.wasm
Normal file
BIN
cli/tests/051_wasm_import/simple.wasm
Normal file
Binary file not shown.
31
cli/tests/051_wasm_import/simple.wat
Normal file
31
cli/tests/051_wasm_import/simple.wat
Normal file
@ -0,0 +1,31 @@
|
||||
;; From https://github.com/nodejs/node/blob/bbc254db5db672643aad89a436a4938412a5704e/test/fixtures/es-modules/simple.wat
|
||||
;; MIT Licensed
|
||||
;; $ wat2wasm simple.wat -o simple.wasm
|
||||
|
||||
(module
|
||||
(import "./wasm-dep.js" "jsFn" (func $jsFn (result i32)))
|
||||
(import "./wasm-dep.js" "jsInitFn" (func $jsInitFn))
|
||||
(import "http://127.0.0.1:4545/cli/tests/051_wasm_import/remote.ts" "jsRemoteFn" (func $jsRemoteFn (result i32)))
|
||||
(export "add" (func $add))
|
||||
(export "addImported" (func $addImported))
|
||||
(export "addRemote" (func $addRemote))
|
||||
(start $startFn)
|
||||
(func $startFn
|
||||
call $jsInitFn
|
||||
)
|
||||
(func $add (param $a i32) (param $b i32) (result i32)
|
||||
local.get $a
|
||||
local.get $b
|
||||
i32.add
|
||||
)
|
||||
(func $addImported (param $a i32) (result i32)
|
||||
local.get $a
|
||||
call $jsFn
|
||||
i32.add
|
||||
)
|
||||
(func $addRemote (param $a i32) (result i32)
|
||||
local.get $a
|
||||
call $jsRemoteFn
|
||||
i32.add
|
||||
)
|
||||
)
|
17
cli/tests/051_wasm_import/wasm-dep.js
Normal file
17
cli/tests/051_wasm_import/wasm-dep.js
Normal file
@ -0,0 +1,17 @@
|
||||
function assertEquals(actual, expected, msg) {
|
||||
if (actual !== expected) {
|
||||
throw new Error(msg || "");
|
||||
}
|
||||
}
|
||||
|
||||
export function jsFn() {
|
||||
state = "WASM JS Function Executed";
|
||||
return 42;
|
||||
}
|
||||
|
||||
export let state = "JS Function Executed";
|
||||
|
||||
export function jsInitFn() {
|
||||
assertEquals(state, "JS Function Executed", "Incorrect state");
|
||||
state = "WASM Start Executed";
|
||||
}
|
@ -356,6 +356,12 @@ itest!(_050_more_jsons {
|
||||
output: "050_more_jsons.ts.out",
|
||||
});
|
||||
|
||||
itest!(_051_wasm_import {
|
||||
args: "run --reload --allow-net --allow-read 051_wasm_import.ts",
|
||||
output: "051_wasm_import.ts.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(lock_check_ok {
|
||||
args: "run --lock=lock_check_ok.json http://127.0.0.1:4545/cli/tests/003_relative_import.ts",
|
||||
output: "003_relative_import.ts.out",
|
||||
|
@ -39,9 +39,10 @@ def eslint():
|
||||
script = os.path.join(third_party_path, "node_modules", "eslint", "bin",
|
||||
"eslint")
|
||||
# Find all *directories* in the main repo that contain .ts/.js files.
|
||||
source_files = git_ls_files(
|
||||
root_path,
|
||||
["*.js", "*.ts", ":!:std/prettier/vendor/*", ":!:std/**/testdata/*"])
|
||||
source_files = git_ls_files(root_path, [
|
||||
"*.js", "*.ts", ":!:std/prettier/vendor/*", ":!:std/**/testdata/*",
|
||||
":!:cli/compilers/*"
|
||||
])
|
||||
source_dirs = set([os.path.dirname(f) for f in source_files])
|
||||
# Within the source dirs, eslint does its own globbing, taking into account
|
||||
# the exclusion rules listed in '.eslintignore'.
|
||||
|
Loading…
Reference in New Issue
Block a user