From 1308766ba4f2966658dffcfdd4b6e26ee7a4e215 Mon Sep 17 00:00:00 2001 From: Thomas De Leon <3507743+tdeleon@users.noreply.github.com> Date: Wed, 3 Jan 2024 22:34:49 -0800 Subject: [PATCH] #34: Simplify endpoint macro interface- add parent argument --- Sources/Relax/Macros/APIEndpoint.swift | 2 +- Sources/RelaxMacros/APIEndpointMacro.swift | 40 +++++-------------- .../RelaxMacros/RelaxMacroDiagnostic.swift | 19 --------- .../APIEndpointMacroTests.swift | 33 +-------------- 4 files changed, 14 insertions(+), 80 deletions(-) diff --git a/Sources/Relax/Macros/APIEndpoint.swift b/Sources/Relax/Macros/APIEndpoint.swift index 6707188..ca34fc2 100644 --- a/Sources/Relax/Macros/APIEndpoint.swift +++ b/Sources/Relax/Macros/APIEndpoint.swift @@ -9,5 +9,5 @@ import Foundation @attached(extension, conformances: Endpoint, names: named(Parent), named(path)) -public macro APIEndpoint(_ path: String) = #externalMacro(module: "RelaxMacros", type: "APIEndpointMacro") +public macro APIEndpoint(_ path: String, parent: APIComponent.Type) = #externalMacro(module: "RelaxMacros", type: "APIEndpointMacro") #endif diff --git a/Sources/RelaxMacros/APIEndpointMacro.swift b/Sources/RelaxMacros/APIEndpointMacro.swift index 571004c..941d204 100644 --- a/Sources/RelaxMacros/APIEndpointMacro.swift +++ b/Sources/RelaxMacros/APIEndpointMacro.swift @@ -18,6 +18,16 @@ public struct APIEndpointMacro: ExtensionMacro { conformingTo protocols: [TypeSyntax], in context: some MacroExpansionContext ) throws -> [ExtensionDeclSyntax] { + guard let parent = node + .arguments?.as(LabeledExprListSyntax.self)? + .first(where: { $0.label?.text == "parent" })? + .expression.as(MemberAccessExprSyntax.self)? + .base? + .description + else { + return [] + } + guard let path = node .arguments?.as(LabeledExprListSyntax.self)? .first?.expression.as(StringLiteralExprSyntax.self)? @@ -28,20 +38,8 @@ public struct APIEndpointMacro: ExtensionMacro { context.diagnose(error) return [] } - guard let parent = node.attributeName.as(IdentifierTypeSyntax.self)? - .genericArgumentClause?.as(GenericArgumentClauseSyntax.self)? - .arguments - .description else { - let fixIt = FixIt.replace( - message: RelaxFixItMessage.missingParent, - oldNode: Syntax(node), - newNode: FixItRewriter().visit(node) - ) - let error = Diagnostic(node: node, message: RelaxMacroDiagnostic.missingParent, fixIt: fixIt) - context.diagnose(error) + - return [] - } let decl: DeclSyntax = """ extension \(type.trimmed): Endpoint { @@ -52,20 +50,4 @@ public struct APIEndpointMacro: ExtensionMacro { guard let extensionDecl = decl.as(ExtensionDeclSyntax.self) else { return [] } return [extensionDecl] } - - final private class FixItRewriter: SyntaxRewriter { - override func visitAny(_ node: Syntax) -> Syntax? { - guard let attributeName = node.as(IdentifierTypeSyntax.self), - attributeName.genericArgumentClause == nil - else { return node } - let listSyntax = GenericArgumentListSyntax { - GenericArgumentSyntax(argument: TypeSyntax(stringLiteral: "<#APIComponent#>")) - } - let placeholder = GenericArgumentClauseSyntax(arguments: listSyntax) - guard let genericDecl = placeholder.as(GenericArgumentClauseSyntax.self) else { return node } - var newAttributeName = attributeName - newAttributeName.genericArgumentClause = genericDecl - return newAttributeName.as(Syntax.self) - } - } } diff --git a/Sources/RelaxMacros/RelaxMacroDiagnostic.swift b/Sources/RelaxMacros/RelaxMacroDiagnostic.swift index 8fab725..050c90e 100644 --- a/Sources/RelaxMacros/RelaxMacroDiagnostic.swift +++ b/Sources/RelaxMacros/RelaxMacroDiagnostic.swift @@ -10,7 +10,6 @@ import SwiftDiagnostics enum RelaxMacroDiagnostic: String, DiagnosticMessage { case invalidBaseURL case invalidPath - case missingParent var severity: DiagnosticSeverity { .error } @@ -20,8 +19,6 @@ enum RelaxMacroDiagnostic: String, DiagnosticMessage { "The base URL is invalid." case .invalidPath: "The path is invalid." - case .missingParent: - "The parent APIComponent must be specified as a generic argument." } } @@ -29,19 +26,3 @@ enum RelaxMacroDiagnostic: String, DiagnosticMessage { MessageID(domain: "RelaxMacros", id: rawValue) } } - -enum RelaxFixItMessage: String, FixItMessage { - case missingParent - var message: String { - switch self { - case .missingParent: - "Add generic argument 'APIComponent'" - } - } - - var fixItID: SwiftDiagnostics.MessageID { - MessageID(domain: "RelaxMacros", id: rawValue) - } - - -} diff --git a/Tests/RelaxMacrosTests/APIEndpointMacroTests.swift b/Tests/RelaxMacrosTests/APIEndpointMacroTests.swift index 82cd1bf..7bd1a1d 100644 --- a/Tests/RelaxMacrosTests/APIEndpointMacroTests.swift +++ b/Tests/RelaxMacrosTests/APIEndpointMacroTests.swift @@ -22,7 +22,7 @@ final class APIEndpointMacroTests: XCTestCase { #if canImport(RelaxMacros) assertMacroExpansion( """ - @APIEndpoint("path") + @APIEndpoint("path", parent: MyService.self) enum TestService { } """, @@ -42,40 +42,11 @@ final class APIEndpointMacroTests: XCTestCase { #endif } - func testAPIEndpointNoParent() throws { - #if canImport(RelaxMacros) - assertMacroExpansion( - """ - @APIEndpoint("path") - enum TestService { - } - """, - expandedSource: """ - enum TestService { - } - """, - diagnostics: [ - DiagnosticSpec( - message: RelaxMacroDiagnostic.missingParent.message, - line: 1, - column: 1, - fixIts: [ - FixItSpec(message: RelaxFixItMessage.missingParent.message) - ] - ) - ], - macros: testMacros - ) - #else - throw XCTSkip("macros are only supported when running tests for the host platform") - #endif - } - func testAPIEndpointInvalidPath() throws { #if canImport(RelaxMacros) assertMacroExpansion( """ - @APIEndpoint("") + @APIEndpoint("", parent: MyService.self) enum TestService { } """,