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: 56 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: CI

on:
push:
branches:
- '**'
tags:
- "*.*.*"
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:

tests:
name: Tests
if: github.event_name != 'push' || !startsWith(github.ref, 'refs/tags/')
uses: oversizedev/GithubWorkflows/.github/workflows/test.yml@main
secrets: inherit

build-oversize-macro:
name: Build OversizeMacro
needs:
- tests
uses: oversizedev/GithubWorkflows/.github/workflows/build-swiftpm.yml@main
with:
package: OversizeMacro
destination: platform=macOS,arch=arm64
secrets: inherit

build-oversize-macro-client:
name: Build OversizeMacroClient
needs:
- tests
uses: oversizedev/GithubWorkflows/.github/workflows/build-swiftpm.yml@main
with:
package: OversizeMacroClient
destination: platform=macOS,arch=arm64
secrets: inherit

bump:
name: Bump version
needs:
- build-oversize-macro
- build-oversize-macro-client
if: github.ref == 'refs/heads/main'
uses: oversizedev/GithubWorkflows/.github/workflows/bump.yml@main
secrets: inherit

release:
name: Create Release
if: github.ref != 'refs/heads/main' && startsWith(github.ref, 'refs/tags/')
uses: oversizedev/GithubWorkflows/.github/workflows/release.yml@main
secrets: inherit
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
Package.resolved
/.swiftpm
3 changes: 3 additions & 0 deletions .swiftformat
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
--swiftversion 6.1
--disable preferKeyPath
--ifdef no-indent
15 changes: 0 additions & 15 deletions Package.resolved

This file was deleted.

23 changes: 11 additions & 12 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
// swift-tools-version: 6.1
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription
import CompilerPluginSupport
import PackageDescription

let package = Package(
name: "OversizeMacro",
platforms: [.macOS(.v10_15), .iOS(.v13), .tvOS(.v13), .watchOS(.v6), .macCatalyst(.v13)],
products: [
// Products define the executables and libraries a package produces, making them visible to other packages.
.library(
name: "OversizeMacro",
targets: ["OversizeMacro"]
Expand All @@ -19,25 +18,25 @@ let package = Package(
),
],
dependencies: [
.package(url: "https://github.com/swiftlang/swift-syntax.git", from: "600.0.0"),
.package(url: "https://github.com/swiftlang/swift-syntax.git", .upToNextMajor(from: "601.0.0")),
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
// Macro implementation that performs the source transformation of a macro.
.macro(
name: "OversizeMacroMacros",
dependencies: [
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
.product(name: "SwiftCompilerPlugin", package: "swift-syntax")
.product(name: "SwiftCompilerPlugin", package: "swift-syntax"),
]
),

// Library that exposes a macro as part of its API, which is used in client programs.
.target(name: "OversizeMacro", dependencies: ["OversizeMacroMacros"]),

// A client of the library, which is able to use the macro in its own code.
.executableTarget(name: "OversizeMacroClient", dependencies: ["OversizeMacro"]),

.testTarget(
name: "OversizeMacroTests",
dependencies: [
"OversizeMacro",
"OversizeMacroMacros",
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"),
]
),
]
)
13 changes: 2 additions & 11 deletions Sources/OversizeMacro/OversizeMacro.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,2 @@
// The Swift Programming Language
// https://docs.swift.org/swift-book

/// A macro that produces both a value and a string containing the
/// source code that generated the value. For example,
///
/// #stringify(x + y)
///
/// produces a tuple `(x + y, "x + y")`.
@freestanding(expression)
public macro stringify<T>(_ value: T) -> (T, String) = #externalMacro(module: "OversizeMacroMacros", type: "StringifyMacro")
@attached(member, names: arbitrary)
public macro AutoRoutable() = #externalMacro(module: "OversizeMacroMacros", type: "AutoRoutableMacro")
12 changes: 7 additions & 5 deletions Sources/OversizeMacroClient/main.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import OversizeMacro

let a = 17
let b = 25
@AutoRoutable
enum Screens {
case meta
case instagram
case twitter
}

let (result, code) = #stringify(a + b)

print("The value \(result) was produced by the code \"\(code)\"")
print(Screens.meta.id)
40 changes: 40 additions & 0 deletions Sources/OversizeMacroMacros/AutoRoutableMacro.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import SwiftSyntax
import SwiftSyntaxMacros

public struct AutoRoutableMacro: MemberMacro {
public static func expansion<Declaration: DeclGroupSyntax, Context: MacroExpansionContext>(
of node: AttributeSyntax,
providingMembersOf declaration: Declaration,
conformingTo _: [TypeSyntax],
in context: Context
) throws -> [DeclSyntax] {
try expansion(of: node, providingMembersOf: declaration, in: context)
}
Comment on lines +5 to +12
Copy link

Copilot AI Sep 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method simply delegates to another expansion method but discards the conformingTo and context parameters. Consider removing this wrapper method and using the simpler expansion method directly, or document why this delegation is necessary.

Copilot uses AI. Check for mistakes.

public static func expansion<Declaration: DeclGroupSyntax, Context: MacroExpansionContext>(
of _: AttributeSyntax,
providingMembersOf declaration: Declaration,
in _: Context
) throws -> [DeclSyntax] {
let caseNames: [String] = declaration.memberBlock.members
.compactMap { $0.decl.as(EnumCaseDeclSyntax.self) }
.flatMap { $0.elements.map { $0.name.text } }

let cases = caseNames.map { name in
"""
case .\(name):
return "\(name)"
"""
}.joined(separator: "\n")

return [
"""
var id: String {
switch self {
\(raw: cases)
}
}
""",
]
}
}
33 changes: 0 additions & 33 deletions Sources/OversizeMacroMacros/OversizeMacroMacro.swift

This file was deleted.

9 changes: 9 additions & 0 deletions Sources/OversizeMacroMacros/OversizeMacroPlugin.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import SwiftCompilerPlugin
import SwiftSyntaxMacros

@main
struct OversizeMacroPlugin: CompilerPlugin {
let providingMacros: [Macro.Type] = [
AutoRoutableMacro.self,
]
}
103 changes: 103 additions & 0 deletions Tests/OversizeMacroTests/AutoRoutableTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import OversizeMacro
import OversizeMacroMacros
import SwiftSyntaxMacros
import SwiftSyntaxMacrosTestSupport
import XCTest

// MARK: - Macro Expansion Tests

final class AutoRoutableMacroExpansionTests: XCTestCase {
private let testMacros: [String: any Macro.Type] = [
"AutoRoutable": AutoRoutableMacro.self,
]

func testExpansion_basic() throws {
assertMacroExpansion(
"""
@AutoRoutable
enum Screens {
case main
case settings
case about
case event(id: String)
}
""",
expandedSource:
"""
enum Screens {
case main
case settings
case about
case event(id: String)

var id: String {
switch self {
case .main:
return "main"
case .settings:
return "settings"
case .about:
return "about"
case .event:
return "event"
}
}
}
""",
macros: testMacros
)
}

func testExpansion_multipleElementsInOneLine() throws {
assertMacroExpansion(
"""
@AutoRoutable
enum Screens {
case main
case settings, about
case event(id: String)
}
""",
expandedSource:
"""
enum Screens {
case main
case settings, about
case event(id: String)

var id: String {
switch self {
case .main:
return "main"
case .settings:
return "settings"
case .about:
return "about"
case .event:
return "event"
}
}
}
""",
macros: testMacros
)
}
}

// MARK: - End-to-End Tests

final class AutoRoutableMacroEndToEndTests: XCTestCase {
@AutoRoutable
enum Screens {
case main
case settings, about
case event(id: String)
}

func testRuntime_propertyValues() {
XCTAssertEqual(Screens.main.id, "main")
XCTAssertEqual(Screens.settings.id, "settings")
XCTAssertEqual(Screens.about.id, "about")
XCTAssertEqual(Screens.event(id: "0").id, "event")
}
}