Skip to content

Commit

Permalink
bump swift version
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuawright11 committed May 22, 2024
1 parent 21acdcb commit 274973c
Show file tree
Hide file tree
Showing 17 changed files with 160 additions and 108 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
test-macos:
runs-on: macos-13
env:
DEVELOPER_DIR: /Applications/Xcode_15.0.app/Contents/Developer
DEVELOPER_DIR: /Applications/Xcode_15.4.app/Contents/Developer
steps:
- uses: actions/checkout@v3
- name: Build
Expand All @@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-22.04
strategy:
matrix:
swift: [5.9]
swift: [5.10]
container: swift:${{ matrix.swift }}
steps:
- uses: actions/checkout@v3
Expand Down
2 changes: 1 addition & 1 deletion Example/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Papyrus

@API
@Mock
protocol Sample {
public protocol Sample {
@GET("/todos")
func getTodos() async throws -> [Todo]

Expand Down
4 changes: 4 additions & 0 deletions PapyrusCore/Sources/Macros.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import Foundation
@attached(peer, names: suffixed(API))
public macro API() = #externalMacro(module: "PapyrusPlugin", type: "APIMacro")

@attached(extension, names: named(useAPI))
@attached(peer, names: suffixed(Live), suffixed(Registry))
public macro APIRoutes() = #externalMacro(module: "PapyrusPlugin", type: "APIRoutesMacro")

@attached(peer, names: suffixed(Mock))
public macro Mock() = #externalMacro(module: "PapyrusPlugin", type: "MockMacro")

Expand Down
1 change: 0 additions & 1 deletion PapyrusPlugin/Sources/APIRoutesMacro.swift

This file was deleted.

16 changes: 16 additions & 0 deletions PapyrusPlugin/Sources/Extensions/String+Utilities.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import SwiftSyntax

extension String {
var withoutQuotes: String {
filter { $0 != "\"" }
}

var inQuotes: String {
"\"\(self)\""
}

// Need this since `capitalized` lowercases everything else.
var capitalizeFirst: String {
prefix(1).capitalized + dropFirst()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ extension FunctionParameterSyntax {
var name: String {
(secondName ?? firstName).text
}

var typeName: String {
trimmed.type.description
}
}

extension AttributeSyntax {
Expand Down
File renamed without changes.
61 changes: 61 additions & 0 deletions PapyrusPlugin/Sources/Macros/APIRoutesMacro.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import SwiftSyntax
import SwiftSyntaxMacros

public struct APIRoutesMacro: PeerMacro, ExtensionMacro {
public static func expansion(
of node: SwiftSyntax.AttributeSyntax,
attachedTo declaration: some SwiftSyntax.DeclGroupSyntax,
providingExtensionsOf type: some SwiftSyntax.TypeSyntaxProtocol,
conformingTo protocols: [SwiftSyntax.TypeSyntax],
in context: some SwiftSyntaxMacros.MacroExpansionContext
) throws -> [SwiftSyntax.ExtensionDeclSyntax] {
guard let type = declaration.as(ProtocolDeclSyntax.self) else {
throw PapyrusPluginError("@APIRoutes can only be applied to protocols.")
}

return try [
ExtensionDeclSyntax(
.init(stringLiteral: type.createRoutesExtension())
)
]
}

public static func expansion(of node: AttributeSyntax,
providingPeersOf declaration: some DeclSyntaxProtocol,
in context: some MacroExpansionContext) throws -> [DeclSyntax] {
// try handleError {
// guard let type = declaration.as(ProtocolDeclSyntax.self) else {
// throw PapyrusPluginError("@APIRoutes can only be applied to protocols.")
// }
//
// let name = node.firstArgument ?? "\(type.typeName)Live"
// return try [
// type.createAPI(named: name),
// type.createRegistry(),
// ]
// }
[]
}
}

extension ProtocolDeclSyntax {
func createRoutesExtension() throws -> String {
"""
\(access)extension \(protocolName) where Self: PapyrusRouter {
func useAPI(_ api: (any \(protocolName)).Type) {
\(protocolName)Registry.register(api: self, router: self)
}
}
"""
}

func createRegistry() throws -> String {
"""
private enum \(protocolName)Registry {
static func register(api: \(protocolName), router: PapyrusRouter) {
// TODO
}
}
"""
}
}
File renamed without changes.
71 changes: 71 additions & 0 deletions PapyrusPlugin/Sources/Macros/MockMacro.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import SwiftSyntax
import SwiftSyntaxMacros

public struct MockMacro: PeerMacro {
public static func expansion(
of node: AttributeSyntax,
providingPeersOf declaration: some DeclSyntaxProtocol,
in context: some MacroExpansionContext
) throws -> [DeclSyntax] {
guard let proto = declaration.as(ProtocolDeclSyntax.self) else {
throw PapyrusPluginError("@Mock can only be applied to protocols.")
}

return [
try proto
.mockService(named: "\(proto.protocolName)\(node.attributeName)")
.declSyntax()
]
}
}

extension ProtocolDeclSyntax {
fileprivate func mockService(named mockName: String) throws -> Declaration {
try Declaration("\(access)final class \(mockName): \(protocolName), @unchecked Sendable") {
"private let notMockedError: Error"
"private var mocks: [String: Any]"

Declaration("\(access)init(notMockedError: Error = PapyrusError(\"Not mocked\"))") {
"self.notMockedError = notMockedError"
"mocks = [:]"
}

for function in functions {
try function.mockEndpointFunction(access: access)

function.mockerFunction(access: access)
}
}
}
}

extension FunctionDeclSyntax {
fileprivate func mockEndpointFunction(access: String) throws -> Declaration {
guard effects == ["async", "throws"] else {
throw PapyrusPluginError("Function signature must have `async throws`.")
}

return Declaration("\(access)func \(functionName)\(signature)") {
Declaration("guard let mocker = mocks[\(functionName.inQuotes)] as? \(mockClosureType) else") {
"throw notMockedError"
}

""

let mockerArguments = parameters.map(\.name).joined(separator: ", ")
"return try await mocker(\(mockerArguments))"
}
}

fileprivate func mockerFunction(access: String) -> Declaration {
Declaration("\(access)func mock\(functionName.capitalizeFirst)(mock: @escaping \(mockClosureType))") {
"mocks[\(functionName.inQuotes)] = mock"
}
}

private var mockClosureType: String {
let parameterTypes = parameters.map(\.typeName).joined(separator: ", ")
let returnType = signature.returnClause?.type.trimmedDescription ?? "Void"
return "(\(parameterTypes)) async throws -> \(returnType)"
}
}
91 changes: 0 additions & 91 deletions PapyrusPlugin/Sources/MockMacro.swift

This file was deleted.

1 change: 1 addition & 0 deletions PapyrusPlugin/Sources/Plugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import SwiftSyntaxMacros
struct MyPlugin: CompilerPlugin {
let providingMacros: [Macro.Type] = [
APIMacro.self,
APIRoutesMacro.self,
MockMacro.self,
DecoratorMacro.self,
]
Expand Down
13 changes: 0 additions & 13 deletions PapyrusPlugin/Sources/Utilities/String+Utilities.swift

This file was deleted.

0 comments on commit 274973c

Please sign in to comment.