1 | "use strict";
|
2 |
|
3 |
|
4 | Object.defineProperty(exports, "__esModule", { value: true });
|
5 | exports.MarkdownEmitter = void 0;
|
6 | const tsdoc_1 = require("@microsoft/tsdoc");
|
7 | const node_core_library_1 = require("@rushstack/node-core-library");
|
8 | const IndentedWriter_1 = require("../utils/IndentedWriter");
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | class MarkdownEmitter {
|
14 | emit(stringBuilder, docNode, options) {
|
15 | const writer = new IndentedWriter_1.IndentedWriter(stringBuilder);
|
16 | const context = {
|
17 | writer,
|
18 | insideTable: false,
|
19 | boldRequested: false,
|
20 | italicRequested: false,
|
21 | writingBold: false,
|
22 | writingItalic: false,
|
23 | options
|
24 | };
|
25 | this.writeNode(docNode, context, false);
|
26 | writer.ensureNewLine();
|
27 | return writer.toString();
|
28 | }
|
29 | getEscapedText(text) {
|
30 | const textWithBackslashes = text
|
31 | .replace(/\\/g, '\\\\')
|
32 | .replace(/[*#[\]_|`~]/g, (x) => '\\' + x)
|
33 | .replace(/---/g, '\\-\\-\\-')
|
34 | .replace(/&/g, '&')
|
35 | .replace(/</g, '<')
|
36 | .replace(/>/g, '>');
|
37 | return textWithBackslashes;
|
38 | }
|
39 | getTableEscapedText(text) {
|
40 | return text
|
41 | .replace(/&/g, '&')
|
42 | .replace(/"/g, '"')
|
43 | .replace(/</g, '<')
|
44 | .replace(/>/g, '>')
|
45 | .replace(/\|/g, '|');
|
46 | }
|
47 | |
48 |
|
49 |
|
50 | writeNode(docNode, context, docNodeSiblings) {
|
51 | const writer = context.writer;
|
52 | switch (docNode.kind) {
|
53 | case tsdoc_1.DocNodeKind.PlainText: {
|
54 | const docPlainText = docNode;
|
55 | this.writePlainText(docPlainText.text, context);
|
56 | break;
|
57 | }
|
58 | case tsdoc_1.DocNodeKind.HtmlStartTag:
|
59 | case tsdoc_1.DocNodeKind.HtmlEndTag: {
|
60 | const docHtmlTag = docNode;
|
61 |
|
62 | writer.write(docHtmlTag.emitAsHtml());
|
63 | break;
|
64 | }
|
65 | case tsdoc_1.DocNodeKind.CodeSpan: {
|
66 | const docCodeSpan = docNode;
|
67 | if (context.insideTable) {
|
68 | writer.write('<code>');
|
69 | }
|
70 | else {
|
71 | writer.write('`');
|
72 | }
|
73 | if (context.insideTable) {
|
74 | const code = this.getTableEscapedText(docCodeSpan.code);
|
75 | const parts = code.split(/\r?\n/g);
|
76 | writer.write(parts.join('</code><br/><code>'));
|
77 | }
|
78 | else {
|
79 | writer.write(docCodeSpan.code);
|
80 | }
|
81 | if (context.insideTable) {
|
82 | writer.write('</code>');
|
83 | }
|
84 | else {
|
85 | writer.write('`');
|
86 | }
|
87 | break;
|
88 | }
|
89 | case tsdoc_1.DocNodeKind.LinkTag: {
|
90 | const docLinkTag = docNode;
|
91 | if (docLinkTag.codeDestination) {
|
92 | this.writeLinkTagWithCodeDestination(docLinkTag, context);
|
93 | }
|
94 | else if (docLinkTag.urlDestination) {
|
95 | this.writeLinkTagWithUrlDestination(docLinkTag, context);
|
96 | }
|
97 | else if (docLinkTag.linkText) {
|
98 | this.writePlainText(docLinkTag.linkText, context);
|
99 | }
|
100 | break;
|
101 | }
|
102 | case tsdoc_1.DocNodeKind.Paragraph: {
|
103 | const docParagraph = docNode;
|
104 | const trimmedParagraph = tsdoc_1.DocNodeTransforms.trimSpacesInParagraph(docParagraph);
|
105 | if (context.insideTable) {
|
106 | if (docNodeSiblings) {
|
107 |
|
108 |
|
109 |
|
110 |
|
111 | writer.writeTentative('<p>', '</p>', () => {
|
112 | this.writeNodes(trimmedParagraph.nodes, context);
|
113 | });
|
114 | }
|
115 | else {
|
116 |
|
117 | this.writeNodes(trimmedParagraph.nodes, context);
|
118 | }
|
119 | }
|
120 | else {
|
121 | this.writeNodes(trimmedParagraph.nodes, context);
|
122 | writer.ensureNewLine();
|
123 | writer.writeLine();
|
124 | }
|
125 | break;
|
126 | }
|
127 | case tsdoc_1.DocNodeKind.FencedCode: {
|
128 | const docFencedCode = docNode;
|
129 | writer.ensureNewLine();
|
130 | writer.write('```');
|
131 | writer.write(docFencedCode.language);
|
132 | writer.writeLine();
|
133 | writer.write(docFencedCode.code);
|
134 | writer.ensureNewLine();
|
135 | writer.writeLine('```');
|
136 | break;
|
137 | }
|
138 | case tsdoc_1.DocNodeKind.Section: {
|
139 | const docSection = docNode;
|
140 | this.writeNodes(docSection.nodes, context);
|
141 | break;
|
142 | }
|
143 | case tsdoc_1.DocNodeKind.SoftBreak: {
|
144 | if (!/^\s?$/.test(writer.peekLastCharacter())) {
|
145 | writer.write(' ');
|
146 | }
|
147 | break;
|
148 | }
|
149 | case tsdoc_1.DocNodeKind.EscapedText: {
|
150 | const docEscapedText = docNode;
|
151 | this.writePlainText(docEscapedText.decodedText, context);
|
152 | break;
|
153 | }
|
154 | case tsdoc_1.DocNodeKind.ErrorText: {
|
155 | const docErrorText = docNode;
|
156 | this.writePlainText(docErrorText.text, context);
|
157 | break;
|
158 | }
|
159 | case tsdoc_1.DocNodeKind.InlineTag: {
|
160 | break;
|
161 | }
|
162 | case tsdoc_1.DocNodeKind.BlockTag: {
|
163 | const tagNode = docNode;
|
164 | console.warn('Unsupported block tag: ' + tagNode.tagName);
|
165 | break;
|
166 | }
|
167 | default:
|
168 | throw new node_core_library_1.InternalError('Unsupported DocNodeKind kind: ' + docNode.kind);
|
169 | }
|
170 | }
|
171 |
|
172 | writeLinkTagWithCodeDestination(docLinkTag, context) {
|
173 |
|
174 | throw new node_core_library_1.InternalError('writeLinkTagWithCodeDestination()');
|
175 | }
|
176 |
|
177 | writeLinkTagWithUrlDestination(docLinkTag, context) {
|
178 | const linkText = docLinkTag.linkText !== undefined ? docLinkTag.linkText : docLinkTag.urlDestination;
|
179 | const encodedLinkText = this.getEscapedText(linkText.replace(/\s+/g, ' '));
|
180 | context.writer.write('[');
|
181 | context.writer.write(encodedLinkText);
|
182 | context.writer.write(`](${docLinkTag.urlDestination})`);
|
183 | }
|
184 | writePlainText(text, context) {
|
185 | const writer = context.writer;
|
186 |
|
187 | const parts = text.match(/^(\s*)(.*?)(\s*)$/) || [];
|
188 | writer.write(parts[1]);
|
189 | const middle = parts[2];
|
190 | if (middle !== '') {
|
191 | switch (writer.peekLastCharacter()) {
|
192 | case '':
|
193 | case '\n':
|
194 | case ' ':
|
195 | case '[':
|
196 | case '>':
|
197 |
|
198 | break;
|
199 | default:
|
200 |
|
201 |
|
202 |
|
203 | writer.write('<!-- -->');
|
204 | break;
|
205 | }
|
206 | if (context.boldRequested) {
|
207 | writer.write('**');
|
208 | }
|
209 | if (context.italicRequested) {
|
210 | writer.write('_');
|
211 | }
|
212 | writer.write(this.getEscapedText(middle));
|
213 | if (context.italicRequested) {
|
214 | writer.write('_');
|
215 | }
|
216 | if (context.boldRequested) {
|
217 | writer.write('**');
|
218 | }
|
219 | }
|
220 | writer.write(parts[3]);
|
221 | }
|
222 | writeNodes(docNodes, context) {
|
223 | for (const docNode of docNodes) {
|
224 | this.writeNode(docNode, context, docNodes.length > 1);
|
225 | }
|
226 | }
|
227 | }
|
228 | exports.MarkdownEmitter = MarkdownEmitter;
|
229 |
|
\ | No newline at end of file |