File size: 5,432 Bytes
6abff73
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
Object.defineProperty(exports, "__esModule", { value: true });
exports.ParagraphSplitter = void 0;
const nodes_1 = require("../nodes");
/**
 * The ParagraphSplitter is a secondary stage that runs after the NodeParser has constructed
 * the DocComment.  It splits DocParagraph nodes into multiple paragraphs by looking for
 * paragraph delimiters.  Following CommonMark conventions, paragraphs are delimited by
 * one or more blank lines.  (These lines end with SoftBreak nodes.)  The blank lines are
 * not discarded.  Instead, they are attached to the preceding paragraph.  If the DocParagraph
 * starts with blank lines, they are preserved to avoid creating a paragraph containing only
 * whitespace.
 */
class ParagraphSplitter {
    /**
     * Split all paragraphs belonging to the provided subtree.
     */
    static splitParagraphs(node) {
        if (node instanceof nodes_1.DocSection) {
            ParagraphSplitter.splitParagraphsForSection(node);
            // (We don't recurse here, since sections cannot contain subsections)
        }
        else {
            for (const childNode of node.getChildNodes()) {
                ParagraphSplitter.splitParagraphs(childNode);
            }
        }
    }
    /**
     * Split all paragraphs belonging to the provided DocSection.
     */
    static splitParagraphsForSection(docSection) {
        const inputNodes = docSection.nodes;
        const outputNodes = [];
        for (const oldNode of inputNodes) {
            if (oldNode.kind === nodes_1.DocNodeKind.Paragraph) {
                ParagraphSplitter._splitParagraph(oldNode, outputNodes);
            }
            else {
                outputNodes.push(oldNode);
            }
        }
        // Replace the inputNodes with the outputNodes
        docSection.clearNodes();
        docSection.appendNodes(outputNodes);
    }
    static _splitParagraph(oldParagraph, outputNodes) {
        const inputParagraphNodes = oldParagraph.nodes;
        let currentParagraph = new nodes_1.DocParagraph({ configuration: oldParagraph.configuration });
        outputNodes.push(currentParagraph);
        let SplitterState;
        (function (SplitterState) {
            SplitterState[SplitterState["Start"] = 0] = "Start";
            SplitterState[SplitterState["AwaitingTrailer"] = 1] = "AwaitingTrailer";
            SplitterState[SplitterState["ReadingTrailer"] = 2] = "ReadingTrailer";
        })(SplitterState || (SplitterState = {}));
        let state = SplitterState.Start;
        let currentIndex = 0;
        while (currentIndex < inputParagraphNodes.length) {
            // Scan forwards to the end of the line
            let isBlankLine = true;
            let lineEndIndex = currentIndex; // non-inclusive
            do {
                const node = inputParagraphNodes[lineEndIndex++];
                if (node.kind === nodes_1.DocNodeKind.SoftBreak) {
                    break;
                }
                if (isBlankLine) {
                    if (!this._isWhitespace(node)) {
                        isBlankLine = false;
                    }
                }
            } while (lineEndIndex < inputParagraphNodes.length);
            // At this point, the line and SoftBreak will be in inputParagraphNodes.slice(currentIndex, lineEndIndex)
            switch (state) {
                case SplitterState.Start:
                    // We're skipping any blank lines that start the first paragraph
                    if (!isBlankLine) {
                        state = SplitterState.AwaitingTrailer;
                    }
                    break;
                case SplitterState.AwaitingTrailer:
                    // We already saw some content, so now we're looking for a blank line that starts the trailer
                    // at the end of this paragraph
                    if (isBlankLine) {
                        state = SplitterState.ReadingTrailer;
                    }
                    break;
                case SplitterState.ReadingTrailer:
                    // We already found the trailer, so now we're looking for a non-blank line that will
                    // begin a new paragraph
                    if (!isBlankLine) {
                        // Start a new paragraph
                        currentParagraph = new nodes_1.DocParagraph({ configuration: oldParagraph.configuration });
                        outputNodes.push(currentParagraph);
                        state = SplitterState.AwaitingTrailer;
                    }
                    break;
            }
            // Append the line onto the current paragraph
            for (let i = currentIndex; i < lineEndIndex; ++i) {
                currentParagraph.appendNode(inputParagraphNodes[i]);
            }
            currentIndex = lineEndIndex;
        }
    }
    static _isWhitespace(node) {
        switch (node.kind) {
            case nodes_1.DocNodeKind.PlainText:
                const docPlainText = node;
                return ParagraphSplitter._whitespaceRegExp.test(docPlainText.text);
            default:
                return false;
        }
    }
}
exports.ParagraphSplitter = ParagraphSplitter;
ParagraphSplitter._whitespaceRegExp = /^\s*$/;
//# sourceMappingURL=ParagraphSplitter.js.map