@@ -5,13 +5,17 @@ import SwiftSyntaxMacros
55import Foundation
66
77public struct URLPathMacro : PeerMacro {
8- struct CaseParam : Hashable {
9- let index : Int
10- let name : String
8+ enum SupportedType : String {
9+ case String
10+ case Int
11+ case Double
12+ case Float
1113 }
1214
13- struct PatternPathItem {
14-
15+ struct PatternParam : Hashable {
16+ let name : String
17+ let type : SupportedType
18+ let pathIndex : Int
1519 }
1620
1721 public static func expansion(
@@ -23,48 +27,90 @@ public struct URLPathMacro: PeerMacro {
2327 let enumCase = declaration. as ( EnumCaseDeclSyntax . self) ,
2428 let element = enumCase. elements. first
2529 else {
26- throw MacroError . message ( " URLPatternPath macro can only be applied to enum cases" )
30+ throw URLPatternError ( " @URLPathMacro can only be applied to enum cases" )
2731 }
28-
32+
2933 guard
3034 let argument = node. arguments? . as ( LabeledExprListSyntax . self) ? . first,
3135 let pathString = argument. expression. as ( StringLiteralExprSyntax . self) ? . segments. first? . description
3236 else {
33- throw MacroError . message ( " Invalid path " )
37+ throw URLPatternError ( " URLPath is nil " )
3438 }
3539
3640 guard let pathURL = URL ( string: pathString) else {
37- throw MacroError . message ( " URLPatternPath macro requires a string literal path " )
41+ throw URLPatternError ( " URLPath is not in a valid URL format " )
3842 }
3943
4044 let patternPaths = pathURL. pathComponents
41-
42- let pathComponents = pathURL. pathComponents
43- let parameters = pathComponents. enumerated ( )
45+
46+ let caseAssociatedTypes = try element. parameterClause? . parameters. map { param -> ( name: String , type: SupportedType ) in
47+ let name = param. firstName? . text ?? " "
48+ let type = param. type. description
49+
50+ guard let supportedType = SupportedType ( rawValue: type) else {
51+ throw URLPatternError ( " \( type) is not supported as an associated value " )
52+ }
53+ return ( name: name, type: supportedType)
54+ } ?? [ ]
55+
56+ let patternParams = patternPaths. enumerated ( )
4457 . filter { index, value in value. isURLPathParam }
45- . map { CaseParam ( index: $0. offset, name: String ( $0. element. dropFirst ( ) . dropLast ( ) ) ) }
58+ . map { index, value in
59+ let name = String ( value. dropFirst ( ) . dropLast ( ) )
60+ return PatternParam (
61+ name: name ,
62+ type: caseAssociatedTypes. first ( where: { name == $0. name } ) !. type,
63+ pathIndex: index
64+ )
65+ }
4666
47- if Set ( parameters ) . count != parameters . count {
48- throw MacroError . message ( " 변수 이름은 중복되서는 안됩니다. " )
67+ if Set ( patternParams . map { $0 . name } ) . count != patternParams . count {
68+ throw URLPatternError ( " The name of an associated value cannot be duplicated " )
4969 }
50-
70+
71+ if Set ( patternParams) . count != caseAssociatedTypes. count {
72+ throw URLPatternError ( " The number of associated values does not match URLPath " )
73+ }
74+
5175 let staticMethod = try FunctionDeclSyntax ( """
5276 static func \( element. name) (_ url: URL) -> Self? {
53- let inputPaths = url.pathComponents
54- let patternPaths = \( raw: patternPaths)
55-
56- guard isValidURLPaths(inputPaths: inputPaths, patternPaths: patternPaths) else { return nil }
77+ let inputPaths = url.pathComponents
78+ let patternPaths = \( raw: patternPaths)
5779
58- \( raw: parameters. map { param in
59- """
60- let \( param. name) = inputPaths[ \( param. index) ]
61- """
80+ guard isValidURLPaths(inputPaths: inputPaths, patternPaths: patternPaths) else {
81+ return nil
82+ }
83+
84+ \( raw: patternParams. map { param in
85+ switch param. type {
86+ case . Double:
87+ """
88+ guard let \( param. name) = \( param. type. rawValue) (inputPaths[ \( param. pathIndex) ]) else {
89+ return nil
90+ }
91+ """
92+ case . Float:
93+ """
94+ guard let \( param. name) = \( param. type. rawValue) (inputPaths[ \( param. pathIndex) ]) else {
95+ return nil
96+ }
97+ """
98+ case . Int:
99+ """
100+ guard let \( param. name) = \( param. type. rawValue) (inputPaths[ \( param. pathIndex) ]) else {
101+ return nil
102+ }
103+ """
104+ case . String:
105+ """
106+ let \( param. name) = inputPaths[ \( param. pathIndex) ]
107+ """
108+ }
62109 } . joined ( separator: " \n " ) )
63110
64- return . \( raw: element. name. text) ( \( raw: parameters . map { " \( $0. name) : \( $0. name) " } . joined ( separator: " , " ) ) )
111+ return . \( raw: element. name. text) ( \( raw: patternParams . map { " \( $0. name) : \( $0. name) " } . joined ( separator: " , " ) ) )
65112 }
66- """
67- )
113+ """ )
68114
69115 return [ DeclSyntax ( staticMethod) ]
70116 }
0 commit comments