diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift index 8ce91b998..02c623918 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift @@ -928,12 +928,7 @@ extension BridgeType { return LoweringParameterInfo(loweredParameters: [("objectId", .i32)]) } case .caseEnum: - switch context { - case .importTS: - throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") - case .exportSwift: - return LoweringParameterInfo(loweredParameters: [("value", .i32)]) - } + return LoweringParameterInfo(loweredParameters: [("value", .i32)]) case .rawValueEnum(_, let rawType): if rawType == .string { return .string @@ -1011,12 +1006,7 @@ extension BridgeType { return LiftingReturnInfo(valueToLift: .i32) } case .caseEnum: - switch context { - case .importTS: - throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") - case .exportSwift: - return LiftingReturnInfo(valueToLift: .i32) - } + return LiftingReturnInfo(valueToLift: .i32) case .rawValueEnum(_, let rawType): let wasmType = rawType.wasmCoreType ?? .i32 return LiftingReturnInfo(valueToLift: wasmType) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/EnumCaseImport.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/EnumCaseImport.swift new file mode 100644 index 000000000..a6477be95 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/EnumCaseImport.swift @@ -0,0 +1,12 @@ +@JS enum Signal { + case start + case stop +} + +// Case enums (no raw value) bridge as their `Int32` tag as imported-function +// parameters and return values. +@JSClass struct SignalControls { + @JSFunction func send(_ signal: Signal) throws(JSException) + @JSFunction func current() throws(JSException) -> Signal + @JSFunction static func roundTrip(_ signal: Signal) throws(JSException) -> Signal +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.json new file mode 100644 index 000000000..71bf8679e --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.json @@ -0,0 +1,139 @@ +{ + "exported" : { + "classes" : [ + + ], + "enums" : [ + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "start" + }, + { + "associatedValues" : [ + + ], + "name" : "stop" + } + ], + "emitStyle" : "const", + "name" : "Signal", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "Signal", + "tsFullPath" : "Signal" + } + ], + "exposeToGlobal" : false, + "functions" : [ + + ], + "protocols" : [ + + ], + "structs" : [ + + ] + }, + "imported" : { + "children" : [ + { + "functions" : [ + + ], + "types" : [ + { + "accessLevel" : "internal", + "getters" : [ + + ], + "methods" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "send", + "parameters" : [ + { + "name" : "signal", + "type" : { + "caseEnum" : { + "_0" : "Signal" + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "current", + "parameters" : [ + + ], + "returnType" : { + "caseEnum" : { + "_0" : "Signal" + } + } + } + ], + "name" : "SignalControls", + "setters" : [ + + ], + "staticMethods" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "roundTrip", + "parameters" : [ + { + "name" : "signal", + "type" : { + "caseEnum" : { + "_0" : "Signal" + } + } + } + ], + "returnType" : { + "caseEnum" : { + "_0" : "Signal" + } + } + } + ] + } + ] + } + ] + }, + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.swift new file mode 100644 index 000000000..3487ad425 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.swift @@ -0,0 +1,97 @@ +extension Signal: _BridgedSwiftCaseEnum { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + return bridgeJSRawValue + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> Signal { + return bridgeJSLiftParameter(value) + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> Signal { + return Signal(bridgeJSRawValue: value)! + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { + return bridgeJSLowerParameter() + } + + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { + switch bridgeJSRawValue { + case 0: + self = .start + case 1: + self = .stop + default: + return nil + } + } + + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { + switch self { + case .start: + return 0 + case .stop: + return 1 + } + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_SignalControls_roundTrip_static") +fileprivate func bjs_SignalControls_roundTrip_static_extern(_ signal: Int32) -> Int32 +#else +fileprivate func bjs_SignalControls_roundTrip_static_extern(_ signal: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_SignalControls_roundTrip_static(_ signal: Int32) -> Int32 { + return bjs_SignalControls_roundTrip_static_extern(signal) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_SignalControls_send") +fileprivate func bjs_SignalControls_send_extern(_ self: Int32, _ signal: Int32) -> Void +#else +fileprivate func bjs_SignalControls_send_extern(_ self: Int32, _ signal: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_SignalControls_send(_ self: Int32, _ signal: Int32) -> Void { + return bjs_SignalControls_send_extern(self, signal) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_SignalControls_current") +fileprivate func bjs_SignalControls_current_extern(_ self: Int32) -> Int32 +#else +fileprivate func bjs_SignalControls_current_extern(_ self: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_SignalControls_current(_ self: Int32) -> Int32 { + return bjs_SignalControls_current_extern(self) +} + +func _$SignalControls_roundTrip(_ signal: Signal) throws(JSException) -> Signal { + let signalValue = signal.bridgeJSLowerParameter() + let ret = bjs_SignalControls_roundTrip_static(signalValue) + if let error = _swift_js_take_exception() { + throw error + } + return Signal.bridgeJSLiftReturn(ret) +} + +func _$SignalControls_send(_ self: JSObject, _ signal: Signal) throws(JSException) -> Void { + let selfValue = self.bridgeJSLowerParameter() + let signalValue = signal.bridgeJSLowerParameter() + bjs_SignalControls_send(selfValue, signalValue) + if let error = _swift_js_take_exception() { + throw error + } +} + +func _$SignalControls_current(_ self: JSObject) throws(JSException) -> Signal { + let selfValue = self.bridgeJSLowerParameter() + let ret = bjs_SignalControls_current(selfValue) + if let error = _swift_js_take_exception() { + throw error + } + return Signal.bridgeJSLiftReturn(ret) +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.d.ts new file mode 100644 index 000000000..fe48c9174 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.d.ts @@ -0,0 +1,33 @@ +// 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`. + +export const SignalValues: { + readonly Start: 0; + readonly Stop: 1; +}; +export type SignalTag = typeof SignalValues[keyof typeof SignalValues]; + +export type SignalObject = typeof SignalValues; + +export interface SignalControls { + send(signal: SignalTag): void; + current(): SignalTag; +} +export type Exports = { + Signal: SignalObject +} +export type Imports = { + SignalControls: { + roundTrip(signal: SignalTag): SignalTag; + } +} +export function createInstantiator(options: { + imports: Imports; +}, swift: any): Promise<{ + addImports: (importObject: WebAssembly.Imports) => void; + setInstance: (instance: WebAssembly.Instance) => void; + createExports: (instance: WebAssembly.Instance) => Exports; +}>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.js new file mode 100644 index 000000000..e232c7cbb --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.js @@ -0,0 +1,251 @@ +// 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`. + +export const SignalValues = { + Start: 0, + Stop: 1, +}; + +export async function createInstantiator(options, swift) { + let instance; + let memory; + let setException; + let decodeString; + const textDecoder = new TextDecoder("utf-8"); + const textEncoder = new TextEncoder("utf-8"); + let tmpRetString; + let tmpRetBytes; + let tmpRetException; + let tmpRetOptionalBool; + let tmpRetOptionalInt; + let tmpRetOptionalFloat; + let tmpRetOptionalDouble; + let tmpRetOptionalHeapObject; + let strStack = []; + let i32Stack = []; + let i64Stack = []; + let f32Stack = []; + let f64Stack = []; + let ptrStack = []; + let taStack = []; + const enumHelpers = {}; + const structHelpers = {}; + + let _exports = null; + let bjs = null; + + return { + /** + * @param {WebAssembly.Imports} importObject + */ + addImports: (importObject, importsContext) => { + bjs = {}; + importObject["bjs"] = bjs; + bjs["swift_js_return_string"] = function(ptr, len) { + tmpRetString = decodeString(ptr, len); + } + bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { + const source = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const bytes = new Uint8Array(memory.buffer, bytesPtr); + bytes.set(source); + } + bjs["swift_js_make_js_string"] = function(ptr, len) { + return swift.memory.retain(decodeString(ptr, len)); + } + bjs["swift_js_init_memory_with_result"] = function(ptr, len) { + const target = new Uint8Array(memory.buffer, ptr, len); + target.set(tmpRetBytes); + tmpRetBytes = undefined; + } + bjs["swift_js_throw"] = function(id) { + tmpRetException = swift.memory.retainByRef(id); + } + bjs["swift_js_retain"] = function(id) { + return swift.memory.retainByRef(id); + } + bjs["swift_js_release"] = function(id) { + swift.memory.release(id); + } + bjs["swift_js_push_i32"] = function(v) { + i32Stack.push(v | 0); + } + bjs["swift_js_push_f32"] = function(v) { + f32Stack.push(Math.fround(v)); + } + bjs["swift_js_push_f64"] = function(v) { + f64Stack.push(v); + } + bjs["swift_js_push_string"] = function(ptr, len) { + const value = decodeString(ptr, len); + strStack.push(value); + } + bjs["swift_js_pop_i32"] = function() { + return i32Stack.pop(); + } + bjs["swift_js_pop_f32"] = function() { + return f32Stack.pop(); + } + bjs["swift_js_pop_f64"] = function() { + return f64Stack.pop(); + } + bjs["swift_js_push_pointer"] = function(pointer) { + ptrStack.push(pointer); + } + bjs["swift_js_pop_pointer"] = function() { + return ptrStack.pop(); + } + bjs["swift_js_push_i64"] = function(v) { + i64Stack.push(v); + } + bjs["swift_js_pop_i64"] = function() { + return i64Stack.pop(); + } + const taCtors = [Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array]; + bjs["swift_js_push_typed_array"] = function(kind, ptr, count) { + const Ctor = taCtors[kind]; + const byteLen = count * Ctor.BYTES_PER_ELEMENT; + const copy = memory.buffer.slice(ptr, ptr + byteLen); + taStack.push(Array.from(new Ctor(copy))); + } + bjs["swift_js_return_optional_bool"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalBool = null; + } else { + tmpRetOptionalBool = value !== 0; + } + } + bjs["swift_js_return_optional_int"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalInt = null; + } else { + tmpRetOptionalInt = value | 0; + } + } + bjs["swift_js_return_optional_float"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalFloat = null; + } else { + tmpRetOptionalFloat = Math.fround(value); + } + } + bjs["swift_js_return_optional_double"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalDouble = null; + } else { + tmpRetOptionalDouble = value; + } + } + bjs["swift_js_return_optional_string"] = function(isSome, ptr, len) { + if (isSome === 0) { + tmpRetString = null; + } else { + tmpRetString = decodeString(ptr, len); + } + } + bjs["swift_js_return_optional_object"] = function(isSome, objectId) { + if (isSome === 0) { + tmpRetString = null; + } else { + tmpRetString = swift.memory.getObject(objectId); + } + } + bjs["swift_js_return_optional_heap_object"] = function(isSome, pointer) { + if (isSome === 0) { + tmpRetOptionalHeapObject = null; + } else { + tmpRetOptionalHeapObject = pointer; + } + } + bjs["swift_js_get_optional_int_presence"] = function() { + return tmpRetOptionalInt != null ? 1 : 0; + } + bjs["swift_js_get_optional_int_value"] = function() { + const value = tmpRetOptionalInt; + tmpRetOptionalInt = undefined; + return value; + } + bjs["swift_js_get_optional_string"] = function() { + const str = tmpRetString; + tmpRetString = undefined; + if (str == null) { + return -1; + } else { + const bytes = textEncoder.encode(str); + tmpRetBytes = bytes; + return bytes.length; + } + } + bjs["swift_js_get_optional_float_presence"] = function() { + return tmpRetOptionalFloat != null ? 1 : 0; + } + bjs["swift_js_get_optional_float_value"] = function() { + const value = tmpRetOptionalFloat; + tmpRetOptionalFloat = undefined; + return value; + } + bjs["swift_js_get_optional_double_presence"] = function() { + return tmpRetOptionalDouble != null ? 1 : 0; + } + bjs["swift_js_get_optional_double_value"] = function() { + const value = tmpRetOptionalDouble; + tmpRetOptionalDouble = undefined; + return value; + } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } + bjs["swift_js_closure_unregister"] = function(funcRef) {} + const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; + TestModule["bjs_SignalControls_roundTrip_static"] = function bjs_SignalControls_roundTrip_static(signal) { + try { + let ret = imports.SignalControls.roundTrip(signal); + return ret; + } catch (error) { + setException(error); + return 0 + } + } + TestModule["bjs_SignalControls_send"] = function bjs_SignalControls_send(self, signal) { + try { + swift.memory.getObject(self).send(signal); + } catch (error) { + setException(error); + } + } + TestModule["bjs_SignalControls_current"] = function bjs_SignalControls_current(self) { + try { + let ret = swift.memory.getObject(self).current(); + return ret; + } catch (error) { + setException(error); + return 0 + } + } + }, + setInstance: (i) => { + instance = i; + memory = instance.exports.memory; + + decodeString = (ptr, len) => { const bytes = new Uint8Array(memory.buffer, ptr >>> 0, len >>> 0); return textDecoder.decode(bytes); } + + setException = (error) => { + instance.exports._swift_js_exception.value = swift.memory.retain(error) + } + }, + /** @param {WebAssembly.Instance} instance */ + createExports: (instance) => { + const js = swift.memory.heap; + const exports = { + Signal: SignalValues, + }; + _exports = exports; + return exports; + }, + } +} \ No newline at end of file diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 4a94431f2..e6c2f940b 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -4831,6 +4831,45 @@ public func _bjs_NestedStructGroupB_static_roundtripMetadata() -> Void { #endif } +extension LightColor: _BridgedSwiftCaseEnum { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + return bridgeJSRawValue + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> LightColor { + return bridgeJSLiftParameter(value) + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> LightColor { + return LightColor(bridgeJSRawValue: value)! + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { + return bridgeJSLowerParameter() + } + + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { + switch bridgeJSRawValue { + case 0: + self = .red + case 1: + self = .yellow + case 2: + self = .green + default: + return nil + } + } + + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { + switch self { + case .red: + return 0 + case .yellow: + return 1 + case .green: + return 2 + } + } +} + @_expose(wasm, "bjs_IntegerTypesSupportExports_static_roundTripInt") @_cdecl("bjs_IntegerTypesSupportExports_static_roundTripInt") public func _bjs_IntegerTypesSupportExports_static_roundTripInt(_ v: Int32) -> Int32 { @@ -13256,6 +13295,27 @@ func _$Animal_getIsCat(_ self: JSObject) throws(JSException) -> Bool { return Bool.bridgeJSLiftReturn(ret) } +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsRoundTripLightColor") +fileprivate func bjs_jsRoundTripLightColor_extern(_ value: Int32) -> Int32 +#else +fileprivate func bjs_jsRoundTripLightColor_extern(_ value: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsRoundTripLightColor(_ value: Int32) -> Int32 { + return bjs_jsRoundTripLightColor_extern(value) +} + +func _$jsRoundTripLightColor(_ value: LightColor) throws(JSException) -> LightColor { + let valueValue = value.bridgeJSLowerParameter() + let ret = bjs_jsRoundTripLightColor(valueValue) + if let error = _swift_js_take_exception() { + throw error + } + return LightColor.bridgeJSLiftReturn(ret) +} + #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsTranslatePoint") fileprivate func bjs_jsTranslatePoint_extern(_ point: Int32, _ dx: Int32, _ dy: Int32) -> Int32 diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 9ea12bde7..a28843142 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -9254,6 +9254,38 @@ "swiftCallName" : "NestedStructGroupB", "tsFullPath" : "NestedStructGroupB" }, + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "red" + }, + { + "associatedValues" : [ + + ], + "name" : "yellow" + }, + { + "associatedValues" : [ + + ], + "name" : "green" + } + ], + "emitStyle" : "const", + "name" : "LightColor", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "LightColor", + "tsFullPath" : "LightColor" + }, { "cases" : [ @@ -19698,6 +19730,37 @@ } ] }, + { + "functions" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsRoundTripLightColor", + "parameters" : [ + { + "name" : "value", + "type" : { + "caseEnum" : { + "_0" : "LightColor" + } + } + } + ], + "returnType" : { + "caseEnum" : { + "_0" : "LightColor" + } + } + } + ], + "types" : [ + + ] + }, { "functions" : [ { diff --git a/Tests/BridgeJSRuntimeTests/ImportAPITests.swift b/Tests/BridgeJSRuntimeTests/ImportAPITests.swift index 38ff2a205..2bb9158b9 100644 --- a/Tests/BridgeJSRuntimeTests/ImportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ImportAPITests.swift @@ -1,6 +1,14 @@ import XCTest import JavaScriptKit +@JS enum LightColor { + case red + case yellow + case green +} + +@JSFunction func jsRoundTripLightColor(_ value: LightColor) throws(JSException) -> LightColor + class ImportAPITests: XCTestCase { func testRoundTripVoid() throws { try jsRoundTripVoid() @@ -66,6 +74,12 @@ class ImportAPITests: XCTestCase { XCTAssertNil(try jsRoundTripOptionalPoint(nil)) } + func testRoundTripCaseEnum() throws { + for v in [LightColor.red, .yellow, .green] { + try XCTAssertEqual(jsRoundTripLightColor(v), v) + } + } + func ensureThrows(_ f: (Bool) throws(JSException) -> T) throws { do { _ = try f(true) diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index f9e2f7727..05956d8d3 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -88,6 +88,9 @@ export async function setupOptions(options, context) { "jsRoundTripFeatureFlag": (flag) => { return flag; }, + "jsRoundTripLightColor": (value) => { + return value; + }, "jsEchoJSValue": (v) => { return v; },