diff --git a/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json b/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json index cb081ab3..4dff9713 100644 --- a/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json +++ b/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json @@ -449,12 +449,13 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } }, @@ -470,12 +471,13 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } }, @@ -491,12 +493,13 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "bool" : { } - } + }, + "_1" : "null" } } }, @@ -512,12 +515,13 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "bool" : { } - } + }, + "_1" : "null" } } }, @@ -533,12 +537,13 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "double" : { } - } + }, + "_1" : "null" } } }, @@ -554,12 +559,13 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "double" : { } - } + }, + "_1" : "null" } } }, @@ -575,12 +581,13 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -596,12 +603,13 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } @@ -1844,12 +1852,13 @@ "type" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } } @@ -1876,12 +1885,13 @@ "returnType" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } } @@ -1902,12 +1912,13 @@ "type" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } } @@ -1917,12 +1928,13 @@ "returnType" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } } @@ -1943,12 +1955,13 @@ "type" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "swiftStruct" : { "_0" : "Point" } - } + }, + "_1" : "null" } } } @@ -1975,12 +1988,13 @@ "returnType" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "swiftStruct" : { "_0" : "Point" } - } + }, + "_1" : "null" } } } @@ -2001,12 +2015,13 @@ "type" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "swiftStruct" : { "_0" : "Point" } - } + }, + "_1" : "null" } } } @@ -2016,12 +2031,13 @@ "returnType" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "swiftStruct" : { "_0" : "Point" } - } + }, + "_1" : "null" } } } @@ -2040,7 +2056,7 @@ "label" : "_", "name" : "values", "type" : { - "optional" : { + "nullable" : { "_0" : { "array" : { "_0" : { @@ -2049,7 +2065,8 @@ } } } - } + }, + "_1" : "null" } } } @@ -2072,7 +2089,7 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "array" : { "_0" : { @@ -2081,7 +2098,8 @@ } } } - } + }, + "_1" : "null" } } }, @@ -2097,7 +2115,7 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "array" : { "_0" : { @@ -2106,7 +2124,8 @@ } } } - } + }, + "_1" : "null" } } }, @@ -2123,7 +2142,7 @@ "label" : "_", "name" : "values", "type" : { - "optional" : { + "nullable" : { "_0" : { "array" : { "_0" : { @@ -2132,13 +2151,14 @@ } } } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "array" : { "_0" : { @@ -2147,7 +2167,8 @@ } } } - } + }, + "_1" : "null" } } } @@ -2601,12 +2622,13 @@ "isStatic" : false, "name" : "email", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift index 5d654566..30cf8b2c 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift @@ -22,7 +22,7 @@ public struct ClosureCodegen { collectClosureSignatures(from: paramType, into: &signatures) } collectClosureSignatures(from: signature.returnType, into: &signatures) - case .optional(let wrapped): + case .nullable(let wrapped, _): collectClosureSignatures(from: wrapped, into: &signatures) default: break diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index dc8b5e04..cb267c21 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -133,17 +133,27 @@ public class ExportSwift { case .array: typeNameForIntrinsic = param.type.swiftType liftingExpr = StackCodegen().liftExpression(for: param.type) - case .optional(let wrappedType): + case .nullable(let wrappedType, let kind): + let optionalSwiftType: String + if case .null = kind { + optionalSwiftType = "Optional" + } else { + optionalSwiftType = "JSUndefinedOr" + } if case .array(let elementType) = wrappedType { let arrayLift = StackCodegen().liftArrayExpression(elementType: elementType) let isSomeParam = argumentsToLift[0] let swiftTypeName = elementType.swiftType - typeNameForIntrinsic = "Optional<[\(swiftTypeName)]>" + typeNameForIntrinsic = "\(optionalSwiftType)<[\(swiftTypeName)]>" + let absentExpr = + kind == .null + ? "\(optionalSwiftType)<[\(swiftTypeName)]>.none" + : "\(optionalSwiftType)<[\(swiftTypeName)]>.undefinedValue" liftingExpr = ExprSyntax( """ { if \(raw: isSomeParam) == 0 { - return Optional<[\(raw: swiftTypeName)]>.none + return \(raw: absentExpr) } else { return \(arrayLift) } @@ -152,12 +162,12 @@ public class ExportSwift { ) } else if case .swiftProtocol(let protocolName) = wrappedType { let wrapperName = "Any\(protocolName)" - typeNameForIntrinsic = "Optional<\(wrapperName)>" + typeNameForIntrinsic = "\(optionalSwiftType)<\(wrapperName)>" liftingExpr = ExprSyntax( "\(raw: typeNameForIntrinsic).bridgeJSLiftParameter(\(raw: argumentsToLift.joined(separator: ", ")))" ) } else { - typeNameForIntrinsic = "Optional<\(wrappedType.swiftType)>" + typeNameForIntrinsic = "\(optionalSwiftType)<\(wrappedType.swiftType)>" liftingExpr = ExprSyntax( "\(raw: typeNameForIntrinsic).bridgeJSLiftParameter(\(raw: argumentsToLift.joined(separator: ", ")))" ) @@ -220,7 +230,7 @@ public class ExportSwift { return CodeBlockItemSyntax( item: .init(DeclSyntax("let ret = \(raw: callExpr) as! \(raw: wrapperName)")) ) - case .optional(let wrappedType): + case .nullable(let wrappedType, _): if case .swiftProtocol(let protocolName) = wrappedType { let wrapperName = "Any\(protocolName)" return CodeBlockItemSyntax( @@ -251,7 +261,7 @@ public class ExportSwift { case .swiftProtocol(let protocolName): let wrapperName = "Any\(protocolName)" append("let ret = \(raw: name) as! \(raw: wrapperName)") - case .optional(let wrappedType): + case .nullable(let wrappedType, _): if case .swiftProtocol(let protocolName) = wrappedType { let wrapperName = "Any\(protocolName)" append("let ret = \(raw: name).flatMap { $0 as? \(raw: wrapperName) }") @@ -278,8 +288,8 @@ public class ExportSwift { private func generateParameterLifting() { let stackParamIndices = parameters.enumerated().compactMap { index, param -> Int? in switch param.type { - case .swiftStruct, .optional(.swiftStruct), - .associatedValueEnum, .optional(.associatedValueEnum), + case .swiftStruct, .nullable(.swiftStruct, _), + .associatedValueEnum, .nullable(.associatedValueEnum, _), .array: return index default: @@ -308,7 +318,7 @@ public class ExportSwift { case .swiftProtocol(let protocolName): let wrapperName = "Any\(protocolName)" append("let ret = \(raw: selfExpr).\(raw: propertyName) as! \(raw: wrapperName)") - case .optional(let wrappedType): + case .nullable(let wrappedType, _): if case .swiftProtocol(let protocolName) = wrappedType { let wrapperName = "Any\(protocolName)" append("let ret = \(raw: selfExpr).\(raw: propertyName).flatMap { $0 as? \(raw: wrapperName) }") @@ -356,7 +366,7 @@ public class ExportSwift { switch returnType { case .closure(let signature): append("return _BJS_Closure_\(raw: signature.mangleName).bridgeJSLower(ret)") - case .array, .optional(.array): + case .array, .nullable(.array, _): let stackCodegen = StackCodegen() for stmt in stackCodegen.lowerStatements(for: returnType, accessor: "ret", varPrefix: "ret") { append(stmt) @@ -818,8 +828,8 @@ struct StackCodegen { } case .associatedValueEnum: return "\(raw: type.swiftType).bridgeJSLiftParameter(_swift_js_pop_i32())" - case .optional(let wrappedType): - return liftOptionalExpression(wrappedType: wrappedType) + case .nullable(let wrappedType, let kind): + return liftNullableExpression(wrappedType: wrappedType, kind: kind) case .array(let elementType): return liftArrayExpression(elementType: elementType) case .closure: @@ -839,7 +849,7 @@ struct StackCodegen { return liftArrayExpressionInline(elementType: elementType) case .swiftProtocol(let protocolName): return "[Any\(raw: protocolName)].bridgeJSLiftParameter()" - case .optional, .array, .closure: + case .nullable, .array, .closure: return liftArrayExpressionInline(elementType: elementType) case .void, .namespaceEnum: fatalError("Invalid array element type: \(elementType)") @@ -863,28 +873,32 @@ struct StackCodegen { """ } - private func liftOptionalExpression(wrappedType: BridgeType) -> ExprSyntax { + private func liftNullableExpression(wrappedType: BridgeType, kind: JSOptionalKind) -> ExprSyntax { + let typeName = kind == .null ? "Optional" : "JSUndefinedOr" switch wrappedType { case .string, .int, .uint, .bool, .float, .double, .jsObject(nil), .swiftStruct, .swiftHeapObject, .caseEnum, .associatedValueEnum, .rawValueEnum: - return "Optional<\(raw: wrappedType.swiftType)>.bridgeJSLiftParameter()" + return "\(raw: typeName)<\(raw: wrappedType.swiftType)>.bridgeJSLiftParameter()" case .jsObject(let className?): - return "Optional.bridgeJSLiftParameter().map { \(raw: className)(unsafelyWrapping: $0) }" + return "\(raw: typeName).bridgeJSLiftParameter().map { \(raw: className)(unsafelyWrapping: $0) }" case .array(let elementType): let arrayLift = liftArrayExpression(elementType: elementType) let swiftTypeName = elementType.swiftType + let absentExpr = + kind == .null + ? "\(typeName)<[\(swiftTypeName)]>.none" : "\(typeName)<[\(swiftTypeName)]>.undefinedValue" return """ { let __isSome = _swift_js_pop_i32() if __isSome == 0 { - return Optional<[\(raw: swiftTypeName)]>.none + return \(raw: absentExpr) } else { return \(arrayLift) } }() """ - case .void, .namespaceEnum, .closure, .optional, .unsafePointer, .swiftProtocol: - fatalError("Invalid optional wrapped type: \(wrappedType)") + case .nullable, .void, .namespaceEnum, .closure, .unsafePointer, .swiftProtocol: + fatalError("Invalid nullable wrapped type: \(wrappedType)") } } @@ -915,7 +929,7 @@ struct StackCodegen { return ["\(raw: accessor).bridgeJSLowerStackReturn()"] case .associatedValueEnum, .swiftStruct: return ["\(raw: accessor).bridgeJSLowerReturn()"] - case .optional(let wrappedType): + case .nullable(let wrappedType, _): return lowerOptionalStatements(wrappedType: wrappedType, accessor: accessor, varPrefix: varPrefix) case .void, .namespaceEnum: return [] @@ -938,7 +952,7 @@ struct StackCodegen { return ["\(raw: accessor).map { $0.jsObject }.bridgeJSLowerReturn()"] case .swiftProtocol(let protocolName): return ["\(raw: accessor).map { $0 as! Any\(raw: protocolName) }.bridgeJSLowerReturn()"] - case .optional, .array, .closure: + case .nullable, .array, .closure: return lowerArrayStatementsInline( elementType: elementType, accessor: accessor, @@ -1596,7 +1610,8 @@ extension BridgeType { case .unsafePointer(let ptr): return ptr.swiftType case .swiftProtocol(let name): return "Any\(name)" case .void: return "Void" - case .optional(let wrappedType): return "Optional<\(wrappedType.swiftType)>" + case .nullable(let wrappedType, let kind): + return kind == .null ? "Optional<\(wrappedType.swiftType)>" : "JSUndefinedOr<\(wrappedType.swiftType)>" case .array(let elementType): return "[\(elementType.swiftType)]" case .caseEnum(let name): return name case .rawValueEnum(let name, _): return name @@ -1640,7 +1655,7 @@ extension BridgeType { case .unsafePointer: return .unsafePointer case .swiftProtocol: return .jsObject case .void: return .void - case .optional(let wrappedType): + case .nullable(let wrappedType, _): var optionalParams: [(name: String, type: WasmCoreType)] = [("isSome", .i32)] optionalParams.append(contentsOf: try wrappedType.liftParameterInfo().parameters) return LiftingIntrinsicInfo(parameters: optionalParams) @@ -1692,7 +1707,7 @@ extension BridgeType { case .unsafePointer: return .unsafePointer case .swiftProtocol: return .jsObject case .void: return .void - case .optional: return .optional + case .nullable: return .optional case .caseEnum: return .caseEnum case .rawValueEnum(_, let rawType): return rawType.loweringIntrinsicInfo diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift index 7c391eea..cd3f8444 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift @@ -924,16 +924,11 @@ extension BridgeType { } case .namespaceEnum: throw BridgeJSCoreError("Namespace enums cannot be used as parameters") - case .optional(let wrappedType): - switch context { - case .importTS: - throw BridgeJSCoreError("Optional types are not yet supported in TypeScript imports") - case .exportSwift: - let wrappedInfo = try wrappedType.loweringParameterInfo(context: context) - var params = [("isSome", WasmCoreType.i32)] - params.append(contentsOf: wrappedInfo.loweredParameters) - return LoweringParameterInfo(loweredParameters: params) - } + case .nullable(let wrappedType, _): + let wrappedInfo = try wrappedType.loweringParameterInfo(context: context) + var params = [("isSome", WasmCoreType.i32)] + params.append(contentsOf: wrappedInfo.loweredParameters) + return LoweringParameterInfo(loweredParameters: params) case .array: switch context { case .importTS: @@ -1018,14 +1013,9 @@ extension BridgeType { } case .namespaceEnum: throw BridgeJSCoreError("Namespace enums cannot be used as return values") - case .optional(let wrappedType): - switch context { - case .importTS: - throw BridgeJSCoreError("Optional types are not yet supported in TypeScript imports") - case .exportSwift: - let wrappedInfo = try wrappedType.liftingReturnInfo(context: context) - return LiftingReturnInfo(valueToLift: wrappedInfo.valueToLift) - } + case .nullable(let wrappedType, _): + let wrappedInfo = try wrappedType.liftingReturnInfo(context: context) + return LiftingReturnInfo(valueToLift: wrappedInfo.valueToLift) case .array: switch context { case .importTS: diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index b780012f..adc49c89 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -130,7 +130,31 @@ public final class SwiftToSkeleton { if let optionalType = type.as(OptionalTypeSyntax.self) { let wrappedType = optionalType.wrappedType if let baseType = lookupType(for: wrappedType, errors: &errors) { - return .optional(baseType) + return .nullable(baseType, .null) + } + } + // JSUndefinedOr + if let identifierType = type.as(IdentifierTypeSyntax.self), + identifierType.name.text == "JSUndefinedOr", + let genericArgs = identifierType.genericArgumentClause?.arguments, + genericArgs.count == 1, + let argType = TypeSyntax(genericArgs.first?.argument) + { + if let baseType = lookupType(for: argType, errors: &errors) { + return .nullable(baseType, .undefined) + } + } + // JavaScriptKit.JSUndefinedOr + if let memberType = type.as(MemberTypeSyntax.self), + let baseType = memberType.baseType.as(IdentifierTypeSyntax.self), + baseType.name.text == "JavaScriptKit", + memberType.name.text == "JSUndefinedOr", + let genericArgs = memberType.genericArgumentClause?.arguments, + genericArgs.count == 1, + let argType = TypeSyntax(genericArgs.first?.argument) + { + if let wrappedType = lookupType(for: argType, errors: &errors) { + return .nullable(wrappedType, .undefined) } } // Optional @@ -141,7 +165,7 @@ public final class SwiftToSkeleton { let argType = TypeSyntax(genericArgs.first?.argument) { if let baseType = lookupType(for: argType, errors: &errors) { - return .optional(baseType) + return .nullable(baseType, .null) } } // Swift.Optional @@ -154,7 +178,7 @@ public final class SwiftToSkeleton { let argType = TypeSyntax(genericArgs.first?.argument) { if let wrappedType = lookupType(for: argType, errors: &errors) { - return .optional(wrappedType) + return .nullable(wrappedType, .null) } } // [T] @@ -535,7 +559,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { switch type { case .caseEnum(let name), .rawValueEnum(let name, _), .associatedValueEnum(let name): enumName = name - case .optional(let wrappedType): + case .nullable(let wrappedType, _): switch wrappedType { case .caseEnum(let name), .rawValueEnum(let name, _), .associatedValueEnum(let name): enumName = name @@ -584,7 +608,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { let expr = defaultClause.value if expr.is(NilLiteralExprSyntax.self) { - guard case .optional(_) = type else { + guard case .nullable = type else { diagnose( node: expr, message: "nil is only valid for optional parameters", @@ -640,10 +664,10 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { let isStructType: Bool let expectedTypeName: String? switch type { - case .swiftStruct(let name), .optional(.swiftStruct(let name)): + case .swiftStruct(let name), .nullable(.swiftStruct(let name), _): isStructType = true expectedTypeName = name.split(separator: ".").last.map(String.init) - case .swiftHeapObject(let name), .optional(.swiftHeapObject(let name)): + case .swiftHeapObject(let name), .nullable(.swiftHeapObject(let name), _): isStructType = false expectedTypeName = name.split(separator: ".").last.map(String.init) default: @@ -779,7 +803,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { switch type { case .array(let element): elementType = element - case .optional(.array(let element)): + case .nullable(.array(let element), _): elementType = element default: diagnose( @@ -834,11 +858,11 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { continue } } - if case .optional(let wrappedType) = type, wrappedType.isOptional { + if case .nullable(let wrappedType, _) = type, wrappedType.isOptional { diagnoseNestedOptional(node: param.type, type: param.type.trimmedDescription) continue } - if case .optional(let wrappedType) = type, wrappedType.isOptional { + if case .nullable(let wrappedType, _) = type, wrappedType.isOptional { diagnoseNestedOptional(node: param.type, type: param.type.trimmedDescription) continue } @@ -960,7 +984,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { if let returnClause = node.signature.returnClause { let resolvedType = withLookupErrors { self.parent.lookupType(for: returnClause.type, errors: &$0) } - if let type = resolvedType, case .optional(let wrappedType) = type, wrappedType.isOptional { + if let type = resolvedType, case .nullable(let wrappedType, _) = type, wrappedType.isOptional { diagnoseNestedOptional(node: returnClause.type, type: returnClause.type.trimmedDescription) return nil } @@ -1398,7 +1422,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { switch associatedValue.type { case .string, .int, .float, .double, .bool: break - case .optional(let wrappedType): + case .nullable(let wrappedType, _): switch wrappedType { case .string, .int, .float, .double, .bool: break @@ -1587,7 +1611,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { if let returnClause = node.signature.returnClause { let resolvedType = withLookupErrors { self.parent.lookupType(for: returnClause.type, errors: &$0) } - if let type = resolvedType, case .optional(let wrappedType) = type, wrappedType.isOptional { + if let type = resolvedType, case .nullable(let wrappedType, _) = type, wrappedType.isOptional { diagnoseNestedOptional(node: returnClause.type, type: returnClause.type.trimmedDescription) return nil } @@ -1812,7 +1836,7 @@ fileprivate extension BridgeType { switch (self, expectedType) { case let (lhs, rhs) where lhs == rhs: return true - case (.optional(let wrapped), expectedType): + case (.nullable(let wrapped, _), expectedType): return wrapped == expectedType default: return false diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 60b55cd4..97678dc6 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -297,7 +297,7 @@ public struct BridgeJSLink { switch type { case .closure: return true - case .optional(let wrapped): + case .nullable(let wrapped, _): return containsClosureType(in: wrapped) default: return false @@ -746,7 +746,7 @@ public struct BridgeJSLink { collectClosureSignatures(from: paramType, into: &signatures) } collectClosureSignatures(from: signature.returnType, into: &signatures) - case .optional(let wrapped): + case .nullable(let wrapped, _): collectClosureSignatures(from: wrapped, into: &signatures) default: break @@ -764,7 +764,7 @@ public struct BridgeJSLink { // Build parameter list for invoke function var invokeParams: [String] = ["callbackId"] for (index, paramType) in signature.parameters.enumerated() { - if case .optional = paramType { + if case .nullable = paramType { invokeParams.append("param\(index)IsSome") invokeParams.append("param\(index)Value") } else { @@ -782,7 +782,7 @@ public struct BridgeJSLink { for (index, paramType) in signature.parameters.enumerated() { let fragment = try! IntrinsicJSFragment.closureLiftParameter(type: paramType) let args: [String] - if case .optional = paramType { + if case .nullable = paramType { args = ["param\(index)IsSome", "param\(index)Value", "param\(index)"] } else { args = ["param\(index)Id", "param\(index)"] @@ -1428,8 +1428,9 @@ public struct BridgeJSLink { return type.tsType case .swiftStruct(let name): return name.components(separatedBy: ".").last ?? name - case .optional(let wrapped): - return "\(resolveTypeScriptType(wrapped, exportedSkeletons: exportedSkeletons)) | null" + case .nullable(let wrapped, let kind): + let base = resolveTypeScriptType(wrapped, exportedSkeletons: exportedSkeletons) + return "\(base) | \(kind.absenceLiteral)" case .array(let elementType): let elementTypeStr = resolveTypeScriptType(elementType, exportedSkeletons: exportedSkeletons) // Parenthesize compound types so `[]` binds correctly in TypeScript @@ -2250,7 +2251,7 @@ extension BridgeJSLink { let objectExpr = "\(JSGlueVariableScope.reservedSwift).memory.getObject(self)" let accessExpr = Self.propertyAccessExpr(objectExpr: objectExpr, propertyName: name) if context == .exportSwift, returnType.usesSideChannelForOptionalReturn() { - guard case .optional(let wrappedType) = returnType else { + guard case .nullable(let wrappedType, _) = returnType else { fatalError("usesSideChannelForOptionalReturn returned true for non-optional type") } @@ -3403,8 +3404,8 @@ extension BridgeType { return name case .unsafePointer: return "number" - case .optional(let wrappedType): - return "\(wrappedType.tsType) | null" + case .nullable(let wrappedType, let kind): + return "\(wrappedType.tsType) | \(kind.absenceLiteral)" case .caseEnum(let name): return "\(name)Tag" case .rawValueEnum(let name, _): diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index c78a92de..90ea5ab0 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -296,19 +296,23 @@ struct IntrinsicJSFragment: Sendable { ) } - static func optionalLiftParameter(wrappedType: BridgeType) throws -> IntrinsicJSFragment { + static func optionalLiftParameter( + wrappedType: BridgeType, + kind: JSOptionalKind + ) throws -> IntrinsicJSFragment { return IntrinsicJSFragment( parameters: ["isSome", "wrappedValue"], printCode: { arguments, scope, printer, cleanupCode in let isSome = arguments[0] let wrappedValue = arguments[1] let resultExpr: String + let absenceLiteral = kind.absenceLiteral switch wrappedType { case .int, .float, .double, .caseEnum: - resultExpr = "\(isSome) ? \(wrappedValue) : null" + resultExpr = "\(isSome) ? \(wrappedValue) : \(absenceLiteral)" case .bool: - resultExpr = "\(isSome) ? \(wrappedValue) !== 0 : null" + resultExpr = "\(isSome) ? \(wrappedValue) !== 0 : \(absenceLiteral)" case .string: let objectLabel = scope.variable("obj") printer.write("let \(objectLabel);") @@ -320,12 +324,12 @@ struct IntrinsicJSFragment: Sendable { printer.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(wrappedValue));") } printer.write("}") - resultExpr = "\(isSome) ? \(objectLabel) : null" + resultExpr = "\(isSome) ? \(objectLabel) : \(absenceLiteral)" case .swiftHeapObject(let name): - resultExpr = "\(isSome) ? \(name).__construct(\(wrappedValue)) : null" + resultExpr = "\(isSome) ? \(name).__construct(\(wrappedValue)) : \(absenceLiteral)" case .jsObject: resultExpr = - "\(isSome) ? \(JSGlueVariableScope.reservedSwift).memory.getObject(\(wrappedValue)) : null" + "\(isSome) ? \(JSGlueVariableScope.reservedSwift).memory.getObject(\(wrappedValue)) : \(absenceLiteral)" case .rawValueEnum(_, let rawType): switch rawType { case .string: @@ -339,11 +343,11 @@ struct IntrinsicJSFragment: Sendable { printer.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(wrappedValue));") } printer.write("}") - resultExpr = "\(isSome) ? \(objectLabel) : null" + resultExpr = "\(isSome) ? \(objectLabel) : \(absenceLiteral)" case .bool: - resultExpr = "\(isSome) ? \(wrappedValue) !== 0 : null" + resultExpr = "\(isSome) ? \(wrappedValue) !== 0 : \(absenceLiteral)" default: - resultExpr = "\(isSome) ? \(wrappedValue) : null" + resultExpr = "\(isSome) ? \(wrappedValue) : \(absenceLiteral)" } case .associatedValueEnum(let fullName): let base = fullName.components(separatedBy: ".").last ?? fullName @@ -356,7 +360,7 @@ struct IntrinsicJSFragment: Sendable { ) } printer.write("}") - resultExpr = "\(isSome) ? \(enumVar) : null" + resultExpr = "\(isSome) ? \(enumVar) : \(absenceLiteral)" case .swiftStruct(let fullName): let base = fullName.components(separatedBy: ".").last ?? fullName let structVar = scope.variable("structValue") @@ -369,7 +373,7 @@ struct IntrinsicJSFragment: Sendable { } printer.write("} else {") printer.indent { - printer.write("\(structVar) = null;") + printer.write("\(structVar) = \(absenceLiteral);") } printer.write("}") resultExpr = structVar @@ -387,12 +391,12 @@ struct IntrinsicJSFragment: Sendable { } printer.write("} else {") printer.indent { - printer.write("\(arrayVar) = null;") + printer.write("\(arrayVar) = \(absenceLiteral);") } printer.write("}") resultExpr = arrayVar default: - resultExpr = "\(isSome) ? \(wrappedValue) : null" + resultExpr = "\(isSome) ? \(wrappedValue) : \(absenceLiteral)" } return [resultExpr] @@ -514,8 +518,10 @@ struct IntrinsicJSFragment: Sendable { static func optionalLiftReturn( wrappedType: BridgeType, - context: BridgeContext = .exportSwift + context: BridgeContext = .exportSwift, + kind: JSOptionalKind ) -> IntrinsicJSFragment { + let absenceLiteral = kind.absenceLiteral return IntrinsicJSFragment( parameters: [], printCode: { arguments, scope, printer, cleanupCode in @@ -550,7 +556,7 @@ struct IntrinsicJSFragment: Sendable { ? "\(className).__construct(\(pointerVar))" : "_exports['\(className)'].__construct(\(pointerVar))" printer.write( - "const \(resultVar) = \(pointerVar) === null ? null : \(constructExpr);" + "const \(resultVar) = \(pointerVar) === null ? \(absenceLiteral) : \(constructExpr);" ) case .caseEnum: printer.write("const \(resultVar) = \(JSGlueVariableScope.reservedStorageToReturnOptionalInt);") @@ -586,7 +592,7 @@ struct IntrinsicJSFragment: Sendable { printer.write("let \(resultVar);") printer.write("if (\(isNullVar)) {") printer.indent { - printer.write("\(resultVar) = null;") + printer.write("\(resultVar) = \(absenceLiteral);") } printer.write("} else {") printer.indent { @@ -608,7 +614,7 @@ struct IntrinsicJSFragment: Sendable { } printer.write("} else {") printer.indent { - printer.write("\(resultVar) = null;") + printer.write("\(resultVar) = \(absenceLiteral);") } printer.write("}") case .array(let elementType): @@ -625,7 +631,7 @@ struct IntrinsicJSFragment: Sendable { } printer.write("} else {") printer.indent { - printer.write("\(resultVar) = null;") + printer.write("\(resultVar) = \(absenceLiteral);") } printer.write("}") default: @@ -637,9 +643,9 @@ struct IntrinsicJSFragment: Sendable { ) } - static func optionalLowerReturn(wrappedType: BridgeType) throws -> IntrinsicJSFragment { + static func optionalLowerReturn(wrappedType: BridgeType, kind: JSOptionalKind) throws -> IntrinsicJSFragment { switch wrappedType { - case .void, .optional, .namespaceEnum, .closure: + case .void, .nullable, .namespaceEnum, .closure: throw BridgeJSLinkError(message: "Unsupported optional wrapped type for protocol export: \(wrappedType)") default: break } @@ -649,7 +655,8 @@ struct IntrinsicJSFragment: Sendable { printCode: { arguments, scope, printer, cleanupCode in let value = arguments[0] let isSomeVar = scope.variable("isSome") - printer.write("const \(isSomeVar) = \(value) != null;") + let presenceExpr = kind.presenceCheck(value: value) + printer.write("const \(isSomeVar) = \(presenceExpr);") switch wrappedType { case .bool: @@ -905,15 +912,19 @@ struct IntrinsicJSFragment: Sendable { return [] } ) - case .optional(let wrappedType): - return try closureOptionalLiftParameter(wrappedType: wrappedType) + case .nullable(let wrappedType, let kind): + return try closureOptionalLiftParameter(wrappedType: wrappedType, kind: kind) default: throw BridgeJSLinkError(message: "Unsupported closure parameter type for lifting: \(type)") } } - /// Handles optional parameter lifting for closure invocation - private static func closureOptionalLiftParameter(wrappedType: BridgeType) throws -> IntrinsicJSFragment { + /// Handles optional parameter lifting for closure invocation. + private static func closureOptionalLiftParameter( + wrappedType: BridgeType, + kind: JSOptionalKind + ) throws -> IntrinsicJSFragment { + let absenceLiteral = kind.absenceLiteral switch wrappedType { case .string, .rawValueEnum, .int, .bool, .double, .float, .jsObject, .swiftHeapObject, .caseEnum, .associatedValueEnum: @@ -975,7 +986,7 @@ struct IntrinsicJSFragment: Sendable { printer.unindent() printer.write("} else {") printer.indent() - printer.write("\(targetVar) = null;") + printer.write("\(targetVar) = \(absenceLiteral);") printer.unindent() printer.write("}") @@ -1106,7 +1117,7 @@ struct IntrinsicJSFragment: Sendable { return [] } ) - case .optional(let wrappedType): + case .nullable(let wrappedType, _): return try closureOptionalLowerReturn(wrappedType: wrappedType) default: throw BridgeJSLinkError(message: "Unsupported closure return type for lowering: \(type)") @@ -1301,21 +1312,28 @@ struct IntrinsicJSFragment: Sendable { return [] } ) - case .optional(let wrappedType): - return try closureOptionalLiftReturn(wrappedType: wrappedType) + case .nullable(let wrappedType, let kind): + return try closureOptionalLiftReturn(wrappedType: wrappedType, kind: kind) default: throw BridgeJSLinkError(message: "Unsupported closure return type for lifting: \(type)") } } /// Handles optional return lifting for Swift closure returns - private static func closureOptionalLiftReturn(wrappedType: BridgeType) throws -> IntrinsicJSFragment { + private static func closureOptionalLiftReturn( + wrappedType: BridgeType, + kind: JSOptionalKind + ) throws -> IntrinsicJSFragment { return IntrinsicJSFragment( parameters: ["invokeCall"], printCode: { arguments, scope, printer, cleanupCode in let invokeCall = arguments[0] printer.write("\(invokeCall);") - let baseFragment = optionalLiftReturn(wrappedType: wrappedType, context: .importTS) + let baseFragment = optionalLiftReturn( + wrappedType: wrappedType, + context: .importTS, + kind: kind + ) let lifted = baseFragment.printCode([], scope, printer, cleanupCode) if !lifted.isEmpty { printer.write("return \(lifted[0]);") @@ -1354,7 +1372,7 @@ struct IntrinsicJSFragment: Sendable { } case .associatedValueEnum: printer.write("return;") - case .optional(let wrappedType): + case .nullable(let wrappedType, _): switch wrappedType { case .swiftHeapObject: printer.write("return 0;") @@ -1382,7 +1400,7 @@ struct IntrinsicJSFragment: Sendable { return .swiftHeapObjectLowerParameter case .swiftProtocol: return .jsObjectLowerParameter case .void: return .void - case .optional(let wrappedType): + case .nullable(let wrappedType, _): return try .optionalLowerParameter(wrappedType: wrappedType) case .caseEnum: return .identity case .rawValueEnum(_, let rawType): @@ -1427,7 +1445,8 @@ struct IntrinsicJSFragment: Sendable { case .unsafePointer: return .identity case .swiftProtocol: return .jsObjectLiftReturn case .void: return .void - case .optional(let wrappedType): return .optionalLiftReturn(wrappedType: wrappedType) + case .nullable(let wrappedType, let kind): + return .optionalLiftReturn(wrappedType: wrappedType, kind: kind) case .caseEnum: return .identity case .rawValueEnum(_, let rawType): switch rawType { @@ -1485,15 +1504,8 @@ struct IntrinsicJSFragment: Sendable { throw BridgeJSLinkError( message: "Void can't appear in parameters of imported JS functions" ) - case .optional(let wrappedType): - switch context { - case .importTS: - throw BridgeJSLinkError( - message: "Optional types are not supported for imported JS functions: \(wrappedType)" - ) - case .exportSwift: - return try .optionalLiftParameter(wrappedType: wrappedType) - } + case .nullable(let wrappedType, let kind): + return try .optionalLiftParameter(wrappedType: wrappedType, kind: kind) case .caseEnum: return .identity case .rawValueEnum(_, let rawType): switch rawType { @@ -1583,15 +1595,8 @@ struct IntrinsicJSFragment: Sendable { } case .swiftProtocol: return .jsObjectLowerReturn case .void: return .void - case .optional(let wrappedType): - switch context { - case .importTS: - throw BridgeJSLinkError( - message: "Optional types are not supported for imported JS functions: \(wrappedType)" - ) - case .exportSwift: - return try .optionalLowerReturn(wrappedType: wrappedType) - } + case .nullable(let wrappedType, let kind): + return try .optionalLowerReturn(wrappedType: wrappedType, kind: kind) case .caseEnum: return .identity case .rawValueEnum(_, let rawType): switch rawType { @@ -1940,13 +1945,13 @@ struct IntrinsicJSFragment: Sendable { return [] } ) - case .optional(let wrappedType): + case .nullable(let wrappedType, let kind): return IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, scope, printer, cleanup in let value = arguments[0] let isSomeVar = scope.variable("isSome") - printer.write("const \(isSomeVar) = \(value) != null;") + printer.write("const \(isSomeVar) = \(kind.presenceCheck(value: value));") switch wrappedType { case .string: @@ -2058,7 +2063,7 @@ struct IntrinsicJSFragment: Sendable { return [dVar] } ) - case .optional(let wrappedType): + case .nullable(let wrappedType, let kind): return IntrinsicJSFragment( parameters: [], printCode: { arguments, scope, printer, cleanup in @@ -2079,7 +2084,7 @@ struct IntrinsicJSFragment: Sendable { } printer.write("} else {") printer.indent { - printer.write("\(optVar) = null;") + printer.write("\(optVar) = \(kind.absenceLiteral);") } printer.write("}") @@ -2329,8 +2334,8 @@ struct IntrinsicJSFragment: Sendable { ) case .array(let innerElementType): return try! arrayLift(elementType: innerElementType) - case .optional(let wrappedType): - return try optionalElementRaiseFragment(wrappedType: wrappedType) + case .nullable(let wrappedType, let kind): + return try optionalElementRaiseFragment(wrappedType: wrappedType, kind: kind) case .unsafePointer: return IntrinsicJSFragment( parameters: [], @@ -2479,8 +2484,11 @@ struct IntrinsicJSFragment: Sendable { ) case .array(let innerElementType): return try! arrayLower(elementType: innerElementType) - case .optional(let wrappedType): - return try optionalElementLowerFragment(wrappedType: wrappedType) + case .nullable(let wrappedType, let kind): + return try optionalElementLowerFragment( + wrappedType: wrappedType, + kind: kind + ) case .swiftProtocol: // Same as jsObject but no cleanup — Swift's AnyProtocol wrapper releases via deinit return IntrinsicJSFragment( @@ -2506,7 +2514,11 @@ struct IntrinsicJSFragment: Sendable { } } - private static func optionalElementRaiseFragment(wrappedType: BridgeType) throws -> IntrinsicJSFragment { + private static func optionalElementRaiseFragment( + wrappedType: BridgeType, + kind: JSOptionalKind + ) throws -> IntrinsicJSFragment { + let absenceLiteral = kind.absenceLiteral return IntrinsicJSFragment( parameters: [], printCode: { arguments, scope, printer, cleanup in @@ -2517,7 +2529,7 @@ struct IntrinsicJSFragment: Sendable { printer.write("let \(resultVar);") printer.write("if (\(isSomeVar) === 0) {") printer.indent { - printer.write("\(resultVar) = null;") + printer.write("\(resultVar) = \(absenceLiteral);") } printer.write("} else {") printer.indent { @@ -2536,14 +2548,18 @@ struct IntrinsicJSFragment: Sendable { ) } - private static func optionalElementLowerFragment(wrappedType: BridgeType) throws -> IntrinsicJSFragment { + private static func optionalElementLowerFragment( + wrappedType: BridgeType, + kind: JSOptionalKind + ) throws -> IntrinsicJSFragment { return IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, scope, printer, cleanup in let value = arguments[0] let isSomeVar = scope.variable("isSome") - printer.write("const \(isSomeVar) = \(value) != null ? 1 : 0;") + let presenceExpr = kind.presenceCheck(value: value) + printer.write("const \(isSomeVar) = \(presenceExpr) ? 1 : 0;") // Cleanup is written inside the if block so retained id is in scope let localCleanupWriter = CodeFragmentPrinter() printer.write("if (\(isSomeVar)) {") @@ -2849,13 +2865,13 @@ struct IntrinsicJSFragment: Sendable { return [idVar] } ) - case .optional(let wrappedType): + case .nullable(let wrappedType, let kind): return IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, scope, printer, cleanup in let value = arguments[0] let isSomeVar = scope.variable("isSome") - printer.write("const \(isSomeVar) = \(value) != null;") + printer.write("const \(isSomeVar) = \(kind.presenceCheck(value: value));") if case .caseEnum = wrappedType { printer.write("if (\(isSomeVar)) {") @@ -3302,7 +3318,7 @@ struct IntrinsicJSFragment: Sendable { return [pVar] } ) - case .optional(let wrappedType): + case .nullable(let wrappedType, let kind): return IntrinsicJSFragment( parameters: [], printCode: { arguments, scope, printer, cleanup in @@ -3340,7 +3356,7 @@ struct IntrinsicJSFragment: Sendable { } printer.write("} else {") printer.indent { - printer.write("\(optVar) = null;") + printer.write("\(optVar) = \(kind.absenceLiteral);") } printer.write("}") return [optVar] diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index 5013dda6..caf725ee 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -126,10 +126,32 @@ public struct UnsafePointerType: Codable, Equatable, Hashable, Sendable { } } +/// JS semantics for optional/nullable types: which value represents "absent". +public enum JSOptionalKind: String, Codable, Equatable, Hashable, Sendable { + case null + case undefined + + /// The JS literal for absence (e.g. in generated glue). + public var absenceLiteral: String { + switch self { + case .null: return "null" + case .undefined: return "undefined" + } + } + + /// JS expression that is true when the value is present. `value` is the variable name. + public func presenceCheck(value: String) -> String { + switch self { + case .null: return "\(value) != null" + case .undefined: return "\(value) !== undefined" + } + } +} + public enum BridgeType: Codable, Equatable, Hashable, Sendable { case int, uint, float, double, string, bool, jsObject(String?), swiftHeapObject(String), void case unsafePointer(UnsafePointerType) - indirect case optional(BridgeType) + indirect case nullable(BridgeType, JSOptionalKind) indirect case array(BridgeType) case caseEnum(String) case rawValueEnum(String, SwiftEnumRawType) @@ -895,7 +917,7 @@ extension BridgeType { return .pointer case .unsafePointer: return .pointer - case .optional(_): + case .nullable: return nil case .caseEnum: return .i32 @@ -920,9 +942,9 @@ extension BridgeType { } } - /// Returns true if this type is optional + /// Returns true if this type is optional (nullable with null or undefined). public var isOptional: Bool { - if case .optional = self { return true } + if case .nullable = self { return true } return false } @@ -959,8 +981,9 @@ extension BridgeType { return "\(kindCode)\(p.count)\(p)" } return kindCode - case .optional(let wrapped): - return "Sq\(wrapped.mangleTypeName)" + case .nullable(let wrapped, let kind): + let prefix = kind == .null ? "Sq" : "Su" + return "\(prefix)\(wrapped.mangleTypeName)" case .caseEnum(let name), .rawValueEnum(let name, _), .associatedValueEnum(let name), @@ -987,7 +1010,9 @@ extension BridgeType { /// Side channels are needed when the wrapped type cannot be directly returned via WASM, /// or when we need to distinguish null from absent value for certain primitives. public func usesSideChannelForOptionalReturn() -> Bool { - guard case .optional(let wrappedType) = self else { return false } + guard case .nullable(let wrappedType, _) = self else { + return false + } switch wrappedType { case .string, .int, .float, .double, .jsObject, .swiftProtocol: diff --git a/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/src/processor.js b/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/src/processor.js index 258334ee..0e458ed4 100644 --- a/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/src/processor.js +++ b/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/src/processor.js @@ -676,6 +676,30 @@ export class TypeProcessor { * @returns {string} */ const convert = (type) => { + // Handle nullable/undefined unions (e.g. T | null, T | undefined) + const isUnionType = (type.flags & ts.TypeFlags.Union) !== 0; + if (isUnionType) { + /** @type {ts.UnionType} */ + // @ts-ignore + const unionType = type; + const unionTypes = unionType.types; + const hasNull = unionTypes.some(t => (t.flags & ts.TypeFlags.Null) !== 0); + const hasUndefined = unionTypes.some(t => (t.flags & ts.TypeFlags.Undefined) !== 0); + const nonNullableTypes = unionTypes.filter( + t => (t.flags & ts.TypeFlags.Null) === 0 && (t.flags & ts.TypeFlags.Undefined) === 0 + ); + if (nonNullableTypes.length === 1 && (hasNull || hasUndefined)) { + const wrapped = this.visitType(nonNullableTypes[0], node); + if (hasNull && hasUndefined) { + return "JSObject"; + } + if (hasNull) { + return `Optional<${wrapped}>`; + } + return `JSUndefinedOr<${wrapped}>`; + } + } + /** @type {Record} */ const typeMap = { "number": "Double", diff --git a/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/test/__snapshots__/ts2swift.test.js.snap b/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/test/__snapshots__/ts2swift.test.js.snap index 6add64de..c1db3e32 100644 --- a/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/test/__snapshots__/ts2swift.test.js.snap +++ b/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/test/__snapshots__/ts2swift.test.js.snap @@ -145,6 +145,47 @@ exports[`ts2swift > snapshots Swift output for MultipleImportedTypes.d.ts > Mult " `; +exports[`ts2swift > snapshots Swift output for OptionalNullUndefined.d.ts > OptionalNullUndefined 1`] = ` +"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +// DO NOT EDIT. +// +// To update this file, just rebuild your project or run +// \`swift package bridge-js\`. + +@_spi(Experimental) @_spi(BridgeJS) import JavaScriptKit + +@JSFunction func roundTripNumberNull(_ value: Optional) throws(JSException) -> Optional + +@JSFunction func roundTripNumberUndefined(_ value: JSUndefinedOr) throws(JSException) -> JSUndefinedOr + +@JSFunction func roundTripStringNull(_ value: Optional) throws(JSException) -> Optional + +@JSFunction func roundTripStringUndefined(_ value: JSUndefinedOr) throws(JSException) -> JSUndefinedOr + +@JSFunction func roundTripBooleanNull(_ value: JSObject) throws(JSException) -> JSObject + +@JSFunction func roundTripBooleanUndefined(_ value: JSObject) throws(JSException) -> JSObject + +@JSFunction func optionalNumberParamNull(_ x: Double, _ maybe: Optional) throws(JSException) -> Double + +@JSFunction func optionalNumberParamUndefined(_ x: Double, _ maybe: JSUndefinedOr) throws(JSException) -> Double + +@JSFunction func roundTripMyInterfaceNull(_ value: Optional) throws(JSException) -> Optional + +@JSClass struct MyInterface { +} + +@JSFunction func roundTripMyInterfaceUndefined(_ value: JSUndefinedOr) throws(JSException) -> JSUndefinedOr + +@JSClass struct WithOptionalFields { + @JSGetter var valueOrNull: Optional + @JSSetter func setValueOrNull(_ value: Optional) throws(JSException) + @JSGetter var valueOrUndefined: JSUndefinedOr + @JSSetter func setValueOrUndefined(_ value: JSUndefinedOr) throws(JSException) +} +" +`; + exports[`ts2swift > snapshots Swift output for PrimitiveParameters.d.ts > PrimitiveParameters 1`] = ` "// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. diff --git a/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/test/fixtures/OptionalNullUndefined.d.ts b/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/test/fixtures/OptionalNullUndefined.d.ts new file mode 100644 index 00000000..8b64528d --- /dev/null +++ b/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/test/fixtures/OptionalNullUndefined.d.ts @@ -0,0 +1,20 @@ +export function roundTripNumberNull(value: number | null): number | null; +export function roundTripNumberUndefined(value: number | undefined): number | undefined; + +export function roundTripStringNull(value: string | null): string | null; +export function roundTripStringUndefined(value: string | undefined): string | undefined; + +export function roundTripBooleanNull(value: boolean | null): boolean | null; +export function roundTripBooleanUndefined(value: boolean | undefined): boolean | undefined; + +export function optionalNumberParamNull(x: number, maybe: number | null): number; +export function optionalNumberParamUndefined(x: number, maybe: number | undefined): number; + +export interface MyInterface {} +export function roundTripMyInterfaceNull(value: MyInterface | null): MyInterface | null; +export function roundTripMyInterfaceUndefined(value: MyInterface | undefined): MyInterface | undefined; + +export class WithOptionalFields { + valueOrNull: MyInterface | null; + valueOrUndefined: MyInterface | undefined; +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Optionals.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Optionals.swift index d256a875..57d99451 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Optionals.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Optionals.swift @@ -90,3 +90,39 @@ typealias OptionalNameAlias = Optional func testMixedOptionals(firstName: String?, lastName: String?, age: Int?, active: Bool) -> String? { return nil } + +@JSClass struct WithOptionalJSClass { + @JSFunction init(valueOrNull: String?, valueOrUndefined: JSUndefinedOr) throws(JSException) + + @JSGetter var stringOrNull: String? + @JSSetter func setStringOrNull(_ value: String?) throws(JSException) + @JSGetter var stringOrUndefined: JSUndefinedOr + @JSSetter func setStringOrUndefined(_ value: JSUndefinedOr) throws(JSException) + @JSFunction func roundTripStringOrNull(value: String?) throws(JSException) -> String? + @JSFunction func roundTripStringOrUndefined( + value: JSUndefinedOr + ) throws(JSException) -> JSUndefinedOr + + @JSGetter var doubleOrNull: Double? + @JSSetter func setDoubleOrNull(_ value: Double?) throws(JSException) + @JSGetter var doubleOrUndefined: JSUndefinedOr + @JSSetter func setDoubleOrUndefined(_ value: JSUndefinedOr) throws(JSException) + @JSFunction func roundTripDoubleOrNull(value: Double?) throws(JSException) -> Double? + @JSFunction func roundTripDoubleOrUndefined( + value: JSUndefinedOr + ) throws(JSException) -> JSUndefinedOr + + @JSGetter var boolOrNull: Bool? + @JSSetter func setBoolOrNull(_ value: Bool?) throws(JSException) + @JSGetter var boolOrUndefined: JSUndefinedOr + @JSSetter func setBoolOrUndefined(_ value: JSUndefinedOr) throws(JSException) + @JSFunction func roundTripBoolOrNull(value: Bool?) throws(JSException) -> Bool? + @JSFunction func roundTripBoolOrUndefined(value: JSUndefinedOr) throws(JSException) -> JSUndefinedOr + + @JSGetter var intOrNull: Int? + @JSSetter func setIntOrNull(_ value: Int?) throws(JSException) + @JSGetter var intOrUndefined: JSUndefinedOr + @JSSetter func setIntOrUndefined(_ value: JSUndefinedOr) throws(JSException) + @JSFunction func roundTripIntOrNull(value: Int?) throws(JSException) -> Int? + @JSFunction func roundTripIntOrUndefined(value: JSUndefinedOr) throws(JSException) -> JSUndefinedOr +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.json index 7950cb66..8dde2cfb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.json @@ -516,12 +516,13 @@ "type" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } } @@ -531,12 +532,13 @@ "returnType" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } } @@ -557,12 +559,13 @@ "type" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } @@ -572,12 +575,13 @@ "returnType" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } @@ -596,7 +600,7 @@ "label" : "_", "name" : "values", "type" : { - "optional" : { + "nullable" : { "_0" : { "array" : { "_0" : { @@ -605,13 +609,14 @@ } } } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "array" : { "_0" : { @@ -620,7 +625,8 @@ } } } - } + }, + "_1" : "null" } } }, @@ -639,12 +645,13 @@ "type" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "swiftStruct" : { "_0" : "Point" } - } + }, + "_1" : "null" } } } @@ -654,12 +661,13 @@ "returnType" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "swiftStruct" : { "_0" : "Point" } - } + }, + "_1" : "null" } } } @@ -680,12 +688,13 @@ "type" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Direction" } - } + }, + "_1" : "null" } } } @@ -695,12 +704,13 @@ "returnType" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Direction" } - } + }, + "_1" : "null" } } } @@ -721,13 +731,14 @@ "type" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Status", "_1" : "Int" } - } + }, + "_1" : "null" } } } @@ -737,13 +748,14 @@ "returnType" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Status", "_1" : "Int" } - } + }, + "_1" : "null" } } } @@ -994,12 +1006,13 @@ "type" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "jsObject" : { } - } + }, + "_1" : "null" } } } @@ -1009,12 +1022,13 @@ "returnType" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "jsObject" : { } - } + }, + "_1" : "null" } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.ReverseOrder.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.ReverseOrder.json index 7f21c86c..59fb8484 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.ReverseOrder.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.ReverseOrder.json @@ -12,12 +12,13 @@ "isStatic" : false, "name" : "linkedB", "type" : { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "ClassB" } - } + }, + "_1" : "null" } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.json index 3f812910..cc10331a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.json @@ -33,12 +33,13 @@ "isStatic" : false, "name" : "linkedB", "type" : { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "ClassB" } - } + }, + "_1" : "null" } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.json index 64cc1a84..8c088a35 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.json @@ -135,12 +135,13 @@ "label" : "tag", "name" : "tag", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } @@ -196,12 +197,13 @@ "isStatic" : false, "name" : "tag", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } @@ -414,23 +416,25 @@ "label" : "name", "name" : "name", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -452,23 +456,25 @@ "label" : "greeting", "name" : "greeting", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -646,23 +652,25 @@ "label" : "point", "name" : "point", "type" : { - "optional" : { + "nullable" : { "_0" : { "swiftStruct" : { "_0" : "Config" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "swiftStruct" : { "_0" : "Config" } - } + }, + "_1" : "null" } } }, @@ -710,23 +718,25 @@ "label" : "point", "name" : "point", "type" : { - "optional" : { + "nullable" : { "_0" : { "swiftStruct" : { "_0" : "Config" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "swiftStruct" : { "_0" : "Config" } - } + }, + "_1" : "null" } } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.json index ecf045c3..ba9ee932 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.json @@ -398,12 +398,13 @@ "associatedValues" : [ { "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } @@ -414,23 +415,25 @@ "associatedValues" : [ { "type" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } }, { "type" : { - "optional" : { + "nullable" : { "_0" : { "bool" : { } - } + }, + "_1" : "null" } } } @@ -441,34 +444,37 @@ "associatedValues" : [ { "type" : { - "optional" : { + "nullable" : { "_0" : { "bool" : { } - } + }, + "_1" : "null" } } }, { "type" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } }, { "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } @@ -570,23 +576,25 @@ "label" : "result", "name" : "result", "type" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIResult" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIResult" } - } + }, + "_1" : "null" } } }, @@ -670,23 +678,25 @@ "label" : "result", "name" : "result", "type" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "ComplexResult" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "ComplexResult" } - } + }, + "_1" : "null" } } }, @@ -703,23 +713,25 @@ "label" : "result", "name" : "result", "type" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "Utilities.Result" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "Utilities.Result" } - } + }, + "_1" : "null" } } }, @@ -736,23 +748,25 @@ "label" : "result", "name" : "result", "type" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "NetworkingResult" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "NetworkingResult" } - } + }, + "_1" : "null" } } }, @@ -769,23 +783,25 @@ "label" : "result", "name" : "result", "type" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIOptionalResult" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIOptionalResult" } - } + }, + "_1" : "null" } } }, @@ -802,12 +818,13 @@ "label" : "result1", "name" : "result1", "type" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIOptionalResult" } - } + }, + "_1" : "null" } } }, @@ -815,23 +832,25 @@ "label" : "result2", "name" : "result2", "type" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIOptionalResult" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIOptionalResult" } - } + }, + "_1" : "null" } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.json index 2d5d5f2f..ea32ad73 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.json @@ -216,23 +216,25 @@ "label" : "_", "name" : "input", "type" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Direction" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Direction" } - } + }, + "_1" : "null" } } }, @@ -291,23 +293,25 @@ "label" : "_", "name" : "input", "type" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "TSDirection" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "TSDirection" } - } + }, + "_1" : "null" } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.json index 20ef1f42..ba36405b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.json @@ -517,25 +517,27 @@ "label" : "_", "name" : "input", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Theme", "_1" : "String" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Theme", "_1" : "String" } - } + }, + "_1" : "null" } } }, @@ -596,25 +598,27 @@ "label" : "_", "name" : "input", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "TSTheme", "_1" : "String" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "TSTheme", "_1" : "String" } - } + }, + "_1" : "null" } } }, @@ -675,25 +679,27 @@ "label" : "_", "name" : "input", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "FeatureFlag", "_1" : "String" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "FeatureFlag", "_1" : "String" } - } + }, + "_1" : "null" } } }, @@ -754,25 +760,27 @@ "label" : "_", "name" : "input", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "HttpStatus", "_1" : "Int" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "HttpStatus", "_1" : "Int" } - } + }, + "_1" : "null" } } }, @@ -833,25 +841,27 @@ "label" : "_", "name" : "input", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "TSHttpStatus", "_1" : "Int" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "TSHttpStatus", "_1" : "Int" } - } + }, + "_1" : "null" } } }, @@ -912,25 +922,27 @@ "label" : "_", "name" : "input", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Priority", "_1" : "Int32" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Priority", "_1" : "Int32" } - } + }, + "_1" : "null" } } }, @@ -991,25 +1003,27 @@ "label" : "_", "name" : "input", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "FileSize", "_1" : "Int64" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "FileSize", "_1" : "Int64" } - } + }, + "_1" : "null" } } }, @@ -1070,25 +1084,27 @@ "label" : "_", "name" : "input", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "UserId", "_1" : "UInt" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "UserId", "_1" : "UInt" } - } + }, + "_1" : "null" } } }, @@ -1149,25 +1165,27 @@ "label" : "_", "name" : "input", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "TokenId", "_1" : "UInt32" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "TokenId", "_1" : "UInt32" } - } + }, + "_1" : "null" } } }, @@ -1228,25 +1246,27 @@ "label" : "_", "name" : "input", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "SessionId", "_1" : "UInt64" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "SessionId", "_1" : "UInt64" } - } + }, + "_1" : "null" } } }, @@ -1307,25 +1327,27 @@ "label" : "_", "name" : "input", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Precision", "_1" : "Float" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Precision", "_1" : "Float" } - } + }, + "_1" : "null" } } }, @@ -1386,25 +1408,27 @@ "label" : "_", "name" : "input", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Ratio", "_1" : "Double" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Ratio", "_1" : "Double" } - } + }, + "_1" : "null" } } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.json index c40f0dc8..cecf16c9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.json @@ -73,12 +73,13 @@ "type" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "jsObject" : { "_0" : "Foo" } - } + }, + "_1" : "null" } } } @@ -88,12 +89,13 @@ "returnType" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "jsObject" : { "_0" : "Foo" } - } + }, + "_1" : "null" } } } @@ -150,12 +152,13 @@ "isStatic" : false, "name" : "optionalFoo", "type" : { - "optional" : { + "nullable" : { "_0" : { "jsObject" : { "_0" : "Foo" } - } + }, + "_1" : "null" } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json index 2af32886..f74b3cdf 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json @@ -14,12 +14,13 @@ "label" : "name", "name" : "name", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } @@ -56,12 +57,13 @@ "label" : "name", "name" : "name", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } @@ -80,12 +82,13 @@ "isStatic" : false, "name" : "name", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } @@ -114,12 +117,13 @@ "isStatic" : false, "name" : "optionalName", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -128,12 +132,13 @@ "isStatic" : false, "name" : "optionalAge", "type" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } }, @@ -142,12 +147,13 @@ "isStatic" : false, "name" : "optionalGreeter", "type" : { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "Greeter" } - } + }, + "_1" : "null" } } } @@ -173,23 +179,25 @@ "label" : "value", "name" : "value", "type" : { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "Greeter" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "Greeter" } - } + }, + "_1" : "null" } } }, @@ -206,23 +214,25 @@ "label" : "_", "name" : "holder", "type" : { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "OptionalPropertyHolder" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "OptionalPropertyHolder" } - } + }, + "_1" : "null" } } }, @@ -239,23 +249,25 @@ "label" : "name", "name" : "name", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -272,23 +284,25 @@ "label" : "value", "name" : "value", "type" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } }, @@ -305,23 +319,25 @@ "label" : "flag", "name" : "flag", "type" : { - "optional" : { + "nullable" : { "_0" : { "bool" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "bool" : { } - } + }, + "_1" : "null" } } }, @@ -338,23 +354,25 @@ "label" : "number", "name" : "number", "type" : { - "optional" : { + "nullable" : { "_0" : { "float" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "float" : { } - } + }, + "_1" : "null" } } }, @@ -371,23 +389,25 @@ "label" : "precision", "name" : "precision", "type" : { - "optional" : { + "nullable" : { "_0" : { "double" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "double" : { } - } + }, + "_1" : "null" } } }, @@ -404,23 +424,25 @@ "label" : "name", "name" : "name", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -437,23 +459,25 @@ "label" : "name", "name" : "name", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -470,23 +494,25 @@ "label" : "name", "name" : "name", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -503,23 +529,25 @@ "label" : "name", "name" : "name", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -536,23 +564,25 @@ "label" : "value", "name" : "value", "type" : { - "optional" : { + "nullable" : { "_0" : { "double" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "double" : { } - } + }, + "_1" : "null" } } }, @@ -569,23 +599,25 @@ "label" : "age", "name" : "age", "type" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } }, @@ -602,23 +634,25 @@ "label" : "name", "name" : "name", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -635,12 +669,13 @@ "label" : "firstName", "name" : "firstName", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -648,12 +683,13 @@ "label" : "lastName", "name" : "lastName", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -661,12 +697,13 @@ "label" : "age", "name" : "age", "type" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } }, @@ -681,12 +718,13 @@ } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } @@ -698,5 +736,495 @@ ] }, + "imported" : { + "children" : [ + { + "functions" : [ + + ], + "types" : [ + { + "constructor" : { + "parameters" : [ + { + "name" : "valueOrNull", + "type" : { + "nullable" : { + "_0" : { + "string" : { + + } + }, + "_1" : "null" + } + } + }, + { + "name" : "valueOrUndefined", + "type" : { + "nullable" : { + "_0" : { + "string" : { + + } + }, + "_1" : "undefined" + } + } + } + ] + }, + "getters" : [ + { + "name" : "stringOrNull", + "type" : { + "nullable" : { + "_0" : { + "string" : { + + } + }, + "_1" : "null" + } + } + }, + { + "name" : "stringOrUndefined", + "type" : { + "nullable" : { + "_0" : { + "string" : { + + } + }, + "_1" : "undefined" + } + } + }, + { + "name" : "doubleOrNull", + "type" : { + "nullable" : { + "_0" : { + "double" : { + + } + }, + "_1" : "null" + } + } + }, + { + "name" : "doubleOrUndefined", + "type" : { + "nullable" : { + "_0" : { + "double" : { + + } + }, + "_1" : "undefined" + } + } + }, + { + "name" : "boolOrNull", + "type" : { + "nullable" : { + "_0" : { + "bool" : { + + } + }, + "_1" : "null" + } + } + }, + { + "name" : "boolOrUndefined", + "type" : { + "nullable" : { + "_0" : { + "bool" : { + + } + }, + "_1" : "undefined" + } + } + }, + { + "name" : "intOrNull", + "type" : { + "nullable" : { + "_0" : { + "int" : { + + } + }, + "_1" : "null" + } + } + }, + { + "name" : "intOrUndefined", + "type" : { + "nullable" : { + "_0" : { + "int" : { + + } + }, + "_1" : "undefined" + } + } + } + ], + "methods" : [ + { + "name" : "roundTripStringOrNull", + "parameters" : [ + { + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "string" : { + + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "string" : { + + } + }, + "_1" : "null" + } + } + }, + { + "name" : "roundTripStringOrUndefined", + "parameters" : [ + { + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "string" : { + + } + }, + "_1" : "undefined" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "string" : { + + } + }, + "_1" : "undefined" + } + } + }, + { + "name" : "roundTripDoubleOrNull", + "parameters" : [ + { + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "double" : { + + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "double" : { + + } + }, + "_1" : "null" + } + } + }, + { + "name" : "roundTripDoubleOrUndefined", + "parameters" : [ + { + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "double" : { + + } + }, + "_1" : "undefined" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "double" : { + + } + }, + "_1" : "undefined" + } + } + }, + { + "name" : "roundTripBoolOrNull", + "parameters" : [ + { + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "bool" : { + + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "bool" : { + + } + }, + "_1" : "null" + } + } + }, + { + "name" : "roundTripBoolOrUndefined", + "parameters" : [ + { + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "bool" : { + + } + }, + "_1" : "undefined" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "bool" : { + + } + }, + "_1" : "undefined" + } + } + }, + { + "name" : "roundTripIntOrNull", + "parameters" : [ + { + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "int" : { + + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "int" : { + + } + }, + "_1" : "null" + } + } + }, + { + "name" : "roundTripIntOrUndefined", + "parameters" : [ + { + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "int" : { + + } + }, + "_1" : "undefined" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "int" : { + + } + }, + "_1" : "undefined" + } + } + } + ], + "name" : "WithOptionalJSClass", + "setters" : [ + { + "functionName" : "stringOrNull_set", + "name" : "stringOrNull", + "type" : { + "nullable" : { + "_0" : { + "string" : { + + } + }, + "_1" : "null" + } + } + }, + { + "functionName" : "stringOrUndefined_set", + "name" : "stringOrUndefined", + "type" : { + "nullable" : { + "_0" : { + "string" : { + + } + }, + "_1" : "undefined" + } + } + }, + { + "functionName" : "doubleOrNull_set", + "name" : "doubleOrNull", + "type" : { + "nullable" : { + "_0" : { + "double" : { + + } + }, + "_1" : "null" + } + } + }, + { + "functionName" : "doubleOrUndefined_set", + "name" : "doubleOrUndefined", + "type" : { + "nullable" : { + "_0" : { + "double" : { + + } + }, + "_1" : "undefined" + } + } + }, + { + "functionName" : "boolOrNull_set", + "name" : "boolOrNull", + "type" : { + "nullable" : { + "_0" : { + "bool" : { + + } + }, + "_1" : "null" + } + } + }, + { + "functionName" : "boolOrUndefined_set", + "name" : "boolOrUndefined", + "type" : { + "nullable" : { + "_0" : { + "bool" : { + + } + }, + "_1" : "undefined" + } + } + }, + { + "functionName" : "intOrNull_set", + "name" : "intOrNull", + "type" : { + "nullable" : { + "_0" : { + "int" : { + + } + }, + "_1" : "null" + } + } + }, + { + "functionName" : "intOrUndefined_set", + "name" : "intOrUndefined", + "type" : { + "nullable" : { + "_0" : { + "int" : { + + } + }, + "_1" : "undefined" + } + } + } + ] + } + ] + } + ] + }, "moduleName" : "TestModule" } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift index 88195f37..471d38a6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift @@ -338,4 +338,463 @@ fileprivate func _bjs_OptionalPropertyHolder_wrap(_ pointer: UnsafeMutableRawPoi fileprivate func _bjs_OptionalPropertyHolder_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { fatalError("Only available on WebAssembly") } -#endif \ No newline at end of file +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_init") +fileprivate func bjs_WithOptionalJSClass_init(_ valueOrNullIsSome: Int32, _ valueOrNullValue: Int32, _ valueOrUndefinedIsSome: Int32, _ valueOrUndefinedValue: Int32) -> Int32 +#else +fileprivate func bjs_WithOptionalJSClass_init(_ valueOrNullIsSome: Int32, _ valueOrNullValue: Int32, _ valueOrUndefinedIsSome: Int32, _ valueOrUndefinedValue: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_stringOrNull_get") +fileprivate func bjs_WithOptionalJSClass_stringOrNull_get(_ self: Int32) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_stringOrNull_get(_ self: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_stringOrUndefined_get") +fileprivate func bjs_WithOptionalJSClass_stringOrUndefined_get(_ self: Int32) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_stringOrUndefined_get(_ self: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_doubleOrNull_get") +fileprivate func bjs_WithOptionalJSClass_doubleOrNull_get(_ self: Int32) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_doubleOrNull_get(_ self: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_doubleOrUndefined_get") +fileprivate func bjs_WithOptionalJSClass_doubleOrUndefined_get(_ self: Int32) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_doubleOrUndefined_get(_ self: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_boolOrNull_get") +fileprivate func bjs_WithOptionalJSClass_boolOrNull_get(_ self: Int32) -> Int32 +#else +fileprivate func bjs_WithOptionalJSClass_boolOrNull_get(_ self: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_boolOrUndefined_get") +fileprivate func bjs_WithOptionalJSClass_boolOrUndefined_get(_ self: Int32) -> Int32 +#else +fileprivate func bjs_WithOptionalJSClass_boolOrUndefined_get(_ self: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_intOrNull_get") +fileprivate func bjs_WithOptionalJSClass_intOrNull_get(_ self: Int32) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_intOrNull_get(_ self: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_intOrUndefined_get") +fileprivate func bjs_WithOptionalJSClass_intOrUndefined_get(_ self: Int32) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_intOrUndefined_get(_ self: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_stringOrNull_set") +fileprivate func bjs_WithOptionalJSClass_stringOrNull_set(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_stringOrNull_set(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_stringOrUndefined_set") +fileprivate func bjs_WithOptionalJSClass_stringOrUndefined_set(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_stringOrUndefined_set(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_doubleOrNull_set") +fileprivate func bjs_WithOptionalJSClass_doubleOrNull_set(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Float64) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_doubleOrNull_set(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_doubleOrUndefined_set") +fileprivate func bjs_WithOptionalJSClass_doubleOrUndefined_set(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Float64) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_doubleOrUndefined_set(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_boolOrNull_set") +fileprivate func bjs_WithOptionalJSClass_boolOrNull_set(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_boolOrNull_set(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_boolOrUndefined_set") +fileprivate func bjs_WithOptionalJSClass_boolOrUndefined_set(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_boolOrUndefined_set(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_intOrNull_set") +fileprivate func bjs_WithOptionalJSClass_intOrNull_set(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_intOrNull_set(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_intOrUndefined_set") +fileprivate func bjs_WithOptionalJSClass_intOrUndefined_set(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_intOrUndefined_set(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_roundTripStringOrNull") +fileprivate func bjs_WithOptionalJSClass_roundTripStringOrNull(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_roundTripStringOrNull(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_roundTripStringOrUndefined") +fileprivate func bjs_WithOptionalJSClass_roundTripStringOrUndefined(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_roundTripStringOrUndefined(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_roundTripDoubleOrNull") +fileprivate func bjs_WithOptionalJSClass_roundTripDoubleOrNull(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Float64) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_roundTripDoubleOrNull(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_roundTripDoubleOrUndefined") +fileprivate func bjs_WithOptionalJSClass_roundTripDoubleOrUndefined(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Float64) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_roundTripDoubleOrUndefined(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_roundTripBoolOrNull") +fileprivate func bjs_WithOptionalJSClass_roundTripBoolOrNull(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Int32 +#else +fileprivate func bjs_WithOptionalJSClass_roundTripBoolOrNull(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_roundTripBoolOrUndefined") +fileprivate func bjs_WithOptionalJSClass_roundTripBoolOrUndefined(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Int32 +#else +fileprivate func bjs_WithOptionalJSClass_roundTripBoolOrUndefined(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_roundTripIntOrNull") +fileprivate func bjs_WithOptionalJSClass_roundTripIntOrNull(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_roundTripIntOrNull(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_roundTripIntOrUndefined") +fileprivate func bjs_WithOptionalJSClass_roundTripIntOrUndefined(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_roundTripIntOrUndefined(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif + +func _$WithOptionalJSClass_init(_ valueOrNull: Optional, _ valueOrUndefined: JSUndefinedOr) throws(JSException) -> JSObject { + let (valueOrNullIsSome, valueOrNullValue) = valueOrNull.bridgeJSLowerParameter() + let (valueOrUndefinedIsSome, valueOrUndefinedValue) = valueOrUndefined.bridgeJSLowerParameter() + let ret = bjs_WithOptionalJSClass_init(valueOrNullIsSome, valueOrNullValue, valueOrUndefinedIsSome, valueOrUndefinedValue) + if let error = _swift_js_take_exception() { + throw error + } + return JSObject.bridgeJSLiftReturn(ret) +} + +func _$WithOptionalJSClass_stringOrNull_get(_ self: JSObject) throws(JSException) -> Optional { + let selfValue = self.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_stringOrNull_get(selfValue) + if let error = _swift_js_take_exception() { + throw error + } + return Optional.bridgeJSLiftReturnFromSideChannel() +} + +func _$WithOptionalJSClass_stringOrUndefined_get(_ self: JSObject) throws(JSException) -> JSUndefinedOr { + let selfValue = self.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_stringOrUndefined_get(selfValue) + if let error = _swift_js_take_exception() { + throw error + } + return JSUndefinedOr.bridgeJSLiftReturnFromSideChannel() +} + +func _$WithOptionalJSClass_doubleOrNull_get(_ self: JSObject) throws(JSException) -> Optional { + let selfValue = self.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_doubleOrNull_get(selfValue) + if let error = _swift_js_take_exception() { + throw error + } + return Optional.bridgeJSLiftReturnFromSideChannel() +} + +func _$WithOptionalJSClass_doubleOrUndefined_get(_ self: JSObject) throws(JSException) -> JSUndefinedOr { + let selfValue = self.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_doubleOrUndefined_get(selfValue) + if let error = _swift_js_take_exception() { + throw error + } + return JSUndefinedOr.bridgeJSLiftReturnFromSideChannel() +} + +func _$WithOptionalJSClass_boolOrNull_get(_ self: JSObject) throws(JSException) -> Optional { + let selfValue = self.bridgeJSLowerParameter() + let ret = bjs_WithOptionalJSClass_boolOrNull_get(selfValue) + if let error = _swift_js_take_exception() { + throw error + } + return Optional.bridgeJSLiftReturn(ret) +} + +func _$WithOptionalJSClass_boolOrUndefined_get(_ self: JSObject) throws(JSException) -> JSUndefinedOr { + let selfValue = self.bridgeJSLowerParameter() + let ret = bjs_WithOptionalJSClass_boolOrUndefined_get(selfValue) + if let error = _swift_js_take_exception() { + throw error + } + return JSUndefinedOr.bridgeJSLiftReturn(ret) +} + +func _$WithOptionalJSClass_intOrNull_get(_ self: JSObject) throws(JSException) -> Optional { + let selfValue = self.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_intOrNull_get(selfValue) + if let error = _swift_js_take_exception() { + throw error + } + return Optional.bridgeJSLiftReturnFromSideChannel() +} + +func _$WithOptionalJSClass_intOrUndefined_get(_ self: JSObject) throws(JSException) -> JSUndefinedOr { + let selfValue = self.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_intOrUndefined_get(selfValue) + if let error = _swift_js_take_exception() { + throw error + } + return JSUndefinedOr.bridgeJSLiftReturnFromSideChannel() +} + +func _$WithOptionalJSClass_stringOrNull_set(_ self: JSObject, _ newValue: Optional) throws(JSException) -> Void { + let selfValue = self.bridgeJSLowerParameter() + let (newValueIsSome, newValueValue) = newValue.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_stringOrNull_set(selfValue, newValueIsSome, newValueValue) + if let error = _swift_js_take_exception() { + throw error + } +} + +func _$WithOptionalJSClass_stringOrUndefined_set(_ self: JSObject, _ newValue: JSUndefinedOr) throws(JSException) -> Void { + let selfValue = self.bridgeJSLowerParameter() + let (newValueIsSome, newValueValue) = newValue.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_stringOrUndefined_set(selfValue, newValueIsSome, newValueValue) + if let error = _swift_js_take_exception() { + throw error + } +} + +func _$WithOptionalJSClass_doubleOrNull_set(_ self: JSObject, _ newValue: Optional) throws(JSException) -> Void { + let selfValue = self.bridgeJSLowerParameter() + let (newValueIsSome, newValueValue) = newValue.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_doubleOrNull_set(selfValue, newValueIsSome, newValueValue) + if let error = _swift_js_take_exception() { + throw error + } +} + +func _$WithOptionalJSClass_doubleOrUndefined_set(_ self: JSObject, _ newValue: JSUndefinedOr) throws(JSException) -> Void { + let selfValue = self.bridgeJSLowerParameter() + let (newValueIsSome, newValueValue) = newValue.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_doubleOrUndefined_set(selfValue, newValueIsSome, newValueValue) + if let error = _swift_js_take_exception() { + throw error + } +} + +func _$WithOptionalJSClass_boolOrNull_set(_ self: JSObject, _ newValue: Optional) throws(JSException) -> Void { + let selfValue = self.bridgeJSLowerParameter() + let (newValueIsSome, newValueValue) = newValue.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_boolOrNull_set(selfValue, newValueIsSome, newValueValue) + if let error = _swift_js_take_exception() { + throw error + } +} + +func _$WithOptionalJSClass_boolOrUndefined_set(_ self: JSObject, _ newValue: JSUndefinedOr) throws(JSException) -> Void { + let selfValue = self.bridgeJSLowerParameter() + let (newValueIsSome, newValueValue) = newValue.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_boolOrUndefined_set(selfValue, newValueIsSome, newValueValue) + if let error = _swift_js_take_exception() { + throw error + } +} + +func _$WithOptionalJSClass_intOrNull_set(_ self: JSObject, _ newValue: Optional) throws(JSException) -> Void { + let selfValue = self.bridgeJSLowerParameter() + let (newValueIsSome, newValueValue) = newValue.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_intOrNull_set(selfValue, newValueIsSome, newValueValue) + if let error = _swift_js_take_exception() { + throw error + } +} + +func _$WithOptionalJSClass_intOrUndefined_set(_ self: JSObject, _ newValue: JSUndefinedOr) throws(JSException) -> Void { + let selfValue = self.bridgeJSLowerParameter() + let (newValueIsSome, newValueValue) = newValue.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_intOrUndefined_set(selfValue, newValueIsSome, newValueValue) + if let error = _swift_js_take_exception() { + throw error + } +} + +func _$WithOptionalJSClass_roundTripStringOrNull(_ self: JSObject, _ value: Optional) throws(JSException) -> Optional { + let selfValue = self.bridgeJSLowerParameter() + let (valueIsSome, valueValue) = value.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_roundTripStringOrNull(selfValue, valueIsSome, valueValue) + if let error = _swift_js_take_exception() { + throw error + } + return Optional.bridgeJSLiftReturnFromSideChannel() +} + +func _$WithOptionalJSClass_roundTripStringOrUndefined(_ self: JSObject, _ value: JSUndefinedOr) throws(JSException) -> JSUndefinedOr { + let selfValue = self.bridgeJSLowerParameter() + let (valueIsSome, valueValue) = value.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_roundTripStringOrUndefined(selfValue, valueIsSome, valueValue) + if let error = _swift_js_take_exception() { + throw error + } + return JSUndefinedOr.bridgeJSLiftReturnFromSideChannel() +} + +func _$WithOptionalJSClass_roundTripDoubleOrNull(_ self: JSObject, _ value: Optional) throws(JSException) -> Optional { + let selfValue = self.bridgeJSLowerParameter() + let (valueIsSome, valueValue) = value.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_roundTripDoubleOrNull(selfValue, valueIsSome, valueValue) + if let error = _swift_js_take_exception() { + throw error + } + return Optional.bridgeJSLiftReturnFromSideChannel() +} + +func _$WithOptionalJSClass_roundTripDoubleOrUndefined(_ self: JSObject, _ value: JSUndefinedOr) throws(JSException) -> JSUndefinedOr { + let selfValue = self.bridgeJSLowerParameter() + let (valueIsSome, valueValue) = value.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_roundTripDoubleOrUndefined(selfValue, valueIsSome, valueValue) + if let error = _swift_js_take_exception() { + throw error + } + return JSUndefinedOr.bridgeJSLiftReturnFromSideChannel() +} + +func _$WithOptionalJSClass_roundTripBoolOrNull(_ self: JSObject, _ value: Optional) throws(JSException) -> Optional { + let selfValue = self.bridgeJSLowerParameter() + let (valueIsSome, valueValue) = value.bridgeJSLowerParameter() + let ret = bjs_WithOptionalJSClass_roundTripBoolOrNull(selfValue, valueIsSome, valueValue) + if let error = _swift_js_take_exception() { + throw error + } + return Optional.bridgeJSLiftReturn(ret) +} + +func _$WithOptionalJSClass_roundTripBoolOrUndefined(_ self: JSObject, _ value: JSUndefinedOr) throws(JSException) -> JSUndefinedOr { + let selfValue = self.bridgeJSLowerParameter() + let (valueIsSome, valueValue) = value.bridgeJSLowerParameter() + let ret = bjs_WithOptionalJSClass_roundTripBoolOrUndefined(selfValue, valueIsSome, valueValue) + if let error = _swift_js_take_exception() { + throw error + } + return JSUndefinedOr.bridgeJSLiftReturn(ret) +} + +func _$WithOptionalJSClass_roundTripIntOrNull(_ self: JSObject, _ value: Optional) throws(JSException) -> Optional { + let selfValue = self.bridgeJSLowerParameter() + let (valueIsSome, valueValue) = value.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_roundTripIntOrNull(selfValue, valueIsSome, valueValue) + if let error = _swift_js_take_exception() { + throw error + } + return Optional.bridgeJSLiftReturnFromSideChannel() +} + +func _$WithOptionalJSClass_roundTripIntOrUndefined(_ self: JSObject, _ value: JSUndefinedOr) throws(JSException) -> JSUndefinedOr { + let selfValue = self.bridgeJSLowerParameter() + let (valueIsSome, valueValue) = value.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_roundTripIntOrUndefined(selfValue, valueIsSome, valueValue) + if let error = _swift_js_take_exception() { + throw error + } + return JSUndefinedOr.bridgeJSLiftReturnFromSideChannel() +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.json index 5713a289..e9f5264c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.json @@ -237,12 +237,13 @@ "isStatic" : false, "name" : "secondDelegate", "type" : { - "optional" : { + "nullable" : { "_0" : { "swiftProtocol" : { "_0" : "MyViewControllerDelegate" } - } + }, + "_1" : "null" } } } @@ -667,12 +668,13 @@ "label" : "_", "name" : "helper", "type" : { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "Helper" } - } + }, + "_1" : "null" } } } @@ -695,12 +697,13 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "Helper" } - } + }, + "_1" : "null" } } }, @@ -789,12 +792,13 @@ "isReadonly" : false, "name" : "optionalName", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -802,13 +806,14 @@ "isReadonly" : false, "name" : "optionalRawEnum", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "ExampleEnum", "_1" : "String" } - } + }, + "_1" : "null" } } }, @@ -835,12 +840,13 @@ "isReadonly" : false, "name" : "optionalResult", "type" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "Result" } - } + }, + "_1" : "null" } } }, @@ -857,12 +863,13 @@ "isReadonly" : false, "name" : "directionOptional", "type" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Direction" } - } + }, + "_1" : "null" } } }, @@ -880,13 +887,14 @@ "isReadonly" : false, "name" : "priorityOptional", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Priority", "_1" : "Int" } - } + }, + "_1" : "null" } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.json index 9b1d0d6b..bb9e4809 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.json @@ -118,12 +118,13 @@ } }, "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.json index b3ccf7e9..d385e388 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.json @@ -118,12 +118,13 @@ } }, "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json index 345582e8..d7172682 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json @@ -202,30 +202,33 @@ "moduleName" : "TestModule", "parameters" : [ { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "Person" } - } + }, + "_1" : "null" } }, { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } }, { - "optional" : { + "nullable" : { "_0" : { "double" : { } - } + }, + "_1" : "null" } } ], @@ -325,12 +328,13 @@ "moduleName" : "TestModule", "parameters" : [ { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "Person" } - } + }, + "_1" : "null" } } ], @@ -353,12 +357,13 @@ "moduleName" : "TestModule", "parameters" : [ { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "Person" } - } + }, + "_1" : "null" } } ], @@ -700,12 +705,13 @@ "moduleName" : "TestModule", "parameters" : [ { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Direction" } - } + }, + "_1" : "null" } } ], @@ -746,13 +752,14 @@ "moduleName" : "TestModule", "parameters" : [ { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Theme", "_1" : "String" } - } + }, + "_1" : "null" } } ], @@ -793,12 +800,13 @@ "moduleName" : "TestModule", "parameters" : [ { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIResult" } - } + }, + "_1" : "null" } } ], @@ -838,12 +846,13 @@ "moduleName" : "TestModule", "parameters" : [ { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Direction" } - } + }, + "_1" : "null" } } ], diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json index 1b2dc531..00c6af5c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json @@ -184,12 +184,13 @@ "label" : "optCount", "name" : "optCount", "type" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } }, @@ -197,12 +198,13 @@ "label" : "optFlag", "name" : "optFlag", "type" : { - "optional" : { + "nullable" : { "_0" : { "bool" : { } - } + }, + "_1" : "null" } } } @@ -248,12 +250,13 @@ "isStatic" : false, "name" : "optCount", "type" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } }, @@ -262,12 +265,13 @@ "isStatic" : false, "name" : "optFlag", "type" : { - "optional" : { + "nullable" : { "_0" : { "bool" : { } - } + }, + "_1" : "null" } } } @@ -305,12 +309,13 @@ "isStatic" : false, "name" : "zipCode", "type" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } } @@ -358,12 +363,13 @@ "isStatic" : false, "name" : "email", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } @@ -431,13 +437,14 @@ "isStatic" : false, "name" : "optionalPrecision", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Precision", "_1" : "Float" } - } + }, + "_1" : "null" } } } @@ -563,12 +570,13 @@ "isStatic" : false, "name" : "optionalObject", "type" : { - "optional" : { + "nullable" : { "_0" : { "jsObject" : { } - } + }, + "_1" : "null" } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts index 5f63e9db..b1a67ccd 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts @@ -21,6 +21,24 @@ export interface OptionalPropertyHolder extends SwiftHeapObject { optionalAge: number | null; optionalGreeter: Greeter | null; } +export interface WithOptionalJSClass { + roundTripStringOrNull(value: string | null): string | null; + roundTripStringOrUndefined(value: string | undefined): string | undefined; + roundTripDoubleOrNull(value: number | null): number | null; + roundTripDoubleOrUndefined(value: number | undefined): number | undefined; + roundTripBoolOrNull(value: boolean | null): boolean | null; + roundTripBoolOrUndefined(value: boolean | undefined): boolean | undefined; + roundTripIntOrNull(value: number | null): number | null; + roundTripIntOrUndefined(value: number | undefined): number | undefined; + stringOrNull: string | null; + stringOrUndefined: string | undefined; + doubleOrNull: number | null; + doubleOrUndefined: number | undefined; + boolOrNull: boolean | null; + boolOrUndefined: boolean | undefined; + intOrNull: number | null; + intOrUndefined: number | undefined; +} export type Exports = { Greeter: { new(name: string | null): Greeter; @@ -45,6 +63,9 @@ export type Exports = { testMixedOptionals(firstName: string | null, lastName: string | null, age: number | null, active: boolean): string | null; } export type Imports = { + WithOptionalJSClass: { + new(valueOrNull: string | null, valueOrUndefined: string | undefined): WithOptionalJSClass; + } } export function createInstantiator(options: { imports: Imports; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js index 2c08e3d9..0ec2f81c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js @@ -42,6 +42,7 @@ export async function createInstantiator(options, swift) { addImports: (importObject, importsContext) => { bjs = {}; importObject["bjs"] = bjs; + const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { const bytes = new Uint8Array(memory.buffer, ptr, len); tmpRetString = textDecoder.decode(bytes); @@ -213,6 +214,273 @@ export async function createInstantiator(options, swift) { const obj = OptionalPropertyHolder.__construct(pointer); return swift.memory.retain(obj); }; + const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; + TestModule["bjs_WithOptionalJSClass_init"] = function bjs_WithOptionalJSClass_init(valueOrNullIsSome, valueOrNullWrappedValue, valueOrUndefinedIsSome, valueOrUndefinedWrappedValue) { + try { + let obj; + if (valueOrNullIsSome) { + obj = swift.memory.getObject(valueOrNullWrappedValue); + swift.memory.release(valueOrNullWrappedValue); + } + let obj1; + if (valueOrUndefinedIsSome) { + obj1 = swift.memory.getObject(valueOrUndefinedWrappedValue); + swift.memory.release(valueOrUndefinedWrappedValue); + } + return swift.memory.retain(new imports.WithOptionalJSClass(valueOrNullIsSome ? obj : null, valueOrUndefinedIsSome ? obj1 : undefined)); + } catch (error) { + setException(error); + return 0 + } + } + TestModule["bjs_WithOptionalJSClass_stringOrNull_get"] = function bjs_WithOptionalJSClass_stringOrNull_get(self) { + try { + let ret = swift.memory.getObject(self).stringOrNull; + const isSome = ret != null; + if (isSome) { + const bytes = textEncoder.encode(ret); + bjs["swift_js_return_optional_string"](1, bytes, bytes.length); + return bytes.length; + } else { + bjs["swift_js_return_optional_string"](0, 0, 0); + return -1; + } + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_stringOrUndefined_get"] = function bjs_WithOptionalJSClass_stringOrUndefined_get(self) { + try { + let ret = swift.memory.getObject(self).stringOrUndefined; + const isSome = ret !== undefined; + if (isSome) { + const bytes = textEncoder.encode(ret); + bjs["swift_js_return_optional_string"](1, bytes, bytes.length); + return bytes.length; + } else { + bjs["swift_js_return_optional_string"](0, 0, 0); + return -1; + } + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_doubleOrNull_get"] = function bjs_WithOptionalJSClass_doubleOrNull_get(self) { + try { + let ret = swift.memory.getObject(self).doubleOrNull; + const isSome = ret != null; + bjs["swift_js_return_optional_double"](isSome ? 1 : 0, isSome ? ret : 0.0); + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_doubleOrUndefined_get"] = function bjs_WithOptionalJSClass_doubleOrUndefined_get(self) { + try { + let ret = swift.memory.getObject(self).doubleOrUndefined; + const isSome = ret !== undefined; + bjs["swift_js_return_optional_double"](isSome ? 1 : 0, isSome ? ret : 0.0); + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_boolOrNull_get"] = function bjs_WithOptionalJSClass_boolOrNull_get(self) { + try { + let ret = swift.memory.getObject(self).boolOrNull; + const isSome = ret != null; + bjs["swift_js_return_optional_bool"](isSome ? 1 : 0, isSome ? (ret ? 1 : 0) : 0); + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_boolOrUndefined_get"] = function bjs_WithOptionalJSClass_boolOrUndefined_get(self) { + try { + let ret = swift.memory.getObject(self).boolOrUndefined; + const isSome = ret !== undefined; + bjs["swift_js_return_optional_bool"](isSome ? 1 : 0, isSome ? (ret ? 1 : 0) : 0); + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_intOrNull_get"] = function bjs_WithOptionalJSClass_intOrNull_get(self) { + try { + let ret = swift.memory.getObject(self).intOrNull; + const isSome = ret != null; + bjs["swift_js_return_optional_int"](isSome ? 1 : 0, isSome ? (ret | 0) : 0); + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_intOrUndefined_get"] = function bjs_WithOptionalJSClass_intOrUndefined_get(self) { + try { + let ret = swift.memory.getObject(self).intOrUndefined; + const isSome = ret !== undefined; + bjs["swift_js_return_optional_int"](isSome ? 1 : 0, isSome ? (ret | 0) : 0); + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_stringOrNull_set"] = function bjs_WithOptionalJSClass_stringOrNull_set(self, newValueIsSome, newValueWrappedValue) { + try { + let obj; + if (newValueIsSome) { + obj = swift.memory.getObject(newValueWrappedValue); + swift.memory.release(newValueWrappedValue); + } + swift.memory.getObject(self).stringOrNull = newValueIsSome ? obj : null; + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_stringOrUndefined_set"] = function bjs_WithOptionalJSClass_stringOrUndefined_set(self, newValueIsSome, newValueWrappedValue) { + try { + let obj; + if (newValueIsSome) { + obj = swift.memory.getObject(newValueWrappedValue); + swift.memory.release(newValueWrappedValue); + } + swift.memory.getObject(self).stringOrUndefined = newValueIsSome ? obj : undefined; + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_doubleOrNull_set"] = function bjs_WithOptionalJSClass_doubleOrNull_set(self, newValueIsSome, newValueWrappedValue) { + try { + swift.memory.getObject(self).doubleOrNull = newValueIsSome ? newValueWrappedValue : null; + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_doubleOrUndefined_set"] = function bjs_WithOptionalJSClass_doubleOrUndefined_set(self, newValueIsSome, newValueWrappedValue) { + try { + swift.memory.getObject(self).doubleOrUndefined = newValueIsSome ? newValueWrappedValue : undefined; + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_boolOrNull_set"] = function bjs_WithOptionalJSClass_boolOrNull_set(self, newValueIsSome, newValueWrappedValue) { + try { + swift.memory.getObject(self).boolOrNull = newValueIsSome ? newValueWrappedValue !== 0 : null; + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_boolOrUndefined_set"] = function bjs_WithOptionalJSClass_boolOrUndefined_set(self, newValueIsSome, newValueWrappedValue) { + try { + swift.memory.getObject(self).boolOrUndefined = newValueIsSome ? newValueWrappedValue !== 0 : undefined; + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_intOrNull_set"] = function bjs_WithOptionalJSClass_intOrNull_set(self, newValueIsSome, newValueWrappedValue) { + try { + swift.memory.getObject(self).intOrNull = newValueIsSome ? newValueWrappedValue : null; + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_intOrUndefined_set"] = function bjs_WithOptionalJSClass_intOrUndefined_set(self, newValueIsSome, newValueWrappedValue) { + try { + swift.memory.getObject(self).intOrUndefined = newValueIsSome ? newValueWrappedValue : undefined; + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_roundTripStringOrNull"] = function bjs_WithOptionalJSClass_roundTripStringOrNull(self, valueIsSome, valueWrappedValue) { + try { + let obj; + if (valueIsSome) { + obj = swift.memory.getObject(valueWrappedValue); + swift.memory.release(valueWrappedValue); + } + let ret = swift.memory.getObject(self).roundTripStringOrNull(valueIsSome ? obj : null); + const isSome = ret != null; + if (isSome) { + const bytes = textEncoder.encode(ret); + bjs["swift_js_return_optional_string"](1, bytes, bytes.length); + return bytes.length; + } else { + bjs["swift_js_return_optional_string"](0, 0, 0); + return -1; + } + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_roundTripStringOrUndefined"] = function bjs_WithOptionalJSClass_roundTripStringOrUndefined(self, valueIsSome, valueWrappedValue) { + try { + let obj; + if (valueIsSome) { + obj = swift.memory.getObject(valueWrappedValue); + swift.memory.release(valueWrappedValue); + } + let ret = swift.memory.getObject(self).roundTripStringOrUndefined(valueIsSome ? obj : undefined); + const isSome = ret !== undefined; + if (isSome) { + const bytes = textEncoder.encode(ret); + bjs["swift_js_return_optional_string"](1, bytes, bytes.length); + return bytes.length; + } else { + bjs["swift_js_return_optional_string"](0, 0, 0); + return -1; + } + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_roundTripDoubleOrNull"] = function bjs_WithOptionalJSClass_roundTripDoubleOrNull(self, valueIsSome, valueWrappedValue) { + try { + let ret = swift.memory.getObject(self).roundTripDoubleOrNull(valueIsSome ? valueWrappedValue : null); + const isSome = ret != null; + bjs["swift_js_return_optional_double"](isSome ? 1 : 0, isSome ? ret : 0.0); + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_roundTripDoubleOrUndefined"] = function bjs_WithOptionalJSClass_roundTripDoubleOrUndefined(self, valueIsSome, valueWrappedValue) { + try { + let ret = swift.memory.getObject(self).roundTripDoubleOrUndefined(valueIsSome ? valueWrappedValue : undefined); + const isSome = ret !== undefined; + bjs["swift_js_return_optional_double"](isSome ? 1 : 0, isSome ? ret : 0.0); + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_roundTripBoolOrNull"] = function bjs_WithOptionalJSClass_roundTripBoolOrNull(self, valueIsSome, valueWrappedValue) { + try { + let ret = swift.memory.getObject(self).roundTripBoolOrNull(valueIsSome ? valueWrappedValue !== 0 : null); + const isSome = ret != null; + bjs["swift_js_return_optional_bool"](isSome ? 1 : 0, isSome ? (ret ? 1 : 0) : 0); + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_roundTripBoolOrUndefined"] = function bjs_WithOptionalJSClass_roundTripBoolOrUndefined(self, valueIsSome, valueWrappedValue) { + try { + let ret = swift.memory.getObject(self).roundTripBoolOrUndefined(valueIsSome ? valueWrappedValue !== 0 : undefined); + const isSome = ret !== undefined; + bjs["swift_js_return_optional_bool"](isSome ? 1 : 0, isSome ? (ret ? 1 : 0) : 0); + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_roundTripIntOrNull"] = function bjs_WithOptionalJSClass_roundTripIntOrNull(self, valueIsSome, valueWrappedValue) { + try { + let ret = swift.memory.getObject(self).roundTripIntOrNull(valueIsSome ? valueWrappedValue : null); + const isSome = ret != null; + bjs["swift_js_return_optional_int"](isSome ? 1 : 0, isSome ? (ret | 0) : 0); + } catch (error) { + setException(error); + } + } + TestModule["bjs_WithOptionalJSClass_roundTripIntOrUndefined"] = function bjs_WithOptionalJSClass_roundTripIntOrUndefined(self, valueIsSome, valueWrappedValue) { + try { + let ret = swift.memory.getObject(self).roundTripIntOrUndefined(valueIsSome ? valueWrappedValue : undefined); + const isSome = ret !== undefined; + bjs["swift_js_return_optional_int"](isSome ? 1 : 0, isSome ? (ret | 0) : 0); + } catch (error) { + setException(error); + } + } }, setInstance: (i) => { instance = i; diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index 7b2d97f0..e337124e 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -105,6 +105,14 @@ public protocol _BridgedSwiftStackType { consuming func bridgeJSLowerStackReturn() } +/// Types that bridge with the same (isSome, value) ABI as Optional. +/// Used by JSUndefinedOr so all bridge methods delegate to Optional. +public protocol _BridgedAsOptional { + associatedtype Wrapped + var optionalRepresentation: Wrapped? { get } + init(optional: Wrapped?) +} + extension Bool: _BridgedSwiftTypeLoweredIntoSingleWasmCoreType, _BridgedSwiftStackType { // MARK: ImportTS @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { @@ -1015,11 +1023,6 @@ extension UnsafeMutablePointer: _BridgedSwiftStackType { } extension Optional where Wrapped == Bool { - // MARK: ImportTS - - @available(*, unavailable, message: "Optional Bool type is not supported to be passed to imported JS functions") - @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Void {} - // MARK: ExportSwift @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> ( @@ -1071,11 +1074,6 @@ extension Optional where Wrapped == Bool { } extension Optional where Wrapped == Int { - // MARK: ImportTS - - @available(*, unavailable, message: "Optional Int type is not supported to be passed to imported JS functions") - @_spi(BridgeJS) public func bridgeJSLowerParameter() -> Void {} - // MARK: ExportSwift @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> ( @@ -1123,14 +1121,7 @@ extension Optional where Wrapped == Int { } extension Optional where Wrapped == UInt { - // MARK: ImportTS - - @available(*, unavailable, message: "Optional UInt type is not supported to be passed to imported JS functions") - @_spi(BridgeJS) public func bridgeJSLowerParameter() -> Void {} - - // MARK: ExportSwift - - @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameterWithPresence() -> ( + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> ( isSome: Int32, value: Int32 ) { switch consume self { @@ -1790,6 +1781,379 @@ extension Optional where Wrapped: _BridgedSwiftStruct { } } +// MARK: - _BridgedAsOptional (JSUndefinedOr) delegating to Optional + +extension _BridgedAsOptional where Wrapped == Bool { + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> (isSome: Int32, value: Int32) { + optionalRepresentation.bridgeJSLowerParameter() + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Int32) -> Self { + Self(optional: Optional.bridgeJSLiftParameter(isSome, wrappedValue)) + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> Self { + Self(optional: Optional.bridgeJSLiftParameter()) + } + + @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ value: Int32) -> Self { + Self(optional: Optional.bridgeJSLiftReturn(value)) + } + + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + optionalRepresentation.bridgeJSLowerReturn() + } +} + +extension _BridgedAsOptional where Wrapped == Int { + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> (isSome: Int32, value: Int32) { + optionalRepresentation.bridgeJSLowerParameter() + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Int32) -> Self { + Self(optional: Optional.bridgeJSLiftParameter(isSome, wrappedValue)) + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> Self { + Self(optional: Optional.bridgeJSLiftParameter()) + } + + @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Self { + Self(optional: Optional.bridgeJSLiftReturnFromSideChannel()) + } + + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + optionalRepresentation.bridgeJSLowerReturn() + } +} + +extension _BridgedAsOptional where Wrapped == UInt { + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> (isSome: Int32, value: Int32) { + optionalRepresentation.bridgeJSLowerParameter() + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Int32) -> Self { + Self(optional: Optional.bridgeJSLiftParameter(isSome, wrappedValue)) + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> Self { + Self(optional: Optional.bridgeJSLiftParameter()) + } + + @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Self { + Self(optional: Optional.bridgeJSLiftReturnFromSideChannel()) + } + + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + optionalRepresentation.bridgeJSLowerReturn() + } +} + +extension _BridgedAsOptional where Wrapped == String { + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> (isSome: Int32, value: Int32) { + optionalRepresentation.bridgeJSLowerParameter() + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter( + _ isSome: Int32, + _ bytes: Int32, + _ count: Int32 + ) -> Self { + Self(optional: Optional.bridgeJSLiftParameter(isSome, bytes, count)) + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> Self { + Self(optional: Optional.bridgeJSLiftParameter()) + } + + @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Self { + Self(optional: Optional.bridgeJSLiftReturnFromSideChannel()) + } + + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + optionalRepresentation.bridgeJSLowerReturn() + } +} + +extension _BridgedAsOptional where Wrapped == JSObject { + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> (isSome: Int32, value: Int32) { + optionalRepresentation.bridgeJSLowerParameter() + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ objectId: Int32) -> Self { + Self(optional: Optional.bridgeJSLiftParameter(isSome, objectId)) + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> Self { + Self(optional: Optional.bridgeJSLiftParameter()) + } + + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + optionalRepresentation.bridgeJSLowerReturn() + } +} + +extension _BridgedAsOptional where Wrapped: _BridgedSwiftProtocolWrapper { + @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ objectId: Int32) -> Self { + Self(optional: Optional.bridgeJSLiftParameter(isSome, objectId)) + } + + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + optionalRepresentation.bridgeJSLowerReturn() + } +} + +extension _BridgedAsOptional where Wrapped: _BridgedSwiftHeapObject { + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> (isSome: Int32, pointer: UnsafeMutableRawPointer) + { + optionalRepresentation.bridgeJSLowerParameter() + } + + @_spi(BridgeJS) public consuming func bridgeJSLowerParameterWithRetain() -> ( + isSome: Int32, pointer: UnsafeMutableRawPointer + ) { + optionalRepresentation.bridgeJSLowerParameterWithRetain() + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter( + _ isSome: Int32, + _ pointer: UnsafeMutableRawPointer + ) -> Self { + Self(optional: Optional.bridgeJSLiftParameter(isSome, pointer)) + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> Self { + Self(optional: Optional.bridgeJSLiftParameter()) + } + + @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Self { + Self(optional: Optional.bridgeJSLiftReturnFromSideChannel()) + } + + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + optionalRepresentation.bridgeJSLowerReturn() + } +} + +extension _BridgedAsOptional where Wrapped == Float { + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> (isSome: Int32, value: Float32) { + optionalRepresentation.bridgeJSLowerParameter() + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Float32) -> Self { + Self(optional: Optional.bridgeJSLiftParameter(isSome, wrappedValue)) + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> Self { + Self(optional: Optional.bridgeJSLiftParameter()) + } + + @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Self { + Self(optional: Optional.bridgeJSLiftReturnFromSideChannel()) + } + + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + optionalRepresentation.bridgeJSLowerReturn() + } +} + +extension _BridgedAsOptional where Wrapped == Double { + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> (isSome: Int32, value: Float64) { + optionalRepresentation.bridgeJSLowerParameter() + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Float64) -> Self { + Self(optional: Optional.bridgeJSLiftParameter(isSome, wrappedValue)) + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> Self { + Self(optional: Optional.bridgeJSLiftParameter()) + } + + @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Self { + Self(optional: Optional.bridgeJSLiftReturnFromSideChannel()) + } + + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + optionalRepresentation.bridgeJSLowerReturn() + } +} + +extension _BridgedAsOptional where Wrapped: _BridgedSwiftCaseEnum { + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> (isSome: Int32, value: Int32) { + optionalRepresentation.bridgeJSLowerParameter() + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ caseId: Int32) -> Self { + Self(optional: Optional.bridgeJSLiftParameter(isSome, caseId)) + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> Self { + Self(optional: Optional.bridgeJSLiftParameter()) + } + + @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ caseId: Int32) -> Self { + Self(optional: Optional.bridgeJSLiftReturn(caseId)) + } + + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + optionalRepresentation.bridgeJSLowerReturn() + } +} + +extension _BridgedAsOptional where Wrapped: _BridgedSwiftTypeLoweredIntoVoidType { + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + optionalRepresentation.bridgeJSLowerReturn() + } +} + +extension _BridgedAsOptional +where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.RawValue == String { + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> (isSome: Int32, value: Int32) { + optionalRepresentation.bridgeJSLowerParameter() + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter( + _ isSome: Int32, + _ bytes: Int32, + _ count: Int32 + ) -> Self { + Self(optional: Optional.bridgeJSLiftParameter(isSome, bytes, count)) + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> Self { + Self(optional: Optional.bridgeJSLiftParameter()) + } + + @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Self { + Self(optional: Optional.bridgeJSLiftReturnFromSideChannel()) + } + + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + optionalRepresentation.bridgeJSLowerReturn() + } +} + +extension _BridgedAsOptional +where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.RawValue == Int { + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> (isSome: Int32, value: Int32) { + optionalRepresentation.bridgeJSLowerParameter() + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Int32) -> Self { + Self(optional: Optional.bridgeJSLiftParameter(isSome, wrappedValue)) + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> Self { + Self(optional: Optional.bridgeJSLiftParameter()) + } + + @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Self { + Self(optional: Optional.bridgeJSLiftReturnFromSideChannel()) + } + + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + optionalRepresentation.bridgeJSLowerReturn() + } +} + +extension _BridgedAsOptional +where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.RawValue == Bool { + @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Int32) -> Self { + Self(optional: Optional.bridgeJSLiftParameter(isSome, wrappedValue)) + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> Self { + Self(optional: Optional.bridgeJSLiftParameter()) + } + + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + optionalRepresentation.bridgeJSLowerReturn() + } +} + +extension _BridgedAsOptional +where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.RawValue == Float { + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> (isSome: Int32, value: Float32) { + optionalRepresentation.bridgeJSLowerParameter() + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Float32) -> Self { + Self(optional: Optional.bridgeJSLiftParameter(isSome, wrappedValue)) + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> Self { + Self(optional: Optional.bridgeJSLiftParameter()) + } + + @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Self { + Self(optional: Optional.bridgeJSLiftReturnFromSideChannel()) + } + + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + optionalRepresentation.bridgeJSLowerReturn() + } +} + +extension _BridgedAsOptional +where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.RawValue == Double { + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> (isSome: Int32, value: Float64) { + optionalRepresentation.bridgeJSLowerParameter() + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Float64) -> Self { + Self(optional: Optional.bridgeJSLiftParameter(isSome, wrappedValue)) + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> Self { + Self(optional: Optional.bridgeJSLiftParameter()) + } + + @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Self { + Self(optional: Optional.bridgeJSLiftReturnFromSideChannel()) + } + + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + optionalRepresentation.bridgeJSLowerReturn() + } +} + +extension _BridgedAsOptional where Wrapped: _BridgedSwiftAssociatedValueEnum { + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> (isSome: Int32, caseId: Int32) { + optionalRepresentation.bridgeJSLowerParameter() + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ caseId: Int32) -> Self { + Self(optional: Optional.bridgeJSLiftParameter(isSome, caseId)) + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> Self { + Self(optional: Optional.bridgeJSLiftParameter()) + } + + @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ caseId: Int32) -> Self { + Self(optional: Optional.bridgeJSLiftReturn(caseId)) + } + + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + optionalRepresentation.bridgeJSLowerReturn() + } +} + +extension _BridgedAsOptional where Wrapped: _BridgedSwiftStruct { + @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32) -> Self { + Self(optional: Optional.bridgeJSLiftParameter(isSome)) + } + + @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> Self { + Self(optional: Optional.bridgeJSLiftParameter()) + } + + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + optionalRepresentation.bridgeJSLowerReturn() + } +} + // MARK: - Array Support extension Array where Element: _BridgedSwiftStackType, Element.StackLiftResult == Element { diff --git a/Sources/JavaScriptKit/JSUndefinedOr.swift b/Sources/JavaScriptKit/JSUndefinedOr.swift new file mode 100644 index 00000000..82e21810 --- /dev/null +++ b/Sources/JavaScriptKit/JSUndefinedOr.swift @@ -0,0 +1,45 @@ +@frozen public enum JSUndefinedOr { + case undefined + case value(Wrapped) + + /// Convenience accessor for the undefined case. + public static var undefinedValue: Self { .undefined } + + @inlinable + public init(optional: Wrapped?) { + self = optional.map(Self.value) ?? .undefined + } + + @inlinable + public var optionalRepresentation: Wrapped? { + switch self { + case .undefined: + return nil + case .value(let wrapped): + return wrapped + } + } +} + +extension JSUndefinedOr: ConstructibleFromJSValue where Wrapped: ConstructibleFromJSValue { + public static func construct(from value: JSValue) -> Self? { + if value.isUndefined { return .undefined } + guard let wrapped = Wrapped.construct(from: value) else { return nil } + return .value(wrapped) + } +} + +extension JSUndefinedOr: ConvertibleToJSValue where Wrapped: ConvertibleToJSValue { + public var jsValue: JSValue { + switch self { + case .undefined: + return .undefined + case .value(let wrapped): + return wrapped.jsValue + } + } +} + +// MARK: - BridgeJS (via _BridgedAsOptional in BridgeJSIntrinsics) + +extension JSUndefinedOr: _BridgedAsOptional {} diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index a20ea2dd..007f0b26 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -611,6 +611,29 @@ typealias OptionalAge = Int? @JS func roundTripOptionalClass(value: Greeter?) -> Greeter? { return value } + +@JS func roundTripOptionalGreeter(_ value: Greeter?) -> Greeter? { + value +} + +@JS func applyOptionalGreeter(_ value: Greeter?, _ transform: (Greeter?) -> Greeter?) -> Greeter? { + transform(value) +} + +@JS class OptionalHolder { + @JS var nullableGreeter: Greeter? + @JS var undefinedNumber: JSUndefinedOr + + @JS init(nullableGreeter: Greeter?, undefinedNumber: JSUndefinedOr) { + self.nullableGreeter = nullableGreeter + self.undefinedNumber = undefinedNumber + } +} + +@JS func makeOptionalHolder(nullableGreeter: Greeter?, undefinedNumber: JSUndefinedOr) -> OptionalHolder { + OptionalHolder(nullableGreeter: nullableGreeter, undefinedNumber: undefinedNumber) +} + @JS class OptionalPropertyHolder { @JS var optionalName: String? @JS var optionalAge: Int? = nil diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.Macros.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.Macros.swift index e066ad27..ee0455c3 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.Macros.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.Macros.swift @@ -14,6 +14,10 @@ @JSFunction func jsRoundTripString(_ v: String) throws(JSException) -> String +@JSFunction func jsRoundTripOptionalNumberNull(_ v: Optional) throws(JSException) -> Optional + +@JSFunction func jsRoundTripOptionalNumberUndefined(_ v: JSUndefinedOr) throws(JSException) -> JSUndefinedOr + @JSFunction func jsThrowOrVoid(_ shouldThrow: Bool) throws(JSException) -> Void @JSFunction func jsThrowOrNumber(_ shouldThrow: Bool) throws(JSException) -> Double diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 94359a70..72b10468 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -679,6 +679,54 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq7 #endif } +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq7GreeterC_Sq7GreeterC") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq7GreeterC_Sq7GreeterC(_ callback: Int32, _ param0IsSome: Int32, _ param0Pointer: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq7GreeterC_Sq7GreeterC(_ callback: Int32, _ param0IsSome: Int32, _ param0Pointer: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + fatalError("Only available on WebAssembly") +} +#endif + +private final class _BJS_ClosureBox_20BridgeJSRuntimeTestsSq7GreeterC_Sq7GreeterC: _BridgedSwiftClosureBox { + let closure: (Optional) -> Optional + init(_ closure: @escaping (Optional) -> Optional) { + self.closure = closure + } +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestsSq7GreeterC_Sq7GreeterC { + static func bridgeJSLower(_ closure: @escaping (Optional) -> Optional) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_20BridgeJSRuntimeTestsSq7GreeterC_Sq7GreeterC(closure) + return Unmanaged.passRetained(box).toOpaque() + } + static func bridgeJSLift(_ callbackId: Int32) -> (Optional) -> Optional { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let (param0IsSome, param0Pointer) = param0.bridgeJSLowerParameter() + let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq7GreeterC_Sq7GreeterC(callbackValue, param0IsSome, param0Pointer) + return Optional.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq7GreeterC_Sq7GreeterC") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq7GreeterC_Sq7GreeterC") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq7GreeterC_Sq7GreeterC(_ boxPtr: UnsafeMutableRawPointer, _ param0IsSome: Int32, _ param0Value: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_20BridgeJSRuntimeTestsSq7GreeterC_Sq7GreeterC>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Optional.bridgeJSLiftParameter(param0IsSome, param0Value)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq9APIResultO_SS") fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq9APIResultO_SS(_ callback: Int32, _ param0IsSome: Int32, _ param0CaseId: Int32) -> Int32 @@ -4416,6 +4464,39 @@ public func _bjs_roundTripOptionalClass(_ valueIsSome: Int32, _ valueValue: Unsa #endif } +@_expose(wasm, "bjs_roundTripOptionalGreeter") +@_cdecl("bjs_roundTripOptionalGreeter") +public func _bjs_roundTripOptionalGreeter(_ valueIsSome: Int32, _ valueValue: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = roundTripOptionalGreeter(_: Optional.bridgeJSLiftParameter(valueIsSome, valueValue)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_applyOptionalGreeter") +@_cdecl("bjs_applyOptionalGreeter") +public func _bjs_applyOptionalGreeter(_ valueIsSome: Int32, _ valueValue: UnsafeMutableRawPointer, _ transform: Int32) -> Void { + #if arch(wasm32) + let ret = applyOptionalGreeter(_: Optional.bridgeJSLiftParameter(valueIsSome, valueValue), _: _BJS_Closure_20BridgeJSRuntimeTestsSq7GreeterC_Sq7GreeterC.bridgeJSLift(transform)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeOptionalHolder") +@_cdecl("bjs_makeOptionalHolder") +public func _bjs_makeOptionalHolder(_ nullableGreeterIsSome: Int32, _ nullableGreeterValue: UnsafeMutableRawPointer, _ undefinedNumberIsSome: Int32, _ undefinedNumberValue: Float64) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = makeOptionalHolder(nullableGreeter: Optional.bridgeJSLiftParameter(nullableGreeterIsSome, nullableGreeterValue), undefinedNumber: JSUndefinedOr.bridgeJSLiftParameter(undefinedNumberIsSome, undefinedNumberValue)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_roundTripOptionalAPIOptionalResult") @_cdecl("bjs_roundTripOptionalAPIOptionalResult") public func _bjs_roundTripOptionalAPIOptionalResult(_ resultIsSome: Int32, _ resultCaseId: Int32) -> Void { @@ -5826,6 +5907,84 @@ fileprivate func _bjs_TestServer_wrap(_ pointer: UnsafeMutableRawPointer) -> Int } #endif +@_expose(wasm, "bjs_OptionalHolder_init") +@_cdecl("bjs_OptionalHolder_init") +public func _bjs_OptionalHolder_init(_ nullableGreeterIsSome: Int32, _ nullableGreeterValue: UnsafeMutableRawPointer, _ undefinedNumberIsSome: Int32, _ undefinedNumberValue: Float64) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = OptionalHolder(nullableGreeter: Optional.bridgeJSLiftParameter(nullableGreeterIsSome, nullableGreeterValue), undefinedNumber: JSUndefinedOr.bridgeJSLiftParameter(undefinedNumberIsSome, undefinedNumberValue)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_OptionalHolder_nullableGreeter_get") +@_cdecl("bjs_OptionalHolder_nullableGreeter_get") +public func _bjs_OptionalHolder_nullableGreeter_get(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = OptionalHolder.bridgeJSLiftParameter(_self).nullableGreeter + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_OptionalHolder_nullableGreeter_set") +@_cdecl("bjs_OptionalHolder_nullableGreeter_set") +public func _bjs_OptionalHolder_nullableGreeter_set(_ _self: UnsafeMutableRawPointer, _ valueIsSome: Int32, _ valueValue: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + OptionalHolder.bridgeJSLiftParameter(_self).nullableGreeter = Optional.bridgeJSLiftParameter(valueIsSome, valueValue) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_OptionalHolder_undefinedNumber_get") +@_cdecl("bjs_OptionalHolder_undefinedNumber_get") +public func _bjs_OptionalHolder_undefinedNumber_get(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = OptionalHolder.bridgeJSLiftParameter(_self).undefinedNumber + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_OptionalHolder_undefinedNumber_set") +@_cdecl("bjs_OptionalHolder_undefinedNumber_set") +public func _bjs_OptionalHolder_undefinedNumber_set(_ _self: UnsafeMutableRawPointer, _ valueIsSome: Int32, _ valueValue: Float64) -> Void { + #if arch(wasm32) + OptionalHolder.bridgeJSLiftParameter(_self).undefinedNumber = JSUndefinedOr.bridgeJSLiftParameter(valueIsSome, valueValue) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_OptionalHolder_deinit") +@_cdecl("bjs_OptionalHolder_deinit") +public func _bjs_OptionalHolder_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension OptionalHolder: ConvertibleToJSValue, _BridgedSwiftHeapObject { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_OptionalHolder_wrap(Unmanaged.passRetained(self).toOpaque())))) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_OptionalHolder_wrap") +fileprivate func _bjs_OptionalHolder_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_OptionalHolder_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif + @_expose(wasm, "bjs_OptionalPropertyHolder_init") @_cdecl("bjs_OptionalPropertyHolder_init") public func _bjs_OptionalPropertyHolder_init(_ optionalNameIsSome: Int32, _ optionalNameBytes: Int32, _ optionalNameLength: Int32) -> UnsafeMutableRawPointer { @@ -7855,6 +8014,42 @@ func _$jsRoundTripString(_ v: String) throws(JSException) -> String { return String.bridgeJSLiftReturn(ret) } +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsRoundTripOptionalNumberNull") +fileprivate func bjs_jsRoundTripOptionalNumberNull(_ vIsSome: Int32, _ vValue: Float64) -> Void +#else +fileprivate func bjs_jsRoundTripOptionalNumberNull(_ vIsSome: Int32, _ vValue: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif + +func _$jsRoundTripOptionalNumberNull(_ v: Optional) throws(JSException) -> Optional { + let (vIsSome, vValue) = v.bridgeJSLowerParameter() + bjs_jsRoundTripOptionalNumberNull(vIsSome, vValue) + if let error = _swift_js_take_exception() { + throw error + } + return Optional.bridgeJSLiftReturnFromSideChannel() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsRoundTripOptionalNumberUndefined") +fileprivate func bjs_jsRoundTripOptionalNumberUndefined(_ vIsSome: Int32, _ vValue: Float64) -> Void +#else +fileprivate func bjs_jsRoundTripOptionalNumberUndefined(_ vIsSome: Int32, _ vValue: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif + +func _$jsRoundTripOptionalNumberUndefined(_ v: JSUndefinedOr) throws(JSException) -> JSUndefinedOr { + let (vIsSome, vValue) = v.bridgeJSLowerParameter() + bjs_jsRoundTripOptionalNumberUndefined(vIsSome, vValue) + if let error = _swift_js_take_exception() { + throw error + } + return JSUndefinedOr.bridgeJSLiftReturnFromSideChannel() +} + #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsThrowOrVoid") fileprivate func bjs_jsThrowOrVoid(_ shouldThrow: Int32) -> Void diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 4b8ac7c7..f73b25c3 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -525,6 +525,83 @@ ], "swiftCallName" : "Internal.TestServer" }, + { + "constructor" : { + "abiName" : "bjs_OptionalHolder_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "nullableGreeter", + "name" : "nullableGreeter", + "type" : { + "nullable" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + }, + "_1" : "null" + } + } + }, + { + "label" : "undefinedNumber", + "name" : "undefinedNumber", + "type" : { + "nullable" : { + "_0" : { + "double" : { + + } + }, + "_1" : "undefined" + } + } + } + ] + }, + "methods" : [ + + ], + "name" : "OptionalHolder", + "properties" : [ + { + "isReadonly" : false, + "isStatic" : false, + "name" : "nullableGreeter", + "type" : { + "nullable" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + }, + "_1" : "null" + } + } + }, + { + "isReadonly" : false, + "isStatic" : false, + "name" : "undefinedNumber", + "type" : { + "nullable" : { + "_0" : { + "double" : { + + } + }, + "_1" : "undefined" + } + } + } + ], + "swiftCallName" : "OptionalHolder" + }, { "constructor" : { "abiName" : "bjs_OptionalPropertyHolder_init", @@ -538,12 +615,13 @@ "label" : "optionalName", "name" : "optionalName", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } @@ -559,12 +637,13 @@ "isStatic" : false, "name" : "optionalName", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -573,12 +652,13 @@ "isStatic" : false, "name" : "optionalAge", "type" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } }, @@ -587,12 +667,13 @@ "isStatic" : false, "name" : "optionalGreeter", "type" : { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "Greeter" } - } + }, + "_1" : "null" } } } @@ -1057,12 +1138,13 @@ "label" : "tag", "name" : "tag", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } @@ -1134,12 +1216,13 @@ "isStatic" : false, "name" : "tag", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } @@ -1293,12 +1376,13 @@ } }, "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -1312,12 +1396,13 @@ } }, "type" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } }, @@ -1499,12 +1584,13 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } }, @@ -1537,12 +1623,13 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -1559,12 +1646,13 @@ "label" : "_", "name" : "tag", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } @@ -1587,12 +1675,13 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } }, @@ -1609,12 +1698,13 @@ "label" : "_", "name" : "count", "type" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } } @@ -1637,12 +1727,13 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Direction" } - } + }, + "_1" : "null" } } }, @@ -1659,12 +1750,13 @@ "label" : "_", "name" : "direction", "type" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Direction" } - } + }, + "_1" : "null" } } } @@ -1687,13 +1779,14 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Theme", "_1" : "String" } - } + }, + "_1" : "null" } } }, @@ -1710,13 +1803,14 @@ "label" : "_", "name" : "theme", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Theme", "_1" : "String" } - } + }, + "_1" : "null" } } } @@ -1739,13 +1833,14 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "HttpStatus", "_1" : "Int" } - } + }, + "_1" : "null" } } }, @@ -1762,13 +1857,14 @@ "label" : "_", "name" : "status", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "HttpStatus", "_1" : "Int" } - } + }, + "_1" : "null" } } } @@ -1791,12 +1887,13 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIResult" } - } + }, + "_1" : "null" } } }, @@ -1813,12 +1910,13 @@ "label" : "_", "name" : "apiResult", "type" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIResult" } - } + }, + "_1" : "null" } } } @@ -1847,12 +1945,13 @@ "isStatic" : false, "name" : "backupProcessor", "type" : { - "optional" : { + "nullable" : { "_0" : { "swiftProtocol" : { "_0" : "DataProcessor" } - } + }, + "_1" : "null" } } } @@ -2037,12 +2136,13 @@ "label" : "_", "name" : "greeter", "type" : { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "Greeter" } - } + }, + "_1" : "null" } } } @@ -2065,12 +2165,13 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "Greeter" } - } + }, + "_1" : "null" } } }, @@ -2087,12 +2188,13 @@ "label" : "_", "name" : "result", "type" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIResult" } - } + }, + "_1" : "null" } } } @@ -2115,12 +2217,13 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIResult" } - } + }, + "_1" : "null" } } } @@ -2152,12 +2255,13 @@ "isStatic" : false, "name" : "optionalTag", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -2166,12 +2270,13 @@ "isStatic" : false, "name" : "optionalCount", "type" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } }, @@ -2180,12 +2285,13 @@ "isStatic" : false, "name" : "direction", "type" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Direction" } - } + }, + "_1" : "null" } } }, @@ -2194,13 +2300,14 @@ "isStatic" : false, "name" : "optionalTheme", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Theme", "_1" : "String" } - } + }, + "_1" : "null" } } }, @@ -2209,13 +2316,14 @@ "isStatic" : false, "name" : "httpStatus", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "HttpStatus", "_1" : "Int" } - } + }, + "_1" : "null" } } }, @@ -2224,12 +2332,13 @@ "isStatic" : false, "name" : "apiResult", "type" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIResult" } - } + }, + "_1" : "null" } } }, @@ -2248,12 +2357,13 @@ "isStatic" : false, "name" : "optionalHelper", "type" : { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "Greeter" } - } + }, + "_1" : "null" } } } @@ -2439,12 +2549,13 @@ "moduleName" : "BridgeJSRuntimeTests", "parameters" : [ { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } ], @@ -2485,12 +2596,13 @@ "moduleName" : "BridgeJSRuntimeTests", "parameters" : [ { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } ], @@ -2531,12 +2643,13 @@ "moduleName" : "BridgeJSRuntimeTests", "parameters" : [ { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "Greeter" } - } + }, + "_1" : "null" } } ], @@ -2576,12 +2689,13 @@ "moduleName" : "BridgeJSRuntimeTests", "parameters" : [ { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } ], @@ -2616,12 +2730,13 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "Greeter" } - } + }, + "_1" : "null" } } } @@ -2957,12 +3072,13 @@ "moduleName" : "BridgeJSRuntimeTests", "parameters" : [ { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Direction" } - } + }, + "_1" : "null" } } ], @@ -3003,13 +3119,14 @@ "moduleName" : "BridgeJSRuntimeTests", "parameters" : [ { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Theme", "_1" : "String" } - } + }, + "_1" : "null" } } ], @@ -3050,12 +3167,13 @@ "moduleName" : "BridgeJSRuntimeTests", "parameters" : [ { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIResult" } - } + }, + "_1" : "null" } } ], @@ -3095,12 +3213,13 @@ "moduleName" : "BridgeJSRuntimeTests", "parameters" : [ { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Direction" } - } + }, + "_1" : "null" } } ], @@ -3142,12 +3261,13 @@ "label" : "config", "name" : "config", "type" : { - "optional" : { + "nullable" : { "_0" : { "swiftStruct" : { "_0" : "Config" } - } + }, + "_1" : "null" } } } @@ -3173,12 +3293,13 @@ "isStatic" : false, "name" : "config", "type" : { - "optional" : { + "nullable" : { "_0" : { "swiftStruct" : { "_0" : "Config" } - } + }, + "_1" : "null" } } } @@ -4242,12 +4363,13 @@ "associatedValues" : [ { "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } @@ -4258,23 +4380,25 @@ "associatedValues" : [ { "type" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } }, { "type" : { - "optional" : { + "nullable" : { "_0" : { "bool" : { } - } + }, + "_1" : "null" } } } @@ -4285,34 +4409,37 @@ "associatedValues" : [ { "type" : { - "optional" : { + "nullable" : { "_0" : { "bool" : { } - } + }, + "_1" : "null" } } }, { "type" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } }, { "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } @@ -6782,23 +6909,25 @@ "label" : "name", "name" : "name", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -6815,23 +6944,25 @@ "label" : "value", "name" : "value", "type" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } }, @@ -6848,23 +6979,25 @@ "label" : "flag", "name" : "flag", "type" : { - "optional" : { + "nullable" : { "_0" : { "bool" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "bool" : { } - } + }, + "_1" : "null" } } }, @@ -6881,23 +7014,25 @@ "label" : "number", "name" : "number", "type" : { - "optional" : { + "nullable" : { "_0" : { "float" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "float" : { } - } + }, + "_1" : "null" } } }, @@ -6914,23 +7049,25 @@ "label" : "precision", "name" : "precision", "type" : { - "optional" : { + "nullable" : { "_0" : { "double" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "double" : { } - } + }, + "_1" : "null" } } }, @@ -6947,23 +7084,25 @@ "label" : "name", "name" : "name", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -6980,23 +7119,25 @@ "label" : "name", "name" : "name", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -7013,23 +7154,25 @@ "label" : "name", "name" : "name", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -7046,23 +7189,25 @@ "label" : "value", "name" : "value", "type" : { - "optional" : { + "nullable" : { "_0" : { "double" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "double" : { } - } + }, + "_1" : "null" } } }, @@ -7079,23 +7224,25 @@ "label" : "age", "name" : "age", "type" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } }, @@ -7112,23 +7259,25 @@ "label" : "value", "name" : "value", "type" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Status" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Status" } - } + }, + "_1" : "null" } } }, @@ -7145,25 +7294,27 @@ "label" : "value", "name" : "value", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Theme", "_1" : "String" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Theme", "_1" : "String" } - } + }, + "_1" : "null" } } }, @@ -7180,25 +7331,27 @@ "label" : "value", "name" : "value", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "HttpStatus", "_1" : "Int" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "HttpStatus", "_1" : "Int" } - } + }, + "_1" : "null" } } }, @@ -7215,23 +7368,25 @@ "label" : "value", "name" : "value", "type" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "TSDirection" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "TSDirection" } - } + }, + "_1" : "null" } } }, @@ -7248,25 +7403,27 @@ "label" : "value", "name" : "value", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "TSTheme", "_1" : "String" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "TSTheme", "_1" : "String" } - } + }, + "_1" : "null" } } }, @@ -7283,23 +7440,25 @@ "label" : "_", "name" : "method", "type" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Networking.API.Method" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Networking.API.Method" } - } + }, + "_1" : "null" } } }, @@ -7316,23 +7475,25 @@ "label" : "value", "name" : "value", "type" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIResult" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIResult" } - } + }, + "_1" : "null" } } }, @@ -7349,12 +7510,13 @@ "label" : "_", "name" : "r1", "type" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIResult" } - } + }, + "_1" : "null" } } }, @@ -7362,12 +7524,13 @@ "label" : "_", "name" : "r2", "type" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIResult" } - } + }, + "_1" : "null" } } } @@ -7391,23 +7554,25 @@ "label" : "_", "name" : "result", "type" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "ComplexResult" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "ComplexResult" } - } + }, + "_1" : "null" } } }, @@ -7424,24 +7589,176 @@ "label" : "value", "name" : "value", "type" : { - "optional" : { + "nullable" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + }, + "_1" : "null" + } + } + }, + { + "abiName" : "bjs_roundTripOptionalGreeter", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundTripOptionalGreeter", + "parameters" : [ + { + "label" : "_", + "name" : "value", + "type" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "Greeter" } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + }, + "_1" : "null" + } + } + }, + { + "abiName" : "bjs_applyOptionalGreeter", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "applyOptionalGreeter", + "parameters" : [ + { + "label" : "_", + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + }, + "_1" : "null" + } + } + }, + { + "label" : "_", + "name" : "transform", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "20BridgeJSRuntimeTestsSq7GreeterC_Sq7GreeterC", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + { + "nullable" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + }, + "_1" : "null" + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + }, + "_1" : "null" + } + } } } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "Greeter" } + }, + "_1" : "null" + } + } + }, + { + "abiName" : "bjs_makeOptionalHolder", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeOptionalHolder", + "parameters" : [ + { + "label" : "nullableGreeter", + "name" : "nullableGreeter", + "type" : { + "nullable" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + }, + "_1" : "null" + } + } + }, + { + "label" : "undefinedNumber", + "name" : "undefinedNumber", + "type" : { + "nullable" : { + "_0" : { + "double" : { + + } + }, + "_1" : "undefined" + } } } + ], + "returnType" : { + "swiftHeapObject" : { + "_0" : "OptionalHolder" + } } }, { @@ -7457,23 +7774,25 @@ "label" : "result", "name" : "result", "type" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIOptionalResult" } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIOptionalResult" } - } + }, + "_1" : "null" } } }, @@ -7714,23 +8033,25 @@ "label" : "name", "name" : "name", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -8022,7 +8343,7 @@ "label" : "_", "name" : "values", "type" : { - "optional" : { + "nullable" : { "_0" : { "array" : { "_0" : { @@ -8031,7 +8352,8 @@ } } } - } + }, + "_1" : "null" } } } @@ -8599,12 +8921,13 @@ "type" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } } @@ -8614,12 +8937,13 @@ "returnType" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } } @@ -8640,12 +8964,13 @@ "type" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } @@ -8655,12 +8980,13 @@ "returnType" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } @@ -8681,12 +9007,13 @@ "type" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "swiftStruct" : { "_0" : "DataPoint" } - } + }, + "_1" : "null" } } } @@ -8696,12 +9023,13 @@ "returnType" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "swiftStruct" : { "_0" : "DataPoint" } - } + }, + "_1" : "null" } } } @@ -8722,12 +9050,13 @@ "type" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Direction" } - } + }, + "_1" : "null" } } } @@ -8737,12 +9066,13 @@ "returnType" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Direction" } - } + }, + "_1" : "null" } } } @@ -8763,12 +9093,13 @@ "type" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Status" } - } + }, + "_1" : "null" } } } @@ -8778,12 +9109,13 @@ "returnType" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Status" } - } + }, + "_1" : "null" } } } @@ -8802,7 +9134,7 @@ "label" : "_", "name" : "values", "type" : { - "optional" : { + "nullable" : { "_0" : { "array" : { "_0" : { @@ -8811,13 +9143,14 @@ } } } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "array" : { "_0" : { @@ -8826,7 +9159,8 @@ } } } - } + }, + "_1" : "null" } } }, @@ -8843,7 +9177,7 @@ "label" : "_", "name" : "values", "type" : { - "optional" : { + "nullable" : { "_0" : { "array" : { "_0" : { @@ -8852,13 +9186,14 @@ } } } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "array" : { "_0" : { @@ -8867,7 +9202,8 @@ } } } - } + }, + "_1" : "null" } } }, @@ -8884,7 +9220,7 @@ "label" : "_", "name" : "greeters", "type" : { - "optional" : { + "nullable" : { "_0" : { "array" : { "_0" : { @@ -8893,13 +9229,14 @@ } } } - } + }, + "_1" : "null" } } } ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "array" : { "_0" : { @@ -8908,7 +9245,8 @@ } } } - } + }, + "_1" : "null" } } }, @@ -9498,12 +9836,13 @@ "type" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "jsObject" : { } - } + }, + "_1" : "null" } } } @@ -9513,12 +9852,13 @@ "returnType" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "jsObject" : { } - } + }, + "_1" : "null" } } } @@ -9572,12 +9912,13 @@ "type" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "jsObject" : { "_0" : "Foo" } - } + }, + "_1" : "null" } } } @@ -9587,12 +9928,13 @@ "returnType" : { "array" : { "_0" : { - "optional" : { + "nullable" : { "_0" : { "jsObject" : { "_0" : "Foo" } - } + }, + "_1" : "null" } } } @@ -9933,12 +10275,13 @@ "label" : "_", "name" : "newResult", "type" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIResult" } - } + }, + "_1" : "null" } } }, @@ -10202,12 +10545,13 @@ "label" : "_", "name" : "greeter", "type" : { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "Greeter" } - } + }, + "_1" : "null" } } } @@ -10230,12 +10574,13 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "Greeter" } - } + }, + "_1" : "null" } } }, @@ -10252,12 +10597,13 @@ "label" : "_", "name" : "result", "type" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIResult" } - } + }, + "_1" : "null" } } } @@ -10280,12 +10626,13 @@ ], "returnType" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIResult" } - } + }, + "_1" : "null" } } } @@ -10314,12 +10661,13 @@ "isReadonly" : false, "name" : "optionalTag", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -10327,12 +10675,13 @@ "isReadonly" : false, "name" : "optionalCount", "type" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } }, @@ -10340,12 +10689,13 @@ "isReadonly" : false, "name" : "direction", "type" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Direction" } - } + }, + "_1" : "null" } } }, @@ -10353,13 +10703,14 @@ "isReadonly" : false, "name" : "optionalTheme", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Theme", "_1" : "String" } - } + }, + "_1" : "null" } } }, @@ -10367,13 +10718,14 @@ "isReadonly" : false, "name" : "httpStatus", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "HttpStatus", "_1" : "Int" } - } + }, + "_1" : "null" } } }, @@ -10381,12 +10733,13 @@ "isReadonly" : false, "name" : "apiResult", "type" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIResult" } - } + }, + "_1" : "null" } } }, @@ -10403,12 +10756,13 @@ "isReadonly" : false, "name" : "optionalHelper", "type" : { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "Greeter" } - } + }, + "_1" : "null" } } } @@ -10623,12 +10977,13 @@ "label" : "optCount", "name" : "optCount", "type" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } }, @@ -10636,12 +10991,13 @@ "label" : "optFlag", "name" : "optFlag", "type" : { - "optional" : { + "nullable" : { "_0" : { "bool" : { } - } + }, + "_1" : "null" } } } @@ -10687,12 +11043,13 @@ "isStatic" : false, "name" : "optCount", "type" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } }, @@ -10701,12 +11058,13 @@ "isStatic" : false, "name" : "optFlag", "type" : { - "optional" : { + "nullable" : { "_0" : { "bool" : { } - } + }, + "_1" : "null" } } } @@ -10744,12 +11102,13 @@ "isStatic" : false, "name" : "zipCode", "type" : { - "optional" : { + "nullable" : { "_0" : { "int" : { } - } + }, + "_1" : "null" } } } @@ -10797,12 +11156,13 @@ "isStatic" : false, "name" : "email", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } }, @@ -10811,12 +11171,13 @@ "isStatic" : false, "name" : "secondaryAddress", "type" : { - "optional" : { + "nullable" : { "_0" : { "swiftStruct" : { "_0" : "Address" } - } + }, + "_1" : "null" } } } @@ -10844,13 +11205,14 @@ "isStatic" : false, "name" : "theme", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Theme", "_1" : "String" } - } + }, + "_1" : "null" } } }, @@ -10859,12 +11221,13 @@ "isStatic" : false, "name" : "direction", "type" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Direction" } - } + }, + "_1" : "null" } } }, @@ -10902,12 +11265,13 @@ "isStatic" : false, "name" : "owner", "type" : { - "optional" : { + "nullable" : { "_0" : { "swiftHeapObject" : { "_0" : "Greeter" } - } + }, + "_1" : "null" } } } @@ -10945,12 +11309,13 @@ "isStatic" : false, "name" : "status", "type" : { - "optional" : { + "nullable" : { "_0" : { "caseEnum" : { "_0" : "Status" } - } + }, + "_1" : "null" } } }, @@ -10959,12 +11324,13 @@ "isStatic" : false, "name" : "outcome", "type" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIResult" } - } + }, + "_1" : "null" } } } @@ -11033,12 +11399,13 @@ "isStatic" : false, "name" : "result", "type" : { - "optional" : { + "nullable" : { "_0" : { "associatedValueEnum" : { "_0" : "APIResult" } - } + }, + "_1" : "null" } } }, @@ -11047,12 +11414,13 @@ "isStatic" : false, "name" : "metadata", "type" : { - "optional" : { + "nullable" : { "_0" : { "jsObject" : { } - } + }, + "_1" : "null" } } }, @@ -11061,12 +11429,13 @@ "isStatic" : false, "name" : "location", "type" : { - "optional" : { + "nullable" : { "_0" : { "swiftStruct" : { "_0" : "DataPoint" } - } + }, + "_1" : "null" } } }, @@ -11085,12 +11454,13 @@ "isStatic" : false, "name" : "overrideDefaults", "type" : { - "optional" : { + "nullable" : { "_0" : { "swiftStruct" : { "_0" : "ConfigStruct" } - } + }, + "_1" : "null" } } } @@ -11130,13 +11500,14 @@ "isStatic" : false, "name" : "optionalPrecision", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Precision", "_1" : "Float" } - } + }, + "_1" : "null" } } }, @@ -11145,13 +11516,14 @@ "isStatic" : false, "name" : "optionalRatio", "type" : { - "optional" : { + "nullable" : { "_0" : { "rawValueEnum" : { "_0" : "Ratio", "_1" : "Double" } - } + }, + "_1" : "null" } } } @@ -11362,12 +11734,13 @@ "isStatic" : false, "name" : "note", "type" : { - "optional" : { + "nullable" : { "_0" : { "string" : { } - } + }, + "_1" : "null" } } } @@ -11463,12 +11836,13 @@ "isStatic" : false, "name" : "shippingAddress", "type" : { - "optional" : { + "nullable" : { "_0" : { "swiftStruct" : { "_0" : "Address" } - } + }, + "_1" : "null" } } } @@ -11585,12 +11959,13 @@ "isStatic" : false, "name" : "optionalObject", "type" : { - "optional" : { + "nullable" : { "_0" : { "jsObject" : { } - } + }, + "_1" : "null" } } } @@ -11618,12 +11993,13 @@ "isStatic" : false, "name" : "optionalFoo", "type" : { - "optional" : { + "nullable" : { "_0" : { "jsObject" : { "_0" : "Foo" } - } + }, + "_1" : "null" } } } @@ -11739,6 +12115,62 @@ } } }, + { + "name" : "jsRoundTripOptionalNumberNull", + "parameters" : [ + { + "name" : "v", + "type" : { + "nullable" : { + "_0" : { + "double" : { + + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "double" : { + + } + }, + "_1" : "null" + } + } + }, + { + "name" : "jsRoundTripOptionalNumberUndefined", + "parameters" : [ + { + "name" : "v", + "type" : { + "nullable" : { + "_0" : { + "double" : { + + } + }, + "_1" : "undefined" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "double" : { + + } + }, + "_1" : "undefined" + } + } + }, { "name" : "jsThrowOrVoid", "parameters" : [ diff --git a/Tests/BridgeJSRuntimeTests/ImportAPITests.swift b/Tests/BridgeJSRuntimeTests/ImportAPITests.swift index ea9f8c68..136bd36f 100644 --- a/Tests/BridgeJSRuntimeTests/ImportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ImportAPITests.swift @@ -35,6 +35,26 @@ class ImportAPITests: XCTestCase { } } + func testRoundTripOptionalNumberNull() throws { + try XCTAssertEqual(jsRoundTripOptionalNumberNull(42), 42) + try XCTAssertNil(jsRoundTripOptionalNumberNull(nil)) + } + + 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(.undefinedValue) + if case .value = undefined { + XCTFail("Expected undefined") + } + } + func testRoundTripFeatureFlag() throws { for v in [FeatureFlag.foo, .bar] { try XCTAssertEqual(jsRoundTripFeatureFlag(v), v) diff --git a/Tests/BridgeJSRuntimeTests/bridge-js.d.ts b/Tests/BridgeJSRuntimeTests/bridge-js.d.ts index 983d6052..d1140e20 100644 --- a/Tests/BridgeJSRuntimeTests/bridge-js.d.ts +++ b/Tests/BridgeJSRuntimeTests/bridge-js.d.ts @@ -2,6 +2,8 @@ export function jsRoundTripVoid(): void export function jsRoundTripNumber(v: number): number export function jsRoundTripBool(v: boolean): boolean export function jsRoundTripString(v: string): string +export function jsRoundTripOptionalNumberNull(v: number | null): number | null +export function jsRoundTripOptionalNumberUndefined(v: number | undefined): number | undefined export function jsThrowOrVoid(shouldThrow: boolean): void export function jsThrowOrNumber(shouldThrow: boolean): number export function jsThrowOrBool(shouldThrow: boolean): boolean diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 850b31b6..29931ba3 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -25,6 +25,12 @@ export async function setupOptions(options, context) { "jsRoundTripString": (v) => { return v; }, + "jsRoundTripOptionalNumberNull": (v) => { + return v ?? null; + }, + "jsRoundTripOptionalNumberUndefined": (v) => { + return v === undefined ? undefined : v; + }, "jsThrowOrVoid": (shouldThrow) => { if (shouldThrow) { throw new Error("TestError"); @@ -690,6 +696,26 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { testPropertyGreeter.release(); optionalsHolder.release(); + const optGreeter = new exports.Greeter("Optionaly"); + assert.equal(exports.roundTripOptionalGreeter(null), null); + const optGreeterReturned = exports.roundTripOptionalGreeter(optGreeter); + assert.equal(optGreeterReturned.name, "Optionaly"); + assert.equal(optGreeterReturned.greet(), "Hello, Optionaly!"); + + const appliedOptional = exports.applyOptionalGreeter(null, (g) => g ?? optGreeter); + assert.equal(appliedOptional.name, "Optionaly"); + + const holderOpt = exports.makeOptionalHolder(null, undefined); + assert.equal(holderOpt.nullableGreeter, null); + assert.equal(holderOpt.undefinedNumber, undefined); + holderOpt.nullableGreeter = optGreeter; + holderOpt.undefinedNumber = 123.5; + assert.equal(holderOpt.nullableGreeter.name, "Optionaly"); + assert.equal(holderOpt.undefinedNumber, 123.5); + holderOpt.release(); + optGreeterReturned.release(); + optGreeter.release(); + const aor1 = { tag: APIOptionalResultValues.Tag.Success, param0: "hello world" }; const aor2 = { tag: APIOptionalResultValues.Tag.Success, param0: null }; const aor3 = { tag: APIOptionalResultValues.Tag.Failure, param0: 404, param1: true }; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..c13ef64e --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "strict": true, + "skipLibCheck": true + } +}