@@ -366,14 +366,17 @@ function configureMarked() {
366366 const krokiLanguages = {
367367 'vega-lite' : [ 'vegalite' , 'Vega-Lite' ] ,
368368 vegalite : [ 'vegalite' , 'Vega-Lite' ] ,
369- wavedrom : [ 'wavedrom' , 'WaveDrom' ] ,
370- markmap : [ 'markmap' , 'Markmap' ]
369+ wavedrom : [ 'wavedrom' , 'WaveDrom' ]
371370 } ;
372371 if ( krokiLanguages [ language ] ) {
373372 const [ engine , label ] = krokiLanguages [ language ] ;
374373 const uniqueId = `${ engine } -diagram-worker-${ krokiIdCounter ++ } ` ;
375374 return renderDiagramShell ( engine , 'kroki-container' , 'kroki-diagram' , uniqueId , code , label ) ;
376375 }
376+ if ( language === 'markmap' ) {
377+ const uniqueId = `markmap-diagram-worker-${ krokiIdCounter ++ } ` ;
378+ return renderDiagramShell ( 'markmap' , 'markmap-container' , 'markmap-diagram' , uniqueId , code , 'Markmap' ) ;
379+ }
377380
378381 if ( language === "math" ) {
379382 return `<div class="math-block">$$\n${ code } \n$$</div>\n` ;
@@ -400,6 +403,72 @@ function configureMarked() {
400403 return `<h${ level } id="${ id } ">${ text } </h${ level } >` ;
401404 } ;
402405
406+ function normalizeMarkmapFences ( markdown ) {
407+ const lines = String ( markdown || '' ) . split ( / \r ? \n / ) ;
408+ const output = [ ] ;
409+ let index = 0 ;
410+
411+ while ( index < lines . length ) {
412+ const opening = lines [ index ] . match ( / ^ ( [ \t ] { 0 , 3 } ) ( ` { 3 , } | ~ { 3 , } ) ( [ \t ] * ) ( .* ) $ / ) ;
413+ const info = opening ? opening [ 4 ] . trim ( ) : '' ;
414+ if ( ! opening || ! / ^ m a r k m a p (?: \s | $ ) / i. test ( info ) ) {
415+ output . push ( lines [ index ] ) ;
416+ index += 1 ;
417+ continue ;
418+ }
419+
420+ const indent = opening [ 1 ] ;
421+ const fence = opening [ 2 ] ;
422+ const marker = fence [ 0 ] ;
423+ const content = [ ] ;
424+ let nestedFence = null ;
425+ let maxInnerFenceLength = fence . length ;
426+ let closeIndex = - 1 ;
427+
428+ for ( let scan = index + 1 ; scan < lines . length ; scan += 1 ) {
429+ const line = lines [ scan ] ;
430+ const fenceMatch = line . match ( / ^ [ \t ] { 0 , 3 } ( ` { 3 , } | ~ { 3 , } ) ( [ \t ] * .* ) $ / ) ;
431+ if ( fenceMatch ) {
432+ const currentFence = fenceMatch [ 1 ] ;
433+ const currentMarker = currentFence [ 0 ] ;
434+ const tail = fenceMatch [ 2 ] . trim ( ) ;
435+ if ( currentMarker === marker ) {
436+ maxInnerFenceLength = Math . max ( maxInnerFenceLength , currentFence . length ) ;
437+ }
438+
439+ if ( nestedFence ) {
440+ if ( currentMarker === nestedFence . marker && currentFence . length >= nestedFence . length && tail === '' ) {
441+ nestedFence = null ;
442+ }
443+ } else if ( currentMarker === marker && currentFence . length >= fence . length && tail === '' ) {
444+ closeIndex = scan ;
445+ break ;
446+ } else if ( tail !== '' ) {
447+ nestedFence = {
448+ marker : currentMarker ,
449+ length : currentFence . length
450+ } ;
451+ }
452+ }
453+ content . push ( line ) ;
454+ }
455+
456+ if ( closeIndex === - 1 ) {
457+ output . push ( lines [ index ] ) ;
458+ index += 1 ;
459+ continue ;
460+ }
461+
462+ const normalizedFence = marker . repeat ( maxInnerFenceLength + 1 ) ;
463+ output . push ( `${ indent } ${ normalizedFence } ${ opening [ 3 ] } ${ opening [ 4 ] } ` ) ;
464+ output . push ( ...content ) ;
465+ output . push ( `${ indent } ${ normalizedFence } ` ) ;
466+ index = closeIndex + 1 ;
467+ }
468+
469+ return output . join ( '\n' ) ;
470+ }
471+
403472 marked . use ( {
404473 extensions : [
405474 blockMathExtension ,
@@ -412,7 +481,8 @@ function configureMarked() {
412481 preprocess ( markdown ) {
413482 if ( suppressFootnotePreprocess ) return markdown ;
414483 resetExtendedMarkdownState ( ) ;
415- const protectedMarkdown = markdown . replace ( / \\ \$ / g, "$" ) ;
484+ const normalizedMarkdown = normalizeMarkmapFences ( markdown ) ;
485+ const protectedMarkdown = normalizedMarkdown . replace ( / \\ \$ / g, "$" ) ;
416486 return applyFootnotes ( extractFootnoteDefinitions ( protectedMarkdown ) ) ;
417487 } ,
418488 } ,
@@ -510,11 +580,12 @@ function splitMarkdownBlocks(markdown) {
510580}
511581
512582function renderSegmentedMarkdown ( markdown , options ) {
513- if ( ! isSegmentedPreviewSafe ( markdown ) ) {
583+ const normalizedMarkdown = normalizeMarkmapFences ( markdown ) ;
584+ if ( ! isSegmentedPreviewSafe ( normalizedMarkdown ) ) {
514585 return { mode : "full-required" , reason : "unsafe-markdown" } ;
515586 }
516587
517- const blocks = splitMarkdownBlocks ( markdown ) ;
588+ const blocks = splitMarkdownBlocks ( normalizedMarkdown ) ;
518589 if ( blocks . length < ( options . minimumBlocks || 1 ) ) {
519590 return { mode : "full-required" , reason : "too-few-blocks" } ;
520591 }
0 commit comments