diff --git a/src/js.rs b/src/js.rs index 46b0459b..e1d43b74 100644 --- a/src/js.rs +++ b/src/js.rs @@ -988,6 +988,16 @@ extern "C" { /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/apply #[wasm_bindgen(static_method_of = Reflect, catch)] pub fn apply(target: &Function, this_argument: &JsValue, arguments_list: &Array) -> Result; + + /// The static Reflect.construct() method acts like the new operator, but as a function. + /// It is equivalent to calling new target(...args). It gives also the added option to + /// specify a different prototype. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/construct + #[wasm_bindgen(static_method_of = Reflect, catch)] + pub fn construct(target: &Function, arguments_list: &Array) -> Result; + #[wasm_bindgen(static_method_of = Reflect, js_name = construct, catch)] + pub fn construct_with_new_target(target: &Function, arguments_list: &Array, new_target: &Function) -> Result; } // Set diff --git a/tests/all/js_globals/Reflect.rs b/tests/all/js_globals/Reflect.rs index c9b39bb2..7fb12670 100644 --- a/tests/all/js_globals/Reflect.rs +++ b/tests/all/js_globals/Reflect.rs @@ -38,4 +38,129 @@ fn apply() { "#, ) .test() +} + +#[test] +fn construct() { + 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 construct(target: &js::Function, arguments_list: &js::Array) -> JsValue { + let result = js::Reflect::construct(target, arguments_list); + let result = match result { + Ok(val) => val, + Err(_err) => "TypeError".into() + }; + result + } + "#, + ) + .file( + "test.ts", + r#" + import * as assert from "assert"; + import * as wasm from "./out"; + + export function test() { + class Rectangle { + public x: number; + public y: number; + + constructor(x: number, y: number){ + this.x = x, + this.y = y + } + + static eq(x: number, y: number) { + return x === y; + } + + } + + const args = [10, 10]; + + assert.equal(wasm.construct(Rectangle, args).x, 10); + assert.equal(wasm.construct('', args), "TypeError"); + } + "#, + ) + .test() +} + +#[test] +fn construct_with_new_target() { + 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 construct_with_new_target(target: &js::Function, arguments_list: &js::Array, new_target: &js::Function) -> JsValue { + let result = js::Reflect::construct_with_new_target(target, arguments_list, new_target); + let result = match result { + Ok(val) => val, + Err(_err) => "TypeError".into() + }; + result + } + "#, + ) + .file( + "test.ts", + r#" + import * as assert from "assert"; + import * as wasm from "./out"; + + export function test() { + class Rectangle { + public x: number; + public y: number; + + constructor(x: number, y: number){ + this.x = x, + this.y = y + } + + static eq(x: number, y: number) { + return x === y; + } + + } + + class Rectangle2 { + public x: number; + public y: number; + + constructor(x: number, y: number){ + this.x = x, + this.y = y + } + + static eq(x: number, y: number) { + return x === y; + } + + } + + const args = [10, 10]; + + assert.equal(wasm.construct_with_new_target(Rectangle, args, Rectangle2).x, 10); + assert.equal(wasm.construct_with_new_target(Rectangle, args, ''), "TypeError"); + } + "#, + ) + .test() } \ No newline at end of file