diff --git a/Package.resolved b/Package.resolved index c277d2e..00d1d75 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "ce25c9bdeb39120a6e58c3aa2fa205e436aca11542cc194f7b4520aecb86b27d", + "originHash" : "db12584d48eea6de43652535e6f196bf16b860f1a22c890a09e0ccf979302a90", "pins" : [ { "identity" : "swift-mustache", @@ -7,7 +7,7 @@ "location" : "https://github.com/mahdibm/swift-mustache", "state" : { "branch" : "mmbm-swift-6", - "revision" : "e23122de36452ff04699b0fccc9a53866250c239" + "revision" : "72f3279b228908c786d80289e7260439163654f2" } }, { diff --git a/Sources/EnumeratorMacro/EnumCase.swift b/Sources/EnumeratorMacro/EnumCase.swift index 3b366ea..b667b8c 100644 --- a/Sources/EnumeratorMacro/EnumCase.swift +++ b/Sources/EnumeratorMacro/EnumCase.swift @@ -99,7 +99,7 @@ extension EnumCase.MustacheArray: MustacheTransformable { } else { let joined = self.underlying .map { String(describing: $0) } - .joined(separator: "T ") + .joined(separator: ", ") let string = EnumCase.MustacheString("(\(joined))") return string } @@ -150,7 +150,7 @@ extension EnumCase.MustacheArrayOfOptionals: MustacheTransformable { let joined = self.underlying .enumerated() .map { $1.map { String(describing: $0) } ?? "_unnamed_\($0)" } - .joined(separator: "T ") + .joined(separator: ", ") let string = EnumCase.MustacheString("(\(joined))") return string } @@ -197,7 +197,7 @@ extension EnumCase.Parameters: MustacheTransformable { let joined = names .enumerated() .map { $1?.underlying ?? "_unnamed_\($0)" } - .joined(separator: "T ") + .joined(separator: ", ") let string = EnumCase.MustacheString("(\(joined))") return string } diff --git a/Sources/EnumeratorMacro/EnumeratorMacroType.swift b/Sources/EnumeratorMacro/EnumeratorMacroType.swift index a997388..45b17f8 100644 --- a/Sources/EnumeratorMacro/EnumeratorMacroType.swift +++ b/Sources/EnumeratorMacro/EnumeratorMacroType.swift @@ -1,6 +1,7 @@ import SwiftDiagnostics import SwiftSyntax import SwiftSyntaxMacros +import SwiftParser import Mustache public enum EnumeratorMacroType {} @@ -14,7 +15,7 @@ extension EnumeratorMacroType: MemberMacro { if declaration.hasError { return [] } guard let enumDecl = declaration.as(EnumDeclSyntax.self) else { - fatalError("Not enum") + throw MacroError.isNotEnum } let members = enumDecl.memberBlock.members @@ -23,7 +24,7 @@ extension EnumeratorMacroType: MemberMacro { let cases = try elements.map(EnumCase.init(from:)) guard let arguments = node.arguments else { - fatalError("No arguments") + throw MacroError.macroDeclarationHasNoArguments } let rendered = try arguments.as(LabeledExprListSyntax.self)!.compactMap { $0.expression @@ -34,8 +35,11 @@ extension EnumeratorMacroType: MemberMacro { }.map { template in try MustacheTemplate(string: "{{%CONTENT_TYPE:TEXT}}\n" + template) .render(["cases": cases]) - }.map(DeclSyntax.init(stringLiteral:)) - + }.map { + var parser = Parser($0) + return DeclSyntax.parse(from: &parser) + } + return rendered } } diff --git a/Sources/EnumeratorMacro/MacroError.swift b/Sources/EnumeratorMacro/MacroError.swift new file mode 100644 index 0000000..e8a1e82 --- /dev/null +++ b/Sources/EnumeratorMacro/MacroError.swift @@ -0,0 +1,30 @@ +import SwiftDiagnostics +import SwiftSyntax + +enum MacroError: Error, CustomStringConvertible { + case isNotEnum + case macroDeclarationHasNoArguments + + var description: String { + switch self { + case .isNotEnum: + "Only enums are supported." + case .macroDeclarationHasNoArguments: + "The macro declaration needs to have at least 1 StringLiteral argument." + } + } +} + +extension MacroError: DiagnosticMessage { + var message: String { + self.description + } + + var diagnosticID: MessageID { + .init(domain: "EnumeratorMacro.MacroError", id: self.description) + } + + var severity: DiagnosticSeverity { + .error + } +} diff --git a/Tests/EnumeratorMacroTests/EnumeratorMacroTests.swift b/Tests/EnumeratorMacroTests/EnumeratorMacroTests.swift index 4b7a341..159b6e0 100644 --- a/Tests/EnumeratorMacroTests/EnumeratorMacroTests.swift +++ b/Tests/EnumeratorMacroTests/EnumeratorMacroTests.swift @@ -4,7 +4,7 @@ import SwiftSyntaxMacrosTestSupport import Testing @Suite struct EnumeratorMacroTests { - @Test func works() throws { + @Test func createsCaseName() throws { assertMacroExpansionWithSwiftTesting( #""" @Enumerator( @@ -42,6 +42,96 @@ import Testing macros: EnumeratorMacroEntryPoint.macros ) } + + @Test func createsACopyOfSelf() throws { + assertMacroExpansionWithSwiftTesting( + #""" + @Enumerator(""" + enum CopyOfSelf { + {{#cases}} + case {{name}}{{joinedWithParenthesis(namesWithTypes(parameters))}} + {{/cases}} + } + """) + public enum TestEnum { + case a(val1: String, val2: Int) + case b + case testCase(testValue: String) + } + """#, + expandedSource: #""" + public enum TestEnum { + case a(val1: String, val2: Int) + case b + case testCase(testValue: String) + + enum CopyOfSelf { + case a(val1: String, val2: Int) + case b + case testCase(testValue: String) + } + } + """#, + macros: EnumeratorMacroEntryPoint.macros + ) + } + + @Test func createsDeclarationsForCaseChecking() throws { + assertMacroExpansionWithSwiftTesting( + #""" + @Enumerator(""" + {{#cases}} + var is{{capitalized(name)}}: Bool { + switch self { + case .{{name}}: + return true + default: + return false + } + } + {{/cases}} + """) + public enum TestEnum { + case a(val1: String, val2: Int) + case b + case testCase(testValue: String) + } + """#, + expandedSource: #""" + public enum TestEnum { + case a(val1: String, val2: Int) + case b + case testCase(testValue: String) + + var isA: Bool { + switch self { + case .a: + return true + default: + return false + } + } + var isB: Bool { + switch self { + case .b: + return true + default: + return false + } + } + var isTestcase: Bool { + switch self { + case .testCase: + return true + default: + return false + } + } + } + """#, + macros: EnumeratorMacroEntryPoint.macros + ) + } } @attached(member, names: arbitrary) @@ -50,27 +140,6 @@ macro Enumerator(_ templates: String...) = #externalMacro( type: "EnumeratorMacroType" ) - - - -/// {{#namesWithTypes(parameters)}}{{joined(.)}}{{/namesWithTypes(parameters)}} - -@Enumerator(""" -enum CopyOfSelf: String { -{{#cases}} -case {{name}}{{#namesWithTypes(parameters)}}{{joined(.)}}{{/namesWithTypes(parameters)}} -{{/cases}} -} -""") -public enum TestEnum2 { - case a(val1: String, val2: Int) - case b - case testCase(testValue: String) -} - - - - @Enumerator(""" enum Subtype: String { {{#cases}}