diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index ffb50c7a8..99afffd73 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -931,11 +931,6 @@ struct IntrinsicJSFragment: Sendable { printer.write("\(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(value));") } printer.write("}") - cleanupCode.write("if (\(idVar) !== undefined) {") - cleanupCode.indent { - cleanupCode.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(idVar));") - } - cleanupCode.write("}") return ["+\(isSomeVar)", "\(isSomeVar) ? \(idVar) : 0"] default: return ["+\(isSomeVar)", "\(isSomeVar) ? \(value) : 0"] diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 91dd822c1..96ca9be2e 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -5843,6 +5843,16 @@ public func _bjs_roundTripOptionalTypedPayloadResult(_ resultIsSome: Int32, _ re #endif } +@_expose(wasm, "bjs_takeOptionalJSObject") +@_cdecl("bjs_takeOptionalJSObject") +public func _bjs_takeOptionalJSObject(_ valueIsSome: Int32, _ valueValue: Int32) -> Void { + #if arch(wasm32) + takeOptionalJSObject(_: Optional.bridgeJSLiftParameter(valueIsSome, valueValue)) + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_compareAPIResults") @_cdecl("bjs_compareAPIResults") public func _bjs_compareAPIResults(_ r1IsSome: Int32, _ r1CaseId: Int32, _ r2IsSome: Int32, _ r2CaseId: Int32) -> Void { @@ -10147,93 +10157,93 @@ func _$jsTranslatePoint(_ point: Point, _ dx: Int, _ dy: Int) throws(JSException } #if arch(wasm32) -@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_runJsOptionalSupportTests") -fileprivate func bjs_runJsOptionalSupportTests() -> Void +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_OptionalSupportImports_jsRoundTripOptionalNumberNull_static") +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalNumberNull_static(_ valueIsSome: Int32, _ valueValue: Int32) -> Void #else -fileprivate func bjs_runJsOptionalSupportTests() -> Void { +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalNumberNull_static(_ valueIsSome: Int32, _ valueValue: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -func _$runJsOptionalSupportTests() throws(JSException) -> Void { - bjs_runJsOptionalSupportTests() - if let error = _swift_js_take_exception() { - throw error - } +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_OptionalSupportImports_jsRoundTripOptionalNumberUndefined_static") +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalNumberUndefined_static(_ valueIsSome: Int32, _ valueValue: Int32) -> Void +#else +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalNumberUndefined_static(_ valueIsSome: Int32, _ valueValue: Int32) -> Void { + fatalError("Only available on WebAssembly") } +#endif #if arch(wasm32) -@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsRoundTripOptionalNumberNull") -fileprivate func bjs_jsRoundTripOptionalNumberNull(_ valueIsSome: Int32, _ valueValue: Int32) -> Void +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_OptionalSupportImports_jsRoundTripOptionalStringNull_static") +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringNull_static(_ nameIsSome: Int32, _ nameValue: Int32) -> Void #else -fileprivate func bjs_jsRoundTripOptionalNumberNull(_ valueIsSome: Int32, _ valueValue: Int32) -> Void { +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringNull_static(_ nameIsSome: Int32, _ nameValue: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -func _$jsRoundTripOptionalNumberNull(_ value: Optional) throws(JSException) -> Optional { - let (valueIsSome, valueValue) = value.bridgeJSLowerParameter() - bjs_jsRoundTripOptionalNumberNull(valueIsSome, valueValue) - if let error = _swift_js_take_exception() { - throw error - } - return Optional.bridgeJSLiftReturnFromSideChannel() +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_OptionalSupportImports_jsRoundTripOptionalStringUndefined_static") +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringUndefined_static(_ nameIsSome: Int32, _ nameValue: Int32) -> Void +#else +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringUndefined_static(_ nameIsSome: Int32, _ nameValue: Int32) -> Void { + fatalError("Only available on WebAssembly") } +#endif #if arch(wasm32) -@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsRoundTripOptionalNumberUndefined") -fileprivate func bjs_jsRoundTripOptionalNumberUndefined(_ valueIsSome: Int32, _ valueValue: Int32) -> Void +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_OptionalSupportImports_runJsOptionalSupportTests_static") +fileprivate func bjs_OptionalSupportImports_runJsOptionalSupportTests_static() -> Void #else -fileprivate func bjs_jsRoundTripOptionalNumberUndefined(_ valueIsSome: Int32, _ valueValue: Int32) -> Void { +fileprivate func bjs_OptionalSupportImports_runJsOptionalSupportTests_static() -> Void { fatalError("Only available on WebAssembly") } #endif -func _$jsRoundTripOptionalNumberUndefined(_ value: JSUndefinedOr) throws(JSException) -> JSUndefinedOr { +func _$OptionalSupportImports_jsRoundTripOptionalNumberNull(_ value: Optional) throws(JSException) -> Optional { let (valueIsSome, valueValue) = value.bridgeJSLowerParameter() - bjs_jsRoundTripOptionalNumberUndefined(valueIsSome, valueValue) + bjs_OptionalSupportImports_jsRoundTripOptionalNumberNull_static(valueIsSome, valueValue) if let error = _swift_js_take_exception() { throw error } - return JSUndefinedOr.bridgeJSLiftReturnFromSideChannel() + return Optional.bridgeJSLiftReturnFromSideChannel() } -#if arch(wasm32) -@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsRoundTripOptionalStringNull") -fileprivate func bjs_jsRoundTripOptionalStringNull(_ nameIsSome: Int32, _ nameValue: Int32) -> Void -#else -fileprivate func bjs_jsRoundTripOptionalStringNull(_ nameIsSome: Int32, _ nameValue: Int32) -> Void { - fatalError("Only available on WebAssembly") +func _$OptionalSupportImports_jsRoundTripOptionalNumberUndefined(_ value: JSUndefinedOr) throws(JSException) -> JSUndefinedOr { + let (valueIsSome, valueValue) = value.bridgeJSLowerParameter() + bjs_OptionalSupportImports_jsRoundTripOptionalNumberUndefined_static(valueIsSome, valueValue) + if let error = _swift_js_take_exception() { + throw error + } + return JSUndefinedOr.bridgeJSLiftReturnFromSideChannel() } -#endif -func _$jsRoundTripOptionalStringNull(_ name: Optional) throws(JSException) -> Optional { +func _$OptionalSupportImports_jsRoundTripOptionalStringNull(_ name: Optional) throws(JSException) -> Optional { let (nameIsSome, nameValue) = name.bridgeJSLowerParameter() - bjs_jsRoundTripOptionalStringNull(nameIsSome, nameValue) + bjs_OptionalSupportImports_jsRoundTripOptionalStringNull_static(nameIsSome, nameValue) if let error = _swift_js_take_exception() { throw error } return Optional.bridgeJSLiftReturnFromSideChannel() } -#if arch(wasm32) -@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsRoundTripOptionalStringUndefined") -fileprivate func bjs_jsRoundTripOptionalStringUndefined(_ nameIsSome: Int32, _ nameValue: Int32) -> Void -#else -fileprivate func bjs_jsRoundTripOptionalStringUndefined(_ nameIsSome: Int32, _ nameValue: Int32) -> Void { - fatalError("Only available on WebAssembly") -} -#endif - -func _$jsRoundTripOptionalStringUndefined(_ name: JSUndefinedOr) throws(JSException) -> JSUndefinedOr { +func _$OptionalSupportImports_jsRoundTripOptionalStringUndefined(_ name: JSUndefinedOr) throws(JSException) -> JSUndefinedOr { let (nameIsSome, nameValue) = name.bridgeJSLowerParameter() - bjs_jsRoundTripOptionalStringUndefined(nameIsSome, nameValue) + bjs_OptionalSupportImports_jsRoundTripOptionalStringUndefined_static(nameIsSome, nameValue) if let error = _swift_js_take_exception() { throw error } return JSUndefinedOr.bridgeJSLiftReturnFromSideChannel() } +func _$OptionalSupportImports_runJsOptionalSupportTests() throws(JSException) -> Void { + bjs_OptionalSupportImports_runJsOptionalSupportTests_static() + if let error = _swift_js_take_exception() { + throw error + } +} + #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_SwiftClassSupportImports_jsRoundTripGreeter_static") fileprivate func bjs_SwiftClassSupportImports_jsRoundTripGreeter_static(_ greeter: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index fc650b37d..9c086c808 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -10564,6 +10564,36 @@ } } }, + { + "abiName" : "bjs_takeOptionalJSObject", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "takeOptionalJSObject", + "parameters" : [ + { + "label" : "_", + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "jsObject" : { + + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, { "abiName" : "bjs_compareAPIResults", "effects" : { @@ -15266,23 +15296,39 @@ }, { "functions" : [ + + ], + "types" : [ { - "name" : "runJsOptionalSupportTests", - "parameters" : [ + "getters" : [ ], - "returnType" : { - "void" : { + "methods" : [ - } - } - }, - { - "name" : "jsRoundTripOptionalNumberNull", - "parameters" : [ + ], + "name" : "OptionalSupportImports", + "setters" : [ + + ], + "staticMethods" : [ { - "name" : "value", - "type" : { + "name" : "jsRoundTripOptionalNumberNull", + "parameters" : [ + { + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "int" : { + + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { "nullable" : { "_0" : { "int" : { @@ -15292,25 +15338,25 @@ "_1" : "null" } } - } - ], - "returnType" : { - "nullable" : { - "_0" : { - "int" : { + }, + { + "name" : "jsRoundTripOptionalNumberUndefined", + "parameters" : [ + { + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "int" : { + } + }, + "_1" : "undefined" + } + } } - }, - "_1" : "null" - } - } - }, - { - "name" : "jsRoundTripOptionalNumberUndefined", - "parameters" : [ - { - "name" : "value", - "type" : { + ], + "returnType" : { "nullable" : { "_0" : { "int" : { @@ -15320,25 +15366,25 @@ "_1" : "undefined" } } - } - ], - "returnType" : { - "nullable" : { - "_0" : { - "int" : { + }, + { + "name" : "jsRoundTripOptionalStringNull", + "parameters" : [ + { + "name" : "name", + "type" : { + "nullable" : { + "_0" : { + "string" : { + } + }, + "_1" : "null" + } + } } - }, - "_1" : "undefined" - } - } - }, - { - "name" : "jsRoundTripOptionalStringNull", - "parameters" : [ - { - "name" : "name", - "type" : { + ], + "returnType" : { "nullable" : { "_0" : { "string" : { @@ -15348,25 +15394,25 @@ "_1" : "null" } } - } - ], - "returnType" : { - "nullable" : { - "_0" : { - "string" : { + }, + { + "name" : "jsRoundTripOptionalStringUndefined", + "parameters" : [ + { + "name" : "name", + "type" : { + "nullable" : { + "_0" : { + "string" : { + } + }, + "_1" : "undefined" + } + } } - }, - "_1" : "null" - } - } - }, - { - "name" : "jsRoundTripOptionalStringUndefined", - "parameters" : [ - { - "name" : "name", - "type" : { + ], + "returnType" : { "nullable" : { "_0" : { "string" : { @@ -15376,22 +15422,20 @@ "_1" : "undefined" } } - } - ], - "returnType" : { - "nullable" : { - "_0" : { - "string" : { + }, + { + "name" : "runJsOptionalSupportTests", + "parameters" : [ + + ], + "returnType" : { + "void" : { } - }, - "_1" : "undefined" + } } - } + ] } - ], - "types" : [ - ] }, { diff --git a/Tests/BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs b/Tests/BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs index 8a856582d..58215560c 100644 --- a/Tests/BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs +++ b/Tests/BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs @@ -15,6 +15,31 @@ import { import { ImportedFoo } from './Types.mjs'; +/** + * @returns {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Imports["OptionalSupportImports"]} + */ +export function getImports(importsContext) { + return { + jsRoundTripOptionalNumberNull: (v) => { + return v ?? null; + }, + jsRoundTripOptionalNumberUndefined: (v) => { + return v === undefined ? undefined : v; + }, + jsRoundTripOptionalStringNull: (v) => { + return v ?? null; + }, + jsRoundTripOptionalStringUndefined: (v) => { + return v === undefined ? undefined : v; + }, + runJsOptionalSupportTests: () => { + const exports = importsContext.getExports(); + if (!exports) { throw new Error("No exports!?"); } + runJsOptionalSupportTests(exports); + }, + }; +} + /** * Optional value bridging coverage for BridgeJS runtime tests. * @param {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports @@ -216,4 +241,6 @@ export function runJsOptionalSupportTests(exports) { assert.deepEqual(exports.roundTripOptionalPayloadResultOpt(oatr_empty), oatr_empty); assert.equal(exports.roundTripOptionalPayloadResultOpt(null), null); + exports.takeOptionalJSObject(null); + assert.doesNotThrow(() => exports.takeOptionalJSObject({ key: "value" })); } diff --git a/Tests/BridgeJSRuntimeTests/OptionalSupportTests.swift b/Tests/BridgeJSRuntimeTests/OptionalSupportTests.swift index 998f8b90f..a99bb0bb1 100644 --- a/Tests/BridgeJSRuntimeTests/OptionalSupportTests.swift +++ b/Tests/BridgeJSRuntimeTests/OptionalSupportTests.swift @@ -2,61 +2,59 @@ import XCTest import JavaScriptKit import JavaScriptEventLoop -@JSFunction func runJsOptionalSupportTests() throws +@JSClass struct OptionalSupportImports { + @JSFunction static func jsRoundTripOptionalNumberNull(_ value: Int?) throws -> Int? + @JSFunction static func jsRoundTripOptionalNumberUndefined(_ value: JSUndefinedOr) throws -> JSUndefinedOr + @JSFunction static func jsRoundTripOptionalStringNull(_ name: String?) throws -> String? + @JSFunction static func jsRoundTripOptionalStringUndefined( + _ name: JSUndefinedOr + ) throws -> JSUndefinedOr + + @JSFunction static func runJsOptionalSupportTests() throws(JSException) +} final class OptionalSupportTests: XCTestCase { func testRunJsOptionalSupportTests() throws { - try runJsOptionalSupportTests() + try OptionalSupportImports.runJsOptionalSupportTests() } - func testRoundTripOptionalStringNull() throws { - try XCTAssertEqual(jsRoundTripOptionalStringNull("hello"), "hello") - try XCTAssertNil(jsRoundTripOptionalStringNull(nil)) + private func roundTripTest(_ fn: (T?) throws -> T?, _ some: T) throws { + try XCTAssertNil(fn(nil)) + try XCTAssertEqual(fn(some), some) } - - func testRoundTripOptionalStringUndefined() throws { - let some = try jsRoundTripOptionalStringUndefined(.value("hi")) - switch some { + private func roundTripTest(_ fn: (JSUndefinedOr) throws -> JSUndefinedOr, _ some: T) throws { + let undefined = try fn(.undefined) + if case .value = undefined { + XCTFail("Expected undefined") + } + let value = try fn(.value(some)) + switch value { case .value(let value): - XCTAssertEqual(value, "hi") + XCTAssertEqual(value, some) case .undefined: XCTFail("Expected defined value") } + } - let undefined = try jsRoundTripOptionalStringUndefined(.undefined) - if case .value = undefined { - XCTFail("Expected undefined") - } + func testRoundTripOptionalStringNull() throws { + try roundTripTest(OptionalSupportImports.jsRoundTripOptionalStringNull, "hello") + } + + func testRoundTripOptionalStringUndefined() throws { + try roundTripTest(OptionalSupportImports.jsRoundTripOptionalStringUndefined, "hi") } func testRoundTripOptionalNumberNull() throws { - try XCTAssertEqual(jsRoundTripOptionalNumberNull(42), 42) - try XCTAssertNil(jsRoundTripOptionalNumberNull(nil)) + try roundTripTest(OptionalSupportImports.jsRoundTripOptionalNumberNull, 42) } func testRoundTripOptionalNumberUndefined() throws { - let some = try jsRoundTripOptionalNumberUndefined(.value(42)) - switch some { - case .value(let value): - XCTAssertEqual(value, 42) - case .undefined: - XCTFail("Expected defined value") - } - - let undefined = try jsRoundTripOptionalNumberUndefined(.undefined) - if case .value = undefined { - XCTFail("Expected undefined") - } + try roundTripTest(OptionalSupportImports.jsRoundTripOptionalNumberUndefined, 42) } } // MARK: - Optional Bridging -@JSFunction func jsRoundTripOptionalNumberNull(_ value: Int?) throws -> Int? -@JSFunction func jsRoundTripOptionalNumberUndefined(_ value: JSUndefinedOr) throws -> JSUndefinedOr -@JSFunction func jsRoundTripOptionalStringNull(_ name: String?) throws -> String? -@JSFunction func jsRoundTripOptionalStringUndefined(_ name: JSUndefinedOr) throws -> JSUndefinedOr - @JS func roundTripOptionalString(name: String?) -> String? { name } @@ -130,6 +128,8 @@ typealias OptionalAge = Int? result } +@JS func takeOptionalJSObject(_ value: JSObject?) {} + @JS func compareAPIResults(_ r1: APIResult?, _ r2: APIResult?) -> String { let r1Str: String switch r1 { diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index ec37bdbc4..d40a2845c 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -7,6 +7,7 @@ import { ImportedFoo } from './BridgeJSRuntimeTests/JavaScript/Types.mjs'; import { runJsOptionalSupportTests } from './BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs'; import { getImports as getClosureSupportImports } from './BridgeJSRuntimeTests/JavaScript/ClosureSupportTests.mjs'; import { getImports as getSwiftClassSupportImports } from './BridgeJSRuntimeTests/JavaScript/SwiftClassSupportTests.mjs'; +import { getImports as getOptionalSupportImports } from './BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs'; /** @type {import('../.build/plugins/PackageToJS/outputs/PackageTests/test.d.ts').SetupOptionsFn} */ export async function setupOptions(options, context) { @@ -90,18 +91,6 @@ export async function setupOptions(options, context) { "jsRoundTripUndefinedDictionary": (dict) => { return dict; }, - "jsRoundTripOptionalNumberNull": (v) => { - return v ?? null; - }, - "jsRoundTripOptionalNumberUndefined": (v) => { - return v === undefined ? undefined : v; - }, - "jsRoundTripOptionalStringNull": (v) => { - return v ?? null; - }, - "jsRoundTripOptionalStringUndefined": (v) => { - return v === undefined ? undefined : v; - }, "jsRoundTripJSValue": (v) => { return v; }, @@ -215,6 +204,7 @@ export async function setupOptions(options, context) { }, ClosureSupportImports: getClosureSupportImports(importsContext), SwiftClassSupportImports: getSwiftClassSupportImports(importsContext), + OptionalSupportImports: getOptionalSupportImports(importsContext), }; }, addToCoreImports(importObject, importsContext) {