Skip to content

Commit fac9cbd

Browse files
committed
BridgeJS: Support for static / class properties improvements
1 parent 7fe9b5b commit fac9cbd

File tree

18 files changed

+758
-558
lines changed

18 files changed

+758
-558
lines changed

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 159 additions & 190 deletions
Large diffs are not rendered by default.

Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift

Lines changed: 71 additions & 66 deletions
Large diffs are not rendered by default.

Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -537,11 +537,11 @@ struct IntrinsicJSFragment: Sendable {
537537
}
538538
}
539539
printer.write("},")
540-
540+
541541
for function in enumDefinition.staticMethods {
542542
printer.write("\(function.name): null,")
543543
}
544-
544+
545545
for property in enumDefinition.staticProperties {
546546
printer.write("\(property.name): null,")
547547
}
@@ -633,11 +633,11 @@ struct IntrinsicJSFragment: Sendable {
633633
let caseName = enumCase.name.capitalizedFirstLetter
634634
printer.write("\(caseName): \(index),")
635635
}
636-
636+
637637
for function in enumDefinition.staticMethods {
638638
printer.write("\(function.name): null,")
639639
}
640-
640+
641641
for property in enumDefinition.staticProperties {
642642
printer.write("\(property.name): null,")
643643
}
@@ -667,11 +667,11 @@ struct IntrinsicJSFragment: Sendable {
667667

668668
printer.write("\(caseName): \(formattedValue),")
669669
}
670-
670+
671671
for function in enumDefinition.staticMethods {
672672
printer.write("\(function.name): null,")
673673
}
674-
674+
675675
for property in enumDefinition.staticProperties {
676676
printer.write("\(property.name): null,")
677677
}

Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift

Lines changed: 118 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,57 @@
11
// This file is shared between BridgeTool and BridgeJSLink
22

3+
// MARK: - ABI Name Generation
4+
5+
/// Utility for generating consistent ABI names across all exported types
6+
struct ABINameGenerator {
7+
8+
/// Generates ABI name using standardized namespace + context pattern
9+
static func generateABIName(
10+
baseName: String,
11+
namespace: [String]?,
12+
staticContext: StaticContext?,
13+
operation: String? = nil
14+
) -> String {
15+
16+
let namespacePart: String
17+
if let namespace = namespace, !namespace.isEmpty {
18+
namespacePart = namespace.joined(separator: "_")
19+
} else {
20+
namespacePart = ""
21+
}
22+
23+
let contextPart: String
24+
if let staticContext = staticContext {
25+
switch staticContext {
26+
case .className(let name), .enumName(let name):
27+
contextPart = name
28+
case .namespaceEnum:
29+
contextPart = namespacePart
30+
31+
}
32+
} else {
33+
contextPart = namespacePart
34+
}
35+
36+
var components = ["bjs"]
37+
if !contextPart.isEmpty {
38+
components.append(contextPart)
39+
}
40+
41+
if staticContext != nil {
42+
components.append("static")
43+
}
44+
45+
components.append(baseName)
46+
47+
if let operation = operation {
48+
components.append(operation)
49+
}
50+
51+
return components.joined(separator: "_")
52+
}
53+
}
54+
355
// MARK: - Types
456

557
public enum BridgeType: Codable, Equatable, Sendable {
@@ -91,8 +143,7 @@ public struct Effects: Codable, Equatable, Sendable {
91143
public enum StaticContext: Codable, Equatable, Sendable {
92144
case className(String)
93145
case enumName(String)
94-
case namespaceEnum(String)
95-
case explicitNamespace([String])
146+
case namespaceEnum
96147
}
97148

98149
// MARK: - Enum Skeleton
@@ -131,7 +182,7 @@ public struct ExportedEnum: Codable, Equatable, Sendable {
131182
public let name: String
132183
public let swiftCallName: String
133184
public let explicitAccessControl: String?
134-
public let cases: [EnumCase]
185+
public var cases: [EnumCase]
135186
public let rawType: String?
136187
public let namespace: [String]?
137188
public let emitStyle: EnumEmitStyle
@@ -205,6 +256,19 @@ public struct ExportedFunction: Codable, Equatable, Sendable {
205256
self.namespace = namespace
206257
self.staticContext = staticContext
207258
}
259+
260+
// MARK: - Unified ABI Name Generation (New Approach)
261+
262+
/// Generates ABI name using the new unified approach
263+
/// This method uses the standardized namespace property and ABINameGenerator
264+
public func abiNameUnified() -> String {
265+
return ABINameGenerator.generateABIName(
266+
baseName: name,
267+
namespace: namespace,
268+
staticContext: effects.isStatic ? staticContext : nil,
269+
operation: nil
270+
)
271+
}
208272
}
209273

210274
public struct ExportedClass: Codable {
@@ -253,32 +317,40 @@ public struct ExportedProperty: Codable, Equatable, Sendable {
253317
public var name: String
254318
public var type: BridgeType
255319
public var isReadonly: Bool
256-
public var isStatic: Bool = false
320+
public var isStatic: Bool
321+
public var namespace: [String]?
257322
public var staticContext: StaticContext?
258323

259-
public init(name: String, type: BridgeType, isReadonly: Bool = false, isStatic: Bool = false, staticContext: StaticContext? = nil) {
324+
public init(
325+
name: String,
326+
type: BridgeType,
327+
isReadonly: Bool = false,
328+
isStatic: Bool = false,
329+
namespace: [String]? = nil,
330+
staticContext: StaticContext? = nil
331+
) {
260332
self.name = name
261333
self.type = type
262334
self.isReadonly = isReadonly
263335
self.isStatic = isStatic
336+
self.namespace = namespace
264337
self.staticContext = staticContext
265338
}
266339

267340
public func getterAbiName(className: String) -> String {
268341
if isStatic, let staticContext = staticContext {
269-
// Generate context-aware ABI names for static properties
270342
switch staticContext {
271343
case .className(let className):
272344
return "bjs_\(className)_static_\(name)_get"
273345
case .enumName(let enumName):
274346
return "bjs_\(enumName)_static_\(name)_get"
275-
case .namespaceEnum(let enumName):
276-
// Convert dots to underscores for namespace enums
277-
let abiEnumName = enumName.split(separator: ".").joined(separator: "_")
278-
return "bjs_\(abiEnumName)_static_\(name)_get"
279-
case .explicitNamespace(let namespace):
280-
let abiNamespace = namespace.joined(separator: "_")
281-
return "bjs_\(abiNamespace)_static_\(name)_get"
347+
case .namespaceEnum:
348+
if let namespace = namespace, !namespace.isEmpty {
349+
let abiNamespace = namespace.joined(separator: "_")
350+
return "bjs_\(abiNamespace)_static_\(name)_get"
351+
} else {
352+
return "bjs_static_\(name)_get"
353+
}
282354
}
283355
} else if isStatic {
284356
return "bjs_\(className)_static_\(name)_get"
@@ -295,20 +367,46 @@ public struct ExportedProperty: Codable, Equatable, Sendable {
295367
return "bjs_\(className)_static_\(name)_set"
296368
case .enumName(let enumName):
297369
return "bjs_\(enumName)_static_\(name)_set"
298-
case .namespaceEnum(let enumName):
299-
// Convert dots to underscores for namespace enums
300-
let abiEnumName = enumName.split(separator: ".").joined(separator: "_")
301-
return "bjs_\(abiEnumName)_static_\(name)_set"
302-
case .explicitNamespace(let namespace):
303-
let abiNamespace = namespace.joined(separator: "_")
304-
return "bjs_\(abiNamespace)_static_\(name)_set"
370+
case .namespaceEnum:
371+
// For namespace enums, use ONLY the namespace property to avoid duplication
372+
if let namespace = namespace, !namespace.isEmpty {
373+
let abiNamespace = namespace.joined(separator: "_")
374+
return "bjs_\(abiNamespace)_static_\(name)_set"
375+
} else {
376+
// Fallback if no namespace is available
377+
return "bjs_static_\(name)_set"
378+
}
305379
}
306380
} else if isStatic {
307381
return "bjs_\(className)_static_\(name)_set"
308382
} else {
309383
return "bjs_\(className)_\(name)_set"
310384
}
311385
}
386+
387+
// MARK: - Unified ABI Name Generation (New Approach)
388+
389+
/// Generates getter ABI name using the new unified approach
390+
/// This method uses the standardized namespace property and ABINameGenerator
391+
public func getterAbiNameUnified() -> String {
392+
return ABINameGenerator.generateABIName(
393+
baseName: name,
394+
namespace: namespace,
395+
staticContext: isStatic ? staticContext : nil,
396+
operation: "get"
397+
)
398+
}
399+
400+
/// Generates setter ABI name using the new unified approach
401+
/// This method uses the standardized namespace property and ABINameGenerator
402+
public func setterAbiNameUnified() -> String {
403+
return ABINameGenerator.generateABIName(
404+
baseName: name,
405+
namespace: namespace,
406+
staticContext: isStatic ? staticContext : nil,
407+
operation: "set"
408+
)
409+
}
312410
}
313411

314412
public struct ExportedSkeleton: Codable {

Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/StaticFunctions.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
@JS class func subtract(a: Int, b: Int) -> Int {
55
return a - b
66
}
7-
7+
88
@JS static func add(a: Int, b: Int) -> Int {
99
return a + b
1010
}
@@ -28,7 +28,7 @@ enum APIResult {
2828
case success(String)
2929
case failure(Int)
3030

31-
@JS static func roundtrip(value: APIResult) -> APIResult { }
31+
@JS static func roundtrip(value: APIResult) -> APIResult {}
3232
}
3333

3434
@JS enum Utils {

Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/StaticProperties.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
@JS class PropertyClass {
22
@JS init() {}
3-
3+
44
@JS static let staticConstant: String = "constant"
55
@JS static var staticVariable: Int = 42
66
@JS static var jsObjectProperty: JSObject = JSObject()
77
@JS class var classVariable: String = "overridable"
8-
8+
99
@JS static var computedProperty: String {
1010
get { return "\(staticVariable) computed" }
1111
set { staticVariable = newValue + 5 }
1212
}
13-
13+
1414
@JS static var readOnlyComputed: Int {
1515
return 100
1616
}
17-
17+
1818
@JS static var optionalProperty: String? = nil
1919
}
2020

2121
@JS enum PropertyEnum {
2222
case value1
2323
case value2
24-
24+
2525
@JS static var enumProperty: String = "enum value"
2626
@JS static let enumConstant: Int = 42
2727
@JS static var computedEnum: String {
@@ -33,7 +33,7 @@
3333
@JS enum PropertyNamespace {
3434
@JS static var namespaceProperty: String = "namespace"
3535
@JS static let namespaceConstant: String = "constant"
36-
36+
3737
@JS enum Nested {
3838
@JS nonisolated(unsafe) static var nestedProperty: Int = 999
3939
@JS static let nestedConstant: String = "nested"

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Export.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ const __bjs_createAPIResultHelpers = () => {
5757
}
5858
});
5959
};
60+
if (typeof globalThis.Utils === 'undefined') {
61+
globalThis.Utils = {};
62+
}
63+
64+
6065
export async function createInstantiator(options, swift) {
6166
let instance;
6267
let memory;
@@ -275,10 +280,10 @@ export async function createInstantiator(options, swift) {
275280
};
276281
const exports = {
277282
MathUtils,
278-
uppercase: function bjs_Utils_String_uppercase(text) {
283+
uppercase: function bjs_Utils_String_static_uppercase(text) {
279284
const textBytes = textEncoder.encode(text);
280285
const textId = swift.memory.retain(textBytes);
281-
instance.exports.bjs_Utils_String_uppercase(textId, textBytes.length);
286+
instance.exports.bjs_Utils_String_static_uppercase(textId, textBytes.length);
282287
const ret = tmpRetString;
283288
tmpRetString = undefined;
284289
swift.memory.release(textId);

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Export.js

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,32 @@ export async function createInstantiator(options, swift) {
263263
}
264264
}
265265
}
266+
<<<<<<< HEAD
267+
=======
268+
if (typeof globalThis.PropertyNamespace === 'undefined') {
269+
globalThis.PropertyNamespace = {};
270+
}
271+
if (typeof globalThis.PropertyNamespace.Nested === 'undefined') {
272+
globalThis.PropertyNamespace.Nested = {};
273+
}
274+
Object.defineProperty(globalThis.PropertyNamespace, 'namespaceProperty', { get: function() {
275+
instance.exports.bjs_PropertyNamespace_static_namespaceProperty_get();
276+
const ret = tmpRetString;
277+
tmpRetString = undefined;
278+
return ret;
279+
}, set: function(value) {
280+
const valueBytes = textEncoder.encode(value);
281+
const valueId = swift.memory.retain(valueBytes);
282+
instance.exports.bjs_PropertyNamespace_static_namespaceProperty_set(valueId, valueBytes.length);
283+
swift.memory.release(valueId);
284+
} });
285+
Object.defineProperty(globalThis.PropertyNamespace, 'namespaceConstant', { get: function() {
286+
instance.exports.bjs_PropertyNamespace_static_namespaceConstant_get();
287+
const ret = tmpRetString;
288+
tmpRetString = undefined;
289+
return ret;
290+
} });
291+
>>>>>>> 26a78490 (WIP: Enum handling and nesting simplifications (+1 squashed commit))
266292
Object.defineProperty(globalThis.PropertyNamespace.Nested, 'nestedProperty', { get: function() {
267293
const ret = instance.exports.bjs_PropertyNamespace_Nested_static_nestedProperty_get();
268294
return ret;
@@ -281,23 +307,6 @@ export async function createInstantiator(options, swift) {
281307
}, set: function(value) {
282308
instance.exports.bjs_PropertyNamespace_Nested_static_nestedDouble_set(value);
283309
} });
284-
Object.defineProperty(globalThis.PropertyNamespace, 'namespaceProperty', { get: function() {
285-
instance.exports.bjs_PropertyNamespace_static_namespaceProperty_get();
286-
const ret = tmpRetString;
287-
tmpRetString = undefined;
288-
return ret;
289-
}, set: function(value) {
290-
const valueBytes = textEncoder.encode(value);
291-
const valueId = swift.memory.retain(valueBytes);
292-
instance.exports.bjs_PropertyNamespace_static_namespaceProperty_set(valueId, valueBytes.length);
293-
swift.memory.release(valueId);
294-
} });
295-
Object.defineProperty(globalThis.PropertyNamespace, 'namespaceConstant', { get: function() {
296-
instance.exports.bjs_PropertyNamespace_static_namespaceConstant_get();
297-
const ret = tmpRetString;
298-
tmpRetString = undefined;
299-
return ret;
300-
} });
301310
Object.defineProperty(PropertyEnum, 'enumProperty', { get: function() {
302311
instance.exports.bjs_PropertyEnum_static_enumProperty_get();
303312
const ret = tmpRetString;

0 commit comments

Comments
 (0)