diff --git a/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift b/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift index e54343db7..b522c8bef 100644 --- a/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift +++ b/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift @@ -268,7 +268,9 @@ try test("Call Function With This") { // ``` let objectConstructor = try expectFunction(getJSValue(this: .global, name: "Animal")) let cat1 = objectConstructor.new("Tama", 3, true) + let cat1Value = JSValue.object(cat1) let getIsCat = try expectFunction(getJSValue(this: cat1, name: "getIsCat")) + let setName = try expectFunction(getJSValue(this: cat1, name: "setName")) // Direct call without this try expectEqual(getIsCat(), .undefined) @@ -276,6 +278,16 @@ try test("Call Function With This") { // Call with this let gotIsCat = getIsCat(this: cat1) try expectEqual(gotIsCat, .boolean(true)) + try expectEqual(cat1.getIsCat!(), .boolean(true)) + try expectEqual(cat1Value.getIsCat(), .boolean(true)) + + // Call with this and argument + setName(this: cat1, JSValue.string("Shiro")) + try expectEqual(getJSValue(this: cat1, name: "name"), .string("Shiro")) + _ = cat1.setName!("Tora") + try expectEqual(getJSValue(this: cat1, name: "name"), .string("Tora")) + _ = cat1Value.setName("Chibi") + try expectEqual(getJSValue(this: cat1, name: "name"), .string("Chibi")) } try test("Object Conversion") { @@ -496,3 +508,12 @@ try test("Error") { try expectEqual(JSError(from: .string("error"))?.description, nil) try expectEqual(JSError(from: .object(error.jsObject))?.description, expectedDescription) } + +try test("JSValue accessor") { + let globalObject1 = JSObject.global.globalObject1 + try expectEqual(globalObject1.prop_1.nested_prop, .number(1)) + try expectEqual(globalObject1.object!.prop_1.object!.nested_prop, .number(1)) + + try expectEqual(globalObject1.prop_4[0], .number(3)) + try expectEqual(globalObject1.prop_4[1], .number(4)) +} diff --git a/IntegrationTests/bin/primary-tests.js b/IntegrationTests/bin/primary-tests.js index 1d7c47b78..2ab44c3de 100644 --- a/IntegrationTests/bin/primary-tests.js +++ b/IntegrationTests/bin/primary-tests.js @@ -48,6 +48,9 @@ global.Animal = function (name, age, isCat) { this.getIsCat = function () { return this.isCat; }; + this.setName = function (name) { + this.name = name; + } }; const { startWasiTask } = require("../lib"); diff --git a/Sources/JavaScriptKit/JSValue.swift b/Sources/JavaScriptKit/JSValue.swift index 00f79e1c8..57c835cd5 100644 --- a/Sources/JavaScriptKit/JSValue.swift +++ b/Sources/JavaScriptKit/JSValue.swift @@ -1,6 +1,7 @@ import _CJavaScriptKit /// `JSValue` represents a value in JavaScript. +@dynamicMemberLookup public enum JSValue: Equatable { case boolean(Bool) case string(JSString) @@ -79,6 +80,28 @@ public enum JSValue: Equatable { } } +extension JSValue { + /// An unsafe convenience method of `JSObject.subscript(_ name: String) -> ((ConvertibleToJSValue...) -> JSValue)?` + /// - Precondition: `self` must be a JavaScript Object and specified member should be a callable object. + public subscript(dynamicMember name: String) -> ((ConvertibleToJSValue...) -> JSValue) { + object![dynamicMember: name]! + } + + /// An unsafe convenience method of `JSObject.subscript(_ index: Int) -> JSValue` + /// - Precondition: `self` must be a JavaScript Object. + public subscript(dynamicMember name: String) -> JSValue { + get { self.object![name] } + set { self.object![name] = newValue } + } + + /// An unsafe convenience method of `JSObject.subscript(_ index: Int) -> JSValue` + /// - Precondition: `self` must be a JavaScript Object. + public subscript(_ index: Int) -> JSValue { + get { object![index] } + set { object![index] = newValue } + } +} + extension JSValue { public func fromJSValue() -> Type? where Type: ConstructibleFromJSValue { return Type.construct(from: self)