diff --git a/Sources/SyntaxSparrow/Internal/Extensions/EntityType+Parsing.swift b/Sources/SyntaxSparrow/Internal/Extensions/EntityType+Parsing.swift index 50050511..b0c99bb9 100644 --- a/Sources/SyntaxSparrow/Internal/Extensions/EntityType+Parsing.swift +++ b/Sources/SyntaxSparrow/Internal/Extensions/EntityType+Parsing.swift @@ -9,6 +9,25 @@ import Foundation import SwiftSyntax extension EntityType { + + var isClosure: Bool { + switch self { + case .closure: + return true + default: + return false + } + } + + var isTuple: Bool { + switch self { + case .closure: + return true + default: + return false + } + } + var isVoid: Bool { switch self { case .void: diff --git a/Sources/SyntaxSparrow/Internal/Resolvers/Syntax/ResultSemanticsResolver.swift b/Sources/SyntaxSparrow/Internal/Resolvers/Syntax/ResultSemanticsResolver.swift index 0ac12d25..330d64a5 100644 --- a/Sources/SyntaxSparrow/Internal/Resolvers/Syntax/ResultSemanticsResolver.swift +++ b/Sources/SyntaxSparrow/Internal/Resolvers/Syntax/ResultSemanticsResolver.swift @@ -43,6 +43,17 @@ struct ResultSemanticsResolver: SemanticsResolving { return EntityType(successType.argument) } + func resolveSuccessTypeIsOptional() -> Bool { + guard + let arguments = node.genericArgumentClause?.arguments, + arguments.count == 2, + let successType = arguments.first + else { + return false + } + return successType.resolveIsSyntaxOptional() + } + func resolveFailureType() -> EntityType { guard let arguments = node.genericArgumentClause?.arguments, diff --git a/Sources/SyntaxSparrow/Public/Semantics/Components/Result.swift b/Sources/SyntaxSparrow/Public/Semantics/Components/Result.swift index 8a0fcd95..02026ede 100644 --- a/Sources/SyntaxSparrow/Public/Semantics/Components/Result.swift +++ b/Sources/SyntaxSparrow/Public/Semantics/Components/Result.swift @@ -37,6 +37,19 @@ public struct Result: Hashable, Equatable, CustomStringConvertible { /// For example, `Result?` has `isOptional` as `true`. public var isOptional: Bool { resolver.resolveIsOptional() } + /// Bool indicating whether the resolved `successType` property is optional. + /// + /// For example: + /// ```swift + /// Result + /// Result + /// ``` + /// - The `successType` is `.simple("String?")` and `outputIsOptional` is `true` + /// - The `successType` is `.simple("String")` and `outputIsOptional` is `false` + /// + /// **Note:** Value will be `false` when the `output` is `nil` + public var successTypeIsOptional: Bool { resolver.resolveSuccessTypeIsOptional() } + // MARK: - Properties: Convenience private(set) var resolver: ResultSemanticsResolver diff --git a/Tests/SyntaxSparrowTests/Supporting Types/ResultTests.swift b/Tests/SyntaxSparrowTests/Supporting Types/ResultTests.swift index 91c77460..c0c0365c 100644 --- a/Tests/SyntaxSparrowTests/Supporting Types/ResultTests.swift +++ b/Tests/SyntaxSparrowTests/Supporting Types/ResultTests.swift @@ -24,4 +24,51 @@ final class ResultTests: XCTestCase { } // MARK: - Tests + + func test_successTypeIsOptional_willResolveExpectedFlag() throws { + let source = #""" + typealias Example = Result + typealias Example = Result + typealias Example = Result<() -> Void, Error> + typealias Example = Result<(() -> Void)?, Error> + typealias Example = Result<(name: String, age: Int), Error> + typealias Example = Result<(name: String, age: Int)?, Error> + """# + instanceUnderTest.updateToSource(source) + XCTAssertTrue(instanceUnderTest.isStale) + instanceUnderTest.collectChildren() + XCTAssertFalse(instanceUnderTest.isStale) + XCTAssertEqual(instanceUnderTest.typealiases.count, 6) + + let results = instanceUnderTest.typealiases.map(\.initializedType) + + for i in 0..<4 { + if case let EntityType.result(wrappedResult) = results[i] { + switch i { + case 0: + XCTAssertEqual(wrappedResult.successType, .simple("String")) + XCTAssertFalse(wrappedResult.successTypeIsOptional) + case 1: + XCTAssertEqual(wrappedResult.successType, .simple("String?")) + XCTAssertTrue(wrappedResult.successTypeIsOptional) + case 2: + XCTAssertTrue(wrappedResult.successType.isClosure) + XCTAssertFalse(wrappedResult.successTypeIsOptional) + case 3: + XCTAssertTrue(wrappedResult.successType.isClosure) + XCTAssertTrue(wrappedResult.successTypeIsOptional) + case 4: + XCTAssertTrue(wrappedResult.successType.isTuple) + XCTAssertFalse(wrappedResult.successTypeIsOptional) + case 5: + XCTAssertTrue(wrappedResult.successType.isTuple) + XCTAssertTrue(wrappedResult.successTypeIsOptional) + default: + break + } + } else { + XCTFail("Should have result object") + } + } + } }