Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit c1d778e

Browse files
committed
BridgeJS: Initial protocol support
[fe09c4b1] Simplify export swift [b42bb7c1] WIP: Simplify protocol method generation [75e1ed37] BridgeJSLink simplification [b1fcc4d0] Cleanup [70aa0332] WIP: Final wrap [2f648eaf] WIP: Protocols simplification [f2f89b33] WIP: Fix for parameters in methods [6026fc1d] WIP: Test protocol methods with parameters
1 parent 2c183f3 commit c1d778e

35 files changed

+2604
-105
lines changed

‎Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift‎

Lines changed: 343 additions & 79 deletions
Large diffs are not rendered by default.

‎Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,8 @@ extension BridgeType {
435435
case .void: return .void
436436
case .swiftHeapObject:
437437
throw BridgeJSCoreError("swiftHeapObject is not supported in imported signatures")
438+
case .swiftProtocol:
439+
throw BridgeJSCoreError("swiftProtocol is not supported in imported signatures")
438440
case .caseEnum, .rawValueEnum, .associatedValueEnum, .namespaceEnum:
439441
throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports")
440442
case .optional:
@@ -465,6 +467,8 @@ extension BridgeType {
465467
case .void: return .void
466468
case .swiftHeapObject:
467469
throw BridgeJSCoreError("swiftHeapObject is not supported in imported signatures")
470+
case .swiftProtocol:
471+
throw BridgeJSCoreError("swiftProtocol is not supported in imported signatures")
468472
case .caseEnum, .rawValueEnum, .associatedValueEnum, .namespaceEnum:
469473
throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports")
470474
case .optional:

‎Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift‎

Lines changed: 75 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,9 @@ struct BridgeJSLink {
240240
enumPropertyPrinter.write("},")
241241

242242
if !property.isReadonly {
243-
let setterThunkBuilder = ExportedThunkBuilder(effects: Effects(isAsync: false, isThrows: false))
243+
let setterThunkBuilder = ExportedThunkBuilder(
244+
effects: Effects(isAsync: false, isThrows: false)
245+
)
244246
try setterThunkBuilder.lowerParameter(
245247
param: Parameter(label: "value", name: "value", type: property.type)
246248
)
@@ -300,6 +302,29 @@ struct BridgeJSLink {
300302
data.importObjectBuilders.append(importObjectBuilder)
301303
}
302304

305+
for skeleton in exportedSkeletons {
306+
if !skeleton.protocols.isEmpty {
307+
let importObjectBuilder: ImportObjectBuilder
308+
if let existingBuilder = data.importObjectBuilders.first(where: { 0ドル.moduleName == skeleton.moduleName }
309+
) {
310+
importObjectBuilder = existingBuilder
311+
} else {
312+
importObjectBuilder = ImportObjectBuilder(moduleName: skeleton.moduleName)
313+
data.importObjectBuilders.append(importObjectBuilder)
314+
}
315+
316+
for proto in skeleton.protocols {
317+
for method in proto.methods {
318+
try renderProtocolMethod(
319+
importObjectBuilder: importObjectBuilder,
320+
protocol: proto,
321+
method: method
322+
)
323+
}
324+
}
325+
}
326+
}
327+
303328
return data
304329
}
305330

@@ -572,6 +597,22 @@ struct BridgeJSLink {
572597
"""
573598
let printer = CodeFragmentPrinter(header: header)
574599
printer.nextLine()
600+
601+
for skeleton in exportedSkeletons {
602+
for proto in skeleton.protocols {
603+
printer.write("export interface \(proto.name) {")
604+
printer.indent {
605+
for method in proto.methods {
606+
printer.write(
607+
"\(method.name)\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));"
608+
)
609+
}
610+
}
611+
printer.write("}")
612+
printer.nextLine()
613+
}
614+
}
615+
575616
printer.write(lines: data.topLevelDtsEnumLines)
576617

577618
// Generate Object types for const-style enums
@@ -1468,7 +1509,9 @@ extension BridgeJSLink {
14681509

14691510
if !property.isReadonly {
14701511
// Generate setter
1471-
let setterThunkBuilder = ExportedThunkBuilder(effects: Effects(isAsync: false, isThrows: false))
1512+
let setterThunkBuilder = ExportedThunkBuilder(
1513+
effects: Effects(isAsync: false, isThrows: false)
1514+
)
14721515
try setterThunkBuilder.lowerParameter(
14731516
param: Parameter(label: "value", name: "value", type: property.type)
14741517
)
@@ -1539,7 +1582,9 @@ extension BridgeJSLink {
15391582

15401583
if !property.isReadonly {
15411584
// Generate setter
1542-
let setterThunkBuilder = ExportedThunkBuilder(effects: Effects(isAsync: false, isThrows: false))
1585+
let setterThunkBuilder = ExportedThunkBuilder(
1586+
effects: Effects(isAsync: false, isThrows: false)
1587+
)
15431588
try setterThunkBuilder.lowerParameter(
15441589
param: Parameter(label: "value", name: "value", type: property.type)
15451590
)
@@ -1704,7 +1749,9 @@ extension BridgeJSLink {
17041749

17051750
// Generate static property setter if not readonly
17061751
if !property.isReadonly {
1707-
let setterThunkBuilder = ExportedThunkBuilder(effects: Effects(isAsync: false, isThrows: false))
1752+
let setterThunkBuilder = ExportedThunkBuilder(
1753+
effects: Effects(isAsync: false, isThrows: false)
1754+
)
17081755
try setterThunkBuilder.lowerParameter(
17091756
param: Parameter(label: "value", name: "value", type: property.type)
17101757
)
@@ -1752,7 +1799,9 @@ extension BridgeJSLink {
17521799

17531800
// Generate instance property setter if not readonly
17541801
if !property.isReadonly {
1755-
let setterThunkBuilder = ExportedThunkBuilder(effects: Effects(isAsync: false, isThrows: false))
1802+
let setterThunkBuilder = ExportedThunkBuilder(
1803+
effects: Effects(isAsync: false, isThrows: false)
1804+
)
17561805
setterThunkBuilder.lowerSelf()
17571806
try setterThunkBuilder.lowerParameter(
17581807
param: Parameter(label: "value", name: "value", type: property.type)
@@ -2367,6 +2416,25 @@ extension BridgeJSLink {
23672416
)
23682417
return (funcLines, [])
23692418
}
2419+
2420+
func renderProtocolMethod(
2421+
importObjectBuilder: ImportObjectBuilder,
2422+
protocol: ExportedProtocol,
2423+
method: ExportedFunction
2424+
) throws {
2425+
let thunkBuilder = ImportedThunkBuilder()
2426+
thunkBuilder.liftSelf()
2427+
for param in method.parameters {
2428+
try thunkBuilder.liftParameter(param: param)
2429+
}
2430+
let returnExpr = try thunkBuilder.callMethod(name: method.name, returnType: method.returnType)
2431+
let funcLines = thunkBuilder.renderFunction(
2432+
name: method.abiName,
2433+
returnExpr: returnExpr,
2434+
returnType: method.returnType
2435+
)
2436+
importObjectBuilder.assignToImportObject(name: method.abiName, function: funcLines)
2437+
}
23702438
}
23712439

23722440
struct BridgeJSLinkError: Error {
@@ -2402,6 +2470,8 @@ extension BridgeType {
24022470
return "\(name)Tag"
24032471
case .namespaceEnum(let name):
24042472
return name
2473+
case .swiftProtocol(let name):
2474+
return name
24052475
}
24062476
}
24072477
}

‎Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,25 @@ struct IntrinsicJSFragment: Sendable {
297297
switch wrappedType {
298298
case .swiftHeapObject:
299299
return ["+\(isSomeVar)", "\(isSomeVar) ? \(value).pointer : 0"]
300+
case .swiftProtocol:
301+
return [
302+
"+\(isSomeVar)",
303+
"\(isSomeVar) ? \(JSGlueVariableScope.reservedSwift).memory.retain(\(value)) : 0",
304+
]
305+
case .jsObject:
306+
let idVar = scope.variable("id")
307+
printer.write("let \(idVar);")
308+
printer.write("if (\(isSomeVar)) {")
309+
printer.indent {
310+
printer.write("\(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(value));")
311+
}
312+
printer.write("}")
313+
cleanupCode.write("if (\(idVar) !== undefined) {")
314+
cleanupCode.indent {
315+
cleanupCode.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(idVar));")
316+
}
317+
cleanupCode.write("}")
318+
return ["+\(isSomeVar)", "\(isSomeVar) ? \(idVar) : 0"]
300319
default:
301320
return ["+\(isSomeVar)", "\(isSomeVar) ? \(value) : 0"]
302321
}
@@ -326,6 +345,9 @@ struct IntrinsicJSFragment: Sendable {
326345
case .string:
327346
printer.write("const \(resultVar) = \(JSGlueVariableScope.reservedStorageToReturnString);")
328347
printer.write("\(JSGlueVariableScope.reservedStorageToReturnString) = undefined;")
348+
case .jsObject, .swiftProtocol:
349+
printer.write("const \(resultVar) = \(JSGlueVariableScope.reservedStorageToReturnString);")
350+
printer.write("\(JSGlueVariableScope.reservedStorageToReturnString) = undefined;")
329351
case .swiftHeapObject(let className):
330352
let pointerVar = scope.variable("pointer")
331353
printer.write(
@@ -397,6 +419,7 @@ struct IntrinsicJSFragment: Sendable {
397419
case .jsObject: return .jsObjectLowerParameter
398420
case .swiftHeapObject:
399421
return .swiftHeapObjectLowerParameter
422+
case .swiftProtocol: return .jsObjectLowerParameter
400423
case .void: return .void
401424
case .optional(let wrappedType):
402425
return try .optionalLowerParameter(wrappedType: wrappedType)
@@ -422,6 +445,7 @@ struct IntrinsicJSFragment: Sendable {
422445
case .string: return .stringLiftReturn
423446
case .jsObject: return .jsObjectLiftReturn
424447
case .swiftHeapObject(let name): return .swiftHeapObjectLiftReturn(name)
448+
case .swiftProtocol: return .jsObjectLiftReturn
425449
case .void: return .void
426450
case .optional(let wrappedType): return .optionalLiftReturn(wrappedType: wrappedType)
427451
case .caseEnum: return .identity
@@ -455,6 +479,7 @@ struct IntrinsicJSFragment: Sendable {
455479
message:
456480
"Swift heap objects are not supported to be passed as parameters to imported JS functions: \(name)"
457481
)
482+
case .swiftProtocol: return .jsObjectLiftParameter
458483
case .void:
459484
throw BridgeJSLinkError(
460485
message: "Void can't appear in parameters of imported JS functions"
@@ -494,6 +519,7 @@ struct IntrinsicJSFragment: Sendable {
494519
throw BridgeJSLinkError(
495520
message: "Swift heap objects are not supported to be returned from imported JS functions"
496521
)
522+
case .swiftProtocol: return .jsObjectLowerReturn
497523
case .void: return .void
498524
case .optional(let wrappedType):
499525
throw BridgeJSLinkError(

‎Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift‎

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public enum BridgeType: Codable, Equatable, Sendable {
7474
case rawValueEnum(String, SwiftEnumRawType)
7575
case associatedValueEnum(String)
7676
case namespaceEnum(String)
77+
case swiftProtocol(String)
7778
}
7879

7980
public enum WasmCoreType: String, Codable, Sendable {
@@ -269,6 +270,18 @@ public enum EnumType: String, Codable, Sendable {
269270

270271
// MARK: - Exported Skeleton
271272

273+
public struct ExportedProtocol: Codable, Equatable {
274+
public let name: String
275+
public let methods: [ExportedFunction]
276+
public let namespace: [String]?
277+
278+
public init(name: String, methods: [ExportedFunction], namespace: [String]? = nil) {
279+
self.name = name
280+
self.methods = methods
281+
self.namespace = namespace
282+
}
283+
}
284+
272285
public struct ExportedFunction: Codable, Equatable, Sendable {
273286
public var name: String
274287
public var abiName: String
@@ -407,12 +420,20 @@ public struct ExportedSkeleton: Codable {
407420
public let functions: [ExportedFunction]
408421
public let classes: [ExportedClass]
409422
public let enums: [ExportedEnum]
423+
public let protocols: [ExportedProtocol]
410424

411-
public init(moduleName: String, functions: [ExportedFunction], classes: [ExportedClass], enums: [ExportedEnum]) {
425+
public init(
426+
moduleName: String,
427+
functions: [ExportedFunction],
428+
classes: [ExportedClass],
429+
enums: [ExportedEnum],
430+
protocols: [ExportedProtocol] = []
431+
) {
412432
self.moduleName = moduleName
413433
self.functions = functions
414434
self.classes = classes
415435
self.enums = enums
436+
self.protocols = protocols
416437
}
417438
}
418439

@@ -514,6 +535,9 @@ extension BridgeType {
514535
return nil
515536
case .namespaceEnum:
516537
return nil
538+
case .swiftProtocol:
539+
// Protocols pass JSObject IDs as Int32
540+
return .i32
517541
}
518542
}
519543

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import JavaScriptKit
2+
3+
@JS protocol MyViewControllerDelegate {
4+
func onSomethingHappened()
5+
func onValueChanged(_ value: String)
6+
func onCountUpdated(count: Int) -> Bool
7+
func onLabelUpdated(_ prefix: String, _ suffix: String)
8+
func isCountEven() -> Bool
9+
}
10+
11+
@JS class MyViewController {
12+
@JS
13+
var delegate: MyViewControllerDelegate
14+
15+
@JS
16+
var secondDelegate: MyViewControllerDelegate?
17+
18+
@JS init(delegate: MyViewControllerDelegate) {
19+
self.delegate = delegate
20+
}
21+
22+
@JS func triggerEvent() {
23+
delegate.onSomethingHappened()
24+
}
25+
26+
@JS func updateValue(_ value: String) {
27+
delegate.onValueChanged(value)
28+
}
29+
30+
@JS func updateCount(_ count: Int) -> Bool {
31+
return delegate.onCountUpdated(count: count)
32+
}
33+
34+
@JS func updateLabel(_ prefix: String, _ suffix: String) {
35+
delegate.onLabelUpdated(prefix, suffix)
36+
}
37+
38+
@JS func checkEvenCount() -> Bool {
39+
return delegate.isCountEven()
40+
}
41+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit,
2+
// DO NOT EDIT.
3+
//
4+
// To update this file, just rebuild your project or run
5+
// `swift package bridge-js`.
6+
7+
export interface MyViewControllerDelegate {
8+
onSomethingHappened(): void;
9+
onValueChanged(value: string): void;
10+
onCountUpdated(count: number): boolean;
11+
onLabelUpdated(prefix: string, suffix: string): void;
12+
isCountEven(): boolean;
13+
}
14+
15+
/// Represents a Swift heap object like a class instance or an actor instance.
16+
export interface SwiftHeapObject {
17+
/// Release the heap object.
18+
///
19+
/// Note: Calling this method will release the heap object and it will no longer be accessible.
20+
release(): void;
21+
}
22+
export interface MyViewController extends SwiftHeapObject {
23+
triggerEvent(): void;
24+
updateValue(value: string): void;
25+
updateCount(count: number): boolean;
26+
updateLabel(prefix: string, suffix: string): void;
27+
checkEvenCount(): boolean;
28+
delegate: MyViewControllerDelegate;
29+
secondDelegate: MyViewControllerDelegate | null;
30+
}
31+
export type Exports = {
32+
MyViewController: {
33+
new(delegate: MyViewControllerDelegate): MyViewController;
34+
}
35+
}
36+
export type Imports = {
37+
}
38+
export function createInstantiator(options: {
39+
imports: Imports;
40+
}, swift: any): Promise<{
41+
addImports: (importObject: WebAssembly.Imports) => void;
42+
setInstance: (instance: WebAssembly.Instance) => void;
43+
createExports: (instance: WebAssembly.Instance) => Exports;
44+
}>;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /