265 lines
7.3 KiB
Swift
265 lines
7.3 KiB
Swift
import Foundation
|
|
|
|
struct ImageToGenerate {
|
|
|
|
let size: Int
|
|
|
|
let image: FileResource
|
|
}
|
|
|
|
extension ImageToGenerate: Hashable {
|
|
|
|
func hash(into hasher: inout Hasher) {
|
|
hasher.combine(size)
|
|
hasher.combine(image.id)
|
|
}
|
|
}
|
|
|
|
final class PageGenerationResults: ObservableObject {
|
|
|
|
let itemId: ItemId
|
|
|
|
private unowned let delegate: GenerationResults
|
|
|
|
/// The files that could not be accessed
|
|
private(set) var inaccessibleFiles: Set<FileResource>
|
|
|
|
/// The files that could not be parsed, with the error message produced
|
|
private(set) var unparsableFiles: [FileResource : Set<String>]
|
|
|
|
/// The missing files directly used by this page, and the source of the file
|
|
private(set) var missingFiles: [String: Set<String>]
|
|
|
|
/// The missing files linked to from other files.
|
|
private(set) var missingLinkedFiles: [String : Set<FileResource>]
|
|
|
|
/// The missing tags linked to by this page, and the source of the link
|
|
private(set) var missingLinkedTags: [String : Set<String>]
|
|
|
|
/// The missing pages linked to by this page, and the source of the link
|
|
private(set) var missingLinkedPages: [String : Set<String>]
|
|
|
|
/// The footer scripts or html to add to the end of the body
|
|
private(set) var requiredFooters: Set<String>
|
|
|
|
/// The known header elements to include in the page
|
|
private(set) var requiredHeaders: Set<KnownHeaderElement>
|
|
|
|
/// The known icons that need to be included as hidden SVGs
|
|
private(set) var requiredIcons: Set<PageIcon>
|
|
|
|
/// The pages linked to by the page
|
|
private(set) var linkedPages: Set<Page>
|
|
|
|
/// The tags linked to by this page
|
|
private(set) var linkedTags: Set<Tag>
|
|
|
|
/// The links to external content in this page
|
|
private(set) var externalLinks: Set<String>
|
|
|
|
/// The files used by this page, but not necessarily required in the output folder
|
|
private(set) var usedFiles: Set<FileResource>
|
|
|
|
/// The files that need to be copied
|
|
private(set) var requiredFiles: Set<FileResource>
|
|
|
|
/// The image versions required for this page
|
|
private(set) var imagesToGenerate: Set<ImageVersion>
|
|
|
|
private(set) var invalidCommands: [(command: CommandType?, markdown: String)]
|
|
|
|
private(set) var invalidBlocks: [(block: ContentBlock?, markdown: String)]
|
|
|
|
private(set) var warnings: Set<String>
|
|
|
|
/// The files that could not be saved to the output folder
|
|
private(set) var unsavedOutputFiles: [String: Set<ItemType>] = [:]
|
|
|
|
private(set) var pageIsEmpty: Bool
|
|
|
|
private(set) var redirect: (originalUrl: String, newUrl: String)?
|
|
|
|
init(itemId: ItemId, delegate: GenerationResults) {
|
|
self.itemId = itemId
|
|
self.delegate = delegate
|
|
inaccessibleFiles = []
|
|
unparsableFiles = [:]
|
|
missingFiles = [:]
|
|
missingLinkedFiles = [:]
|
|
missingLinkedTags = [:]
|
|
missingLinkedPages = [:]
|
|
requiredHeaders = []
|
|
requiredFooters = []
|
|
requiredIcons = []
|
|
linkedPages = []
|
|
linkedTags = []
|
|
externalLinks = []
|
|
usedFiles = []
|
|
requiredFiles = []
|
|
imagesToGenerate = []
|
|
invalidCommands = []
|
|
invalidBlocks = []
|
|
warnings = []
|
|
unsavedOutputFiles = [:]
|
|
pageIsEmpty = false
|
|
redirect = nil
|
|
}
|
|
|
|
func reset() {
|
|
inaccessibleFiles = []
|
|
unparsableFiles = [:]
|
|
missingFiles = [:]
|
|
missingLinkedFiles = [:]
|
|
missingLinkedTags = [:]
|
|
missingLinkedPages = [:]
|
|
requiredHeaders = []
|
|
requiredFooters = []
|
|
requiredIcons = []
|
|
linkedPages = []
|
|
linkedTags = []
|
|
externalLinks = []
|
|
usedFiles = []
|
|
requiredFiles = []
|
|
imagesToGenerate = []
|
|
invalidCommands = []
|
|
invalidBlocks = []
|
|
warnings = []
|
|
unsavedOutputFiles = [:]
|
|
pageIsEmpty = false
|
|
redirect = nil
|
|
}
|
|
|
|
// MARK: Adding entries
|
|
|
|
func inaccessibleContent(file: FileResource) {
|
|
inaccessibleFiles.insert(file)
|
|
delegate.inaccessibleContent(file: file)
|
|
}
|
|
|
|
func invalid(command: CommandType?, _ markdown: Substring) {
|
|
let markdown = String(markdown)
|
|
invalidCommands.append((command, markdown))
|
|
delegate.invalidCommand(markdown)
|
|
}
|
|
|
|
func invalid(block: ContentBlock?, _ markdown: Substring) {
|
|
let markdown = String(markdown)
|
|
invalidBlocks.append((block, markdown))
|
|
delegate.invalidBlock(markdown)
|
|
}
|
|
|
|
func missing(page: String, source: String) {
|
|
missingLinkedPages[page, default: []].insert(source)
|
|
delegate.missing(page: page)
|
|
}
|
|
|
|
func missing(tag: String, source: String) {
|
|
missingLinkedTags[tag, default: []].insert(source)
|
|
delegate.missing(tag: tag)
|
|
}
|
|
|
|
func missing(file: String, source: String) {
|
|
missingFiles[file, default: []].insert(source)
|
|
delegate.missing(file: file)
|
|
}
|
|
|
|
func require(image: ImageVersion) {
|
|
imagesToGenerate.insert(image)
|
|
used(file: image.image)
|
|
delegate.generate(image)
|
|
}
|
|
|
|
func require(imageSet: ImageSet) {
|
|
let jobs = imageSet.jobs
|
|
imagesToGenerate.formUnion(jobs)
|
|
used(file: imageSet.image)
|
|
delegate.generate(jobs)
|
|
}
|
|
|
|
func invalidFormat(file: FileResource, error: String) {
|
|
unparsableFiles[file, default: []].insert(error)
|
|
delegate.unparsable(file: file)
|
|
}
|
|
|
|
func missing(file: String, containedIn sourceFile: FileResource) {
|
|
missingLinkedFiles[file, default: []].insert(sourceFile)
|
|
delegate.missing(file: file)
|
|
}
|
|
|
|
func used(file: FileResource) {
|
|
usedFiles.insert(file)
|
|
// TODO: Notify delegate
|
|
}
|
|
|
|
func require(file: FileResource) {
|
|
requiredFiles.insert(file)
|
|
usedFiles.insert(file)
|
|
delegate.require(file: file)
|
|
}
|
|
|
|
func require(files: [FileResource]) {
|
|
requiredFiles.formUnion(files)
|
|
usedFiles.formUnion(files)
|
|
delegate.require(files: files)
|
|
}
|
|
|
|
func require(footer: String) {
|
|
requiredFooters.insert(footer)
|
|
}
|
|
|
|
func require(header: KnownHeaderElement) {
|
|
requiredHeaders.insert(header)
|
|
}
|
|
|
|
func require(headers: KnownHeaderElement...) {
|
|
requiredHeaders.formUnion(headers)
|
|
}
|
|
|
|
func require(icon: PageIcon) {
|
|
requiredIcons.insert(icon)
|
|
}
|
|
|
|
func require(icons: PageIcon...) {
|
|
requiredIcons.formUnion(icons)
|
|
}
|
|
|
|
func require(icons: [PageIcon]) {
|
|
requiredIcons.formUnion(icons)
|
|
}
|
|
|
|
func linked(to page: Page) {
|
|
linkedPages.insert(page)
|
|
}
|
|
|
|
func linked(to tag: Tag) {
|
|
linkedTags.insert(tag)
|
|
}
|
|
|
|
func externalLink(to url: String) {
|
|
externalLinks.insert(url)
|
|
delegate.externalLink(url)
|
|
}
|
|
|
|
func warning(_ warning: String) {
|
|
warnings.insert(warning)
|
|
delegate.warning(warning)
|
|
}
|
|
|
|
func unsavedOutput(_ path: String, source: ItemType) {
|
|
unsavedOutputFiles[path, default: []].insert(source)
|
|
delegate.unsaved(path)
|
|
}
|
|
|
|
func markPageAsEmpty() {
|
|
guard case .page(let page) = itemId.itemType else { return }
|
|
pageIsEmpty = true
|
|
delegate.empty(.init(language: itemId.language, pageId: page.id))
|
|
}
|
|
|
|
func redirect(from originalUrl: String, to newUrl: String) {
|
|
redirect = (originalUrl, newUrl)
|
|
delegate.redirect(from: originalUrl, to: newUrl)
|
|
}
|
|
}
|
|
|