Skip to content
Open
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
53 changes: 45 additions & 8 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
JAVASCRIPTKIT_WASI_BACKEND: ${{ matrix.entry.wasi-backend }}
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Export matrix env
if: ${{ matrix.entry.env != '' && matrix.entry.env != null }}
run: |
Expand Down Expand Up @@ -79,7 +79,7 @@ jobs:
container:
image: ${{ matrix.entry.image }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Setup Node.js
uses: actions/setup-node@v6
with:
Expand All @@ -105,7 +105,7 @@ jobs:
xcode: Xcode_26.0.1
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- run: swift build --product BridgeJSTool
env:
DEVELOPER_DIR: /Applications/${{ matrix.xcode }}.app/Contents/Developer/
Expand All @@ -116,7 +116,7 @@ jobs:
prettier:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- uses: actions/setup-node@v6
with:
node-version: '20'
Expand All @@ -128,7 +128,7 @@ jobs:
container:
image: swift:6.3
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- run: ./Utilities/format.swift
- name: Check for formatting changes
run: |
Expand All @@ -141,7 +141,7 @@ jobs:
check-bridgejs-generated:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- uses: ./.github/actions/install-swift
with:
download-url: https://download.swift.org/development/ubuntu2204/swift-DEVELOPMENT-SNAPSHOT-2026-05-27-a/swift-DEVELOPMENT-SNAPSHOT-2026-05-27-a-ubuntu22.04.tar.gz
Expand All @@ -155,10 +155,47 @@ jobs:
exit 1
}

# Pull requests: compile every example in parallel just to catch breakage.
# One job per example avoids rebuilding JavaScriptKit + swift-syntax 6x in series,
# which collapses the wall-clock time from ~1h to that of the slowest single example.
build-examples:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
example:
- ActorOnWebWorker
- Basic
- Embedded
- Multithreading
- OffscrenCanvas
- PlayBridgeJS
steps:
- uses: actions/checkout@v7
- uses: ./.github/actions/install-swift
with:
download-url: https://download.swift.org/development/ubuntu2204/swift-DEVELOPMENT-SNAPSHOT-2026-05-27-a/swift-DEVELOPMENT-SNAPSHOT-2026-05-27-a-ubuntu22.04.tar.gz
- uses: swiftwasm/setup-swiftwasm@v2
id: setup-wasm32-unknown-wasip1
with: { target: wasm32-unknown-wasip1 }
- uses: swiftwasm/setup-swiftwasm@v2
id: setup-wasm32-unknown-wasip1-threads
with: { target: wasm32-unknown-wasip1-threads }
# build.sh resolves the package relative to the working directory, so run it
# from the example directory (mirroring Utilities/build-examples.sh's `cd`).
- run: ./build.sh release
working-directory: Examples/${{ matrix.example }}
env:
SWIFT_SDK_ID_wasm32_unknown_wasip1_threads: ${{ steps.setup-wasm32-unknown-wasip1-threads.outputs.swift-sdk-id }}
SWIFT_SDK_ID_wasm32_unknown_wasip1: ${{ steps.setup-wasm32-unknown-wasip1.outputs.swift-sdk-id }}

# main: build all examples in release and publish them to GitHub Pages.
build-examples-deploy:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- uses: ./.github/actions/install-swift
with:
download-url: https://download.swift.org/development/ubuntu2204/swift-DEVELOPMENT-SNAPSHOT-2026-05-27-a/swift-DEVELOPMENT-SNAPSHOT-2026-05-27-a-ubuntu22.04.tar.gz
Expand All @@ -184,7 +221,7 @@ jobs:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
needs: build-examples
needs: build-examples-deploy
permissions:
pages: write
id-token: write
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"methods" : [
{
"abiName" : "bjs_PlayBridgeJS_updateDetailed",
"documentation" : "Structured entry point used by the playground so JS doesn't need to parse diagnostics.",
"effects" : {
"isAsync" : false,
"isStatic" : false,
Expand Down
84 changes: 71 additions & 13 deletions Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1266,10 +1266,56 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
returnType: returnType,
effects: effects,
namespace: finalNamespace,
staticContext: staticContext
staticContext: staticContext,
documentation: extractDocumentation(from: node)
)
}

/// Returns the doc comment (`///` or `/** */`) attached to a declaration, with
/// markers stripped and DocC field lists (`- Parameters:`, `- Returns:`) preserved.
private func extractDocumentation(from node: some SyntaxProtocol) -> String? {
var run: [String] = []
for piece in node.leadingTrivia {
switch piece {
case .docLineComment(let text):
var line = Substring(text)
if line.hasPrefix("///") { line = line.dropFirst(3) }
if line.first == " " { line = line.dropFirst() }
if line.last == "\r" { line = line.dropLast() }
run.append(String(line))
case .docBlockComment(let text):
run.append(contentsOf: stripBlockComment(text))
case .newlines(let count), .carriageReturns(let count), .carriageReturnLineFeeds(let count):
if count >= 2 { run.removeAll() }
case .lineComment, .blockComment:
run.removeAll()
default:
continue
}
}
// Trim boundary blank lines so line (`///`) and block (`/** */`) comments
// produce a consistent skeleton value.
while run.first?.trimmingCharacters(in: .whitespaces).isEmpty == true { run.removeFirst() }
while run.last?.trimmingCharacters(in: .whitespaces).isEmpty == true { run.removeLast() }
return run.isEmpty ? nil : run.joined(separator: "\n")
}

private func stripBlockComment(_ text: String) -> [String] {
var body = Substring(text)
if body.hasPrefix("/**") { body = body.dropFirst(3) }
if body.hasSuffix("*/") { body = body.dropLast(2) }
return body.split(separator: "\n", omittingEmptySubsequences: false).map { raw -> String in
var line = raw[...]
if line.last == "\r" { line = line.dropLast() }
while let first = line.first, first == " " || first == "\t" { line = line.dropFirst() }
if line.first == "*" {
line = line.dropFirst()
if line.first == " " { line = line.dropFirst() }
}
return String(line)
}
}

private func collectEffects(signature: FunctionSignatureSyntax, isStatic: Bool = false) -> Effects? {
let isAsync = signature.effectSpecifiers?.asyncSpecifier != nil
var isThrows = false
Expand Down Expand Up @@ -1360,7 +1406,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
let constructor = ExportedConstructor(
abiName: "bjs_\(classAbiName)_init",
parameters: parameters,
effects: effects
effects: effects,
documentation: extractDocumentation(from: node)
)
exportedClassByName[classKey]?.constructor = constructor

Expand All @@ -1383,7 +1430,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
let constructor = ExportedConstructor(
abiName: "bjs_\(structAbiName)_init",
parameters: parameters,
effects: effects
effects: effects,
documentation: extractDocumentation(from: node)
)
exportedStructByName[structKey]?.constructor = constructor

Expand Down Expand Up @@ -1490,7 +1538,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
isReadonly: isReadonly,
isStatic: isStatic,
namespace: finalNamespace,
staticContext: staticContext
staticContext: staticContext,
documentation: extractDocumentation(from: node)
)

if case .enumBody(_, let key) = state {
Expand Down Expand Up @@ -1537,7 +1586,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
methods: [],
properties: [],
namespace: effectiveNamespace,
identityMode: classIdentityMode
identityMode: classIdentityMode,
documentation: extractDocumentation(from: node)
)
let uniqueKey = makeKey(name: name, namespace: effectiveNamespace)

Expand Down Expand Up @@ -1657,7 +1707,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
namespace: effectiveNamespace,
emitStyle: emitStyle,
staticMethods: [],
staticProperties: []
staticProperties: [],
documentation: extractDocumentation(from: node)
)

let enumUniqueKey = makeKey(name: name, namespace: effectiveNamespace)
Expand Down Expand Up @@ -1774,7 +1825,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
name: name,
methods: [],
properties: [],
namespace: effectiveNamespace
namespace: effectiveNamespace,
documentation: extractDocumentation(from: node)
)

stateStack.push(state: .protocolBody(name: name, key: protocolUniqueKey))
Expand All @@ -1798,7 +1850,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
name: name,
methods: methods,
properties: exportedProtocolByName[protocolUniqueKey]?.properties ?? [],
namespace: effectiveNamespace
namespace: effectiveNamespace,
documentation: extractDocumentation(from: node)
)

exportedProtocolByName[protocolUniqueKey] = exportedProtocol
Expand Down Expand Up @@ -1874,7 +1927,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
isReadonly: true,
isStatic: false,
namespace: effectiveNamespace,
staticContext: nil
staticContext: nil,
documentation: extractDocumentation(from: varDecl)
)
properties.append(property)
}
Expand All @@ -1888,7 +1942,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
explicitAccessControl: explicitAccessControl,
properties: properties,
methods: [],
namespace: effectiveNamespace
namespace: effectiveNamespace,
documentation: extractDocumentation(from: node)
)

exportedStructByName[structUniqueKey] = exportedStruct
Expand Down Expand Up @@ -1981,7 +2036,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
returnType: returnType,
effects: effects,
namespace: namespace,
staticContext: nil
staticContext: nil,
documentation: extractDocumentation(from: node)
)
}

Expand Down Expand Up @@ -2022,7 +2078,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
let exportedProperty = ExportedProtocolProperty(
name: propertyName,
type: propertyType,
isReadonly: isReadonly
isReadonly: isReadonly,
documentation: extractDocumentation(from: node)
)

if var currentProtocol = exportedProtocolByName[protocolKey] {
Expand All @@ -2033,7 +2090,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
name: currentProtocol.name,
methods: currentProtocol.methods,
properties: properties,
namespace: currentProtocol.namespace
namespace: currentProtocol.namespace,
documentation: currentProtocol.documentation
)
exportedProtocolByName[protocolKey] = currentProtocol
}
Expand Down
Loading
Loading