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
20 changes: 19 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ let openRenderBoxShims = openSwiftUIBinaryTarget(
checksum: "e8e2935a56c61ee164116b4a0737963ad7e2c9df30e73a881343b6694653cb4b"
)

// MARK: - Host Macro Target
// MARK: - Host Macro Targets

// Mirrored from the matching OpenSwiftUI release by its release workflow.
let openSwiftUIMacros = Target.macro(
Expand All @@ -87,6 +87,20 @@ let openSwiftUIMacros = Target.macro(
]
)

let openObservationMacros = Target.macro(
name: "OpenObservationMacros",
dependencies: [
.product(name: "SwiftDiagnostics", package: "swift-syntax"),
.product(name: "SwiftSyntaxBuilder", package: "swift-syntax"),
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
.product(name: "SwiftCompilerPlugin", package: "swift-syntax"),
],
swiftSettings: [
.swiftLanguageMode(.v5),
]
)

// MARK: - Package

let package = Package(
Expand All @@ -109,6 +123,7 @@ let package = Package(
"OpenQuartzCoreShims",
"OpenRenderBoxShims",
"OpenSwiftUIMacros",
"OpenObservationMacros",
]
),
.library(name: "OpenSwiftUIPlayground", targets: ["OpenSwiftUIPlayground"]),
Expand All @@ -126,6 +141,7 @@ let package = Package(
openQuartzCoreShims,
openRenderBoxShims,
openSwiftUIMacros,
openObservationMacros,
.target(
name: "OpenSwiftUIPlayground",
dependencies: [
Expand All @@ -137,6 +153,7 @@ let package = Package(
"OpenQuartzCoreShims",
"OpenRenderBoxShims",
"OpenSwiftUIMacros",
"OpenObservationMacros",
],
),
.target(name: "SwiftUIPlayground"),
Expand All @@ -151,6 +168,7 @@ let package = Package(
"OpenQuartzCoreShims",
"OpenRenderBoxShims",
"OpenSwiftUIMacros",
"OpenObservationMacros",
],
path: "Tests"
),
Expand Down
20 changes: 19 additions & 1 deletion Package.swift.template
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ let openRenderBoxShims = openSwiftUIBinaryTarget(
checksum: "{{CHECKSUM_OpenRenderBoxShims}}"
)

// MARK: - Host Macro Target
// MARK: - Host Macro Targets

// Mirrored from the matching OpenSwiftUI release by its release workflow.
let openSwiftUIMacros = Target.macro(
Expand All @@ -87,6 +87,20 @@ let openSwiftUIMacros = Target.macro(
]
)

let openObservationMacros = Target.macro(
name: "OpenObservationMacros",
dependencies: [
.product(name: "SwiftDiagnostics", package: "swift-syntax"),
.product(name: "SwiftSyntaxBuilder", package: "swift-syntax"),
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
.product(name: "SwiftCompilerPlugin", package: "swift-syntax"),
],
swiftSettings: [
.swiftLanguageMode(.v5),
]
)

// MARK: - Package

let package = Package(
Expand All @@ -109,6 +123,7 @@ let package = Package(
"OpenQuartzCoreShims",
"OpenRenderBoxShims",
"OpenSwiftUIMacros",
"OpenObservationMacros",
]
),
.library(name: "OpenSwiftUIPlayground", targets: ["OpenSwiftUIPlayground"]),
Expand All @@ -126,6 +141,7 @@ let package = Package(
openQuartzCoreShims,
openRenderBoxShims,
openSwiftUIMacros,
openObservationMacros,
.target(
name: "OpenSwiftUIPlayground",
dependencies: [
Expand All @@ -137,6 +153,7 @@ let package = Package(
"OpenQuartzCoreShims",
"OpenRenderBoxShims",
"OpenSwiftUIMacros",
"OpenObservationMacros",
],
),
.target(name: "SwiftUIPlayground"),
Expand All @@ -151,6 +168,7 @@ let package = Package(
"OpenQuartzCoreShims",
"OpenRenderBoxShims",
"OpenSwiftUIMacros",
"OpenObservationMacros",
],
path: "Tests"
),
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ Currently supports:

## Macro Distribution

Releases whose framework interfaces declare external macros also include `OpenSwiftUIMacros` as a source target. SwiftPM builds this small compiler plugin for the host because macro implementations cannot currently be distributed inside an XCFramework.
The package includes `OpenSwiftUIMacros` and `OpenObservationMacros` as source targets. SwiftPM builds these compiler plugins for the host. The XCFrameworks provide the macro declarations and runtime code; their interfaces alone do not provide the macro implementations.

The OpenSwiftUI release workflow generates `Sources/OpenSwiftUIMacros` from the same tag as the XCFrameworks before publishing this package. Do not edit the generated mirror directly. Macro-enabled releases require Xcode 26.6 or a compatible Swift 6.3 toolchain.
The OpenSwiftUI release workflow generates `Sources/OpenSwiftUIMacros` from the release source and `Sources/OpenObservationMacros` from the OpenObservation revision pinned in that release's `Package.resolved`. Do not edit these generated mirrors directly. Macro-enabled releases require Xcode 26.6 or a compatible Swift 6.3 toolchain.

## Binary Configuration History

Expand Down
109 changes: 109 additions & 0 deletions Sources/OpenObservationMacros/Availability.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//

import SwiftSyntax
import SwiftSyntaxMacros
import SwiftDiagnostics
import SwiftSyntaxBuilder


extension AttributeSyntax {
var availability: AttributeSyntax? {
if attributeName.identifier == "available" {
return self
} else {
return nil
}
}
}

extension IfConfigClauseSyntax.Elements {
var availability: IfConfigClauseSyntax.Elements? {
switch self {
case .attributes(let attributes):
if let availability = attributes.availability {
return .attributes(availability)
} else {
return nil
}
default:
return nil
}
}
}

extension IfConfigClauseSyntax {
var availability: IfConfigClauseSyntax? {
if let availability = elements?.availability {
return with(\.elements, availability)
} else {
return nil
}
}

var clonedAsIf: IfConfigClauseSyntax {
detached.with(\.poundKeyword, .poundIfToken())
}
}

extension IfConfigDeclSyntax {
var availability: IfConfigDeclSyntax? {
var elements = [IfConfigClauseListSyntax.Element]()
for clause in clauses {
if let availability = clause.availability {
if elements.isEmpty {
elements.append(availability.clonedAsIf)
} else {
elements.append(availability)
}
}
}
if elements.isEmpty {
return nil
} else {
return with(\.clauses, IfConfigClauseListSyntax(elements))
}

}
}

extension AttributeListSyntax.Element {
var availability: AttributeListSyntax.Element? {
switch self {
case .attribute(let attribute):
if let availability = attribute.availability {
return .attribute(availability)
}
case .ifConfigDecl(let ifConfig):
if let availability = ifConfig.availability {
return .ifConfigDecl(availability)
}
@unknown default:
break
}
return nil
}
}

extension AttributeListSyntax {
var availability: AttributeListSyntax? {
var elements = [AttributeListSyntax.Element]()
for element in self {
if let availability = element.availability {
elements.append(availability)
}
}
if elements.isEmpty {
return nil
}
return AttributeListSyntax(elements)
}
}
Loading
Loading