@@ -633,6 +633,15 @@ struct IntrinsicJSFragment: Sendable {
633633 kind: JSOptionalKind ,
634634 context bridgeContext: BridgeContext = . importTS
635635 ) throws -> IntrinsicJSFragment {
636+ if wrappedType == . jsString {
637+ let innerFragment = try liftParameter ( type: wrappedType, context: bridgeContext)
638+ return sentinelOptionalLiftSingleValue (
639+ wrappedType: wrappedType,
640+ kind: kind,
641+ innerFragment: { innerFragment }
642+ )
643+ }
644+
636645 if wrappedType. isSingleParamScalar {
637646 let coerce = wrappedType. liftCoerce
638647 return IntrinsicJSFragment (
@@ -716,6 +725,15 @@ struct IntrinsicJSFragment: Sendable {
716725 wrappedType: BridgeType ,
717726 kind: JSOptionalKind
718727 ) throws -> IntrinsicJSFragment {
728+ if wrappedType == . jsString {
729+ let innerFragment = try lowerParameter ( type: wrappedType)
730+ return sentinelOptionalLowerSingleValue (
731+ wrappedType: wrappedType,
732+ kind: kind,
733+ innerFragment: innerFragment
734+ )
735+ }
736+
719737 if wrappedType. isSingleParamScalar {
720738 let wasmType = wrappedType. wasmParams [ 0 ] . type
721739 let coerce = wrappedType. lowerCoerce
@@ -807,6 +825,94 @@ struct IntrinsicJSFragment: Sendable {
807825 )
808826 }
809827
828+ private static func sentinelOptionalLiftSingleValue(
829+ wrappedType: BridgeType ,
830+ kind: JSOptionalKind ,
831+ innerFragment: @escaping @Sendable ( ) throws -> IntrinsicJSFragment
832+ ) -> IntrinsicJSFragment {
833+ let sentinelLiteral = wrappedType. nilSentinel. jsLiteral
834+ let absenceLiteral = kind. absenceLiteral
835+ return IntrinsicJSFragment (
836+ parameters: [ " wrappedValue " ] ,
837+ printCode: { arguments, context in
838+ let ( scope, printer) = ( context. scope, context. printer)
839+ let wrappedValue = arguments [ 0 ]
840+
841+ let bufferPrinter = CodeFragmentPrinter ( )
842+ let innerResults = try innerFragment ( ) . printCode (
843+ [ wrappedValue] ,
844+ context. with ( \. printer, bufferPrinter)
845+ )
846+ let innerExpr = innerResults. first ?? " undefined "
847+
848+ if bufferPrinter. lines. isEmpty {
849+ return [ " \( wrappedValue) === \( sentinelLiteral) ? \( absenceLiteral) : \( innerExpr) " ]
850+ }
851+
852+ let resultVar = scope. variable ( " optResult " )
853+ printer. write ( " let \( resultVar) ; " )
854+ printer. write ( " if ( \( wrappedValue) === \( sentinelLiteral) ) { " )
855+ printer. indent {
856+ printer. write ( " \( resultVar) = \( absenceLiteral) ; " )
857+ }
858+ printer. write ( " } else { " )
859+ printer. indent {
860+ for line in bufferPrinter. lines {
861+ printer. write ( line)
862+ }
863+ printer. write ( " \( resultVar) = \( innerExpr) ; " )
864+ }
865+ printer. write ( " } " )
866+ return [ resultVar]
867+ }
868+ )
869+ }
870+
871+ private static func sentinelOptionalLowerSingleValue(
872+ wrappedType: BridgeType ,
873+ kind: JSOptionalKind ,
874+ innerFragment: IntrinsicJSFragment
875+ ) -> IntrinsicJSFragment {
876+ let sentinelLiteral = wrappedType. nilSentinel. jsLiteral
877+ return IntrinsicJSFragment (
878+ parameters: [ " value " ] ,
879+ printCode: { arguments, context in
880+ let ( scope, printer) = ( context. scope, context. printer)
881+ let value = arguments [ 0 ]
882+ let isSomeVar = scope. variable ( " isSome " )
883+ let presenceExpr = kind. presenceCheck ( value: value)
884+ printer. write ( " const \( isSomeVar) = \( presenceExpr) ; " )
885+
886+ let bufferPrinter = CodeFragmentPrinter ( )
887+ let innerResults = try innerFragment. printCode (
888+ [ value] ,
889+ context. with ( \. printer, bufferPrinter)
890+ )
891+ let innerExpr = innerResults. first ?? sentinelLiteral
892+
893+ if bufferPrinter. lines. isEmpty {
894+ return [ " \( isSomeVar) ? \( innerExpr) : \( sentinelLiteral) " ]
895+ }
896+
897+ let resultVar = scope. variable ( " optResult " )
898+ printer. write ( " let \( resultVar) ; " )
899+ printer. write ( " if ( \( isSomeVar) ) { " )
900+ printer. indent {
901+ for line in bufferPrinter. lines {
902+ printer. write ( line)
903+ }
904+ printer. write ( " \( resultVar) = \( innerExpr) ; " )
905+ }
906+ printer. write ( " } else { " )
907+ printer. indent {
908+ printer. write ( " \( resultVar) = \( sentinelLiteral) ; " )
909+ }
910+ printer. write ( " } " )
911+ return [ resultVar]
912+ }
913+ )
914+ }
915+
810916 private static func optionalLiftReturnFromStorage( storage: String ) -> IntrinsicJSFragment {
811917 IntrinsicJSFragment (
812918 parameters: [ ] ,
@@ -934,6 +1040,14 @@ struct IntrinsicJSFragment: Sendable {
9341040 wrappedType: BridgeType ,
9351041 kind: JSOptionalKind
9361042 ) -> IntrinsicJSFragment {
1043+ if wrappedType == . jsString {
1044+ return sentinelOptionalLiftSingleValue (
1045+ wrappedType: wrappedType,
1046+ kind: kind,
1047+ innerFragment: { try liftReturn ( type: wrappedType) }
1048+ )
1049+ }
1050+
9371051 if let scalarKind = wrappedType. optionalScalarKind {
9381052 return optionalLiftReturnFromStorage ( storage: scalarKind. storageName)
9391053 }
@@ -1068,6 +1182,15 @@ struct IntrinsicJSFragment: Sendable {
10681182 )
10691183 }
10701184
1185+ if wrappedType == . jsString {
1186+ let innerFragment = try lowerReturn ( type: wrappedType, context: . exportSwift)
1187+ return sentinelOptionalLowerReturn (
1188+ wrappedType: wrappedType,
1189+ kind: kind,
1190+ innerFragment: innerFragment
1191+ )
1192+ }
1193+
10711194 if case . sideChannelReturn( let mode) = wrappedType. optionalConvention {
10721195 if mode == . none {
10731196 throw BridgeJSLinkError (
0 commit comments