From dc79c629a1768917492ecc5b6126746ff78d732f Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Wed, 28 Feb 2024 16:25:57 +0800 Subject: [PATCH] CandidateNode // Subclass: ServiceMenuNode. --- .../Sources/Shared/CandidateNode.swift | 2 +- .../Shared/CandidateNode_ServiceImpl.swift | 49 +++++++++++++++++++ .../Tests/SharedTests/SharedTests.swift | 13 +++++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 Packages/vChewing_Shared/Sources/Shared/CandidateNode_ServiceImpl.swift diff --git a/Packages/vChewing_Shared/Sources/Shared/CandidateNode.swift b/Packages/vChewing_Shared/Sources/Shared/CandidateNode.swift index a30ebf9a..166cbec3 100644 --- a/Packages/vChewing_Shared/Sources/Shared/CandidateNode.swift +++ b/Packages/vChewing_Shared/Sources/Shared/CandidateNode.swift @@ -8,7 +8,7 @@ import Foundation -public class CandidateNode { +open class CandidateNode { public var name: String public var members: [CandidateNode] public var previous: CandidateNode? diff --git a/Packages/vChewing_Shared/Sources/Shared/CandidateNode_ServiceImpl.swift b/Packages/vChewing_Shared/Sources/Shared/CandidateNode_ServiceImpl.swift new file mode 100644 index 00000000..ff0ea009 --- /dev/null +++ b/Packages/vChewing_Shared/Sources/Shared/CandidateNode_ServiceImpl.swift @@ -0,0 +1,49 @@ +// (c) 2021 and onwards The vChewing Project (MIT-NTL License). +// ==================== +// This code is released under the MIT license (SPDX-License-Identifier: MIT) +// ... with NTL restriction stating that: +// No trademark license is granted to use the trade names, trademarks, service +// marks, or product names of Contributor, except as required to fulfill notice +// requirements defined in MIT License. + +import Foundation + +public extension CandidateNode { + convenience init( + name: String, services: [CandidateTextService], previous: CandidateNode? = nil + ) { + self.init(name: name, members: services.map(\.asCandidateNode), previous: previous) + } + + var asServiceMenuNode: ServiceMenuNode? { + self as? ServiceMenuNode + } + + var containsCandidateServices: Bool { + !members.compactMap(\.asServiceMenuNode).isEmpty + } + + class ServiceMenuNode: CandidateNode { + public var service: CandidateTextService + public init( + name: String, service givenService: CandidateTextService, previous: CandidateNode? = nil + ) { + service = givenService + super.init(name: name, previous: previous) + } + } +} + +public extension CandidateTextService { + var asCandidateNode: CandidateNode.ServiceMenuNode { + .init(name: menuTitle, service: self) + } + + static func getCurrentServiceMenu( + fromMap map: [String]? = nil, candidate: String, reading: [String] + ) -> CandidateNode? { + let fetchedRaw = map ?? PrefMgr().candidateServiceMenuContents + let fetched = fetchedRaw.parseIntoCandidateTextServiceStack(candidate: candidate, reading: reading) + return fetched.isEmpty ? nil : .init(name: candidate, services: fetched) + } +} diff --git a/Packages/vChewing_Shared/Tests/SharedTests/SharedTests.swift b/Packages/vChewing_Shared/Tests/SharedTests/SharedTests.swift index 0c0c1018..84f22fce 100644 --- a/Packages/vChewing_Shared/Tests/SharedTests/SharedTests.swift +++ b/Packages/vChewing_Shared/Tests/SharedTests/SharedTests.swift @@ -32,4 +32,17 @@ final class SharedTests: XCTestCase { } XCTAssertEqual(stacked.rawRepresentation, Self.testDataMap) } + + func testCandidateServiceMenuNode() throws { + let rootNode = CandidateTextService.getCurrentServiceMenu( + fromMap: Self.testDataMap, + candidate: "🍰", reading: ["ㄉㄢˋ", "ㄍㄠ"] + ) + guard let rootNode = rootNode else { + XCTAssertThrowsError("Root Node Construction Failed.") + return + } + print(rootNode.members.map(\.name)) + print(rootNode.members.compactMap(\.asServiceMenuNode?.service)) + } }