@@ -162,6 +162,20 @@ public final class ImportSwiftMacros {
162162 var getters : [ ImportedGetterSkeleton ] = [ ]
163163 var setters : [ ImportedSetterSkeleton ] = [ ]
164164
165+ // First pass: collect all explicit @JSSetter functions to track which properties have explicit setters
166+ var propertiesWithExplicitSetters = Set < String > ( )
167+ for member in node. memberBlock. members {
168+ if let function = member. decl. as ( FunctionDeclSyntax . self) ,
169+ hasJSSetterAttribute ( function. attributes) ,
170+ !isStatic( function. modifiers)
171+ {
172+ if let setter = parseSetterSkeleton ( function, enclosingTypeName: typeName) {
173+ propertiesWithExplicitSetters. insert ( setter. name)
174+ }
175+ }
176+ }
177+
178+ // Second pass: process all members
165179 for member in node. memberBlock. members {
166180 if let initializer = member. decl. as ( InitializerDeclSyntax . self) {
167181 if hasJSFunctionAttribute ( initializer. attributes) {
@@ -187,7 +201,11 @@ public final class ImportSwiftMacros {
187201 if let parsed = parseFunction ( function, enclosingTypeName: typeName, isStaticMember: true ) {
188202 importedFunctions. append ( parsed)
189203 }
190- } else if let parsed = parseFunction ( function, enclosingTypeName: typeName, isStaticMember: false ) {
204+ } else if let parsed = parseFunction (
205+ function,
206+ enclosingTypeName: typeName,
207+ isStaticMember: false
208+ ) {
191209 methods. append ( parsed)
192210 }
193211 continue
@@ -213,16 +231,11 @@ public final class ImportSwiftMacros {
213231 if isStatic ( variable. modifiers) {
214232 collectTopLevelProperty ( from: variable, enclosingTypeName: typeName)
215233 } else {
216- // Parse as getter/setter skeletons
234+ // Parse as getter skeleton only
235+ // Setters are ONLY generated from explicit @JSSetter functions, never from properties
217236 if let getter = parseGetterSkeleton ( variable, enclosingTypeName: typeName) {
218237 getters. append ( getter)
219238 }
220- let isReadonly = variable. bindingSpecifier. tokenKind == . keyword( . let)
221- if !isReadonly {
222- if let setter = parseSetterSkeletonFromProperty ( variable, enclosingTypeName: typeName) {
223- setters. append ( setter)
224- }
225- }
226239 }
227240 continue
228241 }
@@ -496,9 +509,19 @@ public final class ImportSwiftMacros {
496509 let functionName = node. name. text
497510
498511 // Extract property name from setter function name (e.g., "setFoo" -> "foo")
499- let propertyName = String ( functionName. dropFirst ( 3 ) )
500- // Convert first character to lowercase (e.g., "Foo" -> "foo")
501- let baseName = propertyName. prefix ( 1 ) . lowercased ( ) + propertyName. dropFirst ( )
512+ // Strip backticks if present (e.g., "set`prefix`" -> "prefix")
513+ let rawFunctionName =
514+ functionName. hasPrefix ( " ` " ) && functionName. hasSuffix ( " ` " ) && functionName. count > 2
515+ ? String ( functionName. dropFirst ( ) . dropLast ( ) )
516+ : functionName
517+
518+ guard rawFunctionName. hasPrefix ( " set " ) , rawFunctionName. count > 3 else {
519+ return nil
520+ }
521+
522+ let propertyName = String ( rawFunctionName. dropFirst ( 3 ) )
523+ // Convert first character to lowercase (e.g., "Foo" -> "foo") and normalize
524+ let baseName = normalizeIdentifier ( propertyName. prefix ( 1 ) . lowercased ( ) + propertyName. dropFirst ( ) )
502525
503526 // Get the parameter type
504527 let parameters = node. signature. parameterClause. parameters
0 commit comments