UNPKG

16.6 kBJavaScriptView Raw
1var __spreadArrays = (this && this.__spreadArrays) || function () {
2 for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
3 for (var r = Array(s), k = 0, i = 0; i < il; i++)
4 for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
5 r[k] = a[j];
6 return r;
7};
8import { DocNodeKind } from '../nodes';
9import { DocNodeTransforms } from '../transforms/DocNodeTransforms';
10import { StandardTags } from '../details/StandardTags';
11var LineState;
12(function (LineState) {
13 LineState[LineState["Closed"] = 0] = "Closed";
14 LineState[LineState["StartOfLine"] = 1] = "StartOfLine";
15 LineState[LineState["MiddleOfLine"] = 2] = "MiddleOfLine";
16})(LineState || (LineState = {}));
17/**
18 * Renders a DocNode tree as a code comment.
19 */
20var TSDocEmitter = /** @class */ (function () {
21 function TSDocEmitter() {
22 this.eol = '\n';
23 // Whether to emit the /** */ framing
24 this._emitCommentFraming = true;
25 // This state machine is used by the writer functions to generate the /** */ framing around the emitted lines
26 this._lineState = LineState.Closed;
27 // State for _ensureLineSkipped()
28 this._previousLineHadContent = false;
29 // Normally a paragraph is precede by a blank line (unless it's the first thing written).
30 // But sometimes we want the paragraph to be attached to the previous element, e.g. when it's part of
31 // an "@param" block. Setting _hangingParagraph=true accomplishes that.
32 this._hangingParagraph = false;
33 }
34 TSDocEmitter.prototype.renderComment = function (output, docComment) {
35 this._emitCommentFraming = true;
36 this._renderCompleteObject(output, docComment);
37 };
38 TSDocEmitter.prototype.renderHtmlTag = function (output, htmlTag) {
39 this._emitCommentFraming = false;
40 this._renderCompleteObject(output, htmlTag);
41 };
42 TSDocEmitter.prototype.renderDeclarationReference = function (output, declarationReference) {
43 this._emitCommentFraming = false;
44 this._renderCompleteObject(output, declarationReference);
45 };
46 TSDocEmitter.prototype._renderCompleteObject = function (output, docNode) {
47 this._output = output;
48 this._lineState = LineState.Closed;
49 this._previousLineHadContent = false;
50 this._hangingParagraph = false;
51 this._renderNode(docNode);
52 this._writeEnd();
53 };
54 TSDocEmitter.prototype._renderNode = function (docNode) {
55 var _this = this;
56 if (docNode === undefined) {
57 return;
58 }
59 switch (docNode.kind) {
60 case DocNodeKind.Block:
61 var docBlock = docNode;
62 this._ensureLineSkipped();
63 this._renderNode(docBlock.blockTag);
64 if (docBlock.blockTag.tagNameWithUpperCase === StandardTags.returns.tagNameWithUpperCase) {
65 this._writeContent(' ');
66 this._hangingParagraph = true;
67 }
68 this._renderNode(docBlock.content);
69 break;
70 case DocNodeKind.BlockTag:
71 var docBlockTag = docNode;
72 if (this._lineState === LineState.MiddleOfLine) {
73 this._writeContent(' ');
74 }
75 this._writeContent(docBlockTag.tagName);
76 break;
77 case DocNodeKind.CodeSpan:
78 var docCodeSpan = docNode;
79 this._writeContent('`');
80 this._writeContent(docCodeSpan.code);
81 this._writeContent('`');
82 break;
83 case DocNodeKind.Comment:
84 var docComment = docNode;
85 this._renderNodes(__spreadArrays([
86 docComment.summarySection,
87 docComment.remarksBlock,
88 docComment.privateRemarks,
89 docComment.deprecatedBlock,
90 docComment.params,
91 docComment.typeParams,
92 docComment.returnsBlock
93 ], docComment.customBlocks, docComment.seeBlocks, [
94 docComment.inheritDocTag
95 ]));
96 if (docComment.modifierTagSet.nodes.length > 0) {
97 this._ensureLineSkipped();
98 this._renderNodes(docComment.modifierTagSet.nodes);
99 }
100 break;
101 case DocNodeKind.DeclarationReference:
102 var docDeclarationReference = docNode;
103 this._writeContent(docDeclarationReference.packageName);
104 this._writeContent(docDeclarationReference.importPath);
105 if (docDeclarationReference.packageName !== undefined ||
106 docDeclarationReference.importPath !== undefined) {
107 this._writeContent('#');
108 }
109 this._renderNodes(docDeclarationReference.memberReferences);
110 break;
111 case DocNodeKind.ErrorText:
112 var docErrorText = docNode;
113 this._writeContent(docErrorText.text);
114 break;
115 case DocNodeKind.EscapedText:
116 var docEscapedText = docNode;
117 this._writeContent(docEscapedText.encodedText);
118 break;
119 case DocNodeKind.FencedCode:
120 var docFencedCode = docNode;
121 this._ensureAtStartOfLine();
122 this._writeContent('```');
123 this._writeContent(docFencedCode.language);
124 this._writeNewline();
125 this._writeContent(docFencedCode.code);
126 this._writeContent('```');
127 this._writeNewline();
128 this._writeNewline();
129 break;
130 case DocNodeKind.HtmlAttribute:
131 var docHtmlAttribute = docNode;
132 this._writeContent(docHtmlAttribute.name);
133 this._writeContent(docHtmlAttribute.spacingAfterName);
134 this._writeContent('=');
135 this._writeContent(docHtmlAttribute.spacingAfterEquals);
136 this._writeContent(docHtmlAttribute.value);
137 this._writeContent(docHtmlAttribute.spacingAfterValue);
138 break;
139 case DocNodeKind.HtmlEndTag:
140 var docHtmlEndTag = docNode;
141 this._writeContent('</');
142 this._writeContent(docHtmlEndTag.name);
143 this._writeContent('>');
144 break;
145 case DocNodeKind.HtmlStartTag:
146 var docHtmlStartTag = docNode;
147 this._writeContent('<');
148 this._writeContent(docHtmlStartTag.name);
149 this._writeContent(docHtmlStartTag.spacingAfterName);
150 var needsSpace = docHtmlStartTag.spacingAfterName === undefined || docHtmlStartTag.spacingAfterName.length === 0;
151 for (var _i = 0, _a = docHtmlStartTag.htmlAttributes; _i < _a.length; _i++) {
152 var attribute = _a[_i];
153 if (needsSpace) {
154 this._writeContent(' ');
155 }
156 this._renderNode(attribute);
157 needsSpace = attribute.spacingAfterValue === undefined || attribute.spacingAfterValue.length === 0;
158 }
159 this._writeContent(docHtmlStartTag.selfClosingTag ? '/>' : '>');
160 break;
161 case DocNodeKind.InheritDocTag:
162 var docInheritDocTag_1 = docNode;
163 this._renderInlineTag(docInheritDocTag_1, function () {
164 if (docInheritDocTag_1.declarationReference) {
165 _this._writeContent(' ');
166 _this._renderNode(docInheritDocTag_1.declarationReference);
167 }
168 });
169 break;
170 case DocNodeKind.InlineTag:
171 var docInlineTag_1 = docNode;
172 this._renderInlineTag(docInlineTag_1, function () {
173 if (docInlineTag_1.tagContent.length > 0) {
174 _this._writeContent(' ');
175 _this._writeContent(docInlineTag_1.tagContent);
176 }
177 });
178 break;
179 case DocNodeKind.LinkTag:
180 var docLinkTag_1 = docNode;
181 this._renderInlineTag(docLinkTag_1, function () {
182 if (docLinkTag_1.urlDestination !== undefined || docLinkTag_1.codeDestination !== undefined) {
183 if (docLinkTag_1.urlDestination !== undefined) {
184 _this._writeContent(' ');
185 _this._writeContent(docLinkTag_1.urlDestination);
186 }
187 else if (docLinkTag_1.codeDestination !== undefined) {
188 _this._writeContent(' ');
189 _this._renderNode(docLinkTag_1.codeDestination);
190 }
191 }
192 if (docLinkTag_1.linkText !== undefined) {
193 _this._writeContent(' ');
194 _this._writeContent('|');
195 _this._writeContent(' ');
196 _this._writeContent(docLinkTag_1.linkText);
197 }
198 });
199 break;
200 case DocNodeKind.MemberIdentifier:
201 var docMemberIdentifier = docNode;
202 if (docMemberIdentifier.hasQuotes) {
203 this._writeContent('"');
204 this._writeContent(docMemberIdentifier.identifier); // todo: encoding
205 this._writeContent('"');
206 }
207 else {
208 this._writeContent(docMemberIdentifier.identifier);
209 }
210 break;
211 case DocNodeKind.MemberReference:
212 var docMemberReference = docNode;
213 if (docMemberReference.hasDot) {
214 this._writeContent('.');
215 }
216 if (docMemberReference.selector) {
217 this._writeContent('(');
218 }
219 if (docMemberReference.memberSymbol) {
220 this._renderNode(docMemberReference.memberSymbol);
221 }
222 else {
223 this._renderNode(docMemberReference.memberIdentifier);
224 }
225 if (docMemberReference.selector) {
226 this._writeContent(':');
227 this._renderNode(docMemberReference.selector);
228 this._writeContent(')');
229 }
230 break;
231 case DocNodeKind.MemberSelector:
232 var docMemberSelector = docNode;
233 this._writeContent(docMemberSelector.selector);
234 break;
235 case DocNodeKind.MemberSymbol:
236 var docMemberSymbol = docNode;
237 this._writeContent('[');
238 this._renderNode(docMemberSymbol.symbolReference);
239 this._writeContent(']');
240 break;
241 case DocNodeKind.Section:
242 var docSection = docNode;
243 this._renderNodes(docSection.nodes);
244 break;
245 case DocNodeKind.Paragraph:
246 var trimmedParagraph = DocNodeTransforms.trimSpacesInParagraph(docNode);
247 if (trimmedParagraph.nodes.length > 0) {
248 if (this._hangingParagraph) {
249 // If it's a hanging paragraph, then don't skip a line
250 this._hangingParagraph = false;
251 }
252 else {
253 this._ensureLineSkipped();
254 }
255 this._renderNodes(trimmedParagraph.nodes);
256 this._writeNewline();
257 }
258 break;
259 case DocNodeKind.ParamBlock:
260 var docParamBlock = docNode;
261 this._ensureLineSkipped();
262 this._renderNode(docParamBlock.blockTag);
263 this._writeContent(' ');
264 this._writeContent(docParamBlock.parameterName);
265 this._writeContent(' - ');
266 this._hangingParagraph = true;
267 this._renderNode(docParamBlock.content);
268 this._hangingParagraph = false;
269 break;
270 case DocNodeKind.ParamCollection:
271 var docParamCollection = docNode;
272 this._renderNodes(docParamCollection.blocks);
273 break;
274 case DocNodeKind.PlainText:
275 var docPlainText = docNode;
276 this._writeContent(docPlainText.text);
277 break;
278 }
279 };
280 TSDocEmitter.prototype._renderInlineTag = function (docInlineTagBase, writeInlineTagContent) {
281 this._writeContent('{');
282 this._writeContent(docInlineTagBase.tagName);
283 writeInlineTagContent();
284 this._writeContent('}');
285 };
286 TSDocEmitter.prototype._renderNodes = function (docNodes) {
287 for (var _i = 0, docNodes_1 = docNodes; _i < docNodes_1.length; _i++) {
288 var docNode = docNodes_1[_i];
289 this._renderNode(docNode);
290 }
291 };
292 // Calls _writeNewline() only if we're not already at the start of a new line
293 TSDocEmitter.prototype._ensureAtStartOfLine = function () {
294 if (this._lineState === LineState.MiddleOfLine) {
295 this._writeNewline();
296 }
297 };
298 // Calls _writeNewline() if needed to ensure that we have skipped at least one line
299 TSDocEmitter.prototype._ensureLineSkipped = function () {
300 this._ensureAtStartOfLine();
301 if (this._previousLineHadContent) {
302 this._writeNewline();
303 }
304 };
305 // Writes literal text content. If it contains newlines, they will automatically be converted to
306 // _writeNewline() calls, to ensure that "*" is written at the start of each line.
307 TSDocEmitter.prototype._writeContent = function (content) {
308 if (content === undefined || content.length === 0) {
309 return;
310 }
311 var splitLines = content.split(/\r?\n/g);
312 if (splitLines.length > 1) {
313 var firstLine = true;
314 for (var _i = 0, splitLines_1 = splitLines; _i < splitLines_1.length; _i++) {
315 var line = splitLines_1[_i];
316 if (firstLine) {
317 firstLine = false;
318 }
319 else {
320 this._writeNewline();
321 }
322 this._writeContent(line);
323 }
324 return;
325 }
326 if (this._lineState === LineState.Closed) {
327 if (this._emitCommentFraming) {
328 this._output.append('/**' + this.eol + ' *');
329 }
330 this._lineState = LineState.StartOfLine;
331 }
332 if (this._lineState === LineState.StartOfLine) {
333 if (this._emitCommentFraming) {
334 this._output.append(' ');
335 }
336 }
337 this._output.append(content);
338 this._lineState = LineState.MiddleOfLine;
339 this._previousLineHadContent = true;
340 };
341 // Starts a new line, and inserts "/**" or "*" as appropriate.
342 TSDocEmitter.prototype._writeNewline = function () {
343 if (this._lineState === LineState.Closed) {
344 if (this._emitCommentFraming) {
345 this._output.append('/**' + this.eol + ' *');
346 }
347 this._lineState = LineState.StartOfLine;
348 }
349 this._previousLineHadContent = this._lineState === LineState.MiddleOfLine;
350 if (this._emitCommentFraming) {
351 this._output.append(this.eol + ' *');
352 }
353 else {
354 this._output.append(this.eol);
355 }
356 this._lineState = LineState.StartOfLine;
357 this._hangingParagraph = false;
358 };
359 // Closes the comment, adding the final "*/" delimiter
360 TSDocEmitter.prototype._writeEnd = function () {
361 if (this._lineState === LineState.MiddleOfLine) {
362 if (this._emitCommentFraming) {
363 this._writeNewline();
364 }
365 }
366 if (this._lineState !== LineState.Closed) {
367 if (this._emitCommentFraming) {
368 this._output.append('/' + this.eol);
369 }
370 this._lineState = LineState.Closed;
371 }
372 };
373 return TSDocEmitter;
374}());
375export { TSDocEmitter };
376//# sourceMappingURL=TSDocEmitter.js.map
\No newline at end of file