@@ -6,8 +6,6 @@ let JSDOM,
6
6
createDOMPurify ;
7
7
8
8
const { encodeURL, slugize, stripHTML, url_for, isExternalLink, escapeHTML : escape , unescapeHTML : unescape } = require ( 'hexo-util' ) ;
9
- const MarkedRenderer = marked . Renderer ;
10
- const MarkedTokenizer = marked . Tokenizer ;
11
9
const { basename, dirname, extname, join } = require ( 'path' ) . posix ;
12
10
const rATag = / < a (?: \s + ?| \s + ?[ ^ < > ] + \s + ?) ? h r e f = [ " ' ] (?: # ) ( [ ^ < > " ' ] + ) [ " ' ] [ ^ < > ] * > / i;
13
11
const rDlSyntax = / (?: ^ | \s ) ( \S .+ ) < b r > : \s + ( \S .+ ) / ;
@@ -16,17 +14,27 @@ const anchorId = (str, transformOption) => {
16
14
return slugize ( stripHTML ( unescape ( str ) ) . trim ( ) , { transform : transformOption } ) ;
17
15
} ;
18
16
19
- class Renderer extends MarkedRenderer {
20
- constructor ( hexo ) {
21
- super ( ) ;
22
- this . _headingId = { } ;
23
- this . hexo = hexo ;
17
+ function mangleEmail ( text ) {
18
+ let out = '' ;
19
+ let i ,
20
+ ch ;
21
+
22
+ const l = text . length ;
23
+ for ( i = 0 ; i < l ; i ++ ) {
24
+ ch = text . charCodeAt ( i ) ;
25
+ if ( Math . random ( ) > 0.5 ) {
26
+ ch = 'x' + ch . toString ( 16 ) ;
27
+ }
28
+ out += '&#' + ch + ';' ;
24
29
}
25
30
31
+ return out ;
32
+ }
33
+
34
+ const renderer = {
26
35
// Add id attribute to headings
27
36
heading ( text , level ) {
28
- const { anchorAlias, headerIds, modifyAnchors } = this . options ;
29
- const { _headingId } = this ;
37
+ const { anchorAlias, headerIds, modifyAnchors, _headingId } = this . options ;
30
38
31
39
if ( ! headerIds ) {
32
40
return `<h${ level } >${ text } </h${ level } >` ;
@@ -57,17 +65,25 @@ class Renderer extends MarkedRenderer {
57
65
58
66
// add headerlink
59
67
return `<h${ level } id="${ id } "><a href="#${ id } " class="headerlink" title="${ stripHTML ( text ) } "></a>${ text } </h${ level } >` ;
60
- }
68
+ } ,
61
69
62
70
link ( href , title , text ) {
63
- const { external_link, sanitizeUrl } = this . options ;
64
- const { url : urlCfg } = this . hexo . config ;
71
+ const { external_link, sanitizeUrl, hexo , mangle } = this . options ;
72
+ const { url : urlCfg } = hexo . config ;
65
73
66
74
if ( sanitizeUrl ) {
67
75
if ( href . startsWith ( 'javascript:' ) || href . startsWith ( 'vbscript:' ) || href . startsWith ( 'data:' ) ) {
68
76
href = '' ;
69
77
}
70
78
}
79
+ if ( mangle ) {
80
+ if ( href . startsWith ( 'mailto:' ) ) {
81
+ const email = href . substring ( 7 ) ;
82
+ const mangledEmail = mangleEmail ( email ) ;
83
+
84
+ href = `mailto:${ mangledEmail } ` ;
85
+ }
86
+ }
71
87
72
88
let out = '<a href="' ;
73
89
@@ -99,7 +115,7 @@ class Renderer extends MarkedRenderer {
99
115
100
116
out += `>${ text } </a>` ;
101
117
return out ;
102
- }
118
+ } ,
103
119
104
120
// Support Basic Description Lists
105
121
paragraph ( text ) {
@@ -112,11 +128,12 @@ class Renderer extends MarkedRenderer {
112
128
}
113
129
114
130
return `<p>${ text } </p>\n` ;
115
- }
131
+ } ,
116
132
117
133
// Prepend root to image path
118
134
image ( href , title , text ) {
119
- const { hexo, options } = this ;
135
+ const { options } = this ;
136
+ const { hexo } = options ;
120
137
const { relative_link } = hexo . config ;
121
138
const { lazyload, figcaption, prependRoot, postPath } = options ;
122
139
@@ -142,11 +159,7 @@ class Renderer extends MarkedRenderer {
142
159
}
143
160
return out ;
144
161
}
145
- }
146
-
147
- marked . setOptions ( {
148
- langPrefix : ''
149
- } ) ;
162
+ } ;
150
163
151
164
// https://github.com/markedjs/marked/blob/b6773fca412c339e0cedd56b63f9fa1583cfd372/src/Lexer.js#L8-L24
152
165
const smartypants = ( str , quotes ) => {
@@ -171,15 +184,15 @@ const smartypants = (str, quotes) => {
171
184
. replace ( / \. { 3 } / g, '\u2026' ) ;
172
185
} ;
173
186
174
- class Tokenizer extends MarkedTokenizer {
187
+ const tokenizer = {
175
188
// Support AutoLink option
176
- url ( src , mangle ) {
177
- const { options } = this ;
178
- const { autolink } = options ;
189
+ url ( src ) {
190
+ const { autolink } = this . options ;
179
191
180
192
if ( ! autolink ) return ;
181
- return super . url ( src , mangle ) ;
182
- }
193
+ // return false to use original url tokenizer
194
+ return false ;
195
+ } ,
183
196
184
197
// Override smartypants
185
198
inlineText ( src ) {
@@ -202,21 +215,20 @@ class Tokenizer extends MarkedTokenizer {
202
215
} ;
203
216
}
204
217
}
205
- }
218
+ } ;
206
219
207
220
module . exports = function ( data , options ) {
208
221
const { post_asset_folder, marked : markedCfg , source_dir } = this . config ;
209
- const { prependRoot, postAsset, dompurify } = markedCfg ;
222
+ const { prependRoot, postAsset, dompurify, mangle } = markedCfg ;
210
223
const { path, text } = data ;
211
224
212
225
// exec filter to extend marked
213
226
this . execFilterSync ( 'marked:use' , marked . use , { context : this } ) ;
214
227
215
228
// exec filter to extend renderer.
216
- const renderer = new Renderer ( this ) ;
217
229
this . execFilterSync ( 'marked:renderer' , renderer , { context : this } ) ;
218
230
219
- const tokenizer = new Tokenizer ( ) ;
231
+ // exec filter to extend tokenizer
220
232
this . execFilterSync ( 'marked:tokenizer' , tokenizer , { context : this } ) ;
221
233
222
234
const extensions = [ ] ;
@@ -250,8 +262,13 @@ module.exports = function(data, options) {
250
262
}
251
263
sanitizer = function ( html ) { return DOMPurify . sanitize ( html , param ) ; } ;
252
264
}
253
- return sanitizer ( marked ( text , Object . assign ( {
265
+
266
+ marked . use ( {
254
267
renderer,
255
268
tokenizer
256
- } , markedCfg , options , { postPath } ) ) ) ;
269
+ } ) ;
270
+ return sanitizer ( marked . parse ( text , Object . assign ( {
271
+ // headerIds was removed in marked v8.0.0, but we still need it
272
+ headerIds : true
273
+ } , markedCfg , options , { postPath, hexo : this , _headingId : { } } ) ) ) ;
257
274
} ;
0 commit comments