diff --git a/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift b/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift index 6cbae4bb..03f5ef3d 100644 --- a/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift +++ b/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift @@ -432,7 +432,7 @@ extension FunctionDeclSyntax { genericTypeParams: genericTypeParams, genericWhereClause: genericWhereClause, params: params, - throwsOrRethrows: self.signature.effectSpecifiers?.throwsClause?.throwsSpecifier.text, + throwsOrRethrows: self.signature.effectSpecifiers?.throwsClause?.text, asyncOrReasync: self.signature.effectSpecifiers?.asyncSpecifier?.text, isStatic: isStatic, offset: self.offset, @@ -473,7 +473,7 @@ extension InitializerDeclSyntax { genericTypeParams: genericTypeParams, genericWhereClause: genericWhereClause, params: params, - throwsOrRethrows: self.signature.effectSpecifiers?.throwsClause?.throwsSpecifier.text, + throwsOrRethrows: self.signature.effectSpecifiers?.throwsClause?.text, asyncOrReasync: self.signature.effectSpecifiers?.asyncSpecifier?.text, isStatic: false, offset: self.offset, @@ -796,3 +796,14 @@ extension Trivia { return nil } } + +extension ThrowsClauseSyntax { + + var text: String { + if let type { + "\(throwsSpecifier.text)(\(type.description))" + } else { + throwsSpecifier.text + } + } +} diff --git a/Sources/MockoloFramework/Utils/StringExtensions.swift b/Sources/MockoloFramework/Utils/StringExtensions.swift index 4e694ee3..6c29d23f 100644 --- a/Sources/MockoloFramework/Utils/StringExtensions.swift +++ b/Sources/MockoloFramework/Utils/StringExtensions.swift @@ -108,13 +108,34 @@ extension String { /// """ - var hasThrowsOrRethrows: Bool { return components(separatedBy: .whitespaces).contains { component in - return component == .throws || component == .rethrows - } + let hasTypedThrow = hasPrefix(String.throws.withLeftParen) + return component == .throws || hasTypedThrow || component == .rethrows + } } + /// Extract Error type in typed-throw. + /// + /// - Note: Because any keyword can appear, it was hard to split by whitespace. + /// + /// - ex + /// ``` + /// throws(any LocalizedError) + /// ↓ should extract + /// any LocalizedError + /// ``` + var typedThrowTypeName: String { + let pattern = #"throws\((?.+)\)"# + guard let regex = try? Regex(pattern, as: (Substring, thrownType: Substring).self) else { + return "" + } + guard let match = firstMatch(of: regex) else { + return "" + } + return String(match.output.thrownType) + } + var hasAsync: Bool { return components(separatedBy: .whitespaces).contains { component in return component == .async diff --git a/Sources/MockoloFramework/Utils/TypeParser.swift b/Sources/MockoloFramework/Utils/TypeParser.swift index 4b89b3d1..26aac6bf 100644 --- a/Sources/MockoloFramework/Utils/TypeParser.swift +++ b/Sources/MockoloFramework/Utils/TypeParser.swift @@ -558,9 +558,18 @@ public final class `Type` { displayableReturnType = "(\(displayableReturnType))" } + let hasThrowsOrRethrows = suffix.hasThrowsOrRethrows + let typedThrowTypeName = suffix.typedThrowTypeName + + let thrownSuffix: String = if typedThrowTypeName.isNotEmpty { + "\(String.throws)(\(typedThrowTypeName))" + } else { + String.throws + } + let suffixStr = [ suffix.hasAsync ? String.async + " " : nil, - suffix.hasThrowsOrRethrows ? String.throws + " " : nil, + hasThrowsOrRethrows ? thrownSuffix + " " : nil, ].compactMap { $0 }.joined() let typeStr = "((\(displayableParamStr)) \(suffixStr)-> \(displayableReturnType))?"