99 lines
2.2 KiB
TypeScript
99 lines
2.2 KiB
TypeScript
import crypto from 'crypto'
|
|
|
|
import scopeCss from '@patarapolw/scope-css'
|
|
import cheerio from 'cheerio'
|
|
import ejs from 'ejs'
|
|
import jieba from 'nodejieba'
|
|
import showdown from 'showdown'
|
|
|
|
export class MakeHTML {
|
|
$ = cheerio.load('')
|
|
|
|
mdConverter = new showdown.Converter({
|
|
noHeaderId: true,
|
|
parseImgDimensions: true,
|
|
simplifiedAutoLink: true,
|
|
// literalMidWordUnderscores: true,
|
|
strikethrough: true,
|
|
tables: true,
|
|
tasklists: true,
|
|
// simpleLineBreaks: true,
|
|
openLinksInNewWindow: true,
|
|
backslashEscapesHTMLTags: true,
|
|
emoji: true,
|
|
underline: true,
|
|
metadata: true,
|
|
})
|
|
|
|
constructor() {
|
|
/**
|
|
* ! For some reasons default underscore italic fails to render...
|
|
*/
|
|
this.mdConverter.addExtension(
|
|
{
|
|
type: 'lang',
|
|
regex: /([^\\])_{1}(.*?[^\\])_{1}/g,
|
|
replace: '$1<i>$2</i>',
|
|
},
|
|
'underscore-italic'
|
|
)
|
|
}
|
|
|
|
async parse(
|
|
filename: string
|
|
): Promise<{
|
|
$: cheerio.Cheerio
|
|
html(): string
|
|
clean(): string
|
|
}> {
|
|
const id =
|
|
'md-' +
|
|
crypto
|
|
.createHash('sha256')
|
|
.update(filename)
|
|
.digest()
|
|
.toString('hex')
|
|
.substr(8)
|
|
|
|
const $div = this.$(`<div id="${id}">`)
|
|
$div.html(await this.getHTML(filename))
|
|
$div.find('style').each((_, el) => {
|
|
const $el = this.$(el)
|
|
const html = $el.html() || ''
|
|
if (html.trim()) {
|
|
$el.html(scopeCss(html, `#${id}`))
|
|
}
|
|
})
|
|
|
|
return {
|
|
$: $div,
|
|
html() {
|
|
return $div.html() || ''
|
|
},
|
|
clean() {
|
|
return jieba.cutForSearch($div.text() || '').join(' ')
|
|
},
|
|
}
|
|
}
|
|
|
|
private async getHTML(filename: string) {
|
|
return this.mdConverter.makeHtml(
|
|
await ejs.renderFile(filename, {
|
|
youtube: (id: string) =>
|
|
this.$('<div>')
|
|
.html(
|
|
/* html */ `
|
|
<div style="padding-top:56.25%">
|
|
<iframe src="https://www.youtube.com/embed/${id}"
|
|
frameborder="0"
|
|
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
|
|
allowfullscreen
|
|
style="width:100%; height:100%"></iframe>
|
|
</div>`
|
|
)
|
|
.html(),
|
|
})
|
|
)
|
|
}
|
|
}
|