Spaces:
Sleeping
Sleeping
| // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. | |
| // See LICENSE in the project root for license information. | |
| import { DocSection, DocNodeKind, DocParagraph } from '../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. | |
| */ | |
| export class ParagraphSplitter { | |
| /** | |
| * Split all paragraphs belonging to the provided subtree. | |
| */ | |
| static splitParagraphs(node) { | |
| if (node instanceof 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 === 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 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 === 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 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 DocNodeKind.PlainText: | |
| const docPlainText = node; | |
| return ParagraphSplitter._whitespaceRegExp.test(docPlainText.text); | |
| default: | |
| return false; | |
| } | |
| } | |
| } | |
| ParagraphSplitter._whitespaceRegExp = /^\s*$/; | |
| //# sourceMappingURL=ParagraphSplitter.js.map |