diff --git a/src/js.rs b/src/js.rs index 6ba69db8..1ce4d214 100644 --- a/src/js.rs +++ b/src/js.rs @@ -246,13 +246,20 @@ extern { // Function #[wasm_bindgen] extern { - pub type JsFunction; + pub type Function; + + /// The apply() method calls a function with a given this value, and arguments provided as an array + /// (or an array-like object). + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply + #[wasm_bindgen(method)] + pub fn apply(this: &Function, context: &JsValue, args: &Array) -> Function; /// The length property indicates the number of arguments expected by the function. /// /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/length #[wasm_bindgen(method, getter, structural)] - pub fn length(this: &JsFunction) -> u32; + pub fn length(this: &Function) -> u32; /// A Function object's read-only name property indicates the function's /// name as specified when it was created or "anonymous" for functions @@ -260,7 +267,13 @@ extern { /// /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name #[wasm_bindgen(method, getter, structural)] - pub fn name(this: &JsFunction) -> JsString; + pub fn name(this: &Function) -> JsString; + + /// The toString() method returns a string representing the source code of the function. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/toString + #[wasm_bindgen(method, js_name = toString)] + pub fn to_string(this: &Function) -> JsString; } // Math diff --git a/tests/all/js_globals/Function.rs b/tests/all/js_globals/Function.rs new file mode 100644 index 00000000..b835b569 --- /dev/null +++ b/tests/all/js_globals/Function.rs @@ -0,0 +1,144 @@ +#![allow(non_snake_case)] + +use project; + +#[test] +fn apply() { + project() + .file("src/lib.rs", r#" + #![feature(proc_macro, wasm_custom_section)] + + extern crate wasm_bindgen; + use wasm_bindgen::prelude::*; + use wasm_bindgen::js; + + #[wasm_bindgen] + pub fn apply(this: &js::Function, context: &JsValue, args: &js::Array) -> js::Function { + this.apply(context, args) + } + "#) + .file("test.ts", r#" + import * as assert from "assert"; + import * as wasm from "./out"; + + export function test() { + assert.equal(wasm.apply(Math.max, {}, [1, 2, 3]), 3); + + const arr = [1, 2]; + wasm.apply(Array.prototype.push, arr, [3]); + assert.equal(arr[2], 3); + } + "#) + .test() +} + +#[test] +fn length() { + project() + .file("src/lib.rs", r#" + #![feature(proc_macro, wasm_custom_section)] + + extern crate wasm_bindgen; + use wasm_bindgen::prelude::*; + use wasm_bindgen::js; + + #[wasm_bindgen] + pub fn fn_length(this: &js::Function) -> u32 { + this.length() + } + "#) + .file("test.ts", r#" + import * as assert from "assert"; + import * as wasm from "./out"; + + export function test() { + assert.equal(wasm.fn_length(() => {}), 0); + assert.equal(wasm.fn_length((a: string) => console.log(a)), 1); + assert.equal(wasm.fn_length((a: string, b: string) => console.log({ a, b })), 2); + + function fn0() {} + function fn1(a: string) { + console.log(a); + } + function fn2(a: string, b: string) { + console.log({ a, b }); + } + + assert.equal(wasm.fn_length(fn0), 0); + assert.equal(wasm.fn_length(fn1), 1); + assert.equal(wasm.fn_length(fn2), 2); + } + "#) + .test() +} + +#[test] +fn name() { + project() + .file("src/lib.rs", r#" + #![feature(proc_macro, wasm_custom_section)] + + extern crate wasm_bindgen; + use wasm_bindgen::prelude::*; + use wasm_bindgen::js; + + #[wasm_bindgen] + pub fn fn_name(this: &js::Function) -> js::JsString { + this.name() + } + "#) + .file("test.ts", r#" + import * as assert from "assert"; + import * as wasm from "./out"; + + export function test() { + function namedFn() {} + assert.equal(wasm.fn_name(namedFn), 'namedFn'); + + assert.equal(wasm.fn_name(namedFn.bind({})), 'bound namedFn'); + + const obj = { + method: () => {} + } + assert.equal(wasm.fn_name(obj.method), 'method'); + + assert.equal(wasm.fn_name(new Function()), 'anonymous'); + + assert.equal(wasm.fn_name(() => {}), ''); + + const closure = () => {}; + assert.equal(wasm.fn_name(closure), 'closure'); + } + "#) + .test() +} + +#[test] +fn to_string() { + project() + .file("src/lib.rs", r#" + #![feature(proc_macro, wasm_custom_section)] + + extern crate wasm_bindgen; + use wasm_bindgen::prelude::*; + use wasm_bindgen::js; + + #[wasm_bindgen] + pub fn get_source_code(this: &js::Function) -> js::JsString { + this.to_string() + } + "#) + .file("test.ts", r#" + import * as assert from "assert"; + import * as wasm from "./out"; + + export function test() { + function fn1(a: any, b: any) { return a + b } + const fn2 = (a: number) => console.log(a); + + assert.equal(wasm.get_source_code(fn1), 'function fn1(a, b) { return a + b; }'); + assert.equal(wasm.get_source_code(fn2), 'function (a) { return console.log(a); }'); + } + "#) + .test() +} diff --git a/tests/all/js_globals/JsFunction.rs b/tests/all/js_globals/JsFunction.rs deleted file mode 100644 index e8e5df49..00000000 --- a/tests/all/js_globals/JsFunction.rs +++ /dev/null @@ -1,84 +0,0 @@ -#![allow(non_snake_case)] - -use project; - -#[test] -fn length() { - project() - .file("src/lib.rs", r#" - #![feature(proc_macro, wasm_custom_section)] - - extern crate wasm_bindgen; - use wasm_bindgen::prelude::*; - use wasm_bindgen::js; - - #[wasm_bindgen] - pub fn fn_length(this: &js::JsFunction) -> u32 { - this.length() - } - "#) - .file("test.ts", r#" - import * as assert from "assert"; - import * as wasm from "./out"; - - export function test() { - assert.equal(0, wasm.fn_length(() => {})); - assert.equal(1, wasm.fn_length((a: string) => console.log(a))); - assert.equal(2, wasm.fn_length((a: string, b: string) => console.log({ a, b }))); - - function fn0() {} - function fn1(a: string) { - console.log(a); - } - function fn2(a: string, b: string) { - console.log({ a, b }); - } - - assert.equal(0, wasm.fn_length(fn0)); - assert.equal(1, wasm.fn_length(fn1)); - assert.equal(2, wasm.fn_length(fn2)); - } - "#) - .test() -} - -#[test] -fn name() { - project() - .file("src/lib.rs", r#" - #![feature(proc_macro, wasm_custom_section)] - - extern crate wasm_bindgen; - use wasm_bindgen::prelude::*; - use wasm_bindgen::js; - - #[wasm_bindgen] - pub fn fn_name(this: &js::JsFunction) -> js::JsString { - this.name() - } - "#) - .file("test.ts", r#" - import * as assert from "assert"; - import * as wasm from "./out"; - - export function test() { - function namedFn() {} - assert.equal('namedFn', wasm.fn_name(namedFn)); - - assert.equal('bound namedFn', wasm.fn_name(namedFn.bind({}))); - - const obj = { - method: () => {} - } - assert.equal('method', wasm.fn_name(obj.method)); - - assert.equal('anonymous', wasm.fn_name(new Function())); - - assert.equal('', wasm.fn_name(() => {})); - - const closure = () => {}; - assert.equal('closure', wasm.fn_name(closure)); - } - "#) - .test() -} diff --git a/tests/all/js_globals/mod.rs b/tests/all/js_globals/mod.rs index 32066801..9427d7dc 100644 --- a/tests/all/js_globals/mod.rs +++ b/tests/all/js_globals/mod.rs @@ -5,7 +5,7 @@ use super::project; mod Array; mod ArrayIterator; mod Date; -mod JsFunction; +mod Function; mod JsString; mod Math; mod Number;