@@ -152,6 +152,255 @@ 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 stringLiteral = expr. as ( StringLiteralExprSyntax . self) ,
247+ let segment = stringLiteral. segments. first? . as ( StringSegmentSyntax . self) ,
248+ type. matches ( against: . string)
249+ {
250+ return . string( segment. content. text)
251+ }
252+
253+ if let boolLiteral = expr. as ( BooleanLiteralExprSyntax . self) ,
254+ type. matches ( against: . bool)
255+ {
256+ return . bool( boolLiteral. literal. text == " true " )
257+ }
258+
259+ if let intLiteral = expr. as ( IntegerLiteralExprSyntax . self) ,
260+ let intValue = Int ( intLiteral. literal. text) ,
261+ type. matches ( against: . int)
262+ {
263+ return . int( intValue)
264+ }
265+
266+ if let floatLiteral = expr. as ( FloatLiteralExprSyntax . self) {
267+ if type. matches ( against: . float) ,
268+ let floatValue = Float ( floatLiteral. literal. text)
269+ {
270+ return . float( floatValue)
271+ }
272+ if type. matches ( against: . double) ,
273+ let doubleValue = Double ( floatLiteral. literal. text)
274+ {
275+ return . double( doubleValue)
276+ }
277+ }
278+
279+ if let memberExpr = expr. as ( MemberAccessExprSyntax . self) ,
280+ let enumValue = extractEnumCaseValue ( from: memberExpr, type: type)
281+ {
282+ return enumValue
283+ }
284+
285+ // Constructor calls (e.g., Greeter(name: "John"))
286+ if let funcCall = expr. as ( FunctionCallExprSyntax . self) {
287+ return extractConstructorDefaultValue ( from: funcCall, type: type)
288+ }
289+
290+ diagnose (
291+ node: expr,
292+ message: " Unsupported default parameter value expression " ,
293+ hint: " Use simple literal values like \" text \" , 42, true, false, nil, or enum cases like .caseName "
294+ )
295+ return nil
296+ }
297+
298+ /// Extracts default value from a constructor call expression
299+ private func extractConstructorDefaultValue(
300+ from funcCall: FunctionCallExprSyntax ,
301+ type: BridgeType
302+ ) -> DefaultValue ? {
303+ // Extract class name
304+ guard let calledExpr = funcCall. calledExpression. as ( DeclReferenceExprSyntax . self) else {
305+ diagnose (
306+ node: funcCall,
307+ message: " Complex constructor expressions are not supported " ,
308+ hint: " Use a simple constructor call like ClassName() or ClassName(arg: value) "
309+ )
310+ return nil
311+ }
312+
313+ let className = calledExpr. baseName. text
314+
315+ // Verify type matches
316+ let expectedClassName : String ?
317+ switch type {
318+ case . swiftHeapObject( let name) :
319+ expectedClassName = name. split ( separator: " . " ) . last. map ( String . init)
320+ case . optional( . swiftHeapObject( let name) ) :
321+ expectedClassName = name. split ( separator: " . " ) . last. map ( String . init)
322+ default :
323+ diagnose (
324+ node: funcCall,
325+ message: " Constructor calls are only supported for class types " ,
326+ hint: " Parameter type should be a Swift class "
327+ )
328+ return nil
329+ }
330+
331+ guard let expectedClassName = expectedClassName, className == expectedClassName else {
332+ diagnose (
333+ node: funcCall,
334+ message: " Constructor class name ' \( className) ' doesn't match parameter type " ,
335+ hint: " Ensure the constructor matches the parameter type "
336+ )
337+ return nil
338+ }
339+
340+ // Handle parameterless constructor
341+ if funcCall. arguments. isEmpty {
342+ return . object( className)
343+ }
344+
345+ // Extract arguments for constructor with parameters
346+ var constructorArgs : [ DefaultValue ] = [ ]
347+ for argument in funcCall. arguments {
348+ // Recursively extract the argument's default value
349+ // For now, only support literals in constructor arguments
350+ guard let argValue = extractConstructorArgumentValue ( from: argument. expression) else {
351+ diagnose (
352+ node: argument. expression,
353+ message: " Constructor argument must be a literal value " ,
354+ hint: " Use simple literals like \" text \" , 42, true, false in constructor arguments "
355+ )
356+ return nil
357+ }
358+
359+ constructorArgs. append ( argValue)
360+ }
361+
362+ return . objectWithArguments( className, constructorArgs)
363+ }
364+
365+ /// Extracts a literal value from an expression for use in constructor arguments
366+ private func extractConstructorArgumentValue( from expr: ExprSyntax ) -> DefaultValue ? {
367+ // String literals
368+ if let stringLiteral = expr. as ( StringLiteralExprSyntax . self) ,
369+ let segment = stringLiteral. segments. first? . as ( StringSegmentSyntax . self)
370+ {
371+ return . string( segment. content. text)
372+ }
373+
374+ // Boolean literals
375+ if let boolLiteral = expr. as ( BooleanLiteralExprSyntax . self) {
376+ return . bool( boolLiteral. literal. text == " true " )
377+ }
378+
379+ // Integer literals
380+ if let intLiteral = expr. as ( IntegerLiteralExprSyntax . self) ,
381+ let intValue = Int ( intLiteral. literal. text)
382+ {
383+ return . int( intValue)
384+ }
385+
386+ // Float literals
387+ if let floatLiteral = expr. as ( FloatLiteralExprSyntax . self) {
388+ if let floatValue = Float ( floatLiteral. literal. text) {
389+ return . float( floatValue)
390+ }
391+ if let doubleValue = Double ( floatLiteral. literal. text) {
392+ return . double( doubleValue)
393+ }
394+ }
395+
396+ // nil literal
397+ if expr. is ( NilLiteralExprSyntax . self) {
398+ return . null
399+ }
400+
401+ return nil
402+ }
403+
155404 override func visit( _ node: FunctionDeclSyntax ) -> SyntaxVisitorContinueKind {
156405 guard node. attributes. hasJSAttribute ( ) else {
157406 return . skipChildren
@@ -252,7 +501,10 @@ public class ExportSwift {
252501
253502 let name = param. secondName? . text ?? param. firstName. text
254503 let label = param. firstName. text
255- parameters. append ( Parameter ( label: label, name: name, type: type) )
504+
505+ let defaultValue = extractDefaultValue ( from: param. defaultValue, type: type)
506+
507+ parameters. append ( Parameter ( label: label, name: name, type: type, defaultValue: defaultValue) )
256508 }
257509 let returnType : BridgeType
258510 if let returnClause = node. signature. returnClause {
@@ -409,7 +661,10 @@ public class ExportSwift {
409661 }
410662 let name = param. secondName? . text ?? param. firstName. text
411663 let label = param. firstName. text
412- parameters. append ( Parameter ( label: label, name: name, type: type) )
664+
665+ let defaultValue = extractDefaultValue ( from: param. defaultValue, type: type)
666+
667+ parameters. append ( Parameter ( label: label, name: name, type: type, defaultValue: defaultValue) )
413668 }
414669
415670 guard let effects = collectEffects ( signature: node. signature) else {
@@ -1903,3 +2158,16 @@ extension WithModifiersSyntax {
19032158 }
19042159 }
19052160}
2161+
2162+ fileprivate extension BridgeType {
2163+ func matches( against expected: BridgeType ) -> Bool {
2164+ switch ( self , expected) {
2165+ case let ( lhs, rhs) where lhs == rhs:
2166+ return true
2167+ case ( . optional( let wrapped) , expected) :
2168+ return wrapped == expected
2169+ default :
2170+ return false
2171+ }
2172+ }
2173+ }
0 commit comments