From f12eeaf781c6d4dcd3aeb64cc7a07e349fe81017 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 13 Oct 2020 20:16:50 +0900 Subject: [PATCH 1/2] Add unsafe convenience methods for JSValue --- .../Sources/PrimaryTests/main.swift | 21 +++++++++++++++++++ IntegrationTests/bin/primary-tests.js | 3 +++ Sources/JavaScriptKit/JSValue.swift | 20 ++++++++++++++++++ 3 files changed, 44 insertions(+) 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..379e2e57a 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,25 @@ public enum JSValue: Equatable { } } +extension JSValue { + /// An unsafe convenience method of `JSObject.subscript(_ name: String) -> ((ConvertibleToJSValue...) -> JSValue)?` + public subscript(dynamicMember name: String) -> ((ConvertibleToJSValue...) -> JSValue) { + object![dynamicMember: name]! + } + + /// An unsafe convenience method of `JSObject.subscript(_ index: Int) -> JSValue` + 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` + 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) From 8f6a57246088cd721e1dfac9d12746768092ef04 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 13 Oct 2020 20:46:13 +0900 Subject: [PATCH 2/2] Note method precondition --- Sources/JavaScriptKit/JSValue.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Sources/JavaScriptKit/JSValue.swift b/Sources/JavaScriptKit/JSValue.swift index 379e2e57a..57c835cd5 100644 --- a/Sources/JavaScriptKit/JSValue.swift +++ b/Sources/JavaScriptKit/JSValue.swift @@ -82,17 +82,20 @@ 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 }