enum PageContentAnomaly { case failedToLoadContent(Error) case missingFile(file: String, markdown: String) case missingPage(page: String, markdown: String) case missingTag(tag: String, markdown: String) case invalidCommand(command: ShorthandMarkdownKey?, markdown: String) } extension PageContentAnomaly: Identifiable { var id: String { switch self { case .failedToLoadContent: return "load-failed" case .missingFile(let string, _): return "missing-file-\(string)" case .missingPage(let string, _): return "missing-page-\(string)" case .missingTag(let string, _): return "missing-tag-\(string)" case .invalidCommand(_, let markdown): return "invalid-command-\(markdown)" } } } extension PageContentAnomaly: Equatable { static func == (lhs: PageContentAnomaly, rhs: PageContentAnomaly) -> Bool { lhs.id == rhs.id } } extension PageContentAnomaly: Hashable { func hash(into hasher: inout Hasher) { hasher.combine(id) } } extension PageContentAnomaly { enum Severity: String, CaseIterable { case warning case error } var severity: Severity { switch self { case .failedToLoadContent: return .error case .missingFile, .missingPage, .missingTag, .invalidCommand: return .warning } } } extension PageContentAnomaly: CustomStringConvertible { var description: String { switch self { case .failedToLoadContent(let error): return "Failed to load content: \(error)" case .missingFile(let string, _): return "Missing file: \(string)" case .missingPage(let string, _): return "Missing page: \(string)" case .missingTag(let string, _): return "Missing tag: \(string)" case .invalidCommand(_, let markdown): return "Invalid command: \(markdown)" } } }