Skip to content

Commit ea1cc4b

Browse files
BridgeJS: Remove support for static members in extensions
1 parent cf6c745 commit ea1cc4b

File tree

7 files changed

+119
-153
lines changed

7 files changed

+119
-153
lines changed

Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift

Lines changed: 10 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1856,8 +1856,6 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor {
18561856
private let inputFilePath: String
18571857
private var jsClassNames: Set<String>
18581858
private let parent: SwiftToSkeleton
1859-
private var staticMethodsByType: [String: [ImportedFunctionSkeleton]] = [:]
1860-
18611859
// MARK: - State Management
18621860

18631861
enum State {
@@ -2118,21 +2116,19 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor {
21182116

21192117
private func exitJSClass() {
21202118
if case .jsClassBody(let typeName) = state, let type = currentType, type.name == typeName {
2121-
let externalStaticMethods = staticMethodsByType[type.name] ?? []
21222119
importedTypes.append(
21232120
ImportedTypeSkeleton(
21242121
name: type.name,
21252122
jsName: type.jsName,
21262123
from: type.from,
21272124
constructor: type.constructor,
21282125
methods: type.methods,
2129-
staticMethods: type.staticMethods + externalStaticMethods,
2126+
staticMethods: type.staticMethods,
21302127
getters: type.getters,
21312128
setters: type.setters,
21322129
documentation: nil
21332130
)
21342131
)
2135-
staticMethodsByType[type.name] = nil
21362132
currentType = nil
21372133
}
21382134
stateStack.removeLast()
@@ -2174,7 +2170,15 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor {
21742170

21752171
override func visit(_ node: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind {
21762172
let typeName = node.extendedType.trimmedDescription
2177-
collectStaticMembers(in: node.memberBlock.members, typeName: typeName)
2173+
if jsClassNames.contains(typeName) {
2174+
errors.append(
2175+
DiagnosticError(
2176+
node: node,
2177+
message: "Extensions of @JSClass types are not supported. Declare all members in the type body."
2178+
)
2179+
)
2180+
return .skipChildren
2181+
}
21782182
return .skipChildren
21792183
}
21802184

@@ -2318,45 +2322,6 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor {
23182322
}
23192323
}
23202324

2321-
// MARK: - Member Collection
2322-
2323-
private func collectStaticMembers(in members: MemberBlockItemListSyntax, typeName: String) {
2324-
for member in members {
2325-
if let function = member.decl.as(FunctionDeclSyntax.self) {
2326-
if let jsFunction = AttributeChecker.firstJSFunctionAttribute(function.attributes),
2327-
let parsed = parseFunction(jsFunction, function) {
2328-
if jsClassNames.contains(typeName) {
2329-
if let index = importedTypes.firstIndex(where: { $0.name == typeName }) {
2330-
importedTypes[index].staticMethods.append(parsed)
2331-
} else {
2332-
importedTypes.append(ImportedTypeSkeleton(name: typeName, staticMethods: [parsed]))
2333-
}
2334-
} else {
2335-
importedFunctions.append(parsed)
2336-
}
2337-
} else if AttributeChecker.hasJSSetterAttribute(function.attributes) {
2338-
errors.append(
2339-
DiagnosticError(
2340-
node: function,
2341-
message:
2342-
"@JSSetter is not supported for static members. Use it only for instance members in @JSClass types."
2343-
)
2344-
)
2345-
}
2346-
} else if let variable = member.decl.as(VariableDeclSyntax.self),
2347-
AttributeChecker.hasJSGetterAttribute(variable.attributes)
2348-
{
2349-
errors.append(
2350-
DiagnosticError(
2351-
node: variable,
2352-
message:
2353-
"@JSGetter is not supported for static members. Use it only for instance members in @JSClass types."
2354-
)
2355-
)
2356-
}
2357-
}
2358-
}
2359-
23602325
// MARK: - Parsing Methods
23612326

23622327
private func parseConstructor(

Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,26 @@ public struct BridgeJSLink {
192192
try renderImportedType(importObjectBuilder: importObjectBuilder, type: type)
193193
}
194194
}
195+
importObjectBuilder.flushMergedTypeBlocks { [self] name, constructor, staticMethods in
196+
let dtsPrinter = CodeFragmentPrinter()
197+
dtsPrinter.write("\(name): {")
198+
dtsPrinter.indent {
199+
if let constructor = constructor {
200+
let returnType = BridgeType.jsObject(name)
201+
dtsPrinter.write(
202+
"new\(renderTSSignature(parameters: constructor.parameters, returnType: returnType, effects: Effects(isAsync: false, isThrows: false)));"
203+
)
204+
}
205+
for method in staticMethods {
206+
let methodName = method.jsName ?? method.name
207+
let signature =
208+
"\(renderTSPropertyName(methodName))\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: Effects(isAsync: false, isThrows: false)));"
209+
dtsPrinter.write(signature)
210+
}
211+
}
212+
dtsPrinter.write("}")
213+
return dtsPrinter.lines
214+
}
195215
data.importObjectBuilders.append(importObjectBuilder)
196216
}
197217

@@ -2340,6 +2360,7 @@ extension BridgeJSLink {
23402360
var moduleName: String
23412361
private let importedPrinter: CodeFragmentPrinter = CodeFragmentPrinter()
23422362
private let dtsImportPrinter: CodeFragmentPrinter = CodeFragmentPrinter()
2363+
private var pendingImportedTypeBlocks: [(name: String, constructor: ImportedConstructorSkeleton?, staticMethods: [ImportedFunctionSkeleton])] = []
23432364
var importedLines: [String] {
23442365
importedPrinter.lines
23452366
}
@@ -2364,6 +2385,29 @@ extension BridgeJSLink {
23642385
func appendDts(_ lines: [String]) {
23652386
dtsImportPrinter.write(lines: lines)
23662387
}
2388+
2389+
func recordTypeBlock(type: ImportedTypeSkeleton) {
2390+
guard type.from == nil, type.constructor != nil || !type.staticMethods.isEmpty else { return }
2391+
pendingImportedTypeBlocks.append((type.name, type.constructor, type.staticMethods))
2392+
}
2393+
2394+
func flushMergedTypeBlocks(
2395+
render: (String, ImportedConstructorSkeleton?, [ImportedFunctionSkeleton]) -> [String]
2396+
) {
2397+
let grouped = Dictionary(grouping: pendingImportedTypeBlocks, by: \.name)
2398+
for (name, entries) in grouped.sorted(by: { $0.key < $1.key }) {
2399+
let constructor = entries.lazy.compactMap(\.constructor).first
2400+
var seenMethods = Set<String>()
2401+
let staticMethods = entries.flatMap(\.staticMethods).filter { method in
2402+
let key = method.jsName ?? method.name
2403+
guard !seenMethods.contains(key) else { return false }
2404+
seenMethods.insert(key)
2405+
return true
2406+
}
2407+
appendDts(render(name, constructor, staticMethods))
2408+
}
2409+
pendingImportedTypeBlocks = []
2410+
}
23672411
}
23682412

23692413
struct NamespaceBuilder {
@@ -3144,26 +3188,7 @@ extension BridgeJSLink {
31443188
importObjectBuilder.assignToImportObject(name: abiName, function: js)
31453189
importObjectBuilder.appendDts(dts)
31463190
}
3147-
if type.from == nil, type.constructor != nil || !type.staticMethods.isEmpty {
3148-
let dtsPrinter = CodeFragmentPrinter()
3149-
dtsPrinter.write("\(type.name): {")
3150-
dtsPrinter.indent {
3151-
if let constructor = type.constructor {
3152-
let returnType = BridgeType.jsObject(type.name)
3153-
dtsPrinter.write(
3154-
"new\(renderTSSignature(parameters: constructor.parameters, returnType: returnType, effects: Effects(isAsync: false, isThrows: false)));"
3155-
)
3156-
}
3157-
for method in type.staticMethods {
3158-
let methodName = method.jsName ?? method.name
3159-
let signature =
3160-
"\(renderTSPropertyName(methodName))\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: Effects(isAsync: false, isThrows: false)));"
3161-
dtsPrinter.write(signature)
3162-
}
3163-
}
3164-
dtsPrinter.write("}")
3165-
importObjectBuilder.appendDts(dtsPrinter.lines)
3166-
}
3191+
importObjectBuilder.recordTypeBlock(type: type)
31673192
for method in type.methods {
31683193
let (js, dts) = try renderImportedMethod(context: type, method: method)
31693194
importObjectBuilder.assignToImportObject(name: method.abiName(context: type), function: js)

Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/JSClassStaticFunctions.swift

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
1-
extension StaticBox {
2-
@JSFunction static func makeDefault() throws(JSException) -> StaticBox
3-
}
4-
51
@JSClass struct StaticBox {
62
@JSFunction static func create(_ value: Double) throws(JSException) -> StaticBox
73
@JSFunction func value() throws(JSException) -> Double
84
@JSFunction static func value() throws(JSException) -> Double
9-
}
10-
11-
extension StaticBox {
5+
@JSFunction static func makeDefault() throws(JSException) -> StaticBox
126
@JSFunction(jsName: "with-dashes") static func dashed() throws(JSException) -> StaticBox
137
}
148

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClassStaticFunctions.json

Lines changed: 23 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -24,43 +24,6 @@
2424

2525
],
2626
"types" : [
27-
{
28-
"getters" : [
29-
30-
],
31-
"methods" : [
32-
33-
],
34-
"name" : "StaticBox",
35-
"setters" : [
36-
37-
],
38-
"staticMethods" : [
39-
{
40-
"name" : "makeDefault",
41-
"parameters" : [
42-
43-
],
44-
"returnType" : {
45-
"jsObject" : {
46-
"_0" : "StaticBox"
47-
}
48-
}
49-
},
50-
{
51-
"jsName" : "with-dashes",
52-
"name" : "dashed",
53-
"parameters" : [
54-
55-
],
56-
"returnType" : {
57-
"jsObject" : {
58-
"_0" : "StaticBox"
59-
}
60-
}
61-
}
62-
]
63-
},
6427
{
6528
"getters" : [
6629

@@ -111,6 +74,29 @@
11174

11275
}
11376
}
77+
},
78+
{
79+
"name" : "makeDefault",
80+
"parameters" : [
81+
82+
],
83+
"returnType" : {
84+
"jsObject" : {
85+
"_0" : "StaticBox"
86+
}
87+
}
88+
},
89+
{
90+
"jsName" : "with-dashes",
91+
"name" : "dashed",
92+
"parameters" : [
93+
94+
],
95+
"returnType" : {
96+
"jsObject" : {
97+
"_0" : "StaticBox"
98+
}
99+
}
114100
}
115101
]
116102
},

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClassStaticFunctions.swift

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,35 @@
11
#if arch(wasm32)
2-
@_extern(wasm, module: "TestModule", name: "bjs_StaticBox_makeDefault_static")
3-
fileprivate func bjs_StaticBox_makeDefault_static() -> Int32
2+
@_extern(wasm, module: "TestModule", name: "bjs_StaticBox_create_static")
3+
fileprivate func bjs_StaticBox_create_static(_ value: Float64) -> Int32
44
#else
5-
fileprivate func bjs_StaticBox_makeDefault_static() -> Int32 {
5+
fileprivate func bjs_StaticBox_create_static(_ value: Float64) -> Int32 {
66
fatalError("Only available on WebAssembly")
77
}
88
#endif
99

1010
#if arch(wasm32)
11-
@_extern(wasm, module: "TestModule", name: "bjs_StaticBox_dashed_static")
12-
fileprivate func bjs_StaticBox_dashed_static() -> Int32
11+
@_extern(wasm, module: "TestModule", name: "bjs_StaticBox_value_static")
12+
fileprivate func bjs_StaticBox_value_static() -> Float64
1313
#else
14-
fileprivate func bjs_StaticBox_dashed_static() -> Int32 {
14+
fileprivate func bjs_StaticBox_value_static() -> Float64 {
1515
fatalError("Only available on WebAssembly")
1616
}
1717
#endif
1818

19-
func _$StaticBox_makeDefault() throws(JSException) -> StaticBox {
20-
let ret = bjs_StaticBox_makeDefault_static()
21-
if let error = _swift_js_take_exception() {
22-
throw error
23-
}
24-
return StaticBox.bridgeJSLiftReturn(ret)
25-
}
26-
27-
func _$StaticBox_dashed() throws(JSException) -> StaticBox {
28-
let ret = bjs_StaticBox_dashed_static()
29-
if let error = _swift_js_take_exception() {
30-
throw error
31-
}
32-
return StaticBox.bridgeJSLiftReturn(ret)
33-
}
34-
3519
#if arch(wasm32)
36-
@_extern(wasm, module: "TestModule", name: "bjs_StaticBox_create_static")
37-
fileprivate func bjs_StaticBox_create_static(_ value: Float64) -> Int32
20+
@_extern(wasm, module: "TestModule", name: "bjs_StaticBox_makeDefault_static")
21+
fileprivate func bjs_StaticBox_makeDefault_static() -> Int32
3822
#else
39-
fileprivate func bjs_StaticBox_create_static(_ value: Float64) -> Int32 {
23+
fileprivate func bjs_StaticBox_makeDefault_static() -> Int32 {
4024
fatalError("Only available on WebAssembly")
4125
}
4226
#endif
4327

4428
#if arch(wasm32)
45-
@_extern(wasm, module: "TestModule", name: "bjs_StaticBox_value_static")
46-
fileprivate func bjs_StaticBox_value_static() -> Float64
29+
@_extern(wasm, module: "TestModule", name: "bjs_StaticBox_dashed_static")
30+
fileprivate func bjs_StaticBox_dashed_static() -> Int32
4731
#else
48-
fileprivate func bjs_StaticBox_value_static() -> Float64 {
32+
fileprivate func bjs_StaticBox_dashed_static() -> Int32 {
4933
fatalError("Only available on WebAssembly")
5034
}
5135
#endif
@@ -76,6 +60,22 @@ func _$StaticBox_value() throws(JSException) -> Double {
7660
return Double.bridgeJSLiftReturn(ret)
7761
}
7862

63+
func _$StaticBox_makeDefault() throws(JSException) -> StaticBox {
64+
let ret = bjs_StaticBox_makeDefault_static()
65+
if let error = _swift_js_take_exception() {
66+
throw error
67+
}
68+
return StaticBox.bridgeJSLiftReturn(ret)
69+
}
70+
71+
func _$StaticBox_dashed() throws(JSException) -> StaticBox {
72+
let ret = bjs_StaticBox_dashed_static()
73+
if let error = _swift_js_take_exception() {
74+
throw error
75+
}
76+
return StaticBox.bridgeJSLiftReturn(ret)
77+
}
78+
7979
func _$StaticBox_value(_ self: JSObject) throws(JSException) -> Double {
8080
let selfValue = self.bridgeJSLowerParameter()
8181
let ret = bjs_StaticBox_value(selfValue)

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.d.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
// To update this file, just rebuild your project or run
55
// `swift package bridge-js`.
66

7-
export interface StaticBox {
8-
}
97
export interface StaticBox {
108
value(): number;
119
}
@@ -14,13 +12,11 @@ export interface WithCtor {
1412
export type Exports = {
1513
}
1614
export type Imports = {
17-
StaticBox: {
18-
makeDefault(): StaticBox;
19-
"with-dashes"(): StaticBox;
20-
}
2115
StaticBox: {
2216
create(value: number): StaticBox;
2317
value(): number;
18+
makeDefault(): StaticBox;
19+
"with-dashes"(): StaticBox;
2420
}
2521
WithCtor: {
2622
new(value: number): WithCtor;

0 commit comments

Comments
 (0)