-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Pablo Guardiola
committed
Nov 11, 2024
1 parent
4d2986e
commit e75bdba
Showing
20 changed files
with
722 additions
and
0 deletions.
There are no files selected for viewing
Binary file modified
BIN
+968 Bytes
(100%)
...eproj/project.xcworkspace/xcuserdata/pablojota.xcuserdatad/UserInterfaceState.xcuserstate
Binary file not shown.
Binary file modified
BIN
+388 Bytes
(100%)
...eproj/project.xcworkspace/xcuserdata/pablojota.xcuserdatad/UserInterfaceState.xcuserstate
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"originHash" : "0220b7139e3a149ad907bfb9408312c7d6d65cc7a606e0728e52834fab3778d5", | ||
"pins" : [ | ||
{ | ||
"identity" : "swift-syntax", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/swiftlang/swift-syntax.git", | ||
"state" : { | ||
"revision" : "0687f71944021d616d34d922343dcef086855920", | ||
"version" : "600.0.1" | ||
} | ||
} | ||
], | ||
"version" : 3 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// swift-tools-version: 6.0 | ||
// The swift-tools-version declares the minimum version of Swift required to build this package. | ||
|
||
import PackageDescription | ||
import CompilerPluginSupport | ||
|
||
let package = Package( | ||
name: "EducaSwiftHexMacroPackage", | ||
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: "EducaSwiftHexMacroPackage", | ||
targets: ["EducaSwiftHexMacroPackage"] | ||
), | ||
.executable( | ||
name: "EducaSwiftHexMacroPackageClient", | ||
targets: ["EducaSwiftHexMacroPackageClient"] | ||
), | ||
], | ||
dependencies: [ | ||
.package(url: "https://github.com/swiftlang/swift-syntax.git", from: "600.0.0-latest"), | ||
], | ||
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: "EducaSwiftHexMacroPackageMacros", | ||
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: "EducaSwiftHexMacroPackage", dependencies: ["EducaSwiftHexMacroPackageMacros"]), | ||
|
||
// A client of the library, which is able to use the macro in its own code. | ||
.executableTarget(name: "EducaSwiftHexMacroPackageClient", dependencies: ["EducaSwiftHexMacroPackage"]), | ||
|
||
// A test target used to develop the macro implementation. | ||
.testTarget( | ||
name: "EducaSwiftHexMacroPackageTests", | ||
dependencies: [ | ||
"EducaSwiftHexMacroPackageMacros", | ||
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"), | ||
] | ||
), | ||
] | ||
) |
12 changes: 12 additions & 0 deletions
12
...ucaSwiftHexMacroPackage/Sources/EducaSwiftHexMacroPackage/EducaSwiftHexMacroPackage.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import SwiftUI | ||
|
||
// The Swift Programming Language | ||
// https://docs.swift.org/swift-book | ||
|
||
/// A macro that produces a Color from an hex value. For example, | ||
/// | ||
/// #hexColor("FF00FF") // or FFFF00FF to include alpha value | ||
/// | ||
/// produces a `Color`. | ||
@freestanding(expression) | ||
public macro hexColor(_ hex: String) -> Color = #externalMacro(module: "EducaSwiftHexMacroPackageMacros", type: "HexColorMacro") |
6 changes: 6 additions & 0 deletions
6
Articles/EducaSwiftHexMacroPackage/Sources/EducaSwiftHexMacroPackageClient/main.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import EducaSwiftHexMacroPackage | ||
import SwiftUI | ||
|
||
let color = #hexColor("FFFF00FF") | ||
|
||
print("The value FFFF00FF was produced by the code \"\(color)\"") |
85 changes: 85 additions & 0 deletions
85
...MacroPackage/Sources/EducaSwiftHexMacroPackageMacros/EducaSwiftHexMacroPackageMacro.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import SwiftCompilerPlugin | ||
import SwiftSyntax | ||
import SwiftSyntaxBuilder | ||
import SwiftSyntaxMacros | ||
import SwiftUI | ||
|
||
public enum HexColorMacroError: Error { | ||
|
||
case inputNotValid | ||
case lengthNotValid | ||
|
||
var description: String { | ||
switch self { | ||
case .inputNotValid: | ||
return "Input is not valid." | ||
case .lengthNotValid: | ||
return "Length not valid." | ||
} | ||
} | ||
} | ||
|
||
/// Implementation of the `hexColor` macro, which takes an String | ||
/// and produces a Color with rgba values. For example | ||
/// | ||
/// #hexColor("FFFF00FF") // a-r-g-b | ||
/// | ||
/// will expand to | ||
/// | ||
/// Color( | ||
/// .sRGB, | ||
/// red: 1.0, | ||
/// green: 0.0, | ||
/// blue: 1.0, | ||
/// opacity: 1.0 | ||
/// ) | ||
public struct HexColorMacro: ExpressionMacro { | ||
public static func expansion( | ||
of node: some FreestandingMacroExpansionSyntax, | ||
in context: some MacroExpansionContext | ||
) throws -> ExprSyntax { | ||
guard let argument = node.arguments.first?.expression, | ||
let segments = argument.as(StringLiteralExprSyntax.self)?.segments, | ||
segments.count == 1, | ||
case .stringSegment(let literalSegment)? = segments.first | ||
else { | ||
throw HexColorMacroError.inputNotValid | ||
} | ||
|
||
guard literalSegment.content.text.count == 6 || literalSegment.content.text.count == 8 else { | ||
throw HexColorMacroError.lengthNotValid | ||
} | ||
|
||
let hex = literalSegment.content.text.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) | ||
var int: UInt64 = 0 | ||
Scanner(string: hex).scanHexInt64(&int) | ||
let a, r, g, b: UInt64 | ||
switch hex.count { | ||
case 3: // RGB (12-bit) | ||
(a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17) | ||
case 6: // RGB (24-bit) | ||
(a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF) | ||
case 8: // ARGB (32-bit) | ||
(a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF) | ||
default: | ||
(a, r, g, b) = (1, 1, 1, 0) | ||
} | ||
|
||
return """ | ||
Color( | ||
.sRGB, | ||
red: \(raw: Double(r) / 255), | ||
green: \(raw: Double(g) / 255), | ||
blue: \(raw: Double(b) / 255), | ||
opacity: \(raw: Double(a) / 255) | ||
) | ||
""" | ||
} | ||
} | ||
|
||
@main | ||
struct EducaSwiftHexMacroPackagePlugin: CompilerPlugin { | ||
let providingMacros: [Macro.Type] = [ | ||
HexColorMacro.self, | ||
] | ||
} |
38 changes: 38 additions & 0 deletions
38
...HexMacroPackage/Tests/EducaSwiftHexMacroPackageTests/EducaSwiftHexMacroPackageTests.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import SwiftSyntax | ||
import SwiftSyntaxBuilder | ||
import SwiftSyntaxMacros | ||
import SwiftSyntaxMacrosTestSupport | ||
import XCTest | ||
|
||
// Macro implementations build for the host, so the corresponding module is not available when cross-compiling. Cross-compiled tests may still make use of the macro itself in end-to-end tests. | ||
#if canImport(EducaSwiftHexMacroPackageMacros) | ||
import EducaSwiftHexMacroPackageMacros | ||
|
||
let testMacros: [String: Macro.Type] = [ | ||
"hexColor": HexColorMacro.self, | ||
] | ||
#endif | ||
|
||
final class EducaSwiftHexMacroPackageTests: XCTestCase { | ||
func testMacro() throws { | ||
#if canImport(EducaSwiftHexMacroPackageMacros) | ||
assertMacroExpansion( | ||
""" | ||
#hexColor("FFFF00FF") | ||
""", | ||
expandedSource: """ | ||
Color( | ||
.sRGB, | ||
red: 1.0, | ||
green: 1.0, | ||
blue: 1.0, | ||
opacity: 1.0 | ||
) | ||
""", | ||
macros: testMacros | ||
) | ||
#else | ||
throw XCTSkip("macros are only supported when running tests for the host platform") | ||
#endif | ||
} | ||
} |
Oops, something went wrong.