Skip to content

Commit

Permalink
Add Access Levels with Tests (#2)
Browse files Browse the repository at this point in the history
* Add Access Levels with Tests

* Bumped swift-syntax version and updated Unit tests

---------

Co-authored-by: Lukas Pistrol <[email protected]>
  • Loading branch information
hi2gage and lukepistrol authored Oct 18, 2023
1 parent 7b25b07 commit 728ac4c
Show file tree
Hide file tree
Showing 3 changed files with 233 additions and 8 deletions.
4 changes: 2 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -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" : "74203046135342e4a4a627476dd6caf8b28fe11b",
"version" : "509.0.0"
}
}
],
Expand Down
37 changes: 32 additions & 5 deletions Sources/SFSymbolsMacroImpl/SFSymbolsMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,32 @@ public struct SFSymbolMacro: MemberMacro {
in context: Context
) throws -> [DeclSyntax] {
try validate(declaration)
let accessLevel = try getAccessLevel(declaration)

return [
"""
var image: Image {
\(raw: accessLevel)var image: Image {
Image(systemName: self.rawValue)
}
""",
"""
var name: String {
\(raw: accessLevel)var name: String {
self.rawValue
}
""",
"""
#if canImport(UIKit)
func uiImage(configuration: UIImage.Configuration? = nil) -> UIImage {
\(raw: accessLevel)func uiImage(configuration: UIImage.Configuration? = nil) -> UIImage {
UIImage(systemName: self.rawValue, withConfiguration: configuration)!
}
#else
func nsImage(accessibilityDescription: String? = nil) -> NSImage {
\(raw: accessLevel)func nsImage(accessibilityDescription: String? = nil) -> NSImage {
return NSImage(systemSymbolName: self.rawValue, accessibilityDescription: accessibilityDescription)!
}
#endif
""",
"""
func callAsFunction() -> String {
\(raw: accessLevel)func callAsFunction() -> String {
return self.rawValue
}
"""
Expand Down Expand Up @@ -105,4 +107,29 @@ public struct SFSymbolMacro: MemberMacro {
.init(node: id.node, message: SFSymbolDiagnostic.noValidSFSymbol(symbol: id.0))
])
}

/// Gets access level
private static func getAccessLevel(_ declaration: DeclGroupSyntax) throws -> String {
guard let enumdeclaration = declaration.as(EnumDeclSyntax.self) else {
throw DiagnosticsError(diagnostics: [
.init(node: Syntax(declaration), message: SFSymbolDiagnostic.notAnEnum)
])
}
guard let accessLevel = enumdeclaration.modifiers.first(where: \.isNeededAccessLevelModifier)?.name.trimmed else {
return ""
}
return "\(accessLevel.text) "
}
}

extension DeclModifierSyntax {
var isNeededAccessLevelModifier: Bool {
switch self.name.tokenKind {
case .keyword(.public): return true
case .keyword(.internal): return true
case .keyword(.fileprivate): return true
case .keyword(.private): return true
default: return false
}
}
}
200 changes: 199 additions & 1 deletion Tests/SFSymbolsMacroTests/SFSymbolsMacroTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@ final class SFSymbolsMacroTests: XCTestCase {
enum Symbols: String {
case globe
case circleFill = "circle.fill"
var image: Image {
Image(systemName: self.rawValue)
}
var name: String {
self.rawValue
}
#if canImport(UIKit)
#if canImport (UIKit)
func uiImage(configuration: UIImage.Configuration? = nil) -> UIImage {
UIImage(systemName: self.rawValue, withConfiguration: configuration)!
}
Expand All @@ -39,6 +42,7 @@ final class SFSymbolsMacroTests: XCTestCase {
return NSImage(systemSymbolName: self.rawValue, accessibilityDescription: accessibilityDescription)!
}
#endif
func callAsFunction() -> String {
return self.rawValue
}
Expand All @@ -48,6 +52,178 @@ final class SFSymbolsMacroTests: XCTestCase {
)
}

func testPublicSFSymbolMacro() {
assertMacroExpansion(
"""
@SFSymbol
public enum Symbols: String {
case globe
case circleFill = "circle.fill"
}
""",
expandedSource:
"""
public enum Symbols: String {
case globe
case circleFill = "circle.fill"
public var image: Image {
Image(systemName: self.rawValue)
}
public var name: String {
self.rawValue
}
#if canImport (UIKit)
public func uiImage(configuration: UIImage.Configuration? = nil) -> UIImage {
UIImage(systemName: self.rawValue, withConfiguration: configuration)!
}
#else
public func nsImage(accessibilityDescription: String? = nil) -> NSImage {
return NSImage(systemSymbolName: self.rawValue, accessibilityDescription: accessibilityDescription)!
}
#endif
public func callAsFunction() -> String {
return self.rawValue
}
}
""",
macros: testMacros
)
}

func testInternalSFSymbolMacro() {
assertMacroExpansion(
"""
@SFSymbol
internal enum Symbols: String {
case globe
case circleFill = "circle.fill"
}
""",
expandedSource:
"""
internal enum Symbols: String {
case globe
case circleFill = "circle.fill"
internal var image: Image {
Image(systemName: self.rawValue)
}
internal var name: String {
self.rawValue
}
#if canImport (UIKit)
internal func uiImage(configuration: UIImage.Configuration? = nil) -> UIImage {
UIImage(systemName: self.rawValue, withConfiguration: configuration)!
}
#else
internal func nsImage(accessibilityDescription: String? = nil) -> NSImage {
return NSImage(systemSymbolName: self.rawValue, accessibilityDescription: accessibilityDescription)!
}
#endif
internal func callAsFunction() -> String {
return self.rawValue
}
}
""",
macros: testMacros
)
}

func testFilePrivateSFSymbolMacro() {
assertMacroExpansion(
"""
@SFSymbol
fileprivate enum Symbols: String {
case globe
case circleFill = "circle.fill"
}
""",
expandedSource:
"""
fileprivate enum Symbols: String {
case globe
case circleFill = "circle.fill"
fileprivate var image: Image {
Image(systemName: self.rawValue)
}
fileprivate var name: String {
self.rawValue
}
#if canImport (UIKit)
fileprivate func uiImage(configuration: UIImage.Configuration? = nil) -> UIImage {
UIImage(systemName: self.rawValue, withConfiguration: configuration)!
}
#else
fileprivate func nsImage(accessibilityDescription: String? = nil) -> NSImage {
return NSImage(systemSymbolName: self.rawValue, accessibilityDescription: accessibilityDescription)!
}
#endif
fileprivate func callAsFunction() -> String {
return self.rawValue
}
}
""",
macros: testMacros
)
}

func testPrivateSFSymbolMacro() {
assertMacroExpansion(
"""
@SFSymbol
private enum Symbols: String {
case globe
case circleFill = "circle.fill"
}
""",
expandedSource:
"""
private enum Symbols: String {
case globe
case circleFill = "circle.fill"
private var image: Image {
Image(systemName: self.rawValue)
}
private var name: String {
self.rawValue
}
#if canImport (UIKit)
private func uiImage(configuration: UIImage.Configuration? = nil) -> UIImage {
UIImage(systemName: self.rawValue, withConfiguration: configuration)!
}
#else
private func nsImage(accessibilityDescription: String? = nil) -> NSImage {
return NSImage(systemSymbolName: self.rawValue, accessibilityDescription: accessibilityDescription)!
}
#endif
private func callAsFunction() -> String {
return self.rawValue
}
}
""",
macros: testMacros
)
}

func testInvalidSFSymbolError() {
assertMacroExpansion(
"""
Expand Down Expand Up @@ -135,4 +311,26 @@ final class SFSymbolsMacroTests: XCTestCase {
macros: testMacros
)
}

func testInvalidModifier() {
assertMacroExpansion(
"""
@SFSymbol
struct Symbols {
let xyz = "xyz"
}
""",
expandedSource:
"""
struct Symbols {
let xyz = "xyz"
}
""",
diagnostics: [
.init(message: "Macro \"@SFSymbol\" can only be applied to enums.", line: 1, column: 1)
],
macros: testMacros
)
}
}

0 comments on commit 728ac4c

Please sign in to comment.