@@ -69,6 +69,8 @@ struct BridgeJSLink {
6969 var dtsClassLines : [ String ] = [ ]
7070 var namespacedFunctions : [ ExportedFunction ] = [ ]
7171 var namespacedClasses : [ ExportedClass ] = [ ]
72+ var enumConstantLines : [ String ] = [ ]
73+ var dtsEnumLines : [ String ] = [ ]
7274
7375 if exportedSkeletons. contains ( where: { $0. classes. count > 0 } ) {
7476 classLines. append (
@@ -96,6 +98,15 @@ struct BridgeJSLink {
9698 }
9799 }
98100
101+ if !skeleton. enums. isEmpty {
102+ for enumDef in skeleton. enums {
103+ let ( jsEnum, dtsEnum) = try renderExportedEnum ( enumDef)
104+ enumConstantLines. append ( contentsOf: jsEnum)
105+ exportsLines. append ( " \( enumDef. name) , " )
106+ dtsEnumLines. append ( contentsOf: dtsEnum)
107+ }
108+ }
109+
99110 for function in skeleton. functions {
100111 var ( js, dts) = renderExportedFunction ( function: function)
101112
@@ -135,6 +146,7 @@ struct BridgeJSLink {
135146 . map { $0. indent ( count: 12 ) } . joined ( separator: " \n " )
136147 exportsSection = """
137148 \( classLines. map { $0. indent ( count: 12 ) } . joined ( separator: " \n " ) )
149+ \( enumConstantLines. map { $0. indent ( count: 12 ) } . joined ( separator: " \n " ) )
138150 const exports = {
139151 \( exportsLines. map { $0. indent ( count: 16 ) } . joined ( separator: " \n " ) )
140152 };
@@ -147,6 +159,7 @@ struct BridgeJSLink {
147159 } else {
148160 exportsSection = """
149161 \( classLines. map { $0. indent ( count: 12 ) } . joined ( separator: " \n " ) )
162+ \( enumConstantLines. map { $0. indent ( count: 12 ) } . joined ( separator: " \n " ) )
150163 return {
151164 \( exportsLines. map { $0. indent ( count: 16 ) } . joined ( separator: " \n " ) )
152165 };
@@ -227,6 +240,7 @@ struct BridgeJSLink {
227240 var dtsLines : [ String ] = [ ]
228241 dtsLines. append ( contentsOf: namespaceDeclarations ( ) )
229242 dtsLines. append ( contentsOf: dtsClassLines)
243+ dtsLines. append ( contentsOf: dtsEnumLines)
230244 dtsLines. append ( contentsOf: generateImportedTypeDefinitions ( ) )
231245 dtsLines. append ( " export type Exports = { " )
232246 dtsLines. append ( contentsOf: dtsExportLines. map { $0. indent ( count: 4 ) } )
@@ -437,6 +451,29 @@ struct BridgeJSLink {
437451 cleanupLines. append ( " swift.memory.release( \( bytesIdLabel) ); " )
438452 parameterForwardings. append ( bytesIdLabel)
439453 parameterForwardings. append ( " \( bytesLabel) .length " )
454+ case . caseEnum( _) :
455+ // Case enum: JavaScript receives a number (0,1,2...), pass directly to WASM
456+ parameterForwardings. append ( " \( param. name) | 0 " )
457+ case . rawValueEnum( _, let rawType) :
458+ switch rawType {
459+ case " String " :
460+ let bytesLabel = " \( param. name) Bytes "
461+ let bytesIdLabel = " \( param. name) Id "
462+ bodyLines. append ( " const \( bytesLabel) = textEncoder.encode( \( param. name) ); " )
463+ bodyLines. append ( " const \( bytesIdLabel) = swift.memory.retain( \( bytesLabel) ); " )
464+ cleanupLines. append ( " swift.memory.release( \( bytesIdLabel) ); " )
465+ parameterForwardings. append ( bytesIdLabel)
466+ parameterForwardings. append ( " \( bytesLabel) .length " )
467+ case " Bool " :
468+ parameterForwardings. append ( " \( param. name) ? 1 : 0 " )
469+ default :
470+ parameterForwardings. append ( " \( param. name) " )
471+ }
472+ case . associatedValueEnum:
473+ parameterForwardings. append ( " 0 " )
474+ parameterForwardings. append ( " 0 " )
475+ case . namespaceEnum:
476+ break
440477 case . jsObject:
441478 parameterForwardings. append ( " swift.memory.retain( \( param. name) ) " )
442479 case . swiftHeapObject:
@@ -468,6 +505,30 @@ struct BridgeJSLink {
468505 bodyLines. append ( " const ret = tmpRetString; " )
469506 bodyLines. append ( " tmpRetString = undefined; " )
470507 returnExpr = " ret "
508+ case . caseEnum( _) :
509+ // Case enum: WASM returns Int32, use directly as JavaScript number
510+ bodyLines. append ( " const ret = \( call) ; " )
511+ returnExpr = " ret "
512+ case . rawValueEnum( _, let rawType) :
513+ switch rawType {
514+ case " String " :
515+ bodyLines. append ( " \( call) ; " )
516+ bodyLines. append ( " const ret = tmpRetString; " )
517+ bodyLines. append ( " tmpRetString = undefined; " )
518+ returnExpr = " ret "
519+ case " Bool " :
520+ bodyLines. append ( " const ret = \( call) ; " )
521+ returnExpr = " ret !== 0 "
522+ default :
523+ bodyLines. append ( " const ret = \( call) ; " )
524+ returnExpr = " ret "
525+ }
526+ case . associatedValueEnum:
527+ bodyLines. append ( " \( call) ; " )
528+ returnExpr = " \" \" "
529+ case . namespaceEnum:
530+ bodyLines. append ( " \( call) ; " )
531+ returnExpr = " undefined "
471532 case . int, . float, . double:
472533 bodyLines. append ( " const ret = \( call) ; " )
473534 returnExpr = " ret "
@@ -541,6 +602,86 @@ struct BridgeJSLink {
541602 " ( \( parameters. map { " \( $0. name) : \( $0. type. tsType) " } . joined ( separator: " , " ) ) ): \( returnTypeWithEffect) "
542603 }
543604
605+ func renderExportedEnum( _ enumDef: ExportedEnum ) throws -> ( js: [ String ] , dts: [ String ] ) {
606+ var jsLines : [ String ] = [ ]
607+ var dtsLines : [ String ] = [ ]
608+
609+ switch enumDef. enumType {
610+ case . simple:
611+ jsLines. append ( " const \( enumDef. name) = { " )
612+ for (index, enumCase) in enumDef. cases. enumerated ( ) {
613+ let caseName = enumCase. name. capitalizedFirstLetter
614+ jsLines. append ( " \( caseName) : \( index) , " . indent ( count: 0 ) )
615+ }
616+ jsLines. append ( " }; " )
617+ jsLines. append ( " " )
618+
619+ dtsLines. append ( " export const \( enumDef. name) : { " )
620+ for (index, enumCase) in enumDef. cases. enumerated ( ) {
621+ let caseName = enumCase. name. capitalizedFirstLetter
622+ dtsLines. append ( " readonly \( caseName) : \( index) ; " )
623+ }
624+ dtsLines. append ( " }; " )
625+ dtsLines. append ( " export type \( enumDef. name) = typeof \( enumDef. name) [keyof typeof \( enumDef. name) ]; " )
626+ dtsLines. append ( " " )
627+ case . rawValue:
628+ guard let rawType = enumDef. rawType else {
629+ throw BridgeJSLinkError ( message: " Raw value enum \( enumDef. name) is missing rawType " )
630+ }
631+
632+ jsLines. append ( " const \( enumDef. name) = { " )
633+ for enumCase in enumDef. cases {
634+ let caseName = enumCase. name. capitalizedFirstLetter
635+ let rawValue = enumCase. rawValue ?? enumCase. name
636+ let formattedValue : String
637+
638+ switch rawType {
639+ case " String " :
640+ formattedValue = " \" \( rawValue) \" "
641+ case " Bool " :
642+ formattedValue = rawValue. lowercased ( ) == " true " ? " true " : " false "
643+ case " Float " , " Double " :
644+ formattedValue = rawValue
645+ default :
646+ formattedValue = rawValue
647+ }
648+
649+ jsLines. append ( " \( caseName) : \( formattedValue) , " . indent ( count: 4 ) )
650+ }
651+ jsLines. append ( " }; " )
652+ jsLines. append ( " " )
653+
654+ dtsLines. append ( " export const \( enumDef. name) : { " )
655+ for enumCase in enumDef. cases {
656+ let caseName = enumCase. name. capitalizedFirstLetter
657+ let rawValue = enumCase. rawValue ?? enumCase. name
658+ let formattedValue : String
659+
660+ switch rawType {
661+ case " String " :
662+ formattedValue = " \" \( rawValue) \" "
663+ case " Bool " :
664+ formattedValue = rawValue. lowercased ( ) == " true " ? " true " : " false "
665+ case " Float " , " Double " :
666+ formattedValue = rawValue
667+ default :
668+ formattedValue = rawValue
669+ }
670+
671+ dtsLines. append ( " readonly \( caseName) : \( formattedValue) ; " )
672+ }
673+ dtsLines. append ( " }; " )
674+ dtsLines. append ( " export type \( enumDef. name) = typeof \( enumDef. name) [keyof typeof \( enumDef. name) ]; " )
675+ dtsLines. append ( " " )
676+
677+ case . associatedValue, . namespace:
678+ jsLines. append ( " // TODO: Implement \( enumDef. enumType) enum: \( enumDef. name) " )
679+ dtsLines. append ( " // TODO: Implement \( enumDef. enumType) enum: \( enumDef. name) " )
680+ }
681+
682+ return ( jsLines, dtsLines)
683+ }
684+
544685 func renderExportedFunction( function: ExportedFunction ) -> ( js: [ String ] , dts: [ String ] ) {
545686 let thunkBuilder = ExportedThunkBuilder ( effects: function. effects)
546687 for param in function. parameters {
@@ -698,6 +839,24 @@ struct BridgeJSLink {
698839 bodyLines. append ( " const \( stringObjectName) = swift.memory.getObject( \( param. name) ); " )
699840 bodyLines. append ( " swift.memory.release( \( param. name) ); " )
700841 parameterForwardings. append ( stringObjectName)
842+ case . caseEnum( _) :
843+ parameterForwardings. append ( param. name)
844+ case . rawValueEnum( _, let rawType) :
845+ switch rawType {
846+ case " String " :
847+ let stringObjectName = " \( param. name) Object "
848+ bodyLines. append ( " const \( stringObjectName) = swift.memory.getObject( \( param. name) ); " )
849+ bodyLines. append ( " swift.memory.release( \( param. name) ); " )
850+ parameterForwardings. append ( stringObjectName)
851+ case " Bool " :
852+ parameterForwardings. append ( " \( param. name) !== 0 " )
853+ default :
854+ parameterForwardings. append ( param. name)
855+ }
856+ case . associatedValueEnum:
857+ parameterForwardings. append ( " \" \" " )
858+ case . namespaceEnum:
859+ break
701860 case . jsObject:
702861 parameterForwardings. append ( " swift.memory.getObject( \( param. name) ) " )
703862 default :
@@ -769,6 +928,22 @@ struct BridgeJSLink {
769928 case . string:
770929 bodyLines. append ( " tmpRetBytes = textEncoder.encode(ret); " )
771930 return " tmpRetBytes.length "
931+ case . caseEnum( _) :
932+ return " ret "
933+ case . rawValueEnum( _, let rawType) :
934+ switch rawType {
935+ case " String " :
936+ bodyLines. append ( " tmpRetBytes = textEncoder.encode(ret); " )
937+ return " tmpRetBytes.length "
938+ case " Bool " :
939+ return " ret ? 1 : 0 "
940+ default :
941+ return " ret "
942+ }
943+ case . associatedValueEnum:
944+ return " 0 "
945+ case . namespaceEnum:
946+ return " 0 "
772947 case . int, . float, . double:
773948 return " ret "
774949 case . bool:
@@ -947,6 +1122,11 @@ extension String {
9471122 func indent( count: Int ) -> String {
9481123 return String ( repeating: " " , count: count) + self
9491124 }
1125+
1126+ var capitalizedFirstLetter : String {
1127+ guard !isEmpty else { return self }
1128+ return prefix ( 1 ) . uppercased ( ) + dropFirst( )
1129+ }
9501130}
9511131
9521132extension BridgeType {
@@ -968,6 +1148,14 @@ extension BridgeType {
9681148 return name ?? " any "
9691149 case . swiftHeapObject( let name) :
9701150 return name
1151+ case . caseEnum( let name) :
1152+ return name
1153+ case . rawValueEnum( let name, _) :
1154+ return name
1155+ case . associatedValueEnum( let name) :
1156+ return name
1157+ case . namespaceEnum( let name) :
1158+ return name
9711159 }
9721160 }
9731161}
0 commit comments