From b5fc6bfffa05a3edff2cb35e0ab1cf36e296a0e4 Mon Sep 17 00:00:00 2001 From: Nikita Korobeinikov Date: Fri, 16 Jun 2023 23:16:43 +0400 Subject: [PATCH 01/13] add macro for adding `mutating` func for struct --- Components/Macro/.gitignore | 8 +++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++ Components/Macro/Package.resolved | 14 +++++ Components/Macro/Package.swift | 56 +++++++++++++++++++ .../Macro/MutableMacroDefinition.swift | 6 ++ .../Macro/Sources/MacroClient/main.swift | 37 ++++++++++++ .../Macro/Sources/Macros/MacroError.swift | 13 +++++ .../Macro/Sources/Macros/MutableMacro.swift | 54 ++++++++++++++++++ .../Macro/Tests/MutableMacroTests.swift | 40 +++++++++++++ 9 files changed, 236 insertions(+) create mode 100644 Components/Macro/.gitignore create mode 100644 Components/Macro/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Components/Macro/Package.resolved create mode 100644 Components/Macro/Package.swift create mode 100644 Components/Macro/Sources/Macro/MutableMacroDefinition.swift create mode 100644 Components/Macro/Sources/MacroClient/main.swift create mode 100644 Components/Macro/Sources/Macros/MacroError.swift create mode 100644 Components/Macro/Sources/Macros/MutableMacro.swift create mode 100644 Components/Macro/Tests/MutableMacroTests.swift diff --git a/Components/Macro/.gitignore b/Components/Macro/.gitignore new file mode 100644 index 00000000..0023a534 --- /dev/null +++ b/Components/Macro/.gitignore @@ -0,0 +1,8 @@ +.DS_Store +/.build +/Packages +xcuserdata/ +DerivedData/ +.swiftpm/configuration/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/Components/Macro/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Components/Macro/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/Components/Macro/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Components/Macro/Package.resolved b/Components/Macro/Package.resolved new file mode 100644 index 00000000..c4f97948 --- /dev/null +++ b/Components/Macro/Package.resolved @@ -0,0 +1,14 @@ +{ + "pins" : [ + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-syntax.git", + "state" : { + "revision" : "165fc6d22394c1168ff76ab5d951245971ef07e5", + "version" : "509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-06-05-a" + } + } + ], + "version" : 2 +} diff --git a/Components/Macro/Package.swift b/Components/Macro/Package.swift new file mode 100644 index 00000000..ddf7f3b6 --- /dev/null +++ b/Components/Macro/Package.swift @@ -0,0 +1,56 @@ +// swift-tools-version: 5.9 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription +import CompilerPluginSupport + +let package = Package( + name: "Macro", + 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: "Macro", + targets: ["Macro"] + ), + .executable( + name: "MacroClient", + targets: ["MacroClient"] + ), + ], + dependencies: [ + // Depend on the latest Swift 5.9 prerelease of SwiftSyntax + .package(url: "https://github.com/apple/swift-syntax.git", from: "509.0.0-swift-5.9-DEVELOPMENT-SNAPSHOT-2023-04-25-b"), + ], + 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: "Macros", + dependencies: [ + .product(name: "SwiftSyntaxMacros", 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: "Macro", + dependencies: [ + "Macros" + ] + ), + + // A client of the library, which is able to use the macro in its own code. + .executableTarget(name: "MacroClient", dependencies: ["Macro"]), + + // A test target used to develop the macro implementation. + .testTarget( + name: "MacroTests", + dependencies: [ + "Macro", + .product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"), + ] + ), + ] +) diff --git a/Components/Macro/Sources/Macro/MutableMacroDefinition.swift b/Components/Macro/Sources/Macro/MutableMacroDefinition.swift new file mode 100644 index 00000000..4b2114e3 --- /dev/null +++ b/Components/Macro/Sources/Macro/MutableMacroDefinition.swift @@ -0,0 +1,6 @@ +// The Swift Programming Language +// https://docs.swift.org/swift-book + +/// A macro which generate `mutating func` for all variables inside struct. +@attached(member, names: named(set)) +public macro Mutable() = #externalMacro(module: "Macros", type: "MutableMacro") diff --git a/Components/Macro/Sources/MacroClient/main.swift b/Components/Macro/Sources/MacroClient/main.swift new file mode 100644 index 00000000..893e084c --- /dev/null +++ b/Components/Macro/Sources/MacroClient/main.swift @@ -0,0 +1,37 @@ +import Macro + +// MARK: - Precondition + +@Mutable +struct SomeStruct { + let id: Int = Int.random(in: Int.min...Int.max) + var someFlag: Bool = false + var someString: String = "" +} + +// MARK: - Helpers + +extension SomeStruct { + + func debugPrintAll() { + debugPrint(someFlag) + debugPrint(someString) + } + +} + +// MARK: - Debugging + +var someStruct = SomeStruct() + +someStruct.debugPrintAll() + +someStruct.set(someFlag: true) +someStruct.set(someString: "echo") + +someStruct.debugPrintAll() + +someStruct.set(someFlag: false) +someStruct.set(someString: "horray") + +someStruct.debugPrintAll() diff --git a/Components/Macro/Sources/Macros/MacroError.swift b/Components/Macro/Sources/Macros/MacroError.swift new file mode 100644 index 00000000..07f7e98b --- /dev/null +++ b/Components/Macro/Sources/Macros/MacroError.swift @@ -0,0 +1,13 @@ +// +// MacroError.swift +// +// +// Created by Никита Коробейников on 16.06.2023. +// + +public enum MacroError: Error { + + case onlyApplicableToStruct + case typeAnnotationRequiredFor(variableName: String) + +} diff --git a/Components/Macro/Sources/Macros/MutableMacro.swift b/Components/Macro/Sources/Macros/MutableMacro.swift new file mode 100644 index 00000000..57993021 --- /dev/null +++ b/Components/Macro/Sources/Macros/MutableMacro.swift @@ -0,0 +1,54 @@ +import SwiftCompilerPlugin +import SwiftSyntax +import SwiftSyntaxBuilder +import SwiftSyntaxMacros + +/// A macro which generate `mutating func` for all variables inside struct. +public struct MutableMacro: MemberMacro { + + public static func expansion(of node: AttributeSyntax, + providingMembersOf declaration: Declaration, + in context: Context) throws -> [DeclSyntax] + where Declaration: DeclGroupSyntax, + Context: MacroExpansionContext { + guard let structDecl = declaration.as(StructDeclSyntax.self) else { + throw MacroError.onlyApplicableToStruct + } + + let variables = structDecl.memberBlock + .members + + .compactMap { $0.decl.as(VariableDeclSyntax.self) } + .filter { $0.bindingKeyword.text == "var" } + + let functions = try variables.compactMap { variableDecl -> FunctionDeclSyntax? in + guard let variableBinding = variableDecl.bindings.first, + let variableType = variableBinding.typeAnnotation?.type else { + throw MacroError.typeAnnotationRequiredFor(variableName: variableDecl.bindings.first?.pattern.description ?? "unknown") + } + + let variableName = TokenSyntax(stringLiteral: variableBinding.pattern.description) + + let parameter = FunctionParameterSyntax(firstName: variableName, type: variableType) + let parameterList = FunctionParameterListSyntax(arrayLiteral: parameter) + let modifiers = ModifierListSyntax(arrayLiteral: .init(name: .keyword(.mutating))) + let bodyItem = CodeBlockItemSyntax.Item.expr(.init(stringLiteral: "self.\(variableName.text)=\(variableName.text)")) + let body = CodeBlockSyntax(statements: .init(arrayLiteral: .init(item: bodyItem))) + return FunctionDeclSyntax(modifiers: modifiers, + identifier: .identifier("set"), + signature: .init(input: .init(parameterList: parameterList)), + body: body + ) + } + + return functions.compactMap { $0.as(DeclSyntax.self) } + } + +} + +@main +struct MacroPlugin: CompilerPlugin { + let providingMacros: [Macro.Type] = [ + MutableMacro.self, + ] +} diff --git a/Components/Macro/Tests/MutableMacroTests.swift b/Components/Macro/Tests/MutableMacroTests.swift new file mode 100644 index 00000000..cf15b9e2 --- /dev/null +++ b/Components/Macro/Tests/MutableMacroTests.swift @@ -0,0 +1,40 @@ +import SwiftSyntaxMacros +import SwiftSyntaxMacrosTestSupport +import XCTest +import Macros + +let testMacros: [String: Macro.Type] = [ + "mutable": MutableMacro.self, +] + +final class MutableMacroTests: XCTestCase { + + func testMutableMacro_expansion() { + assertMacroExpansion( + """ + @Mutable + struct SomeStruct { + let id: String = "" + var someVar: Bool = false + } + """, + expandedSource: """ + @Mutable + struct SomeStruct { + let id: String = "" + var someVar: Bool = false + + mutating func set(someVar: Bool) { + self.someVar = someVar + } + } + """, + macros: testMacros + ) + } + + func testMutableMacro_application() { + // TODO: - check that macro throwing error + } + +} From db14181a8fa175972bfd47888633abd6a3196538 Mon Sep 17 00:00:00 2001 From: Nikita Korobeinikov Date: Fri, 16 Jun 2023 23:52:08 +0400 Subject: [PATCH 02/13] extend macro tests --- .../Macro/Tests/MutableMacroTests.swift | 46 +++++++++++++++++-- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/Components/Macro/Tests/MutableMacroTests.swift b/Components/Macro/Tests/MutableMacroTests.swift index cf15b9e2..a3a63ad2 100644 --- a/Components/Macro/Tests/MutableMacroTests.swift +++ b/Components/Macro/Tests/MutableMacroTests.swift @@ -9,13 +9,13 @@ let testMacros: [String: Macro.Type] = [ final class MutableMacroTests: XCTestCase { - func testMutableMacro_expansion() { + func testExpansionSucceded_whenAppliedToStruct_withVariablesAndType() { assertMacroExpansion( """ @Mutable struct SomeStruct { - let id: String = "" - var someVar: Bool = false + let id: String = "" + var someVar: Bool = false } """, expandedSource: """ @@ -33,8 +33,44 @@ final class MutableMacroTests: XCTestCase { ) } - func testMutableMacro_application() { - // TODO: - check that macro throwing error + func testExpansionFailed_whenAppliedTo_nonStruct() { + assertMacroExpansion( + """ + @Mutable + class SomeStruct { + let id: String = "" + var someVar: Bool = false + } + """, + expandedSource: """ + @Mutable + class SomeStruct { + let id: String = "" + var someVar: Bool = false + } + """, + macros: testMacros + ) + } + + func testExpansionFailed_whenAppliedTo_variableWithoutAnnotation() { + assertMacroExpansion( + """ + @Mutable + struct SomeStruct { + let id: String = "" + var someVar = false + } + """, + expandedSource: """ + @Mutable + struct SomeStruct { + let id: String = "" + var someVar = false + } + """, + macros: testMacros + ) } } From 6161160dc05ecf2939164d2a7391bb22db9482a2 Mon Sep 17 00:00:00 2001 From: Nikita Korobeinikov Date: Mon, 19 Jun 2023 09:44:37 +0400 Subject: [PATCH 03/13] apply macro in components and example --- Brewfile.lock.json | 12 ++--- Components/Macro/Package.swift | 1 + Components/Package.resolved | 16 ++++++ Components/Package.swift | 9 ++-- .../Sources/Common/Views/LabelView.swift | 24 +-------- .../Sources/Common/Views/MessageView.swift | 54 +++---------------- Components/project.yml | 13 +++-- Example/project.yml | 11 ++-- Example/targets/template.yml | 6 +-- Package.swift | 2 +- Podfile | 4 +- .../xcshareddata/swiftpm/Package.resolved | 9 ++++ .../ExamplePackage/Package.swift | 2 +- project.yml | 12 +++-- 14 files changed, 73 insertions(+), 102 deletions(-) create mode 100644 Components/Package.resolved diff --git a/Brewfile.lock.json b/Brewfile.lock.json index 0dde257b..79fed623 100644 --- a/Brewfile.lock.json +++ b/Brewfile.lock.json @@ -2,7 +2,7 @@ "entries": { "tap": { "homebrew/cask": { - "revision": "266747f8b172dd47e6c80ce2590889a8a7c96501" + "revision": "c896fe86403b4515fddc15421cce660a306dc3f0" }, "yonaskolb/xcodegen": { "revision": "372f20fe5a3823dc398f52cb6cc1af5003d452f7", @@ -19,7 +19,7 @@ }, "brew": { "xcodegen": { - "version": "2.25.0", + "version": "2.35.0", "bottle": { "rebuild": 0, "root_url": "https://ghcr.io/v2/homebrew/core", @@ -58,7 +58,7 @@ } }, "sourcery": { - "version": "1.8.1", + "version": "2.0.2", "bottle": { "rebuild": 0, "root_url": "https://ghcr.io/v2/homebrew/core", @@ -107,11 +107,11 @@ "macOS": "11.5.1" }, "ventura": { - "HOMEBREW_VERSION": "4.0.19", - "HOMEBREW_PREFIX": "/opt/homebrew", + "HOMEBREW_VERSION": "4.0.23-10-g6abf680", + "HOMEBREW_PREFIX": "/usr/local", "Homebrew/homebrew-core": "api", "CLT": "", - "Xcode": "14.3", + "Xcode": "15.0", "macOS": "13.4" } } diff --git a/Components/Macro/Package.swift b/Components/Macro/Package.swift index ddf7f3b6..817f9fa0 100644 --- a/Components/Macro/Package.swift +++ b/Components/Macro/Package.swift @@ -11,6 +11,7 @@ let package = Package( // Products define the executables and libraries a package produces, making them visible to other packages. .library( name: "Macro", + type: .dynamic, targets: ["Macro"] ), .executable( diff --git a/Components/Package.resolved b/Components/Package.resolved new file mode 100644 index 00000000..cef57fbe --- /dev/null +++ b/Components/Package.resolved @@ -0,0 +1,16 @@ +{ + "object": { + "pins": [ + { + "package": "SwiftSyntax", + "repositoryURL": "https://github.com/apple/swift-syntax.git", + "state": { + "branch": null, + "revision": "165fc6d22394c1168ff76ab5d951245971ef07e5", + "version": "509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-06-05-a" + } + } + ] + }, + "version": 1 +} diff --git a/Components/Package.swift b/Components/Package.swift index f7aa97aa..9b3ace2f 100644 --- a/Components/Package.swift +++ b/Components/Package.swift @@ -1,11 +1,11 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "ReactiveDataComponents", - platforms: [.iOS(.v11)], + platforms: [.iOS(.v13)], products: [ .library( name: "ReactiveDataComponents", @@ -13,12 +13,13 @@ let package = Package( ) ], dependencies: [ - .package(name: "ReactiveDataDisplayManager", path: "../") + .package(name: "ReactiveDataDisplayManager", path: "../"), + .package(name: "Macro", path: "./Macro") ], targets: [ .target( name: "ReactiveDataComponents", - dependencies: ["ReactiveDataDisplayManager"], + dependencies: ["ReactiveDataDisplayManager", "Macro"], path: "Sources" ) ] diff --git a/Components/Sources/Common/Views/LabelView.swift b/Components/Sources/Common/Views/LabelView.swift index d8947e32..4f895bf5 100644 --- a/Components/Sources/Common/Views/LabelView.swift +++ b/Components/Sources/Common/Views/LabelView.swift @@ -7,6 +7,7 @@ import UIKit import ReactiveDataDisplayManager +import Macro /// Base view to implement label within cell public class LabelView: UIView { @@ -23,6 +24,7 @@ extension LabelView: ConfigurableItem { // MARK: - Model + @Mutable public struct Model: AlignmentProvider, TextProvider { // MARK: - Editor @@ -89,28 +91,6 @@ extension LabelView: ConfigurableItem { private(set) public var alignment: Alignment = .all(.zero) private(set) public var textAlignment: NSTextAlignment = .left - // MARK: - Mutation - - mutating func set(text: TextValue) { - self.text = text - } - - mutating func set(style: TextStyle) { - self.style = style - } - - mutating func set(layout: TextLayout) { - self.layout = layout - } - - mutating func set(alignment: Alignment) { - self.alignment = alignment - } - - mutating func set(textAlignment: NSTextAlignment) { - self.textAlignment = textAlignment - } - // MARK: - Builder public static func build(@EditorBuilder content: (Property.Type) -> [Property]) -> Self { diff --git a/Components/Sources/Common/Views/MessageView.swift b/Components/Sources/Common/Views/MessageView.swift index 4f66a000..7409e141 100644 --- a/Components/Sources/Common/Views/MessageView.swift +++ b/Components/Sources/Common/Views/MessageView.swift @@ -7,6 +7,7 @@ #if os(iOS) import UIKit import ReactiveDataDisplayManager +import Macro /// Base view to implement label within cell public class MessageView: UIView { @@ -24,6 +25,7 @@ extension MessageView: ConfigurableItem { // MARK: - Model + @Mutable public struct Model: Equatable, AlignmentProvider, TextProvider { // MARK: - Editor @@ -52,7 +54,7 @@ extension MessageView: ConfigurableItem { public static func style(_ value: TextStyle) -> Property { .init(closure: { model in var model = model - model.set(style: value) + model.set(textStyle: value) return model }) } @@ -60,7 +62,7 @@ extension MessageView: ConfigurableItem { public static func layout(_ value: TextLayout) -> Property { .init(closure: { model in var model = model - model.set(layout: value) + model.set(textLayout: value) return model }) } @@ -84,7 +86,7 @@ extension MessageView: ConfigurableItem { public static func insets(_ value: UIEdgeInsets) -> Property { .init(closure: { model in var model = model - model.set(insets: value) + model.set(internalEdgeInsets: value) return model }) } @@ -92,7 +94,7 @@ extension MessageView: ConfigurableItem { public static func background(_ value: BackgroundStyle) -> Property { .init(closure: { model in var model = model - model.set(background: value) + model.set(backgroundStyle: value) return model }) } @@ -100,7 +102,7 @@ extension MessageView: ConfigurableItem { public static func border(_ value: BorderStyle) -> Property { .init(closure: { model in var model = model - model.set(border: value) + model.set(borderStyle: value) return model }) } @@ -136,48 +138,6 @@ extension MessageView: ConfigurableItem { private(set) public var dataDetection: DataDetectionStyle? private(set) public var selectable: Bool = false - // MARK: - Mutation - - mutating func set(text: TextValue) { - self.text = text - } - - mutating func set(style: TextStyle) { - self.textStyle = style - } - - mutating func set(layout: TextLayout) { - self.textLayout = layout - } - - mutating func set(alignment: Alignment) { - self.alignment = alignment - } - - mutating func set(textAlignment: NSTextAlignment) { - self.textAlignment = textAlignment - } - - mutating func set(insets: UIEdgeInsets) { - self.internalEdgeInsets = insets - } - - mutating func set(background: BackgroundStyle) { - self.backgroundStyle = background - } - - mutating func set(border: BorderStyle) { - self.borderStyle = border - } - - mutating func set(dataDetection: DataDetectionStyle) { - self.dataDetection = dataDetection - } - - mutating func set(selectable: Bool) { - self.selectable = selectable - } - // MARK: - Builder public static func build(@EditorBuilder content: (Property.Type) -> [Property]) -> Self { diff --git a/Components/project.yml b/Components/project.yml index cfceac7b..a7746dff 100644 --- a/Components/project.yml +++ b/Components/project.yml @@ -2,11 +2,12 @@ name: ReactiveDataComponents options: # Версия Xcode - xcodeVersion: 13.4.1 + xcodeVersion: 15.0.0 # Создание пустых директорий generateEmptyDirectories: true # Создание групп createIntermediateGroups: true + targets: ReactiveDataComponents: dependencies: @@ -14,8 +15,8 @@ targets: type: framework platform: [iOS, tvOS] deploymentTarget: - iOS: 11.0 - tvOS: 11.0 + iOS: 13.0 + tvOS: 13.0 scheme: configVariants: all testTargets: @@ -24,7 +25,9 @@ targets: sources: - path: Sources dependencies: + - package: Macro - target: ReactiveDataDisplayManager_${platform} + info: path: Info.plist properties: @@ -47,8 +50,8 @@ targets: type: bundle.unit-test platform: [iOS, tvOS] deploymentTarget: - iOS: 11.0 - tvOS: 11.0 + iOS: 13.0 + tvOS: 13.0 scheme: configVariants: all sources: diff --git a/Example/project.yml b/Example/project.yml index 8623d5fe..3fad64fa 100644 --- a/Example/project.yml +++ b/Example/project.yml @@ -8,7 +8,7 @@ include: name: ReactiveDataDisplayManagerExample options: # Версия Xcode - xcodeVersion: 13.4.1 + xcodeVersion: 15.0.0 # Создание пустых директорий generateEmptyDirectories: true # Создание групп @@ -16,11 +16,6 @@ options: settings: DEVELOPMENT_TEAM: EFAAG9GXN4 -packages: - Vapor: - github: vapor/vapor - from: 4.0.0 - targets: ReactiveServer_macOS: @@ -61,12 +56,12 @@ targets: ReactiveDataDisplayManagerExample_iOS: platform: iOS - deploymentTarget: 11.0 + deploymentTarget: 13.0 scheme: configVariants: all testTargets: - ReactiveDataDisplayManagerExampleUITests - gatherCoverageData: true + gatherCoverageData: false sources: - path: ReactiveDataDisplayManager dependencies: diff --git a/Example/targets/template.yml b/Example/targets/template.yml index a8558135..4dae8f2f 100644 --- a/Example/targets/template.yml +++ b/Example/targets/template.yml @@ -24,11 +24,11 @@ targetTemplates: type: bundle.ui-testing platform: iOS deploymentTarget: - iOS: 11.0 - tvOS: 10.0 + iOS: 13.0 + tvOS: 13.0 scheme: configVariants: all - gatherCoverageData: true + gatherCoverageData: false BaseSettings: settings: diff --git a/Package.swift b/Package.swift index ccf7c388..02b246b3 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 import PackageDescription let package = Package( diff --git a/Podfile b/Podfile index f0a50907..7898cf86 100644 --- a/Podfile +++ b/Podfile @@ -22,7 +22,7 @@ abstract_target 'Targets' do end target 'ReactiveDataDisplayManagerExample_iOS' do - platform :ios, '11.0' + platform :ios, '13.0' utils diffKit target 'ReactiveDataDisplayManagerExampleUITests' @@ -37,7 +37,7 @@ end post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| - config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11' + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13' end end end diff --git a/ReactiveDataDisplayManager.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ReactiveDataDisplayManager.xcworkspace/xcshareddata/swiftpm/Package.resolved index 2a09a19f..2387d365 100644 --- a/ReactiveDataDisplayManager.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ReactiveDataDisplayManager.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -162,6 +162,15 @@ "version" : "1.0.2" } }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-syntax.git", + "state" : { + "revision" : "165fc6d22394c1168ff76ab5d951245971ef07e5", + "version" : "509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-06-05-a" + } + }, { "identity" : "vapor", "kind" : "remoteSourceControl", diff --git a/SPMExample/ReactiveDataDisplayManagerSPMExample/ExamplePackage/Package.swift b/SPMExample/ReactiveDataDisplayManagerSPMExample/ExamplePackage/Package.swift index 7d5b2633..b5b230c2 100644 --- a/SPMExample/ReactiveDataDisplayManagerSPMExample/ExamplePackage/Package.swift +++ b/SPMExample/ReactiveDataDisplayManagerSPMExample/ExamplePackage/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription diff --git a/project.yml b/project.yml index 6d6c8486..8db8a50f 100644 --- a/project.yml +++ b/project.yml @@ -4,12 +4,18 @@ include: - path: Components/project.yml relativePaths: true +packages: + Macro: + path: Components/Macro + Vapor: + github: vapor/vapor + from: 4.0.0 # Название проекта name: ReactiveDataDisplayManager options: # Версия Xcode - xcodeVersion: 13.4.1 + xcodeVersion: 15.0.0 # Создание пустых директорий generateEmptyDirectories: true # Создание групп @@ -21,7 +27,7 @@ targets: type: framework platform: [iOS, tvOS] deploymentTarget: - iOS: 11.0 + iOS: 13.0 tvOS: 10.0 scheme: configVariants: all @@ -52,7 +58,7 @@ targets: type: bundle.unit-test platform: [iOS, tvOS] deploymentTarget: - iOS: 11.0 + iOS: 13.0 tvOS: 10.0 scheme: configVariants: all From 5510a74783ec60af6a01cc53cf91dde50c59a678 Mon Sep 17 00:00:00 2001 From: Nikita Korobeinikov Date: Mon, 19 Jun 2023 10:37:03 +0400 Subject: [PATCH 04/13] update runner images --- .github/workflows/Build.yml | 2 +- .github/workflows/Lint.yml | 2 +- Makefile | 2 +- .../xcshareddata/swiftpm/Package.resolved | 14 ++++++++++++++ 4 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 SPMExample/ReactiveDataDisplayManagerSPMExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 475ec22a..6aa5b4f2 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -72,7 +72,7 @@ jobs: run: make build_example_tvOS build_SPM: - runs-on: macOS-12 + runs-on: macOS-13 steps: - uses: actions/checkout@v1 - name: Build diff --git a/.github/workflows/Lint.yml b/.github/workflows/Lint.yml index e72fbef2..926d1036 100644 --- a/.github/workflows/Lint.yml +++ b/.github/workflows/Lint.yml @@ -16,7 +16,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} pod: - runs-on: macOS-12 + runs-on: macOS-13 steps: - uses: actions/checkout@v1 - name: Generate projects diff --git a/Makefile b/Makefile index 450c05cd..9abafad4 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ projects: -bundle exec pod install ## Build Configuration -destination='platform=iOS Simulator,name=iPhone 14 Pro' +destination='platform=iOS Simulator,name=iPhone 14' destination_tv='platform=tvOS Simulator,name=Apple TV' ## Build lib sources for **tvOS** platform diff --git a/SPMExample/ReactiveDataDisplayManagerSPMExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/SPMExample/ReactiveDataDisplayManagerSPMExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 00000000..c4f97948 --- /dev/null +++ b/SPMExample/ReactiveDataDisplayManagerSPMExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,14 @@ +{ + "pins" : [ + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-syntax.git", + "state" : { + "revision" : "165fc6d22394c1168ff76ab5d951245971ef07e5", + "version" : "509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-06-05-a" + } + } + ], + "version" : 2 +} From 684628954abadb6ccb52abd684efb180fbb2d5cd Mon Sep 17 00:00:00 2001 From: Nikita Korobeinikov Date: Mon, 19 Jun 2023 10:44:02 +0400 Subject: [PATCH 05/13] fix linter issues --- Components/Macro/Package.swift | 8 ++++---- Components/Macro/Sources/Macros/MutableMacro.swift | 2 +- Components/Macro/Tests/MutableMacroTests.swift | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Components/Macro/Package.swift b/Components/Macro/Package.swift index 817f9fa0..f980e6d1 100644 --- a/Components/Macro/Package.swift +++ b/Components/Macro/Package.swift @@ -17,11 +17,11 @@ let package = Package( .executable( name: "MacroClient", targets: ["MacroClient"] - ), + ) ], dependencies: [ // Depend on the latest Swift 5.9 prerelease of SwiftSyntax - .package(url: "https://github.com/apple/swift-syntax.git", from: "509.0.0-swift-5.9-DEVELOPMENT-SNAPSHOT-2023-04-25-b"), + .package(url: "https://github.com/apple/swift-syntax.git", from: "509.0.0-swift-5.9-DEVELOPMENT-SNAPSHOT-2023-04-25-b") ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. @@ -50,8 +50,8 @@ let package = Package( name: "MacroTests", dependencies: [ "Macro", - .product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"), + .product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax") ] - ), + ) ] ) diff --git a/Components/Macro/Sources/Macros/MutableMacro.swift b/Components/Macro/Sources/Macros/MutableMacro.swift index 57993021..6c3013de 100644 --- a/Components/Macro/Sources/Macros/MutableMacro.swift +++ b/Components/Macro/Sources/Macros/MutableMacro.swift @@ -49,6 +49,6 @@ public struct MutableMacro: MemberMacro { @main struct MacroPlugin: CompilerPlugin { let providingMacros: [Macro.Type] = [ - MutableMacro.self, + MutableMacro.self ] } diff --git a/Components/Macro/Tests/MutableMacroTests.swift b/Components/Macro/Tests/MutableMacroTests.swift index a3a63ad2..30e1f719 100644 --- a/Components/Macro/Tests/MutableMacroTests.swift +++ b/Components/Macro/Tests/MutableMacroTests.swift @@ -4,7 +4,7 @@ import XCTest import Macros let testMacros: [String: Macro.Type] = [ - "mutable": MutableMacro.self, + "mutable": MutableMacro.self ] final class MutableMacroTests: XCTestCase { From e45be48a0681be5f600d56c8f46583a71bbcc811 Mon Sep 17 00:00:00 2001 From: Nikita Korobeinikov Date: Tue, 20 Jun 2023 15:50:37 +0400 Subject: [PATCH 06/13] add unit test for mutable macro --- .../Macro/Sources/Macros/MutableMacro.swift | 9 ++++--- .../Macro/Tests/MutableMacroTests.swift | 27 ++++++++++++++----- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/Components/Macro/Sources/Macros/MutableMacro.swift b/Components/Macro/Sources/Macros/MutableMacro.swift index 6c3013de..b8efa615 100644 --- a/Components/Macro/Sources/Macros/MutableMacro.swift +++ b/Components/Macro/Sources/Macros/MutableMacro.swift @@ -23,8 +23,9 @@ public struct MutableMacro: MemberMacro { let functions = try variables.compactMap { variableDecl -> FunctionDeclSyntax? in guard let variableBinding = variableDecl.bindings.first, - let variableType = variableBinding.typeAnnotation?.type else { - throw MacroError.typeAnnotationRequiredFor(variableName: variableDecl.bindings.first?.pattern.description ?? "unknown") + let variableType = variableBinding.typeAnnotation?.type.trimmed else { + let variableName = variableDecl.bindings.first?.pattern.trimmedDescription + throw MacroError.typeAnnotationRequiredFor(variableName: variableName ?? "unknown") } let variableName = TokenSyntax(stringLiteral: variableBinding.pattern.description) @@ -34,7 +35,9 @@ public struct MutableMacro: MemberMacro { let modifiers = ModifierListSyntax(arrayLiteral: .init(name: .keyword(.mutating))) let bodyItem = CodeBlockItemSyntax.Item.expr(.init(stringLiteral: "self.\(variableName.text)=\(variableName.text)")) let body = CodeBlockSyntax(statements: .init(arrayLiteral: .init(item: bodyItem))) - return FunctionDeclSyntax(modifiers: modifiers, + + return FunctionDeclSyntax(leadingTrivia: .newlines(2), + modifiers: modifiers, identifier: .identifier("set"), signature: .init(input: .init(parameterList: parameterList)), body: body diff --git a/Components/Macro/Tests/MutableMacroTests.swift b/Components/Macro/Tests/MutableMacroTests.swift index 30e1f719..03ff900a 100644 --- a/Components/Macro/Tests/MutableMacroTests.swift +++ b/Components/Macro/Tests/MutableMacroTests.swift @@ -4,7 +4,7 @@ import XCTest import Macros let testMacros: [String: Macro.Type] = [ - "mutable": MutableMacro.self + "Mutable": MutableMacro.self ] final class MutableMacroTests: XCTestCase { @@ -18,8 +18,9 @@ final class MutableMacroTests: XCTestCase { var someVar: Bool = false } """, - expandedSource: """ - @Mutable + expandedSource: + """ + struct SomeStruct { let id: String = "" var someVar: Bool = false @@ -42,13 +43,19 @@ final class MutableMacroTests: XCTestCase { var someVar: Bool = false } """, - expandedSource: """ - @Mutable + expandedSource: + """ + class SomeStruct { let id: String = "" var someVar: Bool = false } """, + diagnostics: [ + .init(message: "onlyApplicableToStruct", + line: 1, + column: 1) + ], macros: testMacros ) } @@ -62,13 +69,19 @@ final class MutableMacroTests: XCTestCase { var someVar = false } """, - expandedSource: """ - @Mutable + expandedSource: + """ + struct SomeStruct { let id: String = "" var someVar = false } """, + diagnostics: [ + .init(message: "typeAnnotationRequiredFor(variableName: \"someVar\")", + line: 1, + column: 1) + ], macros: testMacros ) } From 81e0140c9e0698e3cea31e383f2c1485f03034c0 Mon Sep 17 00:00:00 2001 From: Nikita Korobeinikov Date: Tue, 20 Jun 2023 16:36:25 +0400 Subject: [PATCH 07/13] switch CI to xcode 15 --- .github/workflows/Build.yml | 3 +++ .github/workflows/Lint.yml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 6aa5b4f2..173b642c 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -7,6 +7,9 @@ on: - preview/version-8 pull_request: +env: + DEVELOPER_DIR: /Applications/Xcode_15.0.app/Contents/Developer + jobs: build_iOS: diff --git a/.github/workflows/Lint.yml b/.github/workflows/Lint.yml index 926d1036..2d6d0331 100644 --- a/.github/workflows/Lint.yml +++ b/.github/workflows/Lint.yml @@ -2,6 +2,9 @@ name: Lint on: [pull_request] +env: + DEVELOPER_DIR: /Applications/Xcode_15.0.app/Contents/Developer + jobs: danger: runs-on: ubuntu-latest From 4e17ee875ff8c76801777b47aba894f7600d4354 Mon Sep 17 00:00:00 2001 From: Nikita Korobeinikov Date: Tue, 25 Jul 2023 18:58:50 +0400 Subject: [PATCH 08/13] init buildable macro and initialize --- Components/Macro/Package.resolved | 4 +- .../Macro/BuildableMacroDefinition.swift | 11 +++ .../Macro/Sources/Macros/BuildableMacro.swift | 94 +++++++++++++++++++ .../Sources/Macros/Decl+Extensions.swift | 51 ++++++++++ .../Macro/Sources/Macros/MacroPlugin.swift | 17 ++++ .../Macro/Sources/Macros/MutableMacro.swift | 67 +++++++------ .../Macro/Tests/BuildableMacroTests.swift | 70 ++++++++++++++ .../Macro/Tests/MutableMacroTests.swift | 8 +- 8 files changed, 281 insertions(+), 41 deletions(-) create mode 100644 Components/Macro/Sources/Macro/BuildableMacroDefinition.swift create mode 100644 Components/Macro/Sources/Macros/BuildableMacro.swift create mode 100644 Components/Macro/Sources/Macros/Decl+Extensions.swift create mode 100644 Components/Macro/Sources/Macros/MacroPlugin.swift create mode 100644 Components/Macro/Tests/BuildableMacroTests.swift diff --git a/Components/Macro/Package.resolved b/Components/Macro/Package.resolved index c4f97948..de20f808 100644 --- a/Components/Macro/Package.resolved +++ b/Components/Macro/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-syntax.git", "state" : { - "revision" : "165fc6d22394c1168ff76ab5d951245971ef07e5", - "version" : "509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-06-05-a" + "revision" : "67c5007099d9ffdd292f421f81f4efe5ee42963e", + "version" : "509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-07-10-a" } } ], diff --git a/Components/Macro/Sources/Macro/BuildableMacroDefinition.swift b/Components/Macro/Sources/Macro/BuildableMacroDefinition.swift new file mode 100644 index 00000000..4ecc4e3c --- /dev/null +++ b/Components/Macro/Sources/Macro/BuildableMacroDefinition.swift @@ -0,0 +1,11 @@ +// +// BuildableMacroDefinition.swift +// +// +// Created by Никита Коробейников on 25.07.2023. +// + +/// A macro which generate `func build` for all variables inside struct. +/// - Note: builder is based on resultBuilder from Swift 5.4 +@attached(member, names: named(set)) +public macro Buildable() = #externalMacro(module: "Macros", type: "BuildableMacro") diff --git a/Components/Macro/Sources/Macros/BuildableMacro.swift b/Components/Macro/Sources/Macros/BuildableMacro.swift new file mode 100644 index 00000000..41faa597 --- /dev/null +++ b/Components/Macro/Sources/Macros/BuildableMacro.swift @@ -0,0 +1,94 @@ +// +// BuildableMacro.swift +// +// +// Created by Никита Коробейников on 25.07.2023. +// + +import SwiftSyntax +import SwiftSyntaxBuilder +import SwiftSyntaxMacros + +/// A macro which generate `func build` for all variables inside struct. +/// - Note: builder is based on resultBuilder from Swift 5.4 +public struct BuildableMacro: MemberMacro { + + public static func expansion(of node: AttributeSyntax, providingMembersOf declaration: Declaration, in context: Context) throws -> [DeclSyntax] where Declaration : DeclGroupSyntax, Context : MacroExpansionContext { + guard let baseStruct = declaration.as(StructDeclSyntax.self) else { + throw MacroError.onlyApplicableToStruct + } + + let variables = baseStruct.variables + + let editors = try prepareEditorDeclarations(for: variables) + + let propertyStruct = preparePropertyStruct(for: baseStruct, with: editors) + + return [propertyStruct].compactMap { $0.as(DeclSyntax.self) } + } + +} + +// MARK: - Private + +private extension BuildableMacro { + +// static func prepareBuildFunction() -> FunctionDeclSyntax { +// .init(modifiers: .init(itemsBuilder: { +// DeclModifierSyntax(name: .keyword(.public)) +// DeclModifierSyntax(name: .keyword(.static)) +// }), +// identifier: .identifier("build"), +// signature: .init(input: .init(parameterListBuilder: { +// FunctionParameterSyntax(firstName: .identifier("content"), type: ClosureType) +// }))) +// } + + static func preparePropertyStruct(for baseStruct: StructDeclSyntax, with editors: [FunctionDeclSyntax]) -> StructDeclSyntax { + StructDeclSyntax(modifiers: .init(itemsBuilder: { + DeclModifierSyntax(name: .keyword(.public)) + }), + identifier: .identifier("Property"), + memberBlock: .init(membersBuilder: { + .init(itemsBuilder: { + TypealiasDeclSyntax( + modifiers: .init(itemsBuilder: { + DeclModifierSyntax(name: .keyword(.public)) + }), + identifier: + .identifier("Model"), + initializer: .init(baseStruct)!) + + }) + })) + } + + static func prepareEditorDeclarations(for variables: [VariableDeclSyntax]) throws -> [FunctionDeclSyntax] { + try variables.compactMap { variableDecl -> FunctionDeclSyntax? in + + guard let variable = try variableDecl.parseNameAndType() else { + return nil + } + + return FunctionDeclSyntax(leadingTrivia: .newlines(2), + modifiers: .init(itemsBuilder: { + DeclModifierSyntax(name: .keyword(.static)) + }), + identifier: .identifier(variable.name.text), + signature: .init(input: .init(parameterListBuilder: { + FunctionParameterSyntax(leadingTrivia: .space, + firstName: .identifier("value"), + type: variable.type) + })), + body: CodeBlockSyntax(statementsBuilder: { + .init([ + .init(stringLiteral: "var model = model"), + .init(stringLiteral: "model.set(\(variable.name.text):value)"), + .init(stringLiteral: "return model") + ]) + }) + ) + } + } + +} diff --git a/Components/Macro/Sources/Macros/Decl+Extensions.swift b/Components/Macro/Sources/Macros/Decl+Extensions.swift new file mode 100644 index 00000000..518b8107 --- /dev/null +++ b/Components/Macro/Sources/Macros/Decl+Extensions.swift @@ -0,0 +1,51 @@ +// +// Decl+Extensions.swift +// +// +// Created by Никита Коробейников on 25.07.2023. +// + +import SwiftSyntax +import SwiftSyntaxBuilder +import SwiftSyntaxMacros + +// MARK: - Struct + +extension StructDeclSyntax { + + var variables: [VariableDeclSyntax] { + return memberBlock.members + .compactMap { $0.decl.as(VariableDeclSyntax.self) } + .filter { $0.bindingKeyword.text == "var" } + } + + +} + +// MARK: - Variable + +extension VariableDeclSyntax { + + func parseNameAndType() throws -> (name: TokenSyntax, type: TypeSyntax)? { + guard let variableBinding = bindings.first, + let variableType = variableBinding.typeAnnotation?.type.trimmed else { + let variableName = bindings.first?.pattern.trimmedDescription + throw MacroError.typeAnnotationRequiredFor(variableName: variableName ?? "unknown") + } + + let variableName = TokenSyntax(stringLiteral: variableBinding.pattern.description) + + return (name: variableName, type: variableType) + } + +} + +// MARK: - CodeBlockExpression + +extension CodeBlockItemSyntax { + + static func stringItem(_ string: String) -> CodeBlockItemSyntax.Item { + CodeBlockItemSyntax.Item.expr(.init(stringLiteral: string)) + } + +} diff --git a/Components/Macro/Sources/Macros/MacroPlugin.swift b/Components/Macro/Sources/Macros/MacroPlugin.swift new file mode 100644 index 00000000..ec160a1f --- /dev/null +++ b/Components/Macro/Sources/Macros/MacroPlugin.swift @@ -0,0 +1,17 @@ +// +// MacroPlugin.swift +// +// +// Created by Никита Коробейников on 25.07.2023. +// + +import SwiftCompilerPlugin +import SwiftSyntaxMacros + +@main +struct MacroPlugin: CompilerPlugin { + let providingMacros: [Macro.Type] = [ + MutableMacro.self, + BuildableMacro.self + ] +} diff --git a/Components/Macro/Sources/Macros/MutableMacro.swift b/Components/Macro/Sources/Macros/MutableMacro.swift index b8efa615..0527a34c 100644 --- a/Components/Macro/Sources/Macros/MutableMacro.swift +++ b/Components/Macro/Sources/Macros/MutableMacro.swift @@ -1,4 +1,3 @@ -import SwiftCompilerPlugin import SwiftSyntax import SwiftSyntaxBuilder import SwiftSyntaxMacros @@ -11,47 +10,45 @@ public struct MutableMacro: MemberMacro { in context: Context) throws -> [DeclSyntax] where Declaration: DeclGroupSyntax, Context: MacroExpansionContext { - guard let structDecl = declaration.as(StructDeclSyntax.self) else { + guard let baseStruct = declaration.as(StructDeclSyntax.self) else { throw MacroError.onlyApplicableToStruct } - let variables = structDecl.memberBlock - .members - - .compactMap { $0.decl.as(VariableDeclSyntax.self) } - .filter { $0.bindingKeyword.text == "var" } - - let functions = try variables.compactMap { variableDecl -> FunctionDeclSyntax? in - guard let variableBinding = variableDecl.bindings.first, - let variableType = variableBinding.typeAnnotation?.type.trimmed else { - let variableName = variableDecl.bindings.first?.pattern.trimmedDescription - throw MacroError.typeAnnotationRequiredFor(variableName: variableName ?? "unknown") - } - - let variableName = TokenSyntax(stringLiteral: variableBinding.pattern.description) - - let parameter = FunctionParameterSyntax(firstName: variableName, type: variableType) - let parameterList = FunctionParameterListSyntax(arrayLiteral: parameter) - let modifiers = ModifierListSyntax(arrayLiteral: .init(name: .keyword(.mutating))) - let bodyItem = CodeBlockItemSyntax.Item.expr(.init(stringLiteral: "self.\(variableName.text)=\(variableName.text)")) - let body = CodeBlockSyntax(statements: .init(arrayLiteral: .init(item: bodyItem))) - - return FunctionDeclSyntax(leadingTrivia: .newlines(2), - modifiers: modifiers, - identifier: .identifier("set"), - signature: .init(input: .init(parameterList: parameterList)), - body: body - ) - } + let variables = baseStruct.variables + + let functions = try prepareEditorDeclarations(for: variables) return functions.compactMap { $0.as(DeclSyntax.self) } } } -@main -struct MacroPlugin: CompilerPlugin { - let providingMacros: [Macro.Type] = [ - MutableMacro.self - ] +// MARK: - Private + +private extension MutableMacro { + + static func prepareEditorDeclarations(for variables: [VariableDeclSyntax]) throws -> [FunctionDeclSyntax] { + try variables.compactMap { variableDecl -> FunctionDeclSyntax? in + + guard let variable = try variableDecl.parseNameAndType() else { + return nil + } + + return FunctionDeclSyntax(leadingTrivia: .newlines(2), + modifiers: .init(itemsBuilder: { + DeclModifierSyntax(name: .keyword(.mutating)) + }), + identifier: .identifier("set"), + signature: .init(input: .init(parameterListBuilder: { + FunctionParameterSyntax(firstName: variable.name, + type: variable.type) + + })), + body: .init(statementsBuilder: { + CodeBlockItemSyntax(stringLiteral: "self.\(variable.name.text)=\(variable.name.text)") + }) + ) + } + } + } diff --git a/Components/Macro/Tests/BuildableMacroTests.swift b/Components/Macro/Tests/BuildableMacroTests.swift new file mode 100644 index 00000000..0b10fcd7 --- /dev/null +++ b/Components/Macro/Tests/BuildableMacroTests.swift @@ -0,0 +1,70 @@ +// +// BuildableMacrosTests.swift +// +// +// Created by Никита Коробейников on 25.07.2023. +// + +import SwiftSyntaxMacros +import SwiftSyntaxMacrosTestSupport +import XCTest +import Macros + +final class BuildableMacroTests: XCTestCase { + + let testMacros: [String: Macro.Type] = [ + "Buildable": BuildableMacro.self + ] + + func testExpansionSucceded_whenAppliedToStruct_withVariablesAndType() { + assertMacroExpansion( + """ + @Buildable + struct SomeStruct { + let id: String = "" + var someVar: Bool = false + } + """, + expandedSource: + """ + + struct SomeStruct { + let id: String = "" + var someVar: Bool = false + + public struct Property: Editor { + public typealias Model = SomeStruct + + private let closure: (Model) -> Model + + public init(closure: @escaping (Model) -> Model) { + self.closure = closure + } + + public func edit(_ model: Model) -> Model { + return closure(model) + } + + public static func someVar(_ value: TextValue) -> Property { + .init(closure: { model in + var model = model + model.set(someVar: value) + return model + }) + } + } + + // MARK: - Builder + + public static func build(@EditorBuilder content: (Property.Type) -> [Property]) -> Self { + return content(Property.self).reduce(.init(), { model, editor in + editor.edit(model) + }) + } + } + """, + macros: testMacros + ) + } + +} diff --git a/Components/Macro/Tests/MutableMacroTests.swift b/Components/Macro/Tests/MutableMacroTests.swift index 03ff900a..6c1c5e14 100644 --- a/Components/Macro/Tests/MutableMacroTests.swift +++ b/Components/Macro/Tests/MutableMacroTests.swift @@ -3,12 +3,12 @@ import SwiftSyntaxMacrosTestSupport import XCTest import Macros -let testMacros: [String: Macro.Type] = [ - "Mutable": MutableMacro.self -] - final class MutableMacroTests: XCTestCase { + let testMacros: [String: Macro.Type] = [ + "Mutable": MutableMacro.self + ] + func testExpansionSucceded_whenAppliedToStruct_withVariablesAndType() { assertMacroExpansion( """ From 2f36fe1d8d3f031f91711cee640640a3f6fd4668 Mon Sep 17 00:00:00 2001 From: Nikita Korobeinikov Date: Wed, 26 Jul 2023 14:31:54 +0400 Subject: [PATCH 09/13] add propertywrapper protocol --- .../Macro/Sources/Macros/BuildableMacro.swift | 8 ++---- .../Macro/Sources/Macros/MutableMacro.swift | 2 +- .../Common/Protocols/PropertyWrapper.swift | 28 +++++++++++++++++++ .../Sources/Common/Views/LabelView.swift | 16 +++++------ .../Sources/Common/Views/MessageView.swift | 16 +++++------ 5 files changed, 46 insertions(+), 24 deletions(-) create mode 100644 Components/Sources/Common/Protocols/PropertyWrapper.swift diff --git a/Components/Macro/Sources/Macros/BuildableMacro.swift b/Components/Macro/Sources/Macros/BuildableMacro.swift index 41faa597..66f63564 100644 --- a/Components/Macro/Sources/Macros/BuildableMacro.swift +++ b/Components/Macro/Sources/Macros/BuildableMacro.swift @@ -81,11 +81,9 @@ private extension BuildableMacro { type: variable.type) })), body: CodeBlockSyntax(statementsBuilder: { - .init([ - .init(stringLiteral: "var model = model"), - .init(stringLiteral: "model.set(\(variable.name.text):value)"), - .init(stringLiteral: "return model") - ]) + StmtSyntax(stringLiteral: "var model = model") + StmtSyntax(stringLiteral: "model.set(\(variable.name.text):value)") + StmtSyntax(stringLiteral: "return model") }) ) } diff --git a/Components/Macro/Sources/Macros/MutableMacro.swift b/Components/Macro/Sources/Macros/MutableMacro.swift index 0527a34c..1042d244 100644 --- a/Components/Macro/Sources/Macros/MutableMacro.swift +++ b/Components/Macro/Sources/Macros/MutableMacro.swift @@ -45,7 +45,7 @@ private extension MutableMacro { })), body: .init(statementsBuilder: { - CodeBlockItemSyntax(stringLiteral: "self.\(variable.name.text)=\(variable.name.text)") + StmtSyntax(stringLiteral: "self.\(variable.name.text)=\(variable.name.text)") }) ) } diff --git a/Components/Sources/Common/Protocols/PropertyWrapper.swift b/Components/Sources/Common/Protocols/PropertyWrapper.swift new file mode 100644 index 00000000..88101471 --- /dev/null +++ b/Components/Sources/Common/Protocols/PropertyWrapper.swift @@ -0,0 +1,28 @@ +// +// PropertyWrapper.swift +// ReactiveDataDisplayManager +// +// Created by Никита Коробейников on 26.07.2023. +// + +import Foundation + +public protocol PropertyWrapper { + + associatedtype Property: Editor + + static func create() -> Property.Model + +} + +// MARK: - Defaults + +public extension PropertyWrapper where Property.Model == Self { + + static func build(@EditorBuilder content: (Property.Type) -> [Property]) -> Self { + return content(Property.self).reduce(Self.create(), { model, editor in + editor.edit(model) + }) + } + +} diff --git a/Components/Sources/Common/Views/LabelView.swift b/Components/Sources/Common/Views/LabelView.swift index 4f895bf5..f2704bc3 100644 --- a/Components/Sources/Common/Views/LabelView.swift +++ b/Components/Sources/Common/Views/LabelView.swift @@ -25,7 +25,13 @@ extension LabelView: ConfigurableItem { // MARK: - Model @Mutable - public struct Model: AlignmentProvider, TextProvider { + public struct Model: PropertyWrapper, AlignmentProvider, TextProvider { + + // MARK: - PropertyWrapper + + public static func create() -> LabelView.Model { + .init() + } // MARK: - Editor @@ -91,14 +97,6 @@ extension LabelView: ConfigurableItem { private(set) public var alignment: Alignment = .all(.zero) private(set) public var textAlignment: NSTextAlignment = .left - // MARK: - Builder - - public static func build(@EditorBuilder content: (Property.Type) -> [Property]) -> Self { - return content(Property.self).reduce(.init(), { model, editor in - editor.edit(model) - }) - } - } // MARK: - Methods diff --git a/Components/Sources/Common/Views/MessageView.swift b/Components/Sources/Common/Views/MessageView.swift index 7409e141..31b1fe10 100644 --- a/Components/Sources/Common/Views/MessageView.swift +++ b/Components/Sources/Common/Views/MessageView.swift @@ -26,7 +26,13 @@ extension MessageView: ConfigurableItem { // MARK: - Model @Mutable - public struct Model: Equatable, AlignmentProvider, TextProvider { + public struct Model: Equatable, PropertyWrapper, AlignmentProvider, TextProvider { + + // MARK: - PropertyWrapper + + public static func create() -> MessageView.Model { + .init() + } // MARK: - Editor @@ -138,14 +144,6 @@ extension MessageView: ConfigurableItem { private(set) public var dataDetection: DataDetectionStyle? private(set) public var selectable: Bool = false - // MARK: - Builder - - public static func build(@EditorBuilder content: (Property.Type) -> [Property]) -> Self { - return content(Property.self).reduce(.init(), { model, editor in - editor.edit(model) - }) - } - } // MARK: - Methods From c02405bb0774b13a0064af4a02478c26e1aacb65 Mon Sep 17 00:00:00 2001 From: Nikita Korobeinikov Date: Wed, 26 Jul 2023 15:23:44 +0400 Subject: [PATCH 10/13] add conformance to editor wrapper --- .../Macro/Sources/Macros/BuildableMacro.swift | 39 +++++++++++++------ .../Macro/Sources/Macros/MacroError.swift | 1 + .../Macro/Tests/BuildableMacroTests.swift | 14 +++---- .../Sources/Common/Protocols/Editor.swift | 24 ++++++++++++ .../Common/Protocols/PropertyWrapper.swift | 28 ------------- .../Sources/Common/Views/LabelView.swift | 4 +- .../Sources/Common/Views/MessageView.swift | 4 +- .../Impl/Protocols+PropertyWrapper.swift | 2 +- 8 files changed, 62 insertions(+), 54 deletions(-) delete mode 100644 Components/Sources/Common/Protocols/PropertyWrapper.swift diff --git a/Components/Macro/Sources/Macros/BuildableMacro.swift b/Components/Macro/Sources/Macros/BuildableMacro.swift index 66f63564..9262d990 100644 --- a/Components/Macro/Sources/Macros/BuildableMacro.swift +++ b/Components/Macro/Sources/Macros/BuildableMacro.swift @@ -11,7 +11,11 @@ import SwiftSyntaxMacros /// A macro which generate `func build` for all variables inside struct. /// - Note: builder is based on resultBuilder from Swift 5.4 -public struct BuildableMacro: MemberMacro { +public struct BuildableMacro: MemberMacro, ConformanceMacro { + + public static func expansion(of node: AttributeSyntax, providingConformancesOf declaration: Declaration, in context: Context) throws -> [(TypeSyntax, GenericWhereClauseSyntax?)] where Declaration : DeclGroupSyntax, Context : MacroExpansionContext { + return [(TypeSyntax(stringLiteral: "EditorWrapper"), nil)] + } public static func expansion(of node: AttributeSyntax, providingMembersOf declaration: Declaration, in context: Context) throws -> [DeclSyntax] where Declaration : DeclGroupSyntax, Context : MacroExpansionContext { guard let baseStruct = declaration.as(StructDeclSyntax.self) else { @@ -24,7 +28,14 @@ public struct BuildableMacro: MemberMacro { let propertyStruct = preparePropertyStruct(for: baseStruct, with: editors) - return [propertyStruct].compactMap { $0.as(DeclSyntax.self) } + let createFunc = try prepareCreateFunction(for: baseStruct) + + var result: [DeclSyntaxProtocol] = [] + + result.append(createFunc) + result.append(propertyStruct) + + return result.compactMap { $0.as(DeclSyntax.self) } } } @@ -33,16 +44,20 @@ public struct BuildableMacro: MemberMacro { private extension BuildableMacro { -// static func prepareBuildFunction() -> FunctionDeclSyntax { -// .init(modifiers: .init(itemsBuilder: { -// DeclModifierSyntax(name: .keyword(.public)) -// DeclModifierSyntax(name: .keyword(.static)) -// }), -// identifier: .identifier("build"), -// signature: .init(input: .init(parameterListBuilder: { -// FunctionParameterSyntax(firstName: .identifier("content"), type: ClosureType) -// }))) -// } + static func prepareCreateFunction(for baseStruct: StructDeclSyntax) throws -> FunctionDeclSyntax { + guard let baseStuctType = TypeSyntax(baseStruct) else { + throw MacroError.failedToExtractTypeOfBaseStruct + } + + return .init(modifiers: .init(itemsBuilder: { + DeclModifierSyntax(name: .keyword(.public)) + DeclModifierSyntax(name: .keyword(.static)) + }), + identifier: .identifier("create"), + signature: .init(input: .init(parameterListBuilder: { }), + output: .init(returnType: baseStuctType)) + ) + } static func preparePropertyStruct(for baseStruct: StructDeclSyntax, with editors: [FunctionDeclSyntax]) -> StructDeclSyntax { StructDeclSyntax(modifiers: .init(itemsBuilder: { diff --git a/Components/Macro/Sources/Macros/MacroError.swift b/Components/Macro/Sources/Macros/MacroError.swift index 07f7e98b..65fc94ef 100644 --- a/Components/Macro/Sources/Macros/MacroError.swift +++ b/Components/Macro/Sources/Macros/MacroError.swift @@ -9,5 +9,6 @@ public enum MacroError: Error { case onlyApplicableToStruct case typeAnnotationRequiredFor(variableName: String) + case failedToExtractTypeOfBaseStruct } diff --git a/Components/Macro/Tests/BuildableMacroTests.swift b/Components/Macro/Tests/BuildableMacroTests.swift index 0b10fcd7..2b08894a 100644 --- a/Components/Macro/Tests/BuildableMacroTests.swift +++ b/Components/Macro/Tests/BuildableMacroTests.swift @@ -28,10 +28,14 @@ final class BuildableMacroTests: XCTestCase { expandedSource: """ - struct SomeStruct { + struct SomeStruct: EditorWrapper { let id: String = "" var someVar: Bool = false + public static func create() -> SomeStruct { + .init() + } + public struct Property: Editor { public typealias Model = SomeStruct @@ -53,14 +57,6 @@ final class BuildableMacroTests: XCTestCase { }) } } - - // MARK: - Builder - - public static func build(@EditorBuilder content: (Property.Type) -> [Property]) -> Self { - return content(Property.self).reduce(.init(), { model, editor in - editor.edit(model) - }) - } } """, macros: testMacros diff --git a/Components/Sources/Common/Protocols/Editor.swift b/Components/Sources/Common/Protocols/Editor.swift index 511a131b..d7ea9d43 100644 --- a/Components/Sources/Common/Protocols/Editor.swift +++ b/Components/Sources/Common/Protocols/Editor.swift @@ -7,12 +7,24 @@ import Foundation +// MARK: - Protocols + public protocol Editor { associatedtype Model func edit(_ model: Model) -> Model } +public protocol EditorWrapper { + + associatedtype Property: Editor + + static func create() -> Property.Model + +} + +// MARK: - Builder + @resultBuilder public struct EditorBuilder { public static func buildExpression(_ expression: T) -> [T] { @@ -49,3 +61,15 @@ public struct EditorBuilder { return component ?? [] } } + +// MARK: - Shortcut + +public extension EditorWrapper where Property.Model == Self { + + static func build(@EditorBuilder content: (Property.Type) -> [Property]) -> Self { + return content(Property.self).reduce(Self.create(), { model, editor in + editor.edit(model) + }) + } + +} diff --git a/Components/Sources/Common/Protocols/PropertyWrapper.swift b/Components/Sources/Common/Protocols/PropertyWrapper.swift deleted file mode 100644 index 88101471..00000000 --- a/Components/Sources/Common/Protocols/PropertyWrapper.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// PropertyWrapper.swift -// ReactiveDataDisplayManager -// -// Created by Никита Коробейников on 26.07.2023. -// - -import Foundation - -public protocol PropertyWrapper { - - associatedtype Property: Editor - - static func create() -> Property.Model - -} - -// MARK: - Defaults - -public extension PropertyWrapper where Property.Model == Self { - - static func build(@EditorBuilder content: (Property.Type) -> [Property]) -> Self { - return content(Property.self).reduce(Self.create(), { model, editor in - editor.edit(model) - }) - } - -} diff --git a/Components/Sources/Common/Views/LabelView.swift b/Components/Sources/Common/Views/LabelView.swift index f2704bc3..3b950c11 100644 --- a/Components/Sources/Common/Views/LabelView.swift +++ b/Components/Sources/Common/Views/LabelView.swift @@ -25,9 +25,9 @@ extension LabelView: ConfigurableItem { // MARK: - Model @Mutable - public struct Model: PropertyWrapper, AlignmentProvider, TextProvider { + public struct Model: EditorWrapper, AlignmentProvider, TextProvider { - // MARK: - PropertyWrapper + // MARK: - EditorWrapper public static func create() -> LabelView.Model { .init() diff --git a/Components/Sources/Common/Views/MessageView.swift b/Components/Sources/Common/Views/MessageView.swift index 31b1fe10..b9ed88d9 100644 --- a/Components/Sources/Common/Views/MessageView.swift +++ b/Components/Sources/Common/Views/MessageView.swift @@ -26,9 +26,9 @@ extension MessageView: ConfigurableItem { // MARK: - Model @Mutable - public struct Model: Equatable, PropertyWrapper, AlignmentProvider, TextProvider { + public struct Model: Equatable, EditorWrapper, AlignmentProvider, TextProvider { - // MARK: - PropertyWrapper + // MARK: - EditorWrapper public static func create() -> MessageView.Model { .init() diff --git a/Example/ReactiveChat/Transport/Impl/Protocols+PropertyWrapper.swift b/Example/ReactiveChat/Transport/Impl/Protocols+PropertyWrapper.swift index 42cf03e6..5af3afb9 100644 --- a/Example/ReactiveChat/Transport/Impl/Protocols+PropertyWrapper.swift +++ b/Example/ReactiveChat/Transport/Impl/Protocols+PropertyWrapper.swift @@ -1,5 +1,5 @@ // -// Protocols+PropertyWrapper.swift +// Protocols+EditorWrapper.swift // ReactiveChat_iOS // // Created by Никита Коробейников on 29.05.2023. From 3771e0514c565fe47a5505308dbe8bf7e7ceea74 Mon Sep 17 00:00:00 2001 From: Nikita Korobeinikov Date: Wed, 26 Jul 2023 16:43:08 +0400 Subject: [PATCH 11/13] fix macrodefinition --- .../Macro/BuildableMacroDefinition.swift | 11 ----------- ...oDefinition.swift => MacroDefinition.swift} | 4 ++++ .../Macro/Sources/Macros/BuildableMacro.swift | 10 ++++++---- .../Macro/Sources/Macros/MutableMacro.swift | 18 +++++++----------- 4 files changed, 17 insertions(+), 26 deletions(-) delete mode 100644 Components/Macro/Sources/Macro/BuildableMacroDefinition.swift rename Components/Macro/Sources/Macro/{MutableMacroDefinition.swift => MacroDefinition.swift} (61%) diff --git a/Components/Macro/Sources/Macro/BuildableMacroDefinition.swift b/Components/Macro/Sources/Macro/BuildableMacroDefinition.swift deleted file mode 100644 index 4ecc4e3c..00000000 --- a/Components/Macro/Sources/Macro/BuildableMacroDefinition.swift +++ /dev/null @@ -1,11 +0,0 @@ -// -// BuildableMacroDefinition.swift -// -// -// Created by Никита Коробейников on 25.07.2023. -// - -/// A macro which generate `func build` for all variables inside struct. -/// - Note: builder is based on resultBuilder from Swift 5.4 -@attached(member, names: named(set)) -public macro Buildable() = #externalMacro(module: "Macros", type: "BuildableMacro") diff --git a/Components/Macro/Sources/Macro/MutableMacroDefinition.swift b/Components/Macro/Sources/Macro/MacroDefinition.swift similarity index 61% rename from Components/Macro/Sources/Macro/MutableMacroDefinition.swift rename to Components/Macro/Sources/Macro/MacroDefinition.swift index 4b2114e3..237247ce 100644 --- a/Components/Macro/Sources/Macro/MutableMacroDefinition.swift +++ b/Components/Macro/Sources/Macro/MacroDefinition.swift @@ -4,3 +4,7 @@ /// A macro which generate `mutating func` for all variables inside struct. @attached(member, names: named(set)) public macro Mutable() = #externalMacro(module: "Macros", type: "MutableMacro") + +@attached(conformance) +@attached(member, names: named(create), named(Property)) +public macro Buildable() = #externalMacro(module: "Macros", type: "BuildableMacro") diff --git a/Components/Macro/Sources/Macros/BuildableMacro.swift b/Components/Macro/Sources/Macros/BuildableMacro.swift index 9262d990..ea71209d 100644 --- a/Components/Macro/Sources/Macros/BuildableMacro.swift +++ b/Components/Macro/Sources/Macros/BuildableMacro.swift @@ -13,11 +13,11 @@ import SwiftSyntaxMacros /// - Note: builder is based on resultBuilder from Swift 5.4 public struct BuildableMacro: MemberMacro, ConformanceMacro { - public static func expansion(of node: AttributeSyntax, providingConformancesOf declaration: Declaration, in context: Context) throws -> [(TypeSyntax, GenericWhereClauseSyntax?)] where Declaration : DeclGroupSyntax, Context : MacroExpansionContext { + public static func expansion(of node: SwiftSyntax.AttributeSyntax, providingConformancesOf declaration: some SwiftSyntax.DeclGroupSyntax, in context: some SwiftSyntaxMacros.MacroExpansionContext) throws -> [(SwiftSyntax.TypeSyntax, SwiftSyntax.GenericWhereClauseSyntax?)] { return [(TypeSyntax(stringLiteral: "EditorWrapper"), nil)] } - public static func expansion(of node: AttributeSyntax, providingMembersOf declaration: Declaration, in context: Context) throws -> [DeclSyntax] where Declaration : DeclGroupSyntax, Context : MacroExpansionContext { + public static func expansion(of node: SwiftSyntax.AttributeSyntax, providingMembersOf declaration: some SwiftSyntax.DeclGroupSyntax, in context: some SwiftSyntaxMacros.MacroExpansionContext) throws -> [SwiftSyntax.DeclSyntax] { guard let baseStruct = declaration.as(StructDeclSyntax.self) else { throw MacroError.onlyApplicableToStruct } @@ -37,7 +37,7 @@ public struct BuildableMacro: MemberMacro, ConformanceMacro { return result.compactMap { $0.as(DeclSyntax.self) } } - + } // MARK: - Private @@ -73,7 +73,9 @@ private extension BuildableMacro { identifier: .identifier("Model"), initializer: .init(baseStruct)!) - + VariableDeclSyntax(modifiers: .init(itemsBuilder: { + DeclModifierSyntax(name: .keyword(.private)) + }), .keyword(.let), name: .init(stringLiteral: "closure")) }) })) } diff --git a/Components/Macro/Sources/Macros/MutableMacro.swift b/Components/Macro/Sources/Macros/MutableMacro.swift index 1042d244..004c6d91 100644 --- a/Components/Macro/Sources/Macros/MutableMacro.swift +++ b/Components/Macro/Sources/Macros/MutableMacro.swift @@ -5,20 +5,16 @@ import SwiftSyntaxMacros /// A macro which generate `mutating func` for all variables inside struct. public struct MutableMacro: MemberMacro { - public static func expansion(of node: AttributeSyntax, - providingMembersOf declaration: Declaration, - in context: Context) throws -> [DeclSyntax] - where Declaration: DeclGroupSyntax, - Context: MacroExpansionContext { - guard let baseStruct = declaration.as(StructDeclSyntax.self) else { - throw MacroError.onlyApplicableToStruct - } + public static func expansion(of node: SwiftSyntax.AttributeSyntax, providingMembersOf declaration: some SwiftSyntax.DeclGroupSyntax, in context: some SwiftSyntaxMacros.MacroExpansionContext) throws -> [SwiftSyntax.DeclSyntax] { + guard let baseStruct = declaration.as(StructDeclSyntax.self) else { + throw MacroError.onlyApplicableToStruct + } - let variables = baseStruct.variables + let variables = baseStruct.variables - let functions = try prepareEditorDeclarations(for: variables) + let functions = try prepareEditorDeclarations(for: variables) - return functions.compactMap { $0.as(DeclSyntax.self) } + return functions.compactMap { $0.as(DeclSyntax.self) } } } From e398300b43e3ef239bfb5d7c8e3a5c5d50ae0747 Mon Sep 17 00:00:00 2001 From: Nikita Korobeinikov Date: Fri, 4 Aug 2023 15:18:34 +0400 Subject: [PATCH 12/13] fix building of macros --- Components/Macro/Sources/Macros/BuildableMacro.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Components/Macro/Sources/Macros/BuildableMacro.swift b/Components/Macro/Sources/Macros/BuildableMacro.swift index ea71209d..0353150b 100644 --- a/Components/Macro/Sources/Macros/BuildableMacro.swift +++ b/Components/Macro/Sources/Macros/BuildableMacro.swift @@ -73,9 +73,10 @@ private extension BuildableMacro { identifier: .identifier("Model"), initializer: .init(baseStruct)!) - VariableDeclSyntax(modifiers: .init(itemsBuilder: { - DeclModifierSyntax(name: .keyword(.private)) - }), .keyword(.let), name: .init(stringLiteral: "closure")) + +// VariableDeclSyntax(modifiers: .init(itemsBuilder: { +// DeclModifierSyntax(name: .keyword(.private)) +// }), name: .init(stringLiteral: "closure"), .keyword(.let)) }) })) } From 1a5c5ad97810baf18b594b84b6125782cf9e9c7d Mon Sep 17 00:00:00 2001 From: Nikita Korobeinikov Date: Fri, 4 Aug 2023 15:18:48 +0400 Subject: [PATCH 13/13] fix mutable macro test --- Components/Macro/Sources/Macros/MutableMacro.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Components/Macro/Sources/Macros/MutableMacro.swift b/Components/Macro/Sources/Macros/MutableMacro.swift index 004c6d91..d746c974 100644 --- a/Components/Macro/Sources/Macros/MutableMacro.swift +++ b/Components/Macro/Sources/Macros/MutableMacro.swift @@ -41,7 +41,7 @@ private extension MutableMacro { })), body: .init(statementsBuilder: { - StmtSyntax(stringLiteral: "self.\(variable.name.text)=\(variable.name.text)") + ExprSyntax(stringLiteral: "self.\(variable.name.text)=\(variable.name.text)") }) ) }