1
1
import * as cm from 'commonmark' ;
2
2
import { prefixLines , RendererContext } from './markdown' ;
3
3
import { MarkdownRenderer , para , stripPara } from './markdown-renderer' ;
4
+ import { makeXmlEscaper } from './escapes' ;
5
+
6
+ const ESCAPE = makeXmlEscaper ( ) ;
7
+
8
+ // The types for 'xmldom' are not complete.
9
+ /* eslint-disable-next-line @typescript-eslint/no-var-requires,@typescript-eslint/no-require-imports */
10
+ const { DOMParser, XMLSerializer } = require ( 'xmldom' ) ;
4
11
5
12
/* eslint-disable @typescript-eslint/camelcase */
6
13
@@ -16,19 +23,23 @@ export class CSharpXmlCommentRenderer extends MarkdownRenderer {
16
23
}
17
24
18
25
public code ( node : cm . Node , _context : RendererContext ) {
19
- return `<c>${ escapeCharacters ( node . literal ) } </c>` ;
26
+ return `<c>${ ESCAPE . text ( node . literal ) } </c>` ;
20
27
}
21
28
22
29
public code_block ( node : cm . Node , _context : RendererContext ) {
23
30
return para ( `<code><![CDATA[\n${ node . literal } ]]></code>` ) ;
24
31
}
25
32
26
33
public text ( node : cm . Node , _context : RendererContext ) {
27
- return escapeCharacters ( node . literal ) || '' ;
34
+ return ESCAPE . text ( node . literal ) ?? '' ;
28
35
}
29
36
30
37
public link ( node : cm . Node , context : RendererContext ) {
31
- return `${ context . content ( ) } (${ node . destination || '' } )` ;
38
+ return `<a href="${ ESCAPE . attribute ( node . destination ) ?? '' } ">${ context . content ( ) } </a>` ;
39
+ }
40
+
41
+ public image ( node : cm . Node , context : RendererContext ) {
42
+ return `<img alt="${ ESCAPE . text2attr ( context . content ( ) ) } " src="${ ESCAPE . attribute ( node . destination ) ?? '' } " />` ;
32
43
}
33
44
34
45
public emph ( _node : cm . Node , context : RendererContext ) {
@@ -53,14 +64,31 @@ export class CSharpXmlCommentRenderer extends MarkdownRenderer {
53
64
return `<description>${ stripPara ( context . content ( ) ) } </description>\n` ;
54
65
}
55
66
56
- public image ( node : cm . Node , context : RendererContext ) {
57
- return `<img alt=" ${ context . content ( ) } " src=" ${ node . destination || '' } ">` ;
67
+ public thematic_break ( _node : cm . Node , _context : RendererContext ) {
68
+ return para ( '<hr />' ) ;
58
69
}
59
- }
60
70
61
- /**
62
- * Escape the characters that need escaping in XML
63
- */
64
- function escapeCharacters ( x : string | null ) : string {
65
- return x ? x . replace ( / & / g, '&' ) . replace ( / < / g, '<' ) . replace ( / > / g, '>' ) : '' ;
66
- }
71
+ /**
72
+ * HTML needs to be converted to XML
73
+ *
74
+ * If we don't do this, the parser will reject the whole XML block once it seens an unclosed
75
+ * <img> tag.
76
+ */
77
+ public html_inline ( node : cm . Node , _context : RendererContext ) {
78
+ const html = node . literal ?? '' ;
79
+ const doc = new DOMParser ( ) . parseFromString ( html , 'text/html' ) ;
80
+ return new XMLSerializer ( ) . serializeToString ( doc ) ;
81
+ }
82
+
83
+ /**
84
+ * HTML needs to be converted to XML
85
+ *
86
+ * If we don't do this, the parser will reject the whole XML block once it seens an unclosed
87
+ * <img> tag.
88
+ */
89
+ public html_block ( node : cm . Node , _context : RendererContext ) {
90
+ const html = node . literal ?? '' ;
91
+ const doc = new DOMParser ( ) . parseFromString ( html , 'text/html' ) ;
92
+ return new XMLSerializer ( ) . serializeToString ( doc ) ;
93
+ }
94
+ }
0 commit comments