Skip to content
Merged
Changes from 1 commit
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
Next Next commit
BridgeJS: Factor out import object builder
  • Loading branch information
kateinoigakukun committed Jun 13, 2025
commit 328a5b7b5c59fb3190bcd0945a23e291b8aa286a
131 changes: 78 additions & 53 deletions Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,8 @@ struct BridgeJSLink {

func link() throws -> (outputJs: String, outputDts: String) {
var exportsLines: [String] = []
var importedLines: [String] = []
var classLines: [String] = []
var dtsExportLines: [String] = []
var dtsImportLines: [String] = []
var dtsClassLines: [String] = []

if exportedSkeletons.contains(where: { $0.classes.count > 0 }) {
Expand Down Expand Up @@ -84,57 +82,18 @@ struct BridgeJSLink {
}
}

var importObjectBuilders: [ImportObjectBuilder] = []
for skeletonSet in importedSkeletons {
importedLines.append("const \(skeletonSet.moduleName) = importObject[\"\(skeletonSet.moduleName)\"] = {};")
func assignToImportObject(name: String, function: [String]) {
var js = function
js[0] = "\(skeletonSet.moduleName)[\"\(name)\"] = " + js[0]
importedLines.append(contentsOf: js)
}
let importObjectBuilder = ImportObjectBuilder(moduleName: skeletonSet.moduleName)
for fileSkeleton in skeletonSet.children {
for function in fileSkeleton.functions {
let (js, dts) = try renderImportedFunction(function: function)
assignToImportObject(name: function.abiName(context: nil), function: js)
dtsImportLines.append(contentsOf: dts)
try renderImportedFunction(importObjectBuilder: importObjectBuilder, function: function)
}
for type in fileSkeleton.types {
for property in type.properties {
let getterAbiName = property.getterAbiName(context: type)
let (js, dts) = try renderImportedProperty(
property: property,
abiName: getterAbiName,
emitCall: { thunkBuilder in
thunkBuilder.callPropertyGetter(name: property.name, returnType: property.type)
return try thunkBuilder.lowerReturnValue(returnType: property.type)
}
)
assignToImportObject(name: getterAbiName, function: js)
dtsImportLines.append(contentsOf: dts)

if !property.isReadonly {
let setterAbiName = property.setterAbiName(context: type)
let (js, dts) = try renderImportedProperty(
property: property,
abiName: setterAbiName,
emitCall: { thunkBuilder in
thunkBuilder.liftParameter(
param: Parameter(label: nil, name: "newValue", type: property.type)
)
thunkBuilder.callPropertySetter(name: property.name, returnType: property.type)
return nil
}
)
assignToImportObject(name: setterAbiName, function: js)
dtsImportLines.append(contentsOf: dts)
}
}
for method in type.methods {
let (js, dts) = try renderImportedMethod(context: type, method: method)
assignToImportObject(name: method.abiName(context: type), function: js)
dtsImportLines.append(contentsOf: dts)
}
try renderImportedType(importObjectBuilder: importObjectBuilder, type: type)
}
}
importObjectBuilders.append(importObjectBuilder)
}

let outputJs = """
Expand Down Expand Up @@ -175,7 +134,7 @@ struct BridgeJSLink {
target.set(tmpRetBytes);
tmpRetBytes = undefined;
}
\(importedLines.map { $0.indent(count: 12) }.joined(separator: "\n"))
\(importObjectBuilders.flatMap { $0.importedLines }.map { $0.indent(count: 12) }.joined(separator: "\n"))
},
setInstance: (i) => {
instance = i;
Expand All @@ -198,7 +157,7 @@ struct BridgeJSLink {
dtsLines.append(contentsOf: dtsExportLines.map { $0.indent(count: 4) })
dtsLines.append("}")
dtsLines.append("export type Imports = {")
dtsLines.append(contentsOf: dtsImportLines.map { $0.indent(count: 4) })
dtsLines.append(contentsOf: importObjectBuilders.flatMap { $0.dtsImportLines }.map { $0.indent(count: 4) })
dtsLines.append("}")
let outputDts = """
// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit,
Expand Down Expand Up @@ -475,7 +434,31 @@ struct BridgeJSLink {
}
}

func renderImportedFunction(function: ImportedFunctionSkeleton) throws -> (js: [String], dts: [String]) {
class ImportObjectBuilder {
var moduleName: String
var importedLines: [String] = []
var dtsImportLines: [String] = []

init(moduleName: String) {
self.moduleName = moduleName
importedLines.append("const \(moduleName) = importObject[\"\(moduleName)\"] = {};")
}

func assignToImportObject(name: String, function: [String]) {
var js = function
js[0] = "\(moduleName)[\"\(name)\"] = " + js[0]
importedLines.append(contentsOf: js)
}

func appendDts(_ lines: [String]) {
dtsImportLines.append(contentsOf: lines)
}
}

func renderImportedFunction(
importObjectBuilder: ImportObjectBuilder,
function: ImportedFunctionSkeleton
) throws {
let thunkBuilder = ImportedThunkBuilder()
for param in function.parameters {
thunkBuilder.liftParameter(param: param)
Expand All @@ -486,11 +469,53 @@ struct BridgeJSLink {
name: function.abiName(context: nil),
returnExpr: returnExpr
)
var dtsLines: [String] = []
dtsLines.append(
"\(function.name)\(renderTSSignature(parameters: function.parameters, returnType: function.returnType));"
importObjectBuilder.appendDts(
[
"\(function.name)\(renderTSSignature(parameters: function.parameters, returnType: function.returnType));"
]
)
return (funcLines, dtsLines)
importObjectBuilder.assignToImportObject(name: function.abiName(context: nil), function: funcLines)
}

func renderImportedType(
importObjectBuilder: ImportObjectBuilder,
type: ImportedTypeSkeleton
) throws {
for property in type.properties {
let getterAbiName = property.getterAbiName(context: type)
let (js, dts) = try renderImportedProperty(
property: property,
abiName: getterAbiName,
emitCall: { thunkBuilder in
thunkBuilder.callPropertyGetter(name: property.name, returnType: property.type)
return try thunkBuilder.lowerReturnValue(returnType: property.type)
}
)
importObjectBuilder.assignToImportObject(name: getterAbiName, function: js)
importObjectBuilder.appendDts(dts)

if !property.isReadonly {
let setterAbiName = property.setterAbiName(context: type)
let (js, dts) = try renderImportedProperty(
property: property,
abiName: setterAbiName,
emitCall: { thunkBuilder in
thunkBuilder.liftParameter(
param: Parameter(label: nil, name: "newValue", type: property.type)
)
thunkBuilder.callPropertySetter(name: property.name, returnType: property.type)
return nil
}
)
importObjectBuilder.assignToImportObject(name: setterAbiName, function: js)
importObjectBuilder.appendDts(dts)
}
}
for method in type.methods {
let (js, dts) = try renderImportedMethod(context: type, method: method)
importObjectBuilder.assignToImportObject(name: method.abiName(context: type), function: js)
importObjectBuilder.appendDts(dts)
}
}

func renderImportedProperty(
Expand Down