11import * as React from 'react' ;
22import { css } from '@patternfly/react-styles' ;
3- import { Converter } from 'showdown ' ;
3+ import { marked } from 'marked ' ;
44import { useForceRender } from '@console/shared' ;
55import { QuickStartContext , QuickStartContextValues } from '../../utils/quick-start-context' ;
66
@@ -15,18 +15,7 @@ interface ShowdownExtension {
1515 replace ?: ( ...args : any [ ] ) => string ;
1616}
1717
18- export const markdownConvert = ( markdown , extensions ?: ShowdownExtension [ ] ) => {
19- const converter = new Converter ( {
20- tables : true ,
21- openLinksInNewWindow : true ,
22- strikethrough : true ,
23- emoji : false ,
24- } ) ;
25-
26- if ( extensions ) {
27- converter . addExtension ( extensions ) ;
28- }
29-
18+ export const markdownConvert = async ( markdown : string , extensions ?: ShowdownExtension [ ] ) => {
3019 DOMPurify . addHook ( 'beforeSanitizeElements' , function ( node ) {
3120 // nodeType 1 = element type
3221
@@ -82,12 +71,26 @@ export const markdownConvert = (markdown, extensions?: ShowdownExtension[]) => {
8271 }
8372 } ) ;
8473
85- return DOMPurify . sanitize ( converter . makeHtml ( markdown ) , {
86- USE_PROFILES : {
87- html : true ,
88- svg : true ,
89- } ,
90- } ) ;
74+ // Replace code fences with non markdown formatting relates tokens so that marked doesn't try to parse them as code spans
75+ const markdownWithSubstitutedCodeFences = markdown . replace ( / ` ` ` / g, '@@@' ) ;
76+ const parsedMarkdown = await marked . parse ( markdownWithSubstitutedCodeFences ) ;
77+ // Swap the temporary tokens back to code fences before we run the extensions
78+ let md = parsedMarkdown . replace ( / @ @ @ / g, '```' ) ;
79+
80+ if ( extensions ) {
81+ // Convert code spans back to md format before we run the custom extension regexes
82+ md = md . replace ( / < c o d e > ( .* ) < \/ c o d e > / g, '`$1`' ) ;
83+
84+ extensions . forEach ( ( { regex, replace } ) => {
85+ if ( regex ) {
86+ md = md . replace ( regex , replace ) ;
87+ }
88+ } ) ;
89+
90+ // Convert any remaining backticks back into code spans
91+ md = md . replace ( / ` ( .* ) ` / g, '<code>$1</code>' ) ;
92+ }
93+ return DOMPurify . sanitize ( md ) ;
9194} ;
9295
9396interface SyncMarkdownProps {
@@ -116,10 +119,18 @@ export const SyncMarkdownView: React.FC<SyncMarkdownProps> = ({
116119 className,
117120} ) => {
118121 const { getResource } = React . useContext < QuickStartContextValues > ( QuickStartContext ) ;
119- const markup = React . useMemo (
120- ( ) => markdownConvert ( content || emptyMsg || getResource ( 'Not available' ) , extensions ) ,
121- [ content , emptyMsg , extensions , getResource ] ,
122- ) ;
122+ const [ markup , setMarkup ] = React . useState < string > ( '' ) ;
123+
124+ React . useEffect ( ( ) => {
125+ async function getMd ( ) {
126+ const md = await markdownConvert (
127+ content || emptyMsg || getResource ( 'Not available' ) ,
128+ extensions ,
129+ ) ;
130+ setMarkup ( md ) ;
131+ }
132+ getMd ( ) ;
133+ } , [ content , emptyMsg , getResource , extensions ] ) ;
123134 const innerProps : InnerSyncMarkdownProps = {
124135 renderExtension : extensions ?. length > 0 ? renderExtension : undefined ,
125136 exactHeight,
0 commit comments