-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: introduce WireMacros - no ticket #1694
base: develop
Are you sure you want to change the base?
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
.DS_Store | ||
/.build | ||
/Packages | ||
xcuserdata/ | ||
DerivedData/ | ||
.swiftpm/configuration/registries.json | ||
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata | ||
.netrc |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<Scheme | ||
LastUpgradeVersion = "1540" | ||
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 = "WireMacros" | ||
BuildableName = "WireMacros" | ||
BlueprintName = "WireMacros" | ||
ReferencedContainer = "container:"> | ||
</BuildableReference> | ||
</BuildActionEntry> | ||
</BuildActionEntries> | ||
</BuildAction> | ||
<TestAction | ||
buildConfiguration = "Debug" | ||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" | ||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" | ||
shouldUseLaunchSchemeArgsEnv = "YES"> | ||
<TestPlans> | ||
<TestPlanReference | ||
reference = "container:Tests/WireMacrosTests/WireMacros.xctestplan" | ||
default = "YES"> | ||
</TestPlanReference> | ||
</TestPlans> | ||
</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 = "WireMacros" | ||
BuildableName = "WireMacros" | ||
BlueprintName = "WireMacros" | ||
ReferencedContainer = "container:"> | ||
</BuildableReference> | ||
</MacroExpansion> | ||
</ProfileAction> | ||
<AnalyzeAction | ||
buildConfiguration = "Debug"> | ||
</AnalyzeAction> | ||
<ArchiveAction | ||
buildConfiguration = "Release" | ||
revealArchiveInOrganizer = "YES"> | ||
</ArchiveAction> | ||
</Scheme> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<Scheme | ||
LastUpgradeVersion = "1540" | ||
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 = "WireMacrosClient" | ||
BuildableName = "WireMacrosClient" | ||
BlueprintName = "WireMacrosClient" | ||
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"> | ||
<BuildableProductRunnable | ||
runnableDebuggingMode = "0"> | ||
<BuildableReference | ||
BuildableIdentifier = "primary" | ||
BlueprintIdentifier = "WireMacrosClient" | ||
BuildableName = "WireMacrosClient" | ||
BlueprintName = "WireMacrosClient" | ||
ReferencedContainer = "container:"> | ||
</BuildableReference> | ||
</BuildableProductRunnable> | ||
</LaunchAction> | ||
<ProfileAction | ||
buildConfiguration = "Release" | ||
shouldUseLaunchSchemeArgsEnv = "YES" | ||
savedToolIdentifier = "" | ||
useCustomWorkingDirectory = "NO" | ||
debugDocumentVersioning = "YES"> | ||
<BuildableProductRunnable | ||
runnableDebuggingMode = "0"> | ||
<BuildableReference | ||
BuildableIdentifier = "primary" | ||
BlueprintIdentifier = "WireMacrosClient" | ||
BuildableName = "WireMacrosClient" | ||
BlueprintName = "WireMacrosClient" | ||
ReferencedContainer = "container:"> | ||
</BuildableReference> | ||
</BuildableProductRunnable> | ||
</ProfileAction> | ||
<AnalyzeAction | ||
buildConfiguration = "Debug"> | ||
</AnalyzeAction> | ||
<ArchiveAction | ||
buildConfiguration = "Release" | ||
revealArchiveInOrganizer = "YES"> | ||
</ArchiveAction> | ||
</Scheme> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// swift-tools-version: 5.10 | ||
// The swift-tools-version declares the minimum version of Swift required to build this package. | ||
|
||
import PackageDescription | ||
import CompilerPluginSupport | ||
|
||
let package = Package( | ||
name: "WireMacros", | ||
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: "WireMacros", | ||
targets: ["WireMacros"] | ||
), | ||
.executable( | ||
name: "WireMacrosClient", | ||
targets: ["WireMacrosClient"] | ||
), | ||
], | ||
dependencies: [ | ||
.package(url: "https://github.com/apple/swift-syntax.git", from: "509.0.0"), | ||
], | ||
targets: [ | ||
// Targets are the basic building blocks of a package, defining a module or a test suite. | ||
// Targets can depend on other targets in this package and products from dependencies. | ||
// Macro implementation that performs the source transformation of a macro. | ||
.macro( | ||
name: "WireMacrosMacros", | ||
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: "WireMacros", dependencies: ["WireMacrosMacros"]), | ||
|
||
// A client of the library, which is able to use the macro in its own code. | ||
.executableTarget(name: "WireMacrosClient", dependencies: ["WireMacros"]), | ||
|
||
// A test target used to develop the macro implementation. | ||
.testTarget( | ||
name: "WireMacrosTests", | ||
dependencies: [ | ||
"WireMacrosMacros", | ||
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"), | ||
] | ||
), | ||
] | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// | ||
// Wire | ||
// Copyright (C) 2024 Wire Swiss GmbH | ||
// | ||
// This program is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// This program is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with this program. If not, see http://www.gnu.org/licenses/. | ||
// | ||
|
||
import Foundation | ||
|
||
/// A macro that, when attached to a protocol declaration, produces a | ||
/// companion "provider" protocol that can be used inject dependencies. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is pretty interesting. I need to take a look to understand the |
||
/// | ||
/// For example: | ||
/// | ||
/// @Provided | ||
/// protocol MyUseCase { | ||
/// func invoke() | ||
/// } | ||
/// | ||
/// will expand to: | ||
/// | ||
/// protocol MyUseCase { | ||
/// func invoke() | ||
/// } | ||
/// | ||
/// protocol MyUseCaseProvider { | ||
/// func makeMyUseCase() -> any MyUseCase | ||
/// } | ||
/// | ||
/// Any object that is capable of providing the use case can | ||
/// conform to the provider protocol: | ||
/// | ||
/// extension Factory: MyUseCaseProvider { | ||
/// func makeMyUseCase() -> any MyUseCase { | ||
/// MyUseCase(...) | ||
/// } | ||
/// } | ||
/// | ||
/// Instead of injecting a concrete `Factory`, we can now inject | ||
/// some provider: | ||
/// | ||
/// class MyViewModel { | ||
/// | ||
/// let provider: some MyUseCaseProvider | ||
/// | ||
/// func doSomething() { | ||
/// let useCase = provider.makeMyUseCase() | ||
/// useCase.invoke() | ||
/// } | ||
/// | ||
/// } | ||
|
||
@attached(peer, names: suffixed(Provider)) | ||
public macro Provided() = #externalMacro( | ||
module: "WireMacrosMacros", | ||
type: "ProvidedMacro" | ||
) | ||
|
||
/// A macro that validates UUID strings. | ||
/// | ||
/// For example: | ||
/// | ||
/// let validUUID = #UUID("7411ca17-ba08-4905-92d2-0617a8c810ca") | ||
/// | ||
/// will compile and produce a non-optional `UUID`. On the otherhand: | ||
/// | ||
/// let invalidUUID = #UUID("foo") | ||
/// | ||
/// will throw a compile time error. | ||
|
||
@freestanding(expression) | ||
public macro UUID( | ||
_ stringLiteral: String | ||
) -> UUID = #externalMacro( | ||
module: "WireMacrosMacros", | ||
type: "UUIDMacro" | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
// | ||
// Wire | ||
// Copyright (C) 2024 Wire Swiss GmbH | ||
// | ||
// This program is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// This program is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with this program. If not, see http://www.gnu.org/licenses/. | ||
// | ||
|
||
import Foundation | ||
import WireMacros | ||
|
||
@Provided | ||
public protocol FooUseCaseProtocol { | ||
|
||
func invoke() | ||
|
||
} | ||
|
||
struct FooUseCase: FooUseCaseProtocol { | ||
|
||
func invoke() { | ||
|
||
} | ||
|
||
} | ||
|
||
struct FooUseCaseProvider: FooUseCaseProtocolProvider { | ||
|
||
func makeFooUseCaseProtocol() -> any FooUseCaseProtocol { | ||
FooUseCase() | ||
} | ||
|
||
} | ||
|
||
let uuid = #UUID("7411ca17-ba08-4905-92d2-0617a8c810ca") | ||
print(uuid) | ||
Comment on lines
+45
to
+46
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should these lines here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This main file is kind of a playground to develop the macros.... maybe it's not needed since we can do that in tests and/or in our other modules. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd probably remove these two lines of comments