UNPKG

7.42 kBJavaScriptView Raw
1import { TSDocMessageId } from './TSDocMessageId';
2// Internal parser state
3var State;
4(function (State) {
5 // Initial state, looking for "/*"
6 State[State["BeginComment1"] = 0] = "BeginComment1";
7 // Looking for "*" or "* " after "/*"
8 State[State["BeginComment2"] = 1] = "BeginComment2";
9 // Like State.CollectingLine except immediately after the "/**"
10 State[State["CollectingFirstLine"] = 2] = "CollectingFirstLine";
11 // Collecting characters until we reach a newline
12 State[State["CollectingLine"] = 3] = "CollectingLine";
13 // After a newline, looking for the "*" that begins a new line, or the "*/" to end the comment
14 State[State["AdvancingLine"] = 4] = "AdvancingLine";
15 // Exiting the parser loop
16 State[State["Done"] = 5] = "Done";
17})(State || (State = {}));
18/**
19 * The main API for parsing TSDoc comments.
20 */
21var LineExtractor = /** @class */ (function () {
22 function LineExtractor() {
23 }
24 /**
25 * This step parses an entire code comment from slash-star-star until star-slash,
26 * and extracts the content lines. The lines are stored in IDocCommentParameters.lines
27 * and the overall text range is assigned to IDocCommentParameters.range.
28 */
29 LineExtractor.extract = function (parserContext) {
30 var range = parserContext.sourceRange;
31 var buffer = range.buffer;
32 var commentRangeStart = 0;
33 var commentRangeEnd = 0;
34 // These must be set before entering CollectingFirstLine, CollectingLine, or AdvancingLine
35 var collectingLineStart = 0;
36 var collectingLineEnd = 0;
37 var nextIndex = range.pos;
38 var state = State.BeginComment1;
39 var lines = [];
40 while (state !== State.Done) {
41 if (nextIndex >= range.end) {
42 // reached the end of the input
43 switch (state) {
44 case State.BeginComment1:
45 case State.BeginComment2:
46 parserContext.log.addMessageForTextRange(TSDocMessageId.CommentNotFound, 'Expecting a "/**" comment', range);
47 return false;
48 default:
49 parserContext.log.addMessageForTextRange(TSDocMessageId.CommentMissingClosingDelimiter, 'Unexpected end of input', range);
50 return false;
51 }
52 }
53 var current = buffer[nextIndex];
54 var currentIndex = nextIndex;
55 ++nextIndex;
56 var next = nextIndex < range.end ? buffer[nextIndex] : '';
57 switch (state) {
58 case State.BeginComment1:
59 if (current === '/' && next === '*') {
60 commentRangeStart = currentIndex;
61 ++nextIndex; // skip the star
62 state = State.BeginComment2;
63 }
64 else if (!LineExtractor._whitespaceCharacterRegExp.test(current)) {
65 parserContext.log.addMessageForTextRange(TSDocMessageId.CommentOpeningDelimiterSyntax, 'Expecting a leading "/**"', range.getNewRange(currentIndex, currentIndex + 1));
66 return false;
67 }
68 break;
69 case State.BeginComment2:
70 if (current === '*') {
71 if (next === ' ') {
72 ++nextIndex; // Discard the space after the star
73 }
74 collectingLineStart = nextIndex;
75 collectingLineEnd = nextIndex;
76 state = State.CollectingFirstLine;
77 }
78 else {
79 parserContext.log.addMessageForTextRange(TSDocMessageId.CommentOpeningDelimiterSyntax, 'Expecting a leading "/**"', range.getNewRange(currentIndex, currentIndex + 1));
80 return false;
81 }
82 break;
83 case State.CollectingFirstLine:
84 case State.CollectingLine:
85 if (current === '\n') {
86 // Ignore an empty line if it is immediately after the "/**"
87 if (state !== State.CollectingFirstLine || collectingLineEnd > collectingLineStart) {
88 // Record the line that we collected
89 lines.push(range.getNewRange(collectingLineStart, collectingLineEnd));
90 }
91 collectingLineStart = nextIndex;
92 collectingLineEnd = nextIndex;
93 state = State.AdvancingLine;
94 }
95 else if (current === '*' && next === '/') {
96 if (collectingLineEnd > collectingLineStart) {
97 lines.push(range.getNewRange(collectingLineStart, collectingLineEnd));
98 }
99 collectingLineStart = 0;
100 collectingLineEnd = 0;
101 ++nextIndex; // skip the slash
102 commentRangeEnd = nextIndex;
103 state = State.Done;
104 }
105 else if (!LineExtractor._whitespaceCharacterRegExp.test(current)) {
106 collectingLineEnd = nextIndex;
107 }
108 break;
109 case State.AdvancingLine:
110 if (current === '*') {
111 if (next === '/') {
112 collectingLineStart = 0;
113 collectingLineEnd = 0;
114 ++nextIndex; // skip the slash
115 commentRangeEnd = nextIndex;
116 state = State.Done;
117 }
118 else {
119 // Discard the "*" at the start of a line
120 if (next === ' ') {
121 ++nextIndex; // Discard the space after the star
122 }
123 collectingLineStart = nextIndex;
124 collectingLineEnd = nextIndex;
125 state = State.CollectingLine;
126 }
127 }
128 else if (current === '\n') {
129 // Blank line
130 lines.push(range.getNewRange(currentIndex, currentIndex));
131 collectingLineStart = nextIndex;
132 }
133 else if (!LineExtractor._whitespaceCharacterRegExp.test(current)) {
134 // If the star is missing, then start the line here
135 // Example: "/**\nL1*/"
136 // (collectingLineStart was the start of this line)
137 collectingLineEnd = nextIndex;
138 state = State.CollectingLine;
139 }
140 break;
141 }
142 }
143 /**
144 * Only fill in these if we successfully scanned a comment
145 */
146 parserContext.commentRange = range.getNewRange(commentRangeStart, commentRangeEnd);
147 parserContext.lines = lines;
148 return true;
149 };
150 LineExtractor._whitespaceCharacterRegExp = /^\s$/;
151 return LineExtractor;
152}());
153export { LineExtractor };
154//# sourceMappingURL=LineExtractor.js.map
\No newline at end of file