Skip to content

Commit

Permalink
Add macros
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaelesantos committed Oct 14, 2024
1 parent 68a31e7 commit 40b557f
Show file tree
Hide file tree
Showing 18 changed files with 306 additions and 67 deletions.
67 changes: 67 additions & 0 deletions .swiftpm/xcode/xcshareddata/xcschemes/RefdsDesignPatterns.xcscheme
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1600"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "RefdsDesignPatterns"
BuildableName = "RefdsDesignPatterns"
BlueprintName = "RefdsDesignPatterns"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "RefdsDesignPatterns"
BuildableName = "RefdsDesignPatterns"
BlueprintName = "RefdsDesignPatterns"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
18 changes: 12 additions & 6 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription
import CompilerPluginSupport

let package = Package(
name: "RefdsDesignPatterns",
Expand All @@ -21,16 +22,21 @@ let package = Package(
targets: ["RefdsRedux"]),
],
dependencies: [
.package(url: "https://github.com/rafaelesantos/refds-shared.git", branch: "main")
.package(url: "https://github.com/rafaelesantos/refds-shared.git", branch: "main"),
.package(url: "https://github.com/swiftlang/swift-syntax.git", branch: "main")
],
targets: [
.macro(
name: "RefdsReduxMacros",
dependencies: [
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
.product(name: "SwiftCompilerPlugin", package: "swift-syntax")
]),
.target(
name: "RefdsRedux",
dependencies: [
.product(
name: "RefdsShared",
package: "refds-shared"
)
]),
"RefdsReduxMacros",
.product(name: "RefdsShared", package: "refds-shared")
])
]
)
3 changes: 0 additions & 3 deletions Sources/RefdsRedux/RefdsReduxAction.swift

This file was deleted.

6 changes: 6 additions & 0 deletions Sources/RefdsRedux/RefdsReduxActionProtocol.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Foundation

@attached(extension, conformances: RefdsReduxActionProtocol)
public macro RefdsReduxAction() = #externalMacro(module: "RefdsReduxMacros", type: "RefdsReduxActionMacro")

public protocol RefdsReduxActionProtocol: Sendable {}
8 changes: 0 additions & 8 deletions Sources/RefdsRedux/RefdsReduxMiddleware.swift

This file was deleted.

18 changes: 18 additions & 0 deletions Sources/RefdsRedux/RefdsReduxMiddlewareProtocol.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Foundation

@attached(extension, conformances: RefdsReduxMiddlewareProtocol)
public macro RefdsReduxMiddleware<
State: RefdsReduxStateProtocol
>() = #externalMacro(
module: "RefdsReduxMacros",
type: "RefdsReduxMiddlewareMacro"
)

public protocol RefdsReduxMiddlewareProtocol {
associatedtype State: RefdsReduxStateProtocol

func middleware(
state: State,
action: RefdsReduxActionProtocol
) async -> AsyncStream<RefdsReduxActionProtocol>
}
8 changes: 0 additions & 8 deletions Sources/RefdsRedux/RefdsReduxReducer.swift

This file was deleted.

17 changes: 17 additions & 0 deletions Sources/RefdsRedux/RefdsReduxReducerProtocol.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Foundation

@attached(extension, conformances: RefdsReduxReducerProtocol)
public macro RefdsReduxReducer<
State: RefdsReduxStateProtocol,
Action: RefdsReduxActionProtocol
>() = #externalMacro(module: "RefdsReduxMacros", type: "RefdsReduxReducerMacro")

public protocol RefdsReduxReducerProtocol {
associatedtype State: RefdsReduxStateProtocol
associatedtype Action: RefdsReduxActionProtocol

func reduce(
state: State,
action: Action
) async -> State
}
3 changes: 0 additions & 3 deletions Sources/RefdsRedux/RefdsReduxState.swift

This file was deleted.

6 changes: 6 additions & 0 deletions Sources/RefdsRedux/RefdsReduxStateProtocol.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Foundation

@attached(extension, conformances: RefdsReduxStateProtocol)
public macro RefdsReduxState() = #externalMacro(module: "RefdsReduxMacros", type: "RefdsReduxStateMacro")

public protocol RefdsReduxStateProtocol: Sendable, Equatable {}
39 changes: 0 additions & 39 deletions Sources/RefdsRedux/RefdsReduxStore.swift

This file was deleted.

38 changes: 38 additions & 0 deletions Sources/RefdsRedux/RefdsReduxStoreProtocol.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Foundation
import SwiftUI

@attached(extension, conformances: RefdsReduxStoreProtocol)
public macro RefdsReduxStore<
State: RefdsReduxStateProtocol
>() = #externalMacro(
module: "RefdsReduxMacros",
type: "RefdsReduxStoreMacro"
)

@MainActor
public protocol RefdsReduxStoreProtocol: ObservableObject {
associatedtype State: RefdsReduxStateProtocol

var state: State { get set }
var reducer: (State, RefdsReduxActionProtocol) async -> State { get }
var middlewares: [(State, RefdsReduxActionProtocol) async -> AsyncStream<RefdsReduxActionProtocol>] { get }

func dispatch(action: RefdsReduxActionProtocol) async
}

public extension RefdsReduxStoreProtocol {
func dispatch(action: RefdsReduxActionProtocol) async {
let middlewares = self.middlewares
let stateReduced = await reducer(state, action)

withAnimation(.easeInOut) { state = stateReduced }

for middleware in middlewares {
let actions = await middleware(state, action)

for await action in actions {
await dispatch(action: action)
}
}
}
}
19 changes: 19 additions & 0 deletions Sources/RefdsReduxMacros/RefdsReduxActionMacro.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import SwiftCompilerPlugin
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros

public struct RefdsReduxActionMacro: ExpressionMacro {
public static func expansion(
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) -> ExprSyntax {
guard let enumDecl = node.as(EnumDeclSyntax.self) else {
fatalError("@RefdsReduxAction must be applied to an enum.")
}
let protocolConformance = """
extension \(enumDecl.name.text): RefdsReduxActionProtocol {}
"""
return ExprSyntax(stringLiteral: protocolConformance)
}
}
15 changes: 15 additions & 0 deletions Sources/RefdsReduxMacros/RefdsReduxMacroPlugin.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import SwiftCompilerPlugin
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros

@main
struct RefdsReduxMacroPlugin: CompilerPlugin {
let providingMacros: [Macro.Type] = [
RefdsReduxActionMacro.self,
RefdsReduxStateMacro.self,
RefdsReduxReducerMacro.self,
RefdsReduxMiddlewareMacro.self,
RefdsReduxStoreMacro.self
]
}
29 changes: 29 additions & 0 deletions Sources/RefdsReduxMacros/RefdsReduxMiddlewareMacro.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import SwiftCompilerPlugin
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros

public struct RefdsReduxMiddlewareMacro: ExpressionMacro {
public static func expansion(
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) -> ExprSyntax {
guard let enumDecl = node.as(EnumDeclSyntax.self) else {
fatalError("@RefdsReduxMiddleware must be applied to an enum.")
}

let arguments = node.arguments
guard arguments.count == 1,
let stateType = arguments.first?.expression.description else {
fatalError("@RefdsReduxMiddleware must be applied with State type, e.g. @RefdsReduxMiddleware(State).")
}

let protocolConformance = """
extension \(enumDecl.name.text): RefdsReduxMiddlewareProtocol {
typealias State = \(stateType)
}
"""

return ExprSyntax(stringLiteral: protocolConformance)
}
}
31 changes: 31 additions & 0 deletions Sources/RefdsReduxMacros/RefdsReduxReducerMacro.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import SwiftCompilerPlugin
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros

public struct RefdsReduxReducerMacro: ExpressionMacro {
public static func expansion(
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) -> ExprSyntax {
guard let enumDecl = node.as(EnumDeclSyntax.self) else {
fatalError("@RefdsReduxReducer must be applied to an enum.")
}

let arguments = node.arguments
guard arguments.count == 2,
let stateType = arguments.first?.expression.description,
let actionType = arguments.last?.expression.description else {
fatalError("@RefdsReduxReducer must be applied with State and Action types, e.g. @RefdsReduxReducer(State, Action).")
}

let protocolConformance = """
extension \(enumDecl.name.text): RefdsReduxReducerProtocol {
typealias State = \(stateType)
typealias Action = \(actionType)
}
"""

return ExprSyntax(stringLiteral: protocolConformance)
}
}
19 changes: 19 additions & 0 deletions Sources/RefdsReduxMacros/RefdsReduxStateMacro.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import SwiftCompilerPlugin
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros

public struct RefdsReduxStateMacro: ExpressionMacro {
public static func expansion(
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) -> ExprSyntax {
guard let enumDecl = node.as(EnumDeclSyntax.self) else {
fatalError("@RefdsReduxState must be applied to an enum.")
}
let protocolConformance = """
extension \(enumDecl.name.text): RefdsReduxStateProtocol {}
"""
return ExprSyntax(stringLiteral: protocolConformance)
}
}
Loading

0 comments on commit 40b557f

Please sign in to comment.