-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
103 lines (92 loc) · 3.12 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
const z = require('zzz')
const markdown = require('marked')
const hljs = require('highlight.js')
module.exports = z(({ life }, [text]) => {
life(function renderOnce (_, update) {
let init = 0
update(() => {
return init++ === 0
})
})
const tokens = markdown.Lexer.lex(text, markdown.defaults)
return (attrs) => z``(attrs, tokens.map(parse))
})
const slugger = new markdown.Slugger()
const hr = z`hr`
const html = z.trust
const code = ({ lang, escaped }, text) => z`pre.hljs`(highlight(text, lang))
const codespan = text => z`code.hljs-inline`(highlight(text))
const blockquote = z`blockquote`
const paragraph = z`p`
const br = z`br`
const link = ({ href, title }, children) => {
const isCORS = new URL(token.href, window.location).hostname !== window.location.hostname
return z`a`({ href, title, target: isCORS ? '_blank' : '', rel: isCORS ? 'noopener' : '' }, children)
}
const image = z`img`
const strong = z`strong`
const em = z`em`
const del = z`del`
const ol = z`ol`
const ul = z`ul`
const li = z`li`
const error = (token) => { throw token }
function parse (token, top = true) {
switch (token.type) {
case 'space': return ''
case 'hr': return hr
case 'heading': return z`h${token.depth}`({ id: slugger.slug(token.text) }, token.tokens.map(parseInline))
case 'code': return code({ lang: token.lang, escaped: token.escaped }, token.text)
case 'table': return table(token)
case 'blockquote': return blockquote(token.tokens.map(parse))
case 'list': return list(token)
case 'html': return html(token.raw)
case 'paragraph': return paragraph(token.tokens.map(parseInline))
case 'text': {
// TODO needs to keep parsing next text tokens and bundle into one paragraph
const body = token.tokens ? token.tokens.map(parseInline) : token.raw
return top ? paragraph(body) : body
}
default: return error(token)
}
}
function table ({ align, tokens }) {
return z`table`(
z`thead`(tokens.header.map((th, i) =>
z`th`({ align: align[i] }, parseInline(th))
)),
z`tbody`(
tokens.cells.map((tr) =>
z`tr`(tr.map((td, i) =>
z`td`({ align: align[i] }, parseInline(td))
))
)
)
)
}
function list ({ ordered, start, loose, items }) {
return (ordered ? ol : ul)({ start }, items.map(item =>
li(item.tokens.map(t =>
parse(t, loose)
))
))
}
function highlight (code, lang) {
if (lang) return z.trust(hljs.highlight(lang, code).value)
return z.trust(hljs.highlightAuto(code).value)
}
function parseInline (token) {
switch (token.type) {
case 'escape': return token.raw
case 'html': return html(token.raw)
case 'codespan': return codespan(token.text)
case 'br': return br
case 'link': return link({ href: token.href, title: token.title }, token.tokens.map(parseInline))
case 'image': return image({ src: token.href, title: token.title, alt: token.text })
case 'strong': return strong(token.tokens.map(parseInline))
case 'em': return em(token.tokens.map(parseInline))
case 'del': return del(token.tokens.map(parseInline))
case 'text': return token.raw
default: return error(token)
}
}