import { isInternalURL } from '@layr/browser-navigator' ; import { jsx } from '@emotion/react' ; import marked from 'marked' ; import highlightJS from 'highlight.js/lib/core' ; import typescript from 'highlight.js/lib/languages/typescript' ; import json from 'highlight.js/lib/languages/json' ; import xml from 'highlight.js/lib/languages/xml' ; import bash from 'highlight.js/lib/languages/bash' ; import DOMPurify from 'dompurify' ; highlightJS . registerLanguage ( 'typescript' , typescript ) ; highlightJS . registerLanguage ( 'json' , json ) ; highlightJS . registerLanguage ( 'html' , xml ) ; highlightJS . registerLanguage ( 'bash' , bash ) ; export function Markdown ( { languageFilter , children } ) { let html = marked ( children , { highlight : ( code , language ) => { if ( languageFilter !== undefined ) { const matches = code . match ( /^\/\/ (\w+)\n\n/ ) ; if ( matches !== null ) { const languageSpecifier = matches [ 1 ] . toLocaleLowerCase ( ) ; if ( languageSpecifier !== languageFilter ) { return '' ; } code = code . slice ( matches [ 0 ] . length ) ; } } if ( language === '' ) { language = 'ts' ; } if ( language === 'js' ) { language = 'ts' ; } return highlightJS . highlight ( code , { language } ) . value ; } } ) ; if ( languageFilter !== undefined ) { html = html . replace ( /<pre><code( class="language-\w+")?>\s?<\/code><\/pre>\n/g , '' ) ; html = html . replace ( /<!-- <if language="(\w+)"> -->([^]*?)<!-- <\/if> -->/g , ( _ , language , content ) => { return language === languageFilter ? content : '' ; } ) ; } html = DOMPurify . sanitize ( html , { ADD_TAGS : [ 'badge' ] } ) ; html = html . replace ( /<badge(?: type="([\w-]+)")?>([\w ]+)<\/badge>/g , ( _ , type , name ) => { return `<span class='badge${ type !== undefined ? ` badge-${ type }` : '' }'>${ name }</span>` ; } ) ; html = html . replace ( /<h\d id="([\w-]+)">.+\{\#([\w-]+)\}<\/h\d>/g , ( match , currentId , newId ) => { match = match . replace ( ` id="${ currentId }">` , ` id="${ newId }">` ) ; match = match . replace ( ` {#${ newId }}<` , `<` ) ; return match ; } ) ; html = html . replace ( /<h\d id="([\w-]+)">/g , ( match , id ) => { match += `<a href="#${ id }" class="anchor" aria-hidden="true">&nbsp;</a>` ; return match ; } ) ; if ( process . env . NODE_ENV === 'development' ) { const localURL = new URL ( window . location . href ) . origin ; html = html . replace ( /https:\/\/layrjs.com/g , localURL ) ; } html = html . replace ( /<a href="([^"]+)">.*?<\/a>/g , ( match , url ) => { if ( isInternalURL ( url ) ) { const onClick = `document.body.dispatchEvent(new CustomEvent('layrNavigatorNavigate', {detail: {url: '${ url }'}})); return false;` ; match = match . replace ( `<a href="${ url }">` , `<a href="${ url }" onclick="${ onClick }">` ) ; } return match ; } ) ; return < div dangerouslySetInnerHTML = { { __html : html } } />; } export function InlineMarkdown ( { children : markdown } ) { markdown = markdown . replace ( /\n/g , '  \n' ) ; let html = ( marked as any ) . parseInline ( markdown ) ; html = DOMPurify . sanitize ( html ) ; return < span dangerouslySetInnerHTML = { { __html : html } } />; }