Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 47 additions & 9 deletions Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,9 @@ public struct BridgeJSLink {
var structExportEntries: [(js: [String], dts: [String])] = []
for structDefinition in skeleton.structs {
let (jsStruct, dtsType, dtsExportEntry) = try renderExportedStruct(structDefinition)
data.topLevelDtsTypeLines.append(contentsOf: dtsType)
if structDefinition.namespace == nil {
data.topLevelDtsTypeLines.append(contentsOf: dtsType)
}

if structDefinition.namespace == nil && (!jsStruct.isEmpty || !dtsExportEntry.isEmpty) {
structExportEntries.append((js: jsStruct, dts: dtsExportEntry))
Expand Down Expand Up @@ -492,15 +494,15 @@ public struct BridgeJSLink {
printer.write("bjs[\"swift_js_struct_lower_\(structDef.abiName)\"] = function(objectId) {")
printer.indent {
printer.write(
"\(JSGlueVariableScope.reservedStructHelpers).\(structDef.name).lower(\(JSGlueVariableScope.reservedSwift).memory.getObject(objectId));"
"\(JSGlueVariableScope.reservedStructHelpers).\(structDef.abiName).lower(\(JSGlueVariableScope.reservedSwift).memory.getObject(objectId));"
)
}
printer.write("}")

printer.write("bjs[\"swift_js_struct_lift_\(structDef.abiName)\"] = function() {")
printer.indent {
printer.write(
"const value = \(JSGlueVariableScope.reservedStructHelpers).\(structDef.name).lift();"
"const value = \(JSGlueVariableScope.reservedStructHelpers).\(structDef.abiName).lift();"
)
printer.write("return \(JSGlueVariableScope.reservedSwift).memory.retain(value);")
}
Expand Down Expand Up @@ -1005,7 +1007,7 @@ public struct BridgeJSLink {
let structScope = JSGlueVariableScope(intrinsicRegistry: intrinsicRegistry)
let fragment = IntrinsicJSFragment.structHelper(structDefinition: structDef, allStructs: allStructs)
_ = try fragment.printCode(
[structDef.name],
[structDef.abiName],
IntrinsicJSFragment.PrintCodeContext(
scope: structScope,
printer: structPrinter,
Expand Down Expand Up @@ -1159,10 +1161,10 @@ public struct BridgeJSLink {
for skeleton in skeletons.compactMap(\.exported) {
for structDef in skeleton.structs {
printer.write(
"const \(structDef.name)Helpers = __bjs_create\(structDef.name)Helpers();"
"const \(structDef.abiName)Helpers = __bjs_create\(structDef.abiName)Helpers();"
)
printer.write(
"\(JSGlueVariableScope.reservedStructHelpers).\(structDef.name) = \(structDef.name)Helpers;"
"\(JSGlueVariableScope.reservedStructHelpers).\(structDef.abiName) = \(structDef.abiName)Helpers;"
)
printer.nextLine()
}
Expand Down Expand Up @@ -2616,6 +2618,7 @@ extension BridgeJSLink {
var functions: [ExportedFunction] = []
var classes: [ExportedClass] = []
var enums: [ExportedEnum] = []
var structs: [ExportedStruct] = []
var staticProperties: [ExportedProperty] = []
var functionJsLines: [(name: String, lines: [String])] = []
var functionDtsLines: [(name: String, lines: [String])] = []
Expand Down Expand Up @@ -2664,6 +2667,14 @@ extension BridgeJSLink {
currentNode.content.classes.append(klass)
}

for structDef in skeleton.structs where structDef.namespace != nil {
var currentNode = rootNode
for part in structDef.namespace! {
currentNode = currentNode.addChild(part)
}
currentNode.content.structs.append(structDef)
}

for enumDef in skeleton.enums where enumDef.namespace != nil && enumDef.enumType != .namespace {
var currentNode = rootNode
for part in enumDef.namespace! {
Expand Down Expand Up @@ -2845,8 +2856,18 @@ extension BridgeJSLink {
}
}

private func hasExportContent(node: NamespaceNode) -> Bool {
if !node.content.classDtsLines.isEmpty || !node.content.enumDtsLines.isEmpty
|| !node.content.functionDtsLines.isEmpty || !node.content.staticProperties.isEmpty
{
return true
}
return node.children.values.contains(where: { hasExportContent(node: $0) })
}

private func printExportsTypeHierarchy(node: NamespaceNode, printer: CodeFragmentPrinter) {
for (childName, childNode) in node.children.sorted(by: { $0.key < $1.key }) {
guard hasExportContent(node: childNode) else { continue }
printer.write("\(childName): {")
printer.indent {
for (_, lines) in childNode.content.classDtsLines.sorted(by: { $0.name < $1.name }) {
Expand Down Expand Up @@ -2983,8 +3004,8 @@ extension BridgeJSLink {
renderTSSignatureCallback: @escaping ([Parameter], BridgeType, Effects) -> String
) {
func hasContent(node: NamespaceNode) -> Bool {
// Enums are always included
if !node.content.enums.isEmpty {
// Enums and structs are always included
if !node.content.enums.isEmpty || !node.content.structs.isEmpty {
return true
}

Expand Down Expand Up @@ -3164,6 +3185,23 @@ extension BridgeJSLink {
}
}

// Generate struct interface definitions
let sortedStructs = childNode.content.structs.sorted { $0.name < $1.name }
for structDef in sortedStructs {
let instanceProps = structDef.properties.filter { !$0.isStatic }
printer.write("export interface \(structDef.name) {")
printer.indent {
for property in instanceProps {
let tsType = BridgeJSLink.resolveTypeScriptType(
property.type,
exportedSkeletons: exportedSkeletons
)
printer.write("\(property.name): \(tsType);")
}
}
printer.write("}")
}

// Only include functions and properties when exposeToGlobal is true
if exposeToGlobal {
let sortedFunctions = childNode.content.functions.sorted { $0.name < $1.name }
Expand Down Expand Up @@ -3610,7 +3648,7 @@ extension BridgeType {
case .associatedValueEnum(let name):
return "\(name)Tag"
case .swiftStruct(let name):
return name.components(separatedBy: ".").last ?? name
return name
case .namespaceEnum(let name):
return name
case .swiftProtocol(let name):
Expand Down
20 changes: 10 additions & 10 deletions Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -944,7 +944,7 @@ struct IntrinsicJSFragment: Sendable {
fullName: String,
kind: JSOptionalKind
) -> IntrinsicJSFragment {
let base = fullName.components(separatedBy: ".").last ?? fullName
let base = fullName.replacingOccurrences(of: ".", with: "_")
let absenceLiteral = kind.absenceLiteral
return IntrinsicJSFragment(
parameters: [],
Expand Down Expand Up @@ -1300,7 +1300,7 @@ struct IntrinsicJSFragment: Sendable {
let base = fullName.components(separatedBy: ".").last ?? fullName
return .associatedEnumLowerParameter(enumBase: base)
case .swiftStruct(let fullName):
let base = fullName.components(separatedBy: ".").last ?? fullName
let base = fullName.replacingOccurrences(of: ".", with: "_")
return swiftStructLowerParameter(structBase: base)
case .closure:
return IntrinsicJSFragment(
Expand Down Expand Up @@ -1360,7 +1360,7 @@ struct IntrinsicJSFragment: Sendable {
let base = fullName.components(separatedBy: ".").last ?? fullName
return .associatedEnumLiftReturn(enumBase: base)
case .swiftStruct(let fullName):
let base = fullName.components(separatedBy: ".").last ?? fullName
let base = fullName.replacingOccurrences(of: ".", with: "_")
return swiftStructLiftReturn(structBase: base)
case .closure:
return IntrinsicJSFragment(
Expand Down Expand Up @@ -1446,7 +1446,7 @@ struct IntrinsicJSFragment: Sendable {
case .importTS:
return .jsObjectLiftRetainedObjectId
case .exportSwift:
let base = fullName.components(separatedBy: ".").last ?? fullName
let base = fullName.replacingOccurrences(of: ".", with: "_")
return IntrinsicJSFragment(
parameters: [],
printCode: { arguments, context in
Expand Down Expand Up @@ -1805,7 +1805,7 @@ struct IntrinsicJSFragment: Sendable {
}

static func swiftStructLowerReturn(fullName: String) -> IntrinsicJSFragment {
swiftStructLower(structBase: fullName.components(separatedBy: ".").last ?? fullName)
swiftStructLower(structBase: fullName.replacingOccurrences(of: ".", with: "_"))
}

static func swiftStructLowerParameter(structBase: String) -> IntrinsicJSFragment {
Expand Down Expand Up @@ -2008,7 +2008,7 @@ struct IntrinsicJSFragment: Sendable {
}
)
case .swiftStruct(let fullName):
let structBase = fullName.components(separatedBy: ".").last ?? fullName
let structBase = fullName.replacingOccurrences(of: ".", with: "_")
return IntrinsicJSFragment(
parameters: [],
printCode: { arguments, context in
Expand Down Expand Up @@ -2130,7 +2130,7 @@ struct IntrinsicJSFragment: Sendable {
}
)
case .swiftStruct(let fullName):
let structBase = fullName.components(separatedBy: ".").last ?? fullName
let structBase = fullName.replacingOccurrences(of: ".", with: "_")
return IntrinsicJSFragment(
parameters: ["value"],
printCode: { arguments, context in
Expand Down Expand Up @@ -2426,7 +2426,7 @@ struct IntrinsicJSFragment: Sendable {
)
try printer.indent {
printer.write(
"\(JSGlueVariableScope.reservedStructHelpers).\(structDef.name).lower(this);"
"\(JSGlueVariableScope.reservedStructHelpers).\(structDef.abiName).lower(this);"
)

var paramForwardings: [String] = []
Expand Down Expand Up @@ -2502,7 +2502,7 @@ struct IntrinsicJSFragment: Sendable {
let printer = context.printer
let value = arguments[0]
printer.write(
"\(JSGlueVariableScope.reservedStructHelpers).\(nestedName).lower(\(value));"
"\(JSGlueVariableScope.reservedStructHelpers).\(nestedName.replacingOccurrences(of: ".", with: "_")).lower(\(value));"
)
return []
}
Expand Down Expand Up @@ -2540,7 +2540,7 @@ struct IntrinsicJSFragment: Sendable {
let (scope, printer) = (context.scope, context.printer)
let structVar = scope.variable("struct")
printer.write(
"const \(structVar) = \(JSGlueVariableScope.reservedStructHelpers).\(nestedName).lift();"
"const \(structVar) = \(JSGlueVariableScope.reservedStructHelpers).\(nestedName.replacingOccurrences(of: ".", with: "_")).lift();"
)
return [structVar]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,14 @@
var score: Double
}
}

@JS class Player {
@JS func getTag() -> String {
return "player"
}

@JS struct Stats {
var level: Int
var rating: String
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,32 @@

],
"swiftCallName" : "User"
},
{
"methods" : [
{
"abiName" : "bjs_Player_getTag",
"effects" : {
"isAsync" : false,
"isStatic" : false,
"isThrows" : false
},
"name" : "getTag",
"parameters" : [

],
"returnType" : {
"string" : {

}
}
}
],
"name" : "Player",
"properties" : [

],
"swiftCallName" : "Player"
}
],
"enums" : [
Expand Down Expand Up @@ -79,6 +105,47 @@
}
],
"swiftCallName" : "User.Stats"
},
{
"methods" : [

],
"name" : "Stats",
"namespace" : [
"Player"
],
"properties" : [
{
"isReadonly" : true,
"isStatic" : false,
"name" : "level",
"namespace" : [
"Player"
],
"type" : {
"integer" : {
"_0" : {
"isSigned" : true,
"width" : "word"
}
}
}
},
{
"isReadonly" : true,
"isStatic" : false,
"name" : "rating",
"namespace" : [
"Player"
],
"type" : {
"string" : {

}
}
}
],
"swiftCallName" : "Player.Stats"
}
]
},
Expand Down
Loading
Loading