@@ -152,6 +152,240 @@ public class ExportSwift {
152152 )
153153 }
154154
155+ /// Detects whether given expression is supported as default parameter value
156+ private func isSupportedDefaultValueExpression( _ initClause: InitializerClauseSyntax ) -> Bool {
157+ let expression = initClause. value
158+
159+ // Function calls are checked later in extractDefaultValue (as constructors are allowed)
160+ if expression. is ( ArrayExprSyntax . self) { return false }
161+ if expression. is ( DictionaryExprSyntax . self) { return false }
162+ if expression. is ( BinaryOperatorExprSyntax . self) { return false }
163+ if expression. is ( ClosureExprSyntax . self) { return false }
164+
165+ // Method call chains (e.g., obj.foo())
166+ if let memberExpression = expression. as ( MemberAccessExprSyntax . self) ,
167+ memberExpression. base? . is ( FunctionCallExprSyntax . self) == true
168+ {
169+ return false
170+ }
171+
172+ return true
173+ }
174+
175+ /// Extract enum case value from member access expression
176+ private func extractEnumCaseValue(
177+ from memberExpr: MemberAccessExprSyntax ,
178+ type: BridgeType
179+ ) -> DefaultValue ? {
180+ let caseName = memberExpr. declName. baseName. text
181+
182+ let enumName : String ?
183+ switch type {
184+ case . caseEnum( let name) , . rawValueEnum( let name, _) , . associatedValueEnum( let name) :
185+ enumName = name
186+ case . optional( let wrappedType) :
187+ switch wrappedType {
188+ case . caseEnum( let name) , . rawValueEnum( let name, _) , . associatedValueEnum( let name) :
189+ enumName = name
190+ default :
191+ return nil
192+ }
193+ default :
194+ return nil
195+ }
196+
197+ guard let enumName = enumName else { return nil }
198+
199+ if memberExpr. base == nil {
200+ return . enumCase( enumName, caseName)
201+ }
202+
203+ if let baseExpr = memberExpr. base? . as ( DeclReferenceExprSyntax . self) {
204+ let baseName = baseExpr. baseName. text
205+ let lastComponent = enumName. split ( separator: " . " ) . last. map ( String . init) ?? enumName
206+ if baseName == enumName || baseName == lastComponent {
207+ return . enumCase( enumName, caseName)
208+ }
209+ }
210+
211+ return nil
212+ }
213+
214+ /// Extracts default value from parameter's default value clause
215+ private func extractDefaultValue(
216+ from defaultClause: InitializerClauseSyntax ? ,
217+ type: BridgeType
218+ ) -> DefaultValue ? {
219+ guard let defaultClause = defaultClause else {
220+ return nil
221+ }
222+
223+ if !isSupportedDefaultValueExpression( defaultClause) {
224+ diagnose (
225+ node: defaultClause,
226+ message: " Complex default parameter expressions are not supported " ,
227+ hint: " Use simple literal values (e.g., \" text \" , 42, true, nil) or simple constants "
228+ )
229+ return nil
230+ }
231+
232+ let expr = defaultClause. value
233+
234+ if expr. is ( NilLiteralExprSyntax . self) {
235+ guard case . optional( _) = type else {
236+ diagnose (
237+ node: expr,
238+ message: " nil is only valid for optional parameters " ,
239+ hint: " Make the parameter optional by adding ? to the type "
240+ )
241+ return nil
242+ }
243+ return . null
244+ }
245+
246+ if let memberExpr = expr. as ( MemberAccessExprSyntax . self) ,
247+ let enumValue = extractEnumCaseValue ( from: memberExpr, type: type)
248+ {
249+ return enumValue
250+ }
251+
252+ if let funcCall = expr. as ( FunctionCallExprSyntax . self) {
253+ return extractConstructorDefaultValue ( from: funcCall, type: type)
254+ }
255+
256+ if let literalValue = extractLiteralValue ( from: expr, type: type) {
257+ return literalValue
258+ }
259+
260+ diagnose (
261+ node: expr,
262+ message: " Unsupported default parameter value expression " ,
263+ hint: " Use simple literal values like \" text \" , 42, true, false, nil, or enum cases like .caseName "
264+ )
265+ return nil
266+ }
267+
268+ /// Extracts default value from a constructor call expression
269+ private func extractConstructorDefaultValue(
270+ from funcCall: FunctionCallExprSyntax ,
271+ type: BridgeType
272+ ) -> DefaultValue ? {
273+ guard let calledExpr = funcCall. calledExpression. as ( DeclReferenceExprSyntax . self) else {
274+ diagnose (
275+ node: funcCall,
276+ message: " Complex constructor expressions are not supported " ,
277+ hint: " Use a simple constructor call like ClassName() or ClassName(arg: value) "
278+ )
279+ return nil
280+ }
281+
282+ let className = calledExpr. baseName. text
283+ let expectedClassName : String ?
284+ switch type {
285+ case . swiftHeapObject( let name) :
286+ expectedClassName = name. split ( separator: " . " ) . last. map ( String . init)
287+ case . optional( . swiftHeapObject( let name) ) :
288+ expectedClassName = name. split ( separator: " . " ) . last. map ( String . init)
289+ default :
290+ diagnose (
291+ node: funcCall,
292+ message: " Constructor calls are only supported for class types " ,
293+ hint: " Parameter type should be a Swift class "
294+ )
295+ return nil
296+ }
297+
298+ guard let expectedClassName = expectedClassName, className == expectedClassName else {
299+ diagnose (
300+ node: funcCall,
301+ message: " Constructor class name ' \( className) ' doesn't match parameter type " ,
302+ hint: " Ensure the constructor matches the parameter type "
303+ )
304+ return nil
305+ }
306+
307+ if funcCall. arguments. isEmpty {
308+ return . object( className)
309+ }
310+
311+ var constructorArgs : [ DefaultValue ] = [ ]
312+ for argument in funcCall. arguments {
313+ guard let argValue = extractLiteralValue ( from: argument. expression) else {
314+ diagnose (
315+ node: argument. expression,
316+ message: " Constructor argument must be a literal value " ,
317+ hint: " Use simple literals like \" text \" , 42, true, false in constructor arguments "
318+ )
319+ return nil
320+ }
321+
322+ constructorArgs. append ( argValue)
323+ }
324+
325+ return . objectWithArguments( className, constructorArgs)
326+ }
327+
328+ /// Extracts a literal value from an expression with optional type checking
329+ private func extractLiteralValue( from expr: ExprSyntax , type: BridgeType ? = nil ) -> DefaultValue ? {
330+ if expr. is ( NilLiteralExprSyntax . self) {
331+ return . null
332+ }
333+
334+ if let stringLiteral = expr. as ( StringLiteralExprSyntax . self) ,
335+ let segment = stringLiteral. segments. first? . as ( StringSegmentSyntax . self)
336+ {
337+ let value = DefaultValue . string ( segment. content. text)
338+ if let type = type, !type. isCompatibleWith ( . string) {
339+ return nil
340+ }
341+ return value
342+ }
343+
344+ if let boolLiteral = expr. as ( BooleanLiteralExprSyntax . self) {
345+ let value = DefaultValue . bool ( boolLiteral. literal. text == " true " )
346+ if let type = type, !type. isCompatibleWith ( . bool) {
347+ return nil
348+ }
349+ return value
350+ }
351+
352+ var numericExpr = expr
353+ var isNegative = false
354+ if let prefixExpr = expr. as ( PrefixOperatorExprSyntax . self) ,
355+ prefixExpr. operator. text == " - "
356+ {
357+ numericExpr = prefixExpr. expression
358+ isNegative = true
359+ }
360+
361+ if let intLiteral = numericExpr. as ( IntegerLiteralExprSyntax . self) ,
362+ let intValue = Int ( intLiteral. literal. text)
363+ {
364+ let value = DefaultValue . int ( isNegative ? - intValue : intValue)
365+ if let type = type, !type. isCompatibleWith ( . int) {
366+ return nil
367+ }
368+ return value
369+ }
370+
371+ if let floatLiteral = numericExpr. as ( FloatLiteralExprSyntax . self) {
372+ if let floatValue = Float ( floatLiteral. literal. text) {
373+ let value = DefaultValue . float ( isNegative ? - floatValue : floatValue)
374+ if type == nil || type? . isCompatibleWith ( . float) == true {
375+ return value
376+ }
377+ }
378+ if let doubleValue = Double ( floatLiteral. literal. text) {
379+ let value = DefaultValue . double ( isNegative ? - doubleValue : doubleValue)
380+ if type == nil || type? . isCompatibleWith ( . double) == true {
381+ return value
382+ }
383+ }
384+ }
385+
386+ return nil
387+ }
388+
155389 override func visit( _ node: FunctionDeclSyntax ) -> SyntaxVisitorContinueKind {
156390 guard node. attributes. hasJSAttribute ( ) else {
157391 return . skipChildren
@@ -252,7 +486,10 @@ public class ExportSwift {
252486
253487 let name = param. secondName? . text ?? param. firstName. text
254488 let label = param. firstName. text
255- parameters. append ( Parameter ( label: label, name: name, type: type) )
489+
490+ let defaultValue = extractDefaultValue ( from: param. defaultValue, type: type)
491+
492+ parameters. append ( Parameter ( label: label, name: name, type: type, defaultValue: defaultValue) )
256493 }
257494 let returnType : BridgeType
258495 if let returnClause = node. signature. returnClause {
@@ -409,7 +646,10 @@ public class ExportSwift {
409646 }
410647 let name = param. secondName? . text ?? param. firstName. text
411648 let label = param. firstName. text
412- parameters. append ( Parameter ( label: label, name: name, type: type) )
649+
650+ let defaultValue = extractDefaultValue ( from: param. defaultValue, type: type)
651+
652+ parameters. append ( Parameter ( label: label, name: name, type: type, defaultValue: defaultValue) )
413653 }
414654
415655 guard let effects = collectEffects ( signature: node. signature) else {
@@ -630,7 +870,7 @@ public class ExportSwift {
630870 swiftCallName: swiftCallName,
631871 explicitAccessControl: explicitAccessControl,
632872 cases: [ ] , // Will be populated in visit(EnumCaseDeclSyntax)
633- rawType: rawType,
873+ rawType: SwiftEnumRawType ( rawType) ,
634874 namespace: effectiveNamespace,
635875 emitStyle: emitStyle,
636876 staticMethods: [ ] ,
@@ -668,9 +908,7 @@ public class ExportSwift {
668908
669909 if case . tsEnum = emitStyle {
670910 // Check for Bool raw type limitation
671- if let raw = exportedEnum. rawType,
672- let rawEnum = SwiftEnumRawType . from ( raw) , rawEnum == . bool
673- {
911+ if exportedEnum. rawType == . bool {
674912 diagnose (
675913 node: jsAttribute,
676914 message: " TypeScript enum style is not supported for Bool raw-value enums " ,
@@ -925,7 +1163,7 @@ public class ExportSwift {
9251163 return Constants . supportedRawTypes. contains ( typeName)
9261164 } ? . type. trimmedDescription
9271165
928- if let rawTypeString , let rawType = SwiftEnumRawType . from ( rawTypeString) {
1166+ if let rawType = SwiftEnumRawType ( rawTypeString) {
9291167 return . rawValueEnum( swiftCallName, rawType)
9301168 } else {
9311169 let hasAnyCases = enumDecl. memberBlock. members. contains { member in
@@ -1903,3 +2141,17 @@ extension WithModifiersSyntax {
19032141 }
19042142 }
19052143}
2144+
2145+ fileprivate extension BridgeType {
2146+ /// Returns true if a value of `expectedType` can be assigned to this type.
2147+ func isCompatibleWith( _ expectedType: BridgeType ) -> Bool {
2148+ switch ( self , expectedType) {
2149+ case let ( lhs, rhs) where lhs == rhs:
2150+ return true
2151+ case ( . optional( let wrapped) , expectedType) :
2152+ return wrapped == expectedType
2153+ default :
2154+ return false
2155+ }
2156+ }
2157+ }
0 commit comments