diff --git a/WebsiteGenerator/Content/Element.swift b/WebsiteGenerator/Content/Element.swift index 9c3e980..36e0a97 100644 --- a/WebsiteGenerator/Content/Element.swift +++ b/WebsiteGenerator/Content/Element.swift @@ -4,6 +4,23 @@ struct Element { static let overviewItemCountDefault = 6 + /** + The default unique id for the root element + */ + static let defaultRootId = "root" + + /** + The unique id of the element. + + The id is used for short-hand links to pages, in the form of `![page](page_id)` + for thumbnail previews or `[text](page:page_id)` for simple links. + - Note: The default id for the root element is specified by ``defaultRootId`` + + The id can be manually specified using ``GenericMetadata.id``, + otherwise it is set to the name of the element folder. + */ + let id: String + /** The author of the content. @@ -132,6 +149,7 @@ struct Element { return nil } + self.id = metadata.customId ?? Element.defaultRootId self.author = log.required(metadata.author, name: "author", source: source) ?? "author" self.topBarTitle = log .required(metadata.topBarTitle, name: "topBarTitle", source: source) ?? "My Website" @@ -149,6 +167,10 @@ struct Element { .compactMap { language in .init(atRoot: folder, data: language) } ?? [] + + // All properties initialized + + files.add(page: path, id: id) try self.readElements(in: folder, source: nil) } @@ -177,6 +199,7 @@ struct Element { return nil } + self.id = metadata.customId ?? folder.lastPathComponent self.author = metadata.author ?? parent.author self.topBarTitle = log .unused(metadata.topBarTitle, "topBarTitle", source: source) ?? parent.topBarTitle @@ -220,6 +243,10 @@ struct Element { .forEach { log.add(warning: "Language '\($0)' not found in parent, so not generated", source: source) } + + // All properties initialized + + files.add(page: path, id: id) try self.readElements(in: folder, source: path) } } diff --git a/WebsiteGenerator/Content/GenericMetadata.swift b/WebsiteGenerator/Content/GenericMetadata.swift index d43f922..521b224 100644 --- a/WebsiteGenerator/Content/GenericMetadata.swift +++ b/WebsiteGenerator/Content/GenericMetadata.swift @@ -10,6 +10,16 @@ struct GenericMetadata { */ static let metadataFileName = "metadata.json" + /** + A custom id to uniquely identify the element on the site. + + The id is used for short-hand links to pages, in the form of `![page](page_id)` + for thumbnail previews or `[text](page:page_id)` for simple links. + + If no custom id is set, then the name of the element folder is used. + */ + let customId: String? + /** The author of the content. @@ -108,6 +118,7 @@ extension GenericMetadata: Codable { private static var knownKeyList: [CodingKeys] { [ + .customId, .author, .topBarTitle, .date, @@ -177,6 +188,7 @@ extension GenericMetadata { static var full: GenericMetadata { .init( + customId: "", author: "", topBarTitle: "", date: "", diff --git a/WebsiteGenerator/Files/FileSystem.swift b/WebsiteGenerator/Files/FileSystem.swift index 4dec232..b730d2d 100644 --- a/WebsiteGenerator/Files/FileSystem.swift +++ b/WebsiteGenerator/Files/FileSystem.swift @@ -57,6 +57,13 @@ final class FileSystem { */ private var emptyPages: Set = [] + /** + All paths to page element folders, indexed by their unique id. + + This relation is used to generate relative links to pages using the ``Element.id` + */ + private var pagePaths: [String: String] = [:] + /** The image creation tasks. @@ -423,6 +430,13 @@ final class FileSystem { } } + func add(page: String, id: String) { + if let existing = pagePaths[id] { + log.add(error: "Conflicting id with \(existing)", source: page) + } + pagePaths[id] = page + } + // MARK: Writing files