import Foundation extension Page { struct Metadata { let date: Date let endDate: Date? let author: String? let isDraft: Bool let sortIndex: Int? let languages: [LocalizedMetadata] #warning("Add hideFromOverview property") let requiredFiles: [String] #warning("Add files for which errors are ignored when missing") } } extension Page.Metadata: Metadata { static let fileName = "page.json" static var initial: Page.Metadata { .init( date: .now, endDate: .now, author: nil, isDraft: true, sortIndex: 0, languages: [.initial], requiredFiles: []) } } extension Page.Metadata: LanguageContainer { } extension Page.Metadata: Codable { enum CodingKeys: CodingKey { case date case endDate case author case isDraft case sortIndex case languages case requiredFiles } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) let dateString = Page.metadataDateFormatter.string(from: date) try container.encode(dateString, forKey: .date) if let date = endDate { let endDateString = Page.metadataDateFormatter.string(from: date) try container.encode(endDateString, forKey: .endDate) } try container.encodeIfPresent(author, forKey: .author) try container.encode(isDraft, forKey: .isDraft) try container.encodeIfPresent(sortIndex, forKey: .sortIndex) try container.encode(languages, forKey: .languages) if !requiredFiles.isEmpty { try container.encode(requiredFiles, forKey: .requiredFiles) } } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) let dateString = try container.decode(String.self, forKey: .date) self.date = try Page.metadataDateFormatter.date(from: dateString) .unwrap(or: .invalidDateInPageMetadata(dateString)) self.author = try container.decodeIfPresent(String.self, forKey: .author) self.languages = try container.decode([Page.LocalizedMetadata].self, forKey: .languages) self.isDraft = try container.decodeIfPresent(Bool.self, forKey: .isDraft) ?? false self.sortIndex = try container.decodeIfPresent(Int.self, forKey: .sortIndex) if let endDateString = try container.decodeIfPresent(String.self, forKey: .endDate) { self.endDate = try Page.metadataDateFormatter.date(from: endDateString) .unwrap(or: .invalidDateInPageMetadata(endDateString)) } else { self.endDate = nil } self.requiredFiles = try container.decodeIfPresent([String].self, forKey: .requiredFiles) ?? [] } }