Skip to content

Commit

Permalink
Merge pull request #7 from riiid/feature/reducer-macro
Browse files Browse the repository at this point in the history
👔 Support Reducer macro
  • Loading branch information
tisohjung authored Jan 29, 2024
2 parents 07400df + 34db0a8 commit 49f5978
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 67 deletions.
33 changes: 33 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,36 @@ DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc

# Created by https://www.toptal.com/developers/gitignore/api/xcode,swiftpm,swiftpackagemanager
# Edit at https://www.toptal.com/developers/gitignore?templates=xcode,swiftpm,swiftpackagemanager

### SwiftPackageManager ###
Packages
.build/
xcuserdata
DerivedData/
*.xcodeproj


### SwiftPM ###


### Xcode ###
## User settings
xcuserdata/

## Xcode 8 and earlier
*.xcscmblueprint
*.xccheckout

### Xcode Patch ###
*.xcodeproj/*
!*.xcodeproj/project.pbxproj
!*.xcodeproj/xcshareddata/
!*.xcodeproj/project.xcworkspace/
!*.xcworkspace/contents.xcworkspacedata
/*.gcno
**/xcshareddata/WorkspaceSettings.xcsettings

# End of https://www.toptal.com/developers/gitignore/api/xcode,swiftpm,swiftpackagemanager
35 changes: 4 additions & 31 deletions .swiftpm/xcode/xcshareddata/xcschemes/TCADiagram-Package.xcscheme
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1420"
version = "1.3">
LastUpgradeVersion = "1520"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
Expand Down Expand Up @@ -48,41 +48,14 @@
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "TCADiagram"
BuildableName = "TCADiagram"
BlueprintName = "TCADiagram"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "TCADiagramLib"
BuildableName = "TCADiagramLib"
BlueprintName = "TCADiagramLib"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
<Testables>
<TestableReference
skipped = "NO">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1420"
version = "1.3">
LastUpgradeVersion = "1520"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
Expand All @@ -26,9 +26,8 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
Expand Down
20 changes: 5 additions & 15 deletions .swiftpm/xcode/xcshareddata/xcschemes/tca-diagram.xcscheme
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1420"
version = "1.3">
LastUpgradeVersion = "1520"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
Expand Down Expand Up @@ -40,7 +40,8 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
<Testables>
<TestableReference
skipped = "NO">
Expand All @@ -63,8 +64,7 @@
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES"
viewDebuggingEnabled = "No">
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
Expand All @@ -75,16 +75,6 @@
ReferencedContainer = "container:">
</BuildableReference>
</BuildableProductRunnable>
<CommandLineArguments>
<CommandLineArgument
argument = "-r /Users/importre/Workspace/riiid/toeic-ios"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "/Users/importre/Workspace/riiid/toeic-ios/readme.md"
isEnabled = "YES">
</CommandLineArgument>
</CommandLineArguments>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
Expand Down
47 changes: 32 additions & 15 deletions Sources/TCADiagramLib/Internal/Parser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ extension SourceFileSyntax {
actions: inout Set<String>,
relations: inout [Relation]
) throws {
if let (childs, isOptional) = try predicateChildReducerProtocol(node) {
childs.forEach { child in
if let (children, isOptional) = try predicateChildReducerProtocol(node) {
children.forEach { child in
relations.append(
.init(
parent: parent,
Expand All @@ -67,17 +67,32 @@ extension SourceFileSyntax {

extension SourceFileSyntax {

/// Get parent name from feature with superclass of ReducerProtocol
/// Get parent name from feature.
private func predicateReducerProtocol(_ node: Syntax) throws -> String? {
if
let node = StructDeclSyntax(node),
node.inheritanceClause?.tokens(viewMode: .fixedUp)
.contains(where: {
$0.tokenKind == .identifier("ReducerProtocol")
|| $0.tokenKind == .identifier("Reducer")
}) == true
let node = StructDeclSyntax(node)
{
return node.identifier.text
/// Has @Reducer macro
if
node.attributes?.contains(where: { element in
element.tokens(viewMode: .fixedUp).contains { el in
el.tokenKind == .identifier("Reducer")
}
}) == true
{
debugPrint(node.identifier.text)
return node.identifier.text
}
/// superclass of ReducerProtocol or Reducer
if
node.inheritanceClause?.tokens(viewMode: .fixedUp)
.contains(where: {
$0.tokenKind == .identifier("ReducerProtocol")
|| $0.tokenKind == .identifier("Reducer")
}) == true
{
return node.identifier.text
}
}
return nil
}
Expand All @@ -93,23 +108,25 @@ extension SourceFileSyntax {
let child = node.trailingClosure?.statements.first?.description
.firstMatch(of: try Regex("\\s*(.+?)\\(\\)"))?[1]
.substring?
.description {
.description
{
return ([child], false)
}

// ifLet can be in "method chaining"
// therefore find all reducer names that match and save in child
if
node.tokens(viewMode: .fixedUp).contains(where: { $0.tokenKind == .identifier("ifLet") }) {
let childs = node.description
node.tokens(viewMode: .fixedUp).contains(where: { $0.tokenKind == .identifier("ifLet") })
{
let children = node.description
.matches(of: try Regex("ifLet.+{\\s+(.+?)\\(\\)"))
.compactMap {
$0[1].substring?.description
}
.filter {
$0 != "EmptyReducer"
}
return (childs, true)
return (children, true)
}
}
return .none
Expand Down Expand Up @@ -185,7 +202,7 @@ extension SourceFileSyntax {
/// check if `pullback` chains `optional()`.
private func isOptionalPullback(_ node: FunctionCallExprSyntax) -> Bool {
var stack: [Syntax] = node.children(viewMode: .fixedUp).reversed()
while(!stack.isEmpty) {
while !stack.isEmpty {
let node = stack.removeFirst()
if
let node = FunctionCallExprSyntax(node),
Expand Down
24 changes: 23 additions & 1 deletion Tests/TCADiagramLibTests/DiagramTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ final class DiagramTests: XCTestCase {
SignUpAgreement(SignUpAgreement: 1)
```
"""
XCTAssertEqual(result, expected)
XCTAssertEqual(result, expected)
}

func testReducerProtocolExample() throws {
Expand Down Expand Up @@ -67,4 +67,26 @@ final class DiagramTests: XCTestCase {
"""
XCTAssertEqual(result, expected)
}

func testReducerMacroExample() throws {
let result = try Diagram.dump(reducerMacroSampleSource)
let expected = """
```mermaid
%%{ init : { "theme" : "default", "flowchart" : { "curve" : "monotoneY" }}}%%
graph LR
SelfLessonDetail -- optional --> DoubleIfLetChild
SelfLessonDetail ---> DoubleScopeChild
SelfLessonDetail ---> Payment
SelfLessonDetail -- optional --> SantaWeb
SelfLessonDetail -- optional --> SelfLessonDetailFilter
DoubleIfLetChild(DoubleIfLetChild: 1)
DoubleScopeChild(DoubleScopeChild: 1)
Payment(Payment: 1)
SantaWeb(SantaWeb: 1)
SelfLessonDetailFilter(SelfLessonDetailFilter: 1)
```
"""
XCTAssertEqual(result, expected)
}
}
64 changes: 64 additions & 0 deletions Tests/TCADiagramLibTests/Resources/Sources.swift
Original file line number Diff line number Diff line change
Expand Up @@ -200,3 +200,67 @@ let reducerSampleSource: [String] = [
}
"""
]

let reducerMacroSampleSource: [String] = [
"""
@Reducer
public struct SelfLessonDetail {
@Dependency(\\.environmentSelfLessonDetail) private var environment
public init() {}
public var body: some Reducer<State, Action> {
BindingReducer()
Scope(state: \\State.payment, action: /Action.payment) {
Payment()
}
Scope(state: \\.subState, action: .self) {
Scope(
state: /State.SubState.promotionWeb,
action: /Action.promotionWeb
) {
DoubleScopeChild()
}
}
Reduce { state, action in
switch action {
case default:
return .none
}
}
.ifLet(\\.filter, action: \\.filter) {
SelfLessonDetailFilter()
}
.ifLet(\\.selection, action: \\.web) {
SantaWeb()
}
.ifLet(\\SelfLessonDetail.State.selection, action: /SelfLessonDetail.Action.webView) {
EmptyReducer()
.ifLet(\\Identified.value, action: .self) {
DoubleIfLetChild()
}
}
}
}
""",
"""
extension SelfLessonDetail {
public enum Action: Equatable {
}
}
extension Payment {
public enum Action: Equatable {
}
}
extension SantaWeb {
public enum Action: Equatable {
}
}
extension SelfLessonDetailFilter {
public enum Action: Equatable {
}
}
"""
]

0 comments on commit 49f5978

Please sign in to comment.