From 38afefd72a3db9cb4cec0862b76264ae82074e7f Mon Sep 17 00:00:00 2001
From: omochimetaru <omochi.metaru@gmail.com>
Date: Sun, 7 Apr 2024 16:04:28 +0900
Subject: [PATCH 1/3] fix JSObject.construct(from:)

---
 .../FundamentalObjects/JSBigInt.swift          |  4 ----
 .../FundamentalObjects/JSFunction.swift        |  4 ----
 .../FundamentalObjects/JSObject.swift          | 18 ++++++++++++++++--
 .../FundamentalObjects/JSSymbol.swift          |  4 ----
 4 files changed, 16 insertions(+), 14 deletions(-)

diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift b/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift
index 5929f2889..104d194e3 100644
--- a/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift
+++ b/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift
@@ -24,10 +24,6 @@ public final class JSBigInt: JSObject {
         super.init(id: _i64_to_bigint_slow(UInt32(value & 0xffffffff), UInt32(value >> 32), false))
     }
 
-    override public class func construct(from value: JSValue) -> Self? {
-        value.bigInt as? Self
-    }
-
     override public var jsValue: JSValue {
         .bigInt(self)
     }
diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift b/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift
index 66c613402..1de95fd36 100644
--- a/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift
+++ b/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift
@@ -89,10 +89,6 @@ public class JSFunction: JSObject {
         fatalError("unavailable")
     }
 
-    override public class func construct(from value: JSValue) -> Self? {
-        return value.function as? Self
-    }
-
     override public var jsValue: JSValue {
         .function(self)
     }
diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift b/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift
index 4e93853ea..04e7f3d59 100644
--- a/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift
+++ b/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift
@@ -150,8 +150,22 @@ public class JSObject: Equatable {
         return lhs.id == rhs.id
     }
 
-    public class func construct(from value: JSValue) -> Self? {
-        return value.object as? Self
+    public static func construct(from value: JSValue) -> Self? {
+        switch value {
+        case .boolean,
+                .string,
+                .number,
+                .null,
+                .undefined: return nil
+        case .object(let object):
+            return object as? Self
+        case .function(let function):
+            return function as? Self
+        case .symbol(let symbol):
+            return symbol as? Self
+        case .bigInt(let bigInt):
+            return bigInt as? Self
+        }
     }
 
     public var jsValue: JSValue {
diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSSymbol.swift b/Sources/JavaScriptKit/FundamentalObjects/JSSymbol.swift
index f25ee1bd8..f5d194e25 100644
--- a/Sources/JavaScriptKit/FundamentalObjects/JSSymbol.swift
+++ b/Sources/JavaScriptKit/FundamentalObjects/JSSymbol.swift
@@ -41,10 +41,6 @@ public class JSSymbol: JSObject {
         Symbol.keyFor!(symbol).string
     }
 
-    override public class func construct(from value: JSValue) -> Self? {
-        return value.symbol as? Self
-    }
-
     override public var jsValue: JSValue {
         .symbol(self)
     }

From 6d832520d75d1092feb13130ad8364683bba25b4 Mon Sep 17 00:00:00 2001
From: omochimetaru <omochi.metaru@gmail.com>
Date: Sun, 7 Apr 2024 16:56:46 +0900
Subject: [PATCH 2/3] add unittest

---
 .../Sources/PrimaryTests/UnitTestUtils.swift  |  7 ++++
 .../Sources/PrimaryTests/main.swift           | 42 +++++++++++++++++++
 IntegrationTests/bin/primary-tests.js         |  7 ++++
 IntegrationTests/package-lock.json            |  2 +-
 4 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/IntegrationTests/TestSuites/Sources/PrimaryTests/UnitTestUtils.swift b/IntegrationTests/TestSuites/Sources/PrimaryTests/UnitTestUtils.swift
index 199a4cbdf..c4f9a9fb1 100644
--- a/IntegrationTests/TestSuites/Sources/PrimaryTests/UnitTestUtils.swift
+++ b/IntegrationTests/TestSuites/Sources/PrimaryTests/UnitTestUtils.swift
@@ -123,6 +123,13 @@ func expectNotNil<T>(_ value: T?, file: StaticString = #file, line: UInt = #line
         throw MessageError("Expect a non-nil value", file: file, line: line, column: column)
     }
 }
+func expectNil<T>(_ value: T?, file: StaticString = #file, line: UInt = #line, column: UInt = #column) throws {
+    switch value {
+    case .some:
+        throw MessageError("Expect an nil", file: file, line: line, column: column)
+    case .none: return
+    }
+}
 
 class Expectation {
     private(set) var isFulfilled: Bool = false
diff --git a/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift b/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift
index a3e27573a..207a8f865 100644
--- a/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift
+++ b/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift
@@ -337,6 +337,48 @@ try test("New Object Construction") {
     try expectEqual(dog1Bark(), .string("wan"))
 }
 
+try test("Object Decoding") {
+    /* 
+     ```js
+     global.objectDecodingTest = {
+         obj: {},
+         fn: () => {},
+         sym: Symbol("s"),
+         bi: BigInt(3)
+     };
+     ```
+     */
+    let js: JSValue = JSObject.global.objectDecodingTest
+
+    // I can't use regular name like `js.object` here
+    // cz its conflicting with case name and DML.
+    // so I use abbreviated names
+    let object: JSValue = js.obj
+    let function: JSValue = js.fn
+    let symbol: JSValue = js.sym
+    let bigInt: JSValue = js.bi
+
+    try expectNotNil(JSObject.construct(from: object))
+    try expectNotNil(JSObject.construct(from: function))
+    try expectNotNil(JSObject.construct(from: symbol))
+    try expectNotNil(JSObject.construct(from: bigInt))
+
+    try expectNil(JSFunction.construct(from: object))
+    try expectNotNil(JSFunction.construct(from: function))
+    try expectNil(JSFunction.construct(from: symbol))
+    try expectNil(JSFunction.construct(from: bigInt))
+
+    try expectNil(JSSymbol.construct(from: object))
+    try expectNil(JSSymbol.construct(from: function))
+    try expectNotNil(JSSymbol.construct(from: symbol))
+    try expectNil(JSSymbol.construct(from: bigInt))
+
+    try expectNil(JSBigInt.construct(from: object))
+    try expectNil(JSBigInt.construct(from: function))
+    try expectNil(JSBigInt.construct(from: symbol))
+    try expectNotNil(JSBigInt.construct(from: bigInt))
+}
+
 try test("Call Function With This") {
     // ```js
     // global.Animal = function(name, age, isCat) {
diff --git a/IntegrationTests/bin/primary-tests.js b/IntegrationTests/bin/primary-tests.js
index 2d977c3fd..50532ceac 100644
--- a/IntegrationTests/bin/primary-tests.js
+++ b/IntegrationTests/bin/primary-tests.js
@@ -95,6 +95,13 @@ global.callThrowingClosure = (c) => {
     }
 };
 
+global.objectDecodingTest = {
+    obj: {},
+    fn: () => {},
+    sym: Symbol("s"),
+    bi: BigInt(3)
+};
+
 const { startWasiTask, WASI } = require("../lib");
 
 startWasiTask("./dist/PrimaryTests.wasm").catch((err) => {
diff --git a/IntegrationTests/package-lock.json b/IntegrationTests/package-lock.json
index 8ccbcdc21..8aff33b98 100644
--- a/IntegrationTests/package-lock.json
+++ b/IntegrationTests/package-lock.json
@@ -13,7 +13,7 @@
     },
     "..": {
       "name": "javascript-kit-swift",
-      "version": "0.18.0",
+      "version": "0.19.1",
       "license": "MIT",
       "devDependencies": {
         "@rollup/plugin-typescript": "^8.3.1",

From 24aac92de31c2fb92546633d6252ea9c0150ef3a Mon Sep 17 00:00:00 2001
From: omochimetaru <omochi.metaru@gmail.com>
Date: Sun, 7 Apr 2024 17:01:28 +0900
Subject: [PATCH 3/3] more precise tests

---
 IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift b/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift
index 207a8f865..a9d127109 100644
--- a/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift
+++ b/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift
@@ -359,9 +359,9 @@ try test("Object Decoding") {
     let bigInt: JSValue = js.bi
 
     try expectNotNil(JSObject.construct(from: object))
-    try expectNotNil(JSObject.construct(from: function))
-    try expectNotNil(JSObject.construct(from: symbol))
-    try expectNotNil(JSObject.construct(from: bigInt))
+    try expectEqual(JSObject.construct(from: function).map { $0 is JSFunction }, .some(true))
+    try expectEqual(JSObject.construct(from: symbol).map { $0 is JSSymbol }, .some(true))
+    try expectEqual(JSObject.construct(from: bigInt).map { $0 is JSBigInt }, .some(true))
 
     try expectNil(JSFunction.construct(from: object))
     try expectNotNil(JSFunction.construct(from: function))