const slugify = ( s ) => encodeURIComponent ( String ( s ) . trim ( ) . toLowerCase ( ) . replace ( /\s+/g , '-' ) ) ; const defaults = { includeLevel : [ 1 , 2 ] , containerClass : 'table-of-contents' , slugify , markerPattern : /^\[\[toc\]\]/im , listType : 'ul' , format : undefined , forceFullToc : false , subTOC : false , containerHeaderHtml : undefined , containerFooterHtml : undefined , name : 'toc' } ; export const markdownTOC = ( md , o ) => { const options = Object . assign ( { } , defaults , o ) ; const name = options . name ; const tocRegexp = options . markerPattern ; let gstate ; let seen = 0 ; const open = `${ name }_open` ; const body = `${ name }_body` ; const close = `${ name }_close` ; function toc ( state , silent ) { var token ; var match ; if ( state . src . charCodeAt ( state . pos ) !== 0x5b ) { return false ; } if ( silent ) { return false ; } match = tocRegexp . exec ( state . src . substr ( state . pos ) ) ; match = ! match ? [ ] : match . filter ( function ( m ) { return m ; } ) ; if ( match . length < 1 ) { return false ; } gstate = undefined ; seen = 0 ; token = state . push ( open , 'toc' , 1 ) ; token . markup = '[[toc]]' ; token = state . push ( body , '' , 0 ) ; token = state . push ( close , 'toc' , - 1 ) ; var newline = state . src . indexOf ( '\n' , state . pos ) ; if ( newline !== - 1 ) { state . pos = newline ; } else { state . pos = state . pos + state . posMax + 1 ; } return true ; } md . renderer . rules [ open ] = function ( ) { var tocOpenHtml = `<div class="${ options . containerClass }">` ; if ( options . containerHeaderHtml ) { tocOpenHtml += options . containerHeaderHtml ; } return tocOpenHtml ; } ; md . renderer . rules [ close ] = function ( ) { var tocFooterHtml = '' ; if ( options . containerFooterHtml ) { tocFooterHtml = options . containerFooterHtml ; } return tocFooterHtml + `</div>` ; } ; md . renderer . rules [ body ] = function ( ) { if ( options . forceFullToc ) { var tocBody = '' ; var pos = 0 ; var tokenLength = gstate && gstate . tokens && gstate . tokens . length ; while ( pos < tokenLength ) { var tocHierarchy = renderChildsTokens ( pos , gstate . tokens ) ; pos = tocHierarchy [ 0 ] ; tocBody += tocHierarchy [ 1 ] ; } return tocBody ; } else { const result = renderChildsTokens ( seen , gstate . tokens ) ; seen = result [ 0 ] + 1 ; return result [ 1 ] ; } } ; function renderChildsTokens ( pos , tokens ) { var headings = [ ] , buffer = '' , currentLevel , subHeadings , size = tokens . length , i = pos ; while ( i < size ) { var token = tokens [ i ] ; var heading = tokens [ i - 1 ] ; var level = token . tag && parseInt ( token . tag . substr ( 1 , 1 ) ) ; if ( token . type === 'heading_close' && options . includeLevel . indexOf ( level ) == - 1 && currentLevel !== undefined && options . subTOC ) { break ; } if ( token . type !== 'heading_close' || options . includeLevel . indexOf ( level ) == - 1 || heading . type !== 'inline' ) { i ++ ; continue ; } if ( ! currentLevel ) { currentLevel = level ; } else { if ( level > currentLevel ) { subHeadings = renderChildsTokens ( i , tokens ) ; buffer += subHeadings [ 1 ] ; i = subHeadings [ 0 ] ; continue ; } if ( level < currentLevel ) { buffer += `</li>` ; headings . push ( buffer ) ; return [ i , `<${ options . listType }>${ headings . join ( '' ) }</${ options . listType }>` ] ; } if ( level == currentLevel ) { buffer += `</li>` ; headings . push ( buffer ) ; } } buffer = `<li><a href="#${ options . slugify ( heading . content ) }">` ; buffer += typeof options . format === 'function' ? options . format ( heading . content ) : heading . content ; buffer += `</a>` ; i ++ ; } buffer += buffer === '' ? '' : `</li>` ; headings . push ( buffer ) ; return [ i , `<${ options . listType }>${ headings . join ( '' ) }</${ options . listType }>` ] ; } md . core . ruler . push ( 'grab_state' , function ( state ) { if ( gstate === undefined ) { gstate = state ; } } ) ; md . inline . ruler . after ( 'emphasis' , 'toc' , toc ) ; } ;