UNPKG

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