111 lines
3.6 KiB
Swift
111 lines
3.6 KiB
Swift
import Ink
|
|
|
|
extension PageGenerationResults: ItemLinkResults {
|
|
|
|
}
|
|
|
|
struct MarkdownLinkProcessor: MarkdownProcessor {
|
|
|
|
static let modifier: Modifier.Target = .links
|
|
|
|
private let content: Content
|
|
|
|
private let results: ItemLinkResults
|
|
|
|
private let language: ContentLanguage
|
|
|
|
init(content: Content, results: ItemLinkResults, language: ContentLanguage) {
|
|
self.content = content
|
|
self.results = results
|
|
self.language = language
|
|
}
|
|
|
|
init(content: Content, results: PageGenerationResults, language: ContentLanguage) {
|
|
self.content = content
|
|
self.results = results
|
|
self.language = language
|
|
}
|
|
|
|
func process(html: String, markdown: Substring) -> String {
|
|
let markdownUrl = markdown.between("(", and: ")")
|
|
guard let (textToReplace, url) = convert(markdownUrl: markdownUrl) else {
|
|
// Keep original code, no changes needed
|
|
return html
|
|
}
|
|
guard let convertedUrl = url else {
|
|
// Remove link since the target can't be found
|
|
return markdown.between("[", and: "]")
|
|
}
|
|
return html.replacingOccurrences(of: textToReplace, with: convertedUrl)
|
|
}
|
|
|
|
private let pageLinkMarker = "page:"
|
|
|
|
private let tagLinkMarker = "tag:"
|
|
|
|
private let fileLinkMarker = "file:"
|
|
|
|
func convert(markdownUrl: String) -> (textToChange: String, url: String?)? {
|
|
if let result = handle(prefix: pageLinkMarker, in: markdownUrl, handler: convert(inlinePageLink:)) {
|
|
return result
|
|
}
|
|
if let result = handle(prefix: tagLinkMarker, in: markdownUrl, handler: convert(inlineTagLink:)) {
|
|
return result
|
|
}
|
|
if let result = handle(prefix: fileLinkMarker, in: markdownUrl, handler: convert(inlineFileLink:)) {
|
|
return result
|
|
}
|
|
results.externalLink(to: markdownUrl)
|
|
// No need to change anything
|
|
return nil
|
|
}
|
|
|
|
private func handle(prefix: String, in markdownUrl: String, handler: (String) -> String?) -> (textToChange: String, url: String?)? {
|
|
guard markdownUrl.hasPrefix(prefix) else {
|
|
// Continue search
|
|
return nil
|
|
}
|
|
let inlineLink = markdownUrl.replacingOccurrences(of: prefix, with: "")
|
|
let itemId = inlineLink.dropAfterFirst("#")
|
|
let url = handler(itemId)
|
|
return (textToChange: prefix + itemId, url: url)
|
|
}
|
|
|
|
private func convert(inlinePageLink pageId: String) -> String? {
|
|
guard let page = content.page(pageId) else {
|
|
results.missing(page: pageId, source: "Inline page link")
|
|
// Remove link since the page can't be found
|
|
return nil
|
|
}
|
|
// Note link even for draft pages
|
|
results.linked(to: page)
|
|
|
|
guard !page.isDraft else {
|
|
// TODO: Report links to draft pages
|
|
return nil
|
|
}
|
|
return page.absoluteUrl(in: language)
|
|
}
|
|
|
|
private func convert(inlineTagLink: String) -> String? {
|
|
let tagId = inlineTagLink.dropAfterFirst("#")
|
|
guard let tag = content.tag(tagId) else {
|
|
results.missing(tag: tagId, source: "Inline tag link")
|
|
// Remove link since the tag can't be found
|
|
return nil
|
|
}
|
|
results.linked(to: tag)
|
|
return tag.absoluteUrl(in: language)
|
|
}
|
|
|
|
private func convert(inlineFileLink fileId: String) -> String? {
|
|
guard let file = content.file(fileId) else {
|
|
results.missing(file: fileId, source: "Inline file link")
|
|
// Remove link since the file can't be found
|
|
return nil
|
|
}
|
|
results.require(file: file)
|
|
return file.absoluteUrl
|
|
}
|
|
}
|