init()

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))
                }
            }
        })
    }