import * as fs from 'fs-extra' ; import * as _ from 'lodash' ; import * as path from 'path' ; import FileEngine from './file.engine' ; const decache = require ( 'decache' ) ; export interface markdownReadedDatas { markdown : string ; rawData : string ; } export class MarkdownEngine { /**
     * List of markdown files without .md extension
     */ private readonly markdownFiles = [ 'README' , 'CHANGELOG' , 'LICENSE' , 'CONTRIBUTING' , 'TODO' ] ; private markedInstance ; private static instance : MarkdownEngine ; private constructor ( ) { decache ( 'marked' ) ; const { marked } = require ( 'marked' ) ; this . markedInstance = marked ; const renderer = new this . markedInstance . Renderer ( ) ; renderer . code = ( code , language ) => { let highlighted = code ; if ( ! language ) { language = 'none' ; } highlighted = this . escape ( code ) ; return `<div><pre class="line-numbers"><code class="language-${ language }">${ highlighted }</code></pre></div>` ; } ; renderer . table = ( header , body ) => { return ( '<table class="table table-bordered compodoc-table">\n' + '<thead>\n' + header + '</thead>\n' + '<tbody>\n' + body + '</tbody>\n' + '</table>\n' ) ; } ; renderer . image = function ( href , title , text ) { let out = '<img src="' + href + '" alt="' + text + '" class="img-responsive"' ; if ( title ) { out += ' title="' + title + '"' ; } out += '>' ; return out ; } ; this . markedInstance . setOptions ( { renderer : renderer , gfm : true , breaks : false } ) ; } public static getInstance ( ) { if ( ! MarkdownEngine . instance ) { MarkdownEngine . instance = new MarkdownEngine ( ) ; } return MarkdownEngine . instance ; } public getTraditionalMarkdown ( filepath ) { return FileEngine . get ( process . cwd ( ) + path . sep + filepath + '.md' ) . catch ( err => FileEngine . get ( process . cwd ( ) + path . sep + filepath ) . then ( ) ) . then ( data => { const returnedData = { markdown : this . markedInstance ( data ) , rawData : data } ; return returnedData ; } ) ; } public getTraditionalMarkdownSync ( filepath ) { return this . markedInstance ( FileEngine . getSync ( process . cwd ( ) + path . sep + filepath ) ) ; } private getReadmeFile ( ) { return FileEngine . get ( process . cwd ( ) + path . sep + 'README.md' ) . then ( data => this . markedInstance ( data ) ) ; } public readNeighbourReadmeFile ( file ) { let dirname = path . dirname ( file ) ; let readmeFile = dirname + path . sep + path . basename ( file , '.ts' ) + '.md' ; return fs . readFileSync ( readmeFile , 'utf8' ) ; } public hasNeighbourReadmeFile ( file ) { let dirname = path . dirname ( file ) ; let readmeFile = dirname + path . sep + path . basename ( file , '.ts' ) + '.md' ; return FileEngine . existsSync ( readmeFile ) ; } private componentReadmeFile ( file ) { let dirname = path . dirname ( file ) ; let readmeFile = dirname + path . sep + 'README.md' ; let readmeAlternativeFile = dirname + path . sep + path . basename ( file , '.ts' ) + '.md' ; let finalPath = '' ; if ( FileEngine . existsSync ( readmeFile ) ) { finalPath = readmeFile ; } else { finalPath = readmeAlternativeFile ; } return finalPath ; } /**
     * Checks if any of the markdown files is exists with or without endings
     */ public hasRootMarkdowns ( ) { return this . addEndings ( this . markdownFiles ) . some ( x => FileEngine . existsSync ( process . cwd ( ) + path . sep + x ) ) ; } public listRootMarkdowns ( ) { let foundFiles = this . markdownFiles . filter ( x => FileEngine . existsSync ( process . cwd ( ) + path . sep + x + '.md' ) || FileEngine . existsSync ( process . cwd ( ) + path . sep + x ) ) ; return this . addEndings ( foundFiles ) ; } private escape ( html ) { return html . replace ( /&/g , '&amp;' ) . replace ( /</g , '&lt;' ) . replace ( />/g , '&gt;' ) . replace ( /"/g , '&quot;' ) . replace ( /'/g , '&#39;' ) . replace ( /@/g , '&#64;' ) ; } /**
     * ['README'] => ['README', 'README.md']
     */ private addEndings ( files ) { return _ . flatMap ( files , x => [ x , x + '.md' ] ) ; } } export default MarkdownEngine . getInstance ( ) ;