This repository has been archived on 2023-08-30. You can view files and clone it, but cannot push or open issues/pull-requests.
bytedo
/
wcui
Archived
1
0
Fork 0

重构markdown解析器

old
宇天 2020-02-10 03:11:19 +08:00
parent 29dff0d99c
commit 6b17ad76ba
2 changed files with 213 additions and 20 deletions

View File

@ -11,6 +11,8 @@
}
.markd {
padding: 10px;
// white-space: pre-wrap;
// word-wrap: break-word;
}
a {
text-decoration: underline;
@ -27,6 +29,12 @@ em {
strong {
color: nth($cd, 3);
}
a {
strong,
em {
color: inherit;
}
}
em,
strong,
del {
@ -39,17 +47,15 @@ img {
max-width: 100%;
}
blockquote {
&.md-quote {
margin: 10px 0;
padding: 5px 10px;
border-left: 5px solid nth($ct, 1);
background: #f2faf7;
color: nth($cgr, 1);
p {
margin: 0;
}
blockquote.md-quote {
margin: 10px 0;
padding: 5px 10px;
line-height: 1.5;
border-left: 5px solid nth($ct, 1);
background: #f2faf7;
color: nth($cgr, 1);
p {
margin: 0;
}
}
@ -171,14 +177,13 @@ h6 {
padding: 0 5px;
}
a {
visibility: hidden;
position: absolute;
left: -25px;
width: 25px;
padding: 0 3px;
font-weight: bold;
text-decoration: none;
text-align: center;
color: #333;
&::before {
content: '# ';
color: nth($ct, 1);
}
}
&:hover a {
visibility: visible;
@ -225,7 +230,12 @@ table {
}
code.inline {
display: inline-block;
margin: 0 2px;
padding: 0 3px;
color: nth($co, 3);
background: nth($cp, 1);
border-radius: 2px;
}
</style>
@ -233,7 +243,8 @@ code.inline {
import $ from '../utils'
import '../code/index'
import parser from './core'
// import parser from './core'
import parser from './parser'
export default class Markd {
props = {}
@ -246,7 +257,8 @@ export default class Markd {
}
mounted() {
this.__BOX__.innerHTML = parser.safe(this.textContent)
// this.__BOX__.innerHTML = parser.safe(this.textContent)
this.__BOX__.innerHTML = parser(this.textContent)
this.textContent = ''
}
}

181
src/markd/parser.js Normal file
View File

@ -0,0 +1,181 @@
/**
* markdown解析器
* @author yutent<yutent@doui.cc>
* @date 2020/02/07 17:14:19
*/
'use strict'
const HR_LIST = ['=', '-', '_', '*']
const log = console.log
const Helper = {
// 是否分割线
isHr(str) {
var s = str[0]
if (HR_LIST.includes(s)) {
return str.startsWith(s.repeat(3))
}
return false
}
}
const Tool = {
// 初始化字符串, 处理多余换行等
init(str) {
// 去掉\r, 将\t转为空格(2个)
str = str.replace(/\r/g, '').replace(/\t/g, ' ')
var list = []
var lines = str.split('\n')
var isCodeBlock = false // 是否代码块
var emptyLineLength = 0 //连续空行的数量
for (let it of lines) {
let tmp = it.trim()
// 空行
if (!tmp) {
if (list.length === 0 || (!isCodeBlock && emptyLineLength > 0)) {
continue
}
emptyLineLength++
list.push(tmp)
} else {
emptyLineLength = 0
if (tmp.startsWith('```')) {
if (isCodeBlock) {
list.push('</wc-code>')
} else {
list.push(tmp.replace(/^```([\w\#\-]*?)$/, '<wc-code lang="$1">'))
}
isCodeBlock = !isCodeBlock
} else {
list.push(it)
}
}
}
log(list)
this.list = list
return this
},
parse() {
var html = ''
var isCodeBlock = false // 是否代码块
var emptyLineLength = 0 //连续空行的数量
var isBlockquote = false
var blockquoteLevel = 0
var isParagraph = false
//
for (let it of this.list) {
// 空行
if (!it) {
// 如果是在代码中, 直接拼接, 并加上换行
if (isCodeBlock) {
html += it + '\n'
} else {
emptyLineLength++
// 引用结束
if (isBlockquote) {
isBlockquote = false
html += ''
if (emptyLineLength > 0) {
while (blockquoteLevel > 0) {
emptyLineLength = 0
blockquoteLevel--
html += '</blockquote>'
}
}
continue
}
//
if (isParagraph) {
isParagraph = false
html += '</p>'
} /* else {
html += '<br>'
} */
}
} else {
// wc-code标签直接拼接
if (~it.indexOf('wc-code')) {
html += it
isCodeBlock = !isCodeBlock
} else {
// 同上代码块的处理
if (isCodeBlock) {
html += it + '\n'
continue
}
it = it
.replace(/`(.*?)`/g, '<code class="inline">$1</code>')
.replace(/(\-\-|\*\*)(.*?)\1/g, '<strong>$2</strong>')
.replace(/(\-|\*)(.*?)\1/g, '<em>$2</em>')
.replace(/\!\[([^]*?)\]\(([^)]*?)\)/g, '<img src="$2" alt="$1">')
.replace(/\[([^]*?)\]\(([^)]*?)\)/g, '<a href="$2">$1</a>')
//
if (it.startsWith('>')) {
html += it.replace(/^(>+) /, m => {
let len = m.trim().length
let tmp = ''
if (isBlockquote) {
// 若之前已经有一个未闭合的引用, 需要减去已有缩进级别, 避免产生新的引用标签
len = len - blockquoteLevel
} else {
blockquoteLevel = len
}
log('bq: ', blockquoteLevel, it)
while (len > 0) {
len--
tmp += '<blockquote class="md-quote">'
}
return tmp
})
if (isBlockquote) {
html += '<br>'
}
isParagraph = false
isBlockquote = true
continue
}
if (isBlockquote) {
html += it
continue
}
//
if (it.startsWith('#')) {
isParagraph = false
let end = ''
html += it.replace(/^#{1,6} /, m => {
let level = m.trim().length
end = `</a></h${level}>`
return `<h${level}><a href="#">`
})
html += end
continue
}
// log('it => ', isParagraph, it)
if (isParagraph) {
html += `${it}<br>`
} else {
html += `<p>${it}<br>`
}
isParagraph = true
}
}
}
return html
}
}
export default function(str) {
return Tool.init(str).parse()
}