in Sources/SwiftDocC/Model/DocumentationMarkup.swift [105:268]
init(markup: Markup, parseUpToSection: ParserSection = .end) {
self.markup = markup
// The current documentation section being parsed.
var currentSection = ParserSection.title
// Tracking the start indexes of various sections.
var discussionIndex: Int?
var topicsIndex: Int?
var topicsFirstTaskGroupIndex: Int?
var seeAlsoIndex: Int?
// Index all headings as a lookup during parsing the content
markup.children.enumerated().forEach({ pair in
// If we've parsed the last section we're interested in, skip through the rest
guard currentSection <= parseUpToSection || currentSection == .end else { return }
let (index, child) = pair
let isLastChild = index == (markup.childCount - 1)
// Already parsed all expected content, return.
guard currentSection != .end else { return }
// Parse an H1 title, if found.
if currentSection == .title {
currentSection = .abstract
// Index the title child node.
if let heading = child as? Heading, heading.level == 1 {
titleHeading = heading
return
}
}
// Parse an abstract, if found
if currentSection == .abstract {
if abstractSection == nil, let firstParagraph = child as? Paragraph {
abstractSection = AbstractSection(paragraph: firstParagraph)
return
} else if let directive = child as? BlockDirective {
// Found deprecation notice in the abstract.
if directive.name == DeprecationSummary.directiveName {
deprecation = MarkupContainer(directive.children)
}
return
} else {
// Only directives and a single paragraph allowed in an abstract,
// advance to a discussion section.
currentSection = .discussion
}
}
// Parse content into a discussion section and assorted tags
let parseDiscussion: ([Markup])-> (discussion: DiscussionSection, tags: TaggedListItemExtractor) = { children in
// Extract tags
var extractor = TaggedListItemExtractor()
let content: [Markup]
if let remainder = extractor.visit(markup.withUncheckedChildren(children)) {
content = Array(remainder.children)
} else {
content = []
}
return (discussion: DiscussionSection(content: content), tags: extractor)
}
// Parse a discussion, if found
if currentSection == .discussion {
// Scanning for the first discussion content child
if discussionIndex == nil {
// Level 2 heading found at start of discussion
if let heading = child as? Heading, heading.level == 2 {
switch heading.plainText {
case TopicsSection.title:
currentSection = .topics
return
case SeeAlsoSection.title:
currentSection = .seeAlso
return
default: break
}
}
// Discussion content starts at this index
discussionIndex = index
}
guard let discussionIndex = discussionIndex else { return }
// Level 2 heading found inside discussion
if let heading = child as? Heading, heading.level == 2 {
switch heading.plainText {
case TopicsSection.title:
let (discussion, tags) = parseDiscussion(markup.children(at: discussionIndex ..< index))
discussionSection = discussion
discussionTags = tags
currentSection = .topics
return
case SeeAlsoSection.title:
let (discussion, tags) = parseDiscussion(markup.children(at: discussionIndex ..< index))
discussionSection = discussion
discussionTags = tags
currentSection = .seeAlso
return
default: break
}
}
// If at end of content, parse discussion
if isLastChild {
let (discussion, tags) = parseDiscussion(markup.children(at: discussionIndex ... index))
discussionSection = discussion
discussionTags = tags
}
}
if currentSection == .topics {
if let heading = child as? Heading {
// Level 2 heading found inside Topics
if heading.level == 2 {
switch heading.plainText {
case SeeAlsoSection.title:
if let topicsIndex = topicsIndex, topicsFirstTaskGroupIndex != nil {
topicsSection = TopicsSection(content: markup.children(at: topicsIndex ..< index))
}
currentSection = .seeAlso
return
default: break
}
}
if heading.level == 3 {
topicsFirstTaskGroupIndex = index
}
}
if topicsIndex == nil { topicsIndex = index }
// If at end of content, parse topics
if isLastChild && topicsFirstTaskGroupIndex != nil {
topicsSection = TopicsSection(content: markup.children(at: topicsIndex! ... index))
}
}
if currentSection == .seeAlso {
// Level 2 heading found inside See Also
if child is Heading {
if let seeAlsoIndex = seeAlsoIndex {
seeAlsoSection = SeeAlsoSection(content: markup.children(at: seeAlsoIndex ..< index))
}
currentSection = .end
return
}
if seeAlsoIndex == nil { seeAlsoIndex = index }
// If at end of content, parse topics
if isLastChild {
seeAlsoSection = SeeAlsoSection(content: markup.children(at: seeAlsoIndex! ... index))
}
}
})
}