Skip to content

Commit a04bd50

Browse files
committed
BridgeJS: Fix namespace enum with @JS(namespace:) attribute
1 parent d8b0e17 commit a04bd50

File tree

21 files changed

+723
-40
lines changed

21 files changed

+723
-40
lines changed

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -533,14 +533,9 @@ public class ExportSwift {
533533
if function.effects.isStatic, let staticContext = function.staticContext {
534534
let callName: String
535535
switch staticContext {
536-
case .className(let baseName), .enumName(let baseName), .structName(let baseName):
536+
case .className(let baseName), .enumName(let baseName), .structName(let baseName),
537+
.namespaceEnum(let baseName):
537538
callName = "\(baseName).\(function.name)"
538-
case .namespaceEnum:
539-
if let namespace = function.namespace, !namespace.isEmpty {
540-
callName = "\(namespace.joined(separator: ".")).\(function.name)"
541-
} else {
542-
callName = function.name
543-
}
544539
}
545540
builder.call(name: callName, returnType: function.returnType)
546541
} else {

Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -990,7 +990,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
990990
}
991991

992992
let isNamespaceEnum = exportedEnumByName[enumKey]?.cases.isEmpty ?? true
993-
staticContext = isNamespaceEnum ? .namespaceEnum : .enumName(enumName)
993+
let swiftCallName = exportedEnumByName[enumKey]?.swiftCallName ?? enumName
994+
staticContext = isNamespaceEnum ? .namespaceEnum(swiftCallName) : .enumName(enumName)
994995
case .protocolBody(_, _):
995996
return nil
996997
case .structBody(let structName, _):
@@ -1187,7 +1188,10 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
11871188
return .skipChildren
11881189
}
11891190
let isNamespaceEnum = exportedEnumByName[enumKey]?.cases.isEmpty ?? true
1190-
staticContext = isStatic ? (isNamespaceEnum ? .namespaceEnum : .enumName(enumName)) : nil
1191+
// Use swiftCallName for the full Swift call path (handles nested enums correctly)
1192+
let swiftCallName = exportedEnumByName[enumKey]?.swiftCallName ?? enumName
1193+
staticContext =
1194+
isStatic ? (isNamespaceEnum ? .namespaceEnum(swiftCallName) : .enumName(swiftCallName)) : nil
11911195
case .topLevel:
11921196
diagnose(node: node, message: "@JS var must be inside a @JS class or enum")
11931197
return .skipChildren

Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ public enum StaticContext: Codable, Equatable, Sendable {
242242
case className(String)
243243
case structName(String)
244244
case enumName(String)
245-
case namespaceEnum
245+
case namespaceEnum(String)
246246
}
247247

248248
// MARK: - Struct Skeleton
@@ -533,13 +533,9 @@ public struct ExportedProperty: Codable, Equatable, Sendable {
533533
public func callName(prefix: String? = nil) -> String {
534534
if let staticContext = staticContext {
535535
switch staticContext {
536-
case .className(let baseName), .enumName(let baseName), .structName(let baseName):
536+
case .className(let baseName), .enumName(let baseName), .structName(let baseName),
537+
.namespaceEnum(let baseName):
537538
return "\(baseName).\(name)"
538-
case .namespaceEnum:
539-
if let namespace = namespace, !namespace.isEmpty {
540-
let namespacePath = namespace.joined(separator: ".")
541-
return "\(namespacePath).\(name)"
542-
}
543539
}
544540
}
545541
if let prefix = prefix {

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,17 @@ enum Internal {
5353
}
5454
}
5555

56-
// TODO: Add namespace enum with static functions when supported
56+
@JS(namespace: "Services.Graph")
57+
enum GraphOperations {
58+
@JS static func createGraph(rootId: Int) -> Int {
59+
return rootId * 10
60+
}
61+
62+
@JS static func nodeCount(graphId: Int) -> Int {
63+
return graphId
64+
}
65+
66+
@JS static func validate(graphId: Int) throws(JSException) -> Bool {
67+
return graphId > 0
68+
}
69+
}

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Export.d.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,15 @@ export type Exports = {
8484
},
8585
},
8686
},
87+
Services: {
88+
Graph: {
89+
GraphOperations: {
90+
createGraph(rootId: number): number;
91+
nodeCount(graphId: number): number;
92+
validate(graphId: number): boolean;
93+
},
94+
},
95+
},
8796
Utils: {
8897
Converter: {
8998
new(): Converter;

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,30 @@ export async function createInstantiator(options, swift) {
332332
},
333333
},
334334
},
335+
Services: {
336+
Graph: {
337+
GraphOperations: {
338+
createGraph: function bjs_Services_Graph_GraphOperations_static_createGraph(rootId) {
339+
const ret = instance.exports.bjs_Services_Graph_GraphOperations_static_createGraph(rootId);
340+
return ret;
341+
},
342+
nodeCount: function bjs_Services_Graph_GraphOperations_static_nodeCount(graphId) {
343+
const ret = instance.exports.bjs_Services_Graph_GraphOperations_static_nodeCount(graphId);
344+
return ret;
345+
},
346+
validate: function bjs_Services_Graph_GraphOperations_static_validate(graphId) {
347+
const ret = instance.exports.bjs_Services_Graph_GraphOperations_static_validate(graphId);
348+
if (tmpRetException) {
349+
const error = swift.memory.getObject(tmpRetException);
350+
swift.memory.release(tmpRetException);
351+
tmpRetException = undefined;
352+
throw error;
353+
}
354+
return ret !== 0;
355+
},
356+
},
357+
},
358+
},
335359
Utils: {
336360
Converter,
337361
},

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.Export.d.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,15 @@ declare global {
5858
}
5959
}
6060
}
61+
namespace Services {
62+
namespace Graph {
63+
namespace GraphOperations {
64+
createGraph(rootId: number): number;
65+
nodeCount(graphId: number): number;
66+
validate(graphId: number): boolean;
67+
}
68+
}
69+
}
6170
namespace Utils {
6271
class Converter {
6372
constructor();
@@ -103,6 +112,15 @@ export type Exports = {
103112
},
104113
},
105114
},
115+
Services: {
116+
Graph: {
117+
GraphOperations: {
118+
createGraph(rootId: number): number;
119+
nodeCount(graphId: number): number;
120+
validate(graphId: number): boolean;
121+
},
122+
},
123+
},
106124
Utils: {
107125
Converter: {
108126
new(): Converter;

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.Export.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,15 @@ export async function createInstantiator(options, swift) {
349349
if (typeof globalThis.Networking.APIV2.Internal === 'undefined') {
350350
globalThis.Networking.APIV2.Internal = {};
351351
}
352+
if (typeof globalThis.Services === 'undefined') {
353+
globalThis.Services = {};
354+
}
355+
if (typeof globalThis.Services.Graph === 'undefined') {
356+
globalThis.Services.Graph = {};
357+
}
358+
if (typeof globalThis.Services.Graph.GraphOperations === 'undefined') {
359+
globalThis.Services.Graph.GraphOperations = {};
360+
}
352361
if (typeof globalThis.Utils === 'undefined') {
353362
globalThis.Utils = {};
354363
}
@@ -369,6 +378,30 @@ export async function createInstantiator(options, swift) {
369378
},
370379
},
371380
},
381+
Services: {
382+
Graph: {
383+
GraphOperations: {
384+
createGraph: function bjs_Services_Graph_GraphOperations_static_createGraph(rootId) {
385+
const ret = instance.exports.bjs_Services_Graph_GraphOperations_static_createGraph(rootId);
386+
return ret;
387+
},
388+
nodeCount: function bjs_Services_Graph_GraphOperations_static_nodeCount(graphId) {
389+
const ret = instance.exports.bjs_Services_Graph_GraphOperations_static_nodeCount(graphId);
390+
return ret;
391+
},
392+
validate: function bjs_Services_Graph_GraphOperations_static_validate(graphId) {
393+
const ret = instance.exports.bjs_Services_Graph_GraphOperations_static_validate(graphId);
394+
if (tmpRetException) {
395+
const error = swift.memory.getObject(tmpRetException);
396+
swift.memory.release(tmpRetException);
397+
tmpRetException = undefined;
398+
throw error;
399+
}
400+
return ret !== 0;
401+
},
402+
},
403+
},
404+
},
372405
Utils: {
373406
Converter,
374407
},
@@ -377,6 +410,9 @@ export async function createInstantiator(options, swift) {
377410
globalThis.Utils.Converter = exports.Utils.Converter;
378411
globalThis.Networking.API.HTTPServer = exports.Networking.API.HTTPServer;
379412
globalThis.Networking.APIV2.Internal.TestServer = exports.Networking.APIV2.Internal.TestServer;
413+
globalThis.Services.Graph.GraphOperations.createGraph = exports.Services.Graph.GraphOperations.createGraph;
414+
globalThis.Services.Graph.GraphOperations.nodeCount = exports.Services.Graph.GraphOperations.nodeCount;
415+
globalThis.Services.Graph.GraphOperations.validate = exports.Services.Graph.GraphOperations.validate;
380416
return exports;
381417
},
382418
}

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumNamespace.Global.json

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,129 @@
400400
],
401401
"swiftCallName" : "Internal.SupportedMethod",
402402
"tsFullPath" : "Networking.APIV2.Internal.SupportedMethod"
403+
},
404+
{
405+
"cases" : [
406+
407+
],
408+
"emitStyle" : "const",
409+
"name" : "GraphOperations",
410+
"namespace" : [
411+
"Services",
412+
"Graph"
413+
],
414+
"staticMethods" : [
415+
{
416+
"abiName" : "bjs_Services_Graph_GraphOperations_static_createGraph",
417+
"effects" : {
418+
"isAsync" : false,
419+
"isStatic" : true,
420+
"isThrows" : false
421+
},
422+
"name" : "createGraph",
423+
"namespace" : [
424+
"Services",
425+
"Graph",
426+
"GraphOperations"
427+
],
428+
"parameters" : [
429+
{
430+
"label" : "rootId",
431+
"name" : "rootId",
432+
"type" : {
433+
"int" : {
434+
435+
}
436+
}
437+
}
438+
],
439+
"returnType" : {
440+
"int" : {
441+
442+
}
443+
},
444+
"staticContext" : {
445+
"namespaceEnum" : {
446+
"_0" : "GraphOperations"
447+
}
448+
}
449+
},
450+
{
451+
"abiName" : "bjs_Services_Graph_GraphOperations_static_nodeCount",
452+
"effects" : {
453+
"isAsync" : false,
454+
"isStatic" : true,
455+
"isThrows" : false
456+
},
457+
"name" : "nodeCount",
458+
"namespace" : [
459+
"Services",
460+
"Graph",
461+
"GraphOperations"
462+
],
463+
"parameters" : [
464+
{
465+
"label" : "graphId",
466+
"name" : "graphId",
467+
"type" : {
468+
"int" : {
469+
470+
}
471+
}
472+
}
473+
],
474+
"returnType" : {
475+
"int" : {
476+
477+
}
478+
},
479+
"staticContext" : {
480+
"namespaceEnum" : {
481+
"_0" : "GraphOperations"
482+
}
483+
}
484+
},
485+
{
486+
"abiName" : "bjs_Services_Graph_GraphOperations_static_validate",
487+
"effects" : {
488+
"isAsync" : false,
489+
"isStatic" : true,
490+
"isThrows" : true
491+
},
492+
"name" : "validate",
493+
"namespace" : [
494+
"Services",
495+
"Graph",
496+
"GraphOperations"
497+
],
498+
"parameters" : [
499+
{
500+
"label" : "graphId",
501+
"name" : "graphId",
502+
"type" : {
503+
"int" : {
504+
505+
}
506+
}
507+
}
508+
],
509+
"returnType" : {
510+
"bool" : {
511+
512+
}
513+
},
514+
"staticContext" : {
515+
"namespaceEnum" : {
516+
"_0" : "GraphOperations"
517+
}
518+
}
519+
}
520+
],
521+
"staticProperties" : [
522+
523+
],
524+
"swiftCallName" : "GraphOperations",
525+
"tsFullPath" : "Services.Graph.GraphOperations"
403526
}
404527
],
405528
"exposeToGlobal" : true,

0 commit comments

Comments
 (0)