@@ -33,7 +33,10 @@ public final class ImportSwiftMacros {
3333
3434 for (sourceFile, inputFilePath) in sourceFiles {
3535 progress. print ( " Processing \( inputFilePath) " )
36- let collector = APICollector ( inputFilePath: inputFilePath)
36+ let collector = APICollector (
37+ inputFilePath: inputFilePath,
38+ knownJSClassNames: Self . collectJSClassNames ( from: sourceFile)
39+ )
3740 collector. walk ( sourceFile)
3841 if !collector. errors. isEmpty {
3942 perSourceErrors. append ( ( inputFilePath: inputFilePath, errors: collector. errors) )
@@ -66,22 +69,46 @@ public final class ImportSwiftMacros {
6669 return ( outputSwift: outputSwift, outputSkeleton: moduleSkeleton)
6770 }
6871
72+ private static func collectJSClassNames( from sourceFile: SourceFileSyntax ) -> Set < String > {
73+ let collector = JSImportTypeNameCollector ( viewMode: . sourceAccurate)
74+ collector. walk ( sourceFile)
75+ return collector. typeNames
76+ }
77+
78+ private final class JSImportTypeNameCollector : SyntaxAnyVisitor {
79+ var typeNames : Set < String > = [ ]
80+
81+ override func visit( _ node: StructDeclSyntax ) -> SyntaxVisitorContinueKind {
82+ if APICollector . hasJSClassAttributeStatic ( node. attributes) {
83+ typeNames. insert ( node. name. text)
84+ }
85+ return . visitChildren
86+ }
87+
88+ override func visit( _ node: ClassDeclSyntax ) -> SyntaxVisitorContinueKind {
89+ if APICollector . hasJSClassAttributeStatic ( node. attributes) {
90+ typeNames. insert ( node. name. text)
91+ }
92+ return . visitChildren
93+ }
94+ }
95+
6996 fileprivate final class APICollector : SyntaxAnyVisitor {
7097 var importedFunctions : [ ImportedFunctionSkeleton ] = [ ]
7198 var importedTypes : [ ImportedTypeSkeleton ] = [ ]
7299 var errors : [ DiagnosticError ] = [ ]
73100
74101 private let inputFilePath : String
75- private var jsClassNames : Set < String > = [ ]
102+ private var jsClassNames : Set < String >
76103
77- init ( inputFilePath: String ) {
104+ init ( inputFilePath: String , knownJSClassNames : Set < String > ) {
78105 self . inputFilePath = inputFilePath
106+ self . jsClassNames = knownJSClassNames
79107 super. init ( viewMode: . sourceAccurate)
80108 }
81109
82110 override func visit( _ node: StructDeclSyntax ) -> SyntaxVisitorContinueKind {
83111 if hasJSClassAttribute ( node. attributes) {
84- registerJSClassName ( node. name. text)
85112 collectJSImportType ( from: node, typeName: node. name. text)
86113 return . skipChildren
87114 }
@@ -90,7 +117,6 @@ public final class ImportSwiftMacros {
90117
91118 override func visit( _ node: ClassDeclSyntax ) -> SyntaxVisitorContinueKind {
92119 if hasJSClassAttribute ( node. attributes) {
93- registerJSClassName ( node. name. text)
94120 collectJSImportType ( from: node, typeName: node. name. text)
95121 return . skipChildren
96122 }
@@ -200,10 +226,6 @@ public final class ImportSwiftMacros {
200226 }
201227 }
202228
203- private func registerJSClassName( _ name: String ) {
204- jsClassNames. insert ( name)
205- }
206-
207229 private func parseConstructor(
208230 _ initializer: InitializerDeclSyntax ,
209231 typeName: String
@@ -259,7 +281,7 @@ public final class ImportSwiftMacros {
259281 return nil
260282 }
261283
262- let baseName = node. name. text
284+ let baseName = normalizeIdentifier ( node. name. text)
263285 let name : String
264286 if isStaticMember, let enclosingTypeName {
265287 name = " \( enclosingTypeName) _ \( baseName) "
@@ -318,7 +340,7 @@ public final class ImportSwiftMacros {
318340 let propertyType = parseType ( typeAnnotation. type, enclosingTypeName: enclosingTypeName)
319341 let isReadonly = node. bindingSpecifier. tokenKind == . keyword( . let)
320342 return ImportedPropertySkeleton (
321- name: identifier. identifier. text,
343+ name: normalizeIdentifier ( identifier. identifier. text) ,
322344 isReadonly: isReadonly,
323345 type: propertyType,
324346 documentation: nil
@@ -358,7 +380,7 @@ public final class ImportSwiftMacros {
358380 }
359381
360382 let propertyType = parseType ( typeAnnotation. type, enclosingTypeName: enclosingTypeName)
361- let propertyName = identifier. identifier. text
383+ let propertyName = normalizeIdentifier ( identifier. identifier. text)
362384 let isReadonly = node. bindingSpecifier. tokenKind == . keyword( . let)
363385
364386 let prefix : String
@@ -405,7 +427,7 @@ public final class ImportSwiftMacros {
405427 return nil
406428 }
407429 let nameToken = param. secondName ?? param. firstName
408- let name = nameToken. text
430+ let name = normalizeIdentifier ( nameToken. text)
409431 let labelToken = param. secondName == nil ? nil : param. firstName
410432 let label = labelToken? . text == " _ " ? nil : labelToken? . text
411433 let bridgeType = parseType ( type, enclosingTypeName: enclosingTypeName)
@@ -420,7 +442,7 @@ public final class ImportSwiftMacros {
420442
421443 private func parseType( _ type: TypeSyntax , enclosingTypeName: String ? ) -> BridgeType {
422444 if let identifier = type. as ( IdentifierTypeSyntax . self) {
423- let name = identifier. name. text
445+ let name = normalizeIdentifier ( identifier. name. text)
424446 if name == " Self " , let enclosingTypeName {
425447 return . jsObject( enclosingTypeName)
426448 }
@@ -430,13 +452,7 @@ public final class ImportSwiftMacros {
430452 if jsClassNames. contains ( name) {
431453 return . jsObject( name)
432454 }
433- errors. append (
434- DiagnosticError (
435- node: type,
436- message: " Unsupported @JS type ' \( name) '. "
437- )
438- )
439- return . void
455+ return . jsObject( name)
440456 }
441457
442458 errors. append (
@@ -477,11 +493,26 @@ public final class ImportSwiftMacros {
477493 }
478494 }
479495
496+ static func hasJSClassAttributeStatic( _ attributes: AttributeListSyntax ? ) -> Bool {
497+ guard let attributes else { return false }
498+ return attributes. contains { attribute in
499+ guard let syntax = attribute. as ( AttributeSyntax . self) else { return false }
500+ return [ " JSClass " , " JSImportClass " ] . contains ( syntax. attributeName. trimmedDescription)
501+ }
502+ }
503+
480504 private func isStatic( _ modifiers: DeclModifierListSyntax ? ) -> Bool {
481505 guard let modifiers else { return false }
482506 return modifiers. contains { modifier in
483507 modifier. name. tokenKind == . keyword( . static) || modifier. name. tokenKind == . keyword( . class)
484508 }
485509 }
510+
511+ private func normalizeIdentifier( _ name: String ) -> String {
512+ guard name. hasPrefix ( " ` " ) , name. hasSuffix ( " ` " ) , name. count >= 2 else {
513+ return name
514+ }
515+ return String ( name. dropFirst ( ) . dropLast ( ) )
516+ }
486517 }
487518}
0 commit comments