@peaceroad/markdown-it-renderer-fence 0.4.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +491 -114
- package/THIRD_PARTY_NOTICES.md +56 -0
- package/index.js +33 -503
- package/package.json +28 -4
- package/src/custom-highlight/option-validator.js +152 -0
- package/src/custom-highlight/payload-utils.js +43 -0
- package/src/custom-highlight/runtime-utils.js +83 -0
- package/src/custom-highlight/shiki-keyword-rules.js +407 -0
- package/src/custom-highlight/shiki-keyword.js +417 -0
- package/src/entry/custom-highlight-runtime.js +11 -0
- package/src/entry/custom-highlight.js +25 -0
- package/src/entry/markup-highlight.js +27 -0
- package/src/fence/render-api-constants.js +34 -0
- package/src/fence/render-api-provider.js +810 -0
- package/src/fence/render-api-renderer.js +145 -0
- package/src/fence/render-api-runtime.js +712 -0
- package/src/fence/render-api.js +107 -0
- package/src/fence/render-markup.js +177 -0
- package/src/fence/render-shared.js +590 -0
- package/src/utils/attr-utils.js +120 -0
- package/src/utils/pre-code-wrapper-parser.js +114 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Third-Party Notices
|
|
2
|
+
|
|
3
|
+
This repository is licensed under MIT (see `LICENSE`), and also contains documentation assets derived from third-party themes.
|
|
4
|
+
|
|
5
|
+
## highlight.js theme references used in docs
|
|
6
|
+
|
|
7
|
+
Files:
|
|
8
|
+
|
|
9
|
+
- `docs/default-highlight-theme.css`
|
|
10
|
+
|
|
11
|
+
Source references:
|
|
12
|
+
|
|
13
|
+
- `highlight.js` style family (GitHub / GitHub Dark)
|
|
14
|
+
- Upstream paths (for reference):
|
|
15
|
+
- `node_modules/highlight.js/styles/github.css`
|
|
16
|
+
- `node_modules/highlight.js/styles/github-dark.css`
|
|
17
|
+
|
|
18
|
+
Upstream license:
|
|
19
|
+
|
|
20
|
+
- BSD 3-Clause License
|
|
21
|
+
- Copyright (c) 2006, Ivan Sagalaev.
|
|
22
|
+
|
|
23
|
+
Full upstream license text:
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
BSD 3-Clause License
|
|
27
|
+
|
|
28
|
+
Copyright (c) 2006, Ivan Sagalaev.
|
|
29
|
+
All rights reserved.
|
|
30
|
+
|
|
31
|
+
Redistribution and use in source and binary forms, with or without
|
|
32
|
+
modification, are permitted provided that the following conditions are met:
|
|
33
|
+
|
|
34
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
35
|
+
list of conditions and the following disclaimer.
|
|
36
|
+
|
|
37
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
38
|
+
this list of conditions and the following disclaimer in the documentation
|
|
39
|
+
and/or other materials provided with the distribution.
|
|
40
|
+
|
|
41
|
+
* Neither the name of the copyright holder nor the names of its
|
|
42
|
+
contributors may be used to endorse or promote products derived from
|
|
43
|
+
this software without specific prior written permission.
|
|
44
|
+
|
|
45
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
46
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
47
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
48
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
49
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
50
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
51
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
52
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
53
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
54
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
55
|
+
```
|
|
56
|
+
|
package/index.js
CHANGED
|
@@ -1,509 +1,39 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const appendStyleValue = (style, addition) => {
|
|
19
|
-
if (!addition) return style
|
|
20
|
-
let next = addition.trim()
|
|
21
|
-
if (!next) return style
|
|
22
|
-
if (!next.endsWith(';')) next += ';'
|
|
23
|
-
if (!style) return next
|
|
24
|
-
const base = style.trimEnd()
|
|
25
|
-
const separator = base.endsWith(';') ? ' ' : '; '
|
|
26
|
-
return base + separator + next
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const parseHtmlAttrs = (attrText) => {
|
|
30
|
-
const attrs = []
|
|
31
|
-
if (!attrText) return attrs
|
|
32
|
-
htmlAttrReg.lastIndex = 0
|
|
33
|
-
let match
|
|
34
|
-
while ((match = htmlAttrReg.exec(attrText)) !== null) {
|
|
35
|
-
const name = match[1]
|
|
36
|
-
const val = match[2] ?? match[3] ?? match[4] ?? ''
|
|
37
|
-
attrs.push([name, val])
|
|
38
|
-
}
|
|
39
|
-
return attrs
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const mergeAttrSets = (target, source) => {
|
|
43
|
-
if (!source || source.length === 0) return
|
|
44
|
-
const index = new Map()
|
|
45
|
-
for (let i = 0; i < target.length; i++) index.set(target[i][0], i)
|
|
46
|
-
for (const [name, val] of source) {
|
|
47
|
-
const idx = index.get(name)
|
|
48
|
-
if (name === 'class') {
|
|
49
|
-
if (idx === undefined) {
|
|
50
|
-
target.push([name, val])
|
|
51
|
-
index.set(name, target.length - 1)
|
|
52
|
-
} else if (val) {
|
|
53
|
-
const existing = target[idx][1]
|
|
54
|
-
target[idx][1] = existing ? existing + ' ' + val : val
|
|
55
|
-
}
|
|
56
|
-
continue
|
|
57
|
-
}
|
|
58
|
-
if (name === 'style') {
|
|
59
|
-
if (idx === undefined) {
|
|
60
|
-
target.push([name, val])
|
|
61
|
-
index.set(name, target.length - 1)
|
|
62
|
-
} else {
|
|
63
|
-
target[idx][1] = appendStyleValue(target[idx][1], val)
|
|
64
|
-
}
|
|
65
|
-
continue
|
|
66
|
-
}
|
|
67
|
-
if (idx === undefined) {
|
|
68
|
-
target.push([name, val])
|
|
69
|
-
index.set(name, target.length - 1)
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const parseStartNumber = (val) => {
|
|
75
|
-
if (val == null) return null
|
|
76
|
-
const text = String(val).trim()
|
|
77
|
-
if (!nonNegativeIntReg.test(text)) return null
|
|
78
|
-
const n = Number(text)
|
|
79
|
-
if (!Number.isSafeInteger(n)) return null
|
|
80
|
-
return n
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const getLogicalLineCount = (text) => {
|
|
84
|
-
const lines = text.split(lineBreakReg)
|
|
85
|
-
if (lines.length === 0) return 0
|
|
86
|
-
return lines[lines.length - 1] === '' ? lines.length - 1 : lines.length
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const getEmphasizeLines = (attrVal) => {
|
|
90
|
-
const lines = []
|
|
91
|
-
for (const range of attrVal.split(',')) {
|
|
92
|
-
const part = range.trim()
|
|
93
|
-
if (!part) continue
|
|
94
|
-
const dash = part.indexOf('-')
|
|
95
|
-
if (dash > -1) {
|
|
96
|
-
const left = part.slice(0, dash).trim()
|
|
97
|
-
const right = part.slice(dash + 1).trim()
|
|
98
|
-
const s = left ? parseInt(left, 10) : null
|
|
99
|
-
const e = right ? parseInt(right, 10) : null
|
|
100
|
-
if (s !== null && (!Number.isFinite(s) || s <= 0)) continue
|
|
101
|
-
if (e !== null && (!Number.isFinite(e) || e <= 0)) continue
|
|
102
|
-
if (s === null && e === null) {
|
|
103
|
-
lines.push([null, null])
|
|
104
|
-
} else {
|
|
105
|
-
lines.push([s, e])
|
|
106
|
-
}
|
|
107
|
-
} else {
|
|
108
|
-
const s = parseInt(part, 10)
|
|
109
|
-
if (!Number.isFinite(s) || s <= 0) continue
|
|
110
|
-
lines.push([s, s])
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return lines
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const splitFenceBlockToLines = (content, emphasizeLines, needLineNumber, needEmphasis, needEndSpan, threshold, lineEndSpanClass, br, commentLines, commentClass) => {
|
|
117
|
-
const lines = content.split(lineBreakReg)
|
|
118
|
-
const len = lines.length
|
|
119
|
-
const endSpanTag = needEndSpan ? `<span class="${lineEndSpanClass}"></span>` : ''
|
|
120
|
-
const needComment = !!(commentLines && commentClass)
|
|
121
|
-
const maxLine = len - (lines[len - 1] === '' ? 1 : 0)
|
|
122
|
-
let emIdx = 0
|
|
123
|
-
let emStart
|
|
124
|
-
let emEnd
|
|
125
|
-
let doEmphasis = false
|
|
126
|
-
if (needEmphasis && maxLine > 0) {
|
|
127
|
-
const normalized = []
|
|
128
|
-
for (const range of emphasizeLines) {
|
|
129
|
-
let [s, e] = range
|
|
130
|
-
if (s == null) s = 1
|
|
131
|
-
if (e == null) e = maxLine
|
|
132
|
-
if (!Number.isFinite(s) || !Number.isFinite(e) || s <= 0 || e <= 0) continue
|
|
133
|
-
if (s > e) {
|
|
134
|
-
const tmp = s
|
|
135
|
-
s = e
|
|
136
|
-
e = tmp
|
|
137
|
-
}
|
|
138
|
-
if (s > maxLine || e < 1) continue
|
|
139
|
-
if (e > maxLine) e = maxLine
|
|
140
|
-
normalized.push([s, e])
|
|
141
|
-
}
|
|
142
|
-
if (normalized.length > 0) {
|
|
143
|
-
doEmphasis = true
|
|
144
|
-
emphasizeLines = normalized
|
|
145
|
-
;[emStart, emEnd] = emphasizeLines[0]
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
for (let n = 0; n < len; n++) {
|
|
149
|
-
let line = lines[n]
|
|
150
|
-
|
|
151
|
-
if (needEndSpan) {
|
|
152
|
-
let lineLen = line.length
|
|
153
|
-
if (lineLen < threshold) {
|
|
154
|
-
lineLen = 0
|
|
155
|
-
for (let i = 0, L = line.length; i < L; i++) {
|
|
156
|
-
lineLen += line.charCodeAt(i) > 255 ? 2 : 1
|
|
157
|
-
if (lineLen >= threshold) break
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
if (lineLen >= threshold) {
|
|
161
|
-
if (line.slice(-closeTagLen) === closeTag) {
|
|
162
|
-
line = line.slice(0, -closeTagLen) + endSpanTag + closeTag
|
|
163
|
-
} else {
|
|
164
|
-
line = line + endSpanTag
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (needLineNumber && n !== len - 1) {
|
|
170
|
-
if (line.indexOf('<') !== -1) {
|
|
171
|
-
const tagStack = []
|
|
172
|
-
tagReg.lastIndex = 0
|
|
173
|
-
let match
|
|
174
|
-
while ((match = tagReg.exec(line)) !== null) {
|
|
175
|
-
const [fullMatch, tagName] = match
|
|
176
|
-
const tagNameLower = tagName.toLowerCase()
|
|
177
|
-
if (fullMatch.startsWith('</')) {
|
|
178
|
-
if (tagStack[tagStack.length-1] === tagNameLower) tagStack.pop()
|
|
179
|
-
} else if (!fullMatch.endsWith('/>') && !voidTags.has(tagNameLower)) {
|
|
180
|
-
tagStack.push(tagNameLower)
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
for (let i = tagStack.length-1; i >= 0; i--) {
|
|
184
|
-
const tagName = tagStack[i]
|
|
185
|
-
line += `</${tagName}>`
|
|
186
|
-
lines[n+1] = `<${tagName}>` + (lines[n+1]||'')
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (needComment && commentLines[n]) {
|
|
192
|
-
line = `<span class="${commentClass}">` + line + closeTag
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (needLineNumber && n !== len - 1) {
|
|
196
|
-
line = preLineTag + line + closeTag
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
if (doEmphasis) {
|
|
200
|
-
if (emStart === n + 1) line = emphOpenTag + line
|
|
201
|
-
if (emEnd === n) {
|
|
202
|
-
line = closeTag + line
|
|
203
|
-
emIdx++
|
|
204
|
-
[emStart, emEnd] = emphasizeLines[emIdx] || []
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
lines[n] = line
|
|
208
|
-
}
|
|
209
|
-
return lines.join(br)
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
const getInfoAttr = (infoAttr) => {
|
|
213
|
-
let attrSets = infoAttr.trim().split(interAttrsSpaceReg)
|
|
214
|
-
let arr = []
|
|
215
|
-
for (let attrSet of attrSets) {
|
|
216
|
-
const str = attrReg.exec(attrSet)
|
|
217
|
-
if (str) {
|
|
218
|
-
if (str[1] === '.') str[1] = 'class'
|
|
219
|
-
if (str[1] === '#') str[1] = 'id'
|
|
220
|
-
if (str[3]) {
|
|
221
|
-
str[1] = str[3]
|
|
222
|
-
str[2] = str[5] ? str[5].replace(/^['"]/, '').replace(/['"]$/, '') : ''
|
|
223
|
-
}
|
|
224
|
-
arr.push([str[1], str[2]])
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
return arr
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
const orderTokenAttrs = (token, opt) => {
|
|
231
|
-
if (!token.attrs) return
|
|
232
|
-
const order = opt.attrsOrder || []
|
|
233
|
-
token.attrs.sort((a, b) => {
|
|
234
|
-
const idx = (name) => {
|
|
235
|
-
for (let i = 0; i < order.length; i++) {
|
|
236
|
-
const key = order[i]
|
|
237
|
-
if (key.endsWith('*')) {
|
|
238
|
-
const prefix = key.slice(0, -1)
|
|
239
|
-
if (name.startsWith(prefix)) return i
|
|
240
|
-
} else if (name === key) {
|
|
241
|
-
return i
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
return order.length
|
|
245
|
-
}
|
|
246
|
-
return idx(a[0]) - idx(b[0])
|
|
247
|
-
})
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
const getFenceHtml = (tokens, idx, md, opt, slf) => {
|
|
251
|
-
const token = tokens[idx]
|
|
252
|
-
let content = token.content
|
|
253
|
-
const match = token.info.trim().match(infoReg)
|
|
254
|
-
let lang = match ? match[1] : ''
|
|
255
|
-
|
|
256
|
-
if (match && match[2]) {
|
|
257
|
-
getInfoAttr(match[2]).forEach(([name, val]) => token.attrJoin(name, val))
|
|
258
|
-
}
|
|
259
|
-
if (lang && lang !== 'samp') {
|
|
260
|
-
const langClass = opt.langPrefix + lang
|
|
261
|
-
const existingClass = token.attrGet('class')
|
|
262
|
-
token.attrSet('class', existingClass ? langClass + ' ' + existingClass : langClass)
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
let startNumber = -1
|
|
266
|
-
let emphasizeLines = []
|
|
267
|
-
let wrapEnabled = false
|
|
268
|
-
let preWrapValue
|
|
269
|
-
let commentLineValue
|
|
270
|
-
|
|
271
|
-
if (token.attrs) {
|
|
272
|
-
const newAttrs = []
|
|
273
|
-
let dataPreStartIndex = -1
|
|
274
|
-
let dataPreEmphasisIndex = -1
|
|
275
|
-
let styleIndex = -1
|
|
276
|
-
let dataPreCommentIndex = -1
|
|
277
|
-
let startValue
|
|
278
|
-
let emphasisValue
|
|
279
|
-
let styleValue
|
|
280
|
-
let sawCommentLine = false
|
|
281
|
-
let sawStartAttr = false
|
|
282
|
-
let sawEmphasisAttr = false
|
|
283
|
-
const appendOrder = []
|
|
284
|
-
|
|
285
|
-
for (const attr of token.attrs) {
|
|
286
|
-
const name = attr[0]
|
|
287
|
-
const val = attr[1]
|
|
288
|
-
|
|
289
|
-
switch (name) {
|
|
290
|
-
case 'class': {
|
|
291
|
-
if (val.indexOf(opt.langPrefix) !== -1) {
|
|
292
|
-
const hasClassLang = opt._langReg.exec(val)
|
|
293
|
-
if (hasClassLang) lang = hasClassLang[1]
|
|
294
|
-
}
|
|
295
|
-
newAttrs.push(attr)
|
|
296
|
-
break
|
|
297
|
-
}
|
|
298
|
-
case 'style':
|
|
299
|
-
styleIndex = newAttrs.length
|
|
300
|
-
styleValue = val
|
|
301
|
-
newAttrs.push(attr)
|
|
302
|
-
break
|
|
303
|
-
case 'data-pre-start':
|
|
304
|
-
startNumber = parseStartNumber(val) ?? -1
|
|
305
|
-
startValue = val
|
|
306
|
-
dataPreStartIndex = newAttrs.length
|
|
307
|
-
newAttrs.push(attr)
|
|
308
|
-
break
|
|
309
|
-
case 'start':
|
|
310
|
-
case 'pre-start':
|
|
311
|
-
startNumber = parseStartNumber(val) ?? -1
|
|
312
|
-
startValue = val
|
|
313
|
-
if (!sawStartAttr) {
|
|
314
|
-
appendOrder.push('start')
|
|
315
|
-
sawStartAttr = true
|
|
316
|
-
}
|
|
317
|
-
break
|
|
318
|
-
case 'data-pre-emphasis':
|
|
319
|
-
dataPreEmphasisIndex = newAttrs.length
|
|
320
|
-
newAttrs.push(attr)
|
|
321
|
-
break
|
|
322
|
-
case 'data-pre-comment-line':
|
|
323
|
-
dataPreCommentIndex = newAttrs.length
|
|
324
|
-
commentLineValue = val
|
|
325
|
-
newAttrs.push(attr)
|
|
326
|
-
break
|
|
327
|
-
case 'em-lines':
|
|
328
|
-
case 'emphasize-lines':
|
|
329
|
-
if (opt.setEmphasizeLines) emphasizeLines = getEmphasizeLines(val)
|
|
330
|
-
emphasisValue = val
|
|
331
|
-
if (!sawEmphasisAttr) {
|
|
332
|
-
appendOrder.push('emphasis')
|
|
333
|
-
sawEmphasisAttr = true
|
|
334
|
-
}
|
|
335
|
-
break
|
|
336
|
-
case 'comment-line':
|
|
337
|
-
commentLineValue = val
|
|
338
|
-
if (!sawCommentLine) {
|
|
339
|
-
appendOrder.push('comment')
|
|
340
|
-
sawCommentLine = true
|
|
341
|
-
}
|
|
342
|
-
break
|
|
343
|
-
case 'data-pre-wrap':
|
|
344
|
-
preWrapValue = val
|
|
345
|
-
if (val === '' || val === 'true') wrapEnabled = true
|
|
346
|
-
break
|
|
347
|
-
case 'wrap':
|
|
348
|
-
case 'pre-wrap':
|
|
349
|
-
if (val === '' || val === 'true') {
|
|
350
|
-
wrapEnabled = true
|
|
351
|
-
}
|
|
352
|
-
break
|
|
353
|
-
default:
|
|
354
|
-
newAttrs.push(attr)
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
if (startValue !== undefined && dataPreStartIndex >= 0) {
|
|
359
|
-
newAttrs[dataPreStartIndex][1] = startValue
|
|
360
|
-
}
|
|
361
|
-
if (emphasisValue !== undefined && dataPreEmphasisIndex >= 0) {
|
|
362
|
-
newAttrs[dataPreEmphasisIndex][1] = emphasisValue
|
|
363
|
-
}
|
|
364
|
-
if (commentLineValue !== undefined && dataPreCommentIndex >= 0) {
|
|
365
|
-
newAttrs[dataPreCommentIndex][1] = commentLineValue
|
|
366
|
-
}
|
|
367
|
-
for (const kind of appendOrder) {
|
|
368
|
-
if (kind === 'start') {
|
|
369
|
-
if (dataPreStartIndex === -1 && startValue !== undefined) {
|
|
370
|
-
newAttrs.push(['data-pre-start', startValue])
|
|
371
|
-
}
|
|
372
|
-
} else if (kind === 'emphasis') {
|
|
373
|
-
if (dataPreEmphasisIndex === -1 && emphasisValue !== undefined) {
|
|
374
|
-
newAttrs.push(['data-pre-emphasis', emphasisValue])
|
|
375
|
-
}
|
|
376
|
-
} else if (kind === 'comment') {
|
|
377
|
-
if (dataPreCommentIndex === -1 && commentLineValue !== undefined) {
|
|
378
|
-
newAttrs.push(['data-pre-comment-line', commentLineValue])
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
if (startNumber !== -1) {
|
|
383
|
-
styleValue = appendStyleValue(styleValue, 'counter-set:pre-line-number ' + startNumber + ';')
|
|
384
|
-
}
|
|
385
|
-
if (styleIndex >= 0) {
|
|
386
|
-
if (styleValue !== undefined) newAttrs[styleIndex][1] = styleValue
|
|
387
|
-
} else if (styleValue) {
|
|
388
|
-
newAttrs.push(['style', styleValue])
|
|
389
|
-
}
|
|
390
|
-
if (wrapEnabled) preWrapValue = 'true'
|
|
391
|
-
token.attrs = newAttrs
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
const isSamp = opt._sampReg.test(lang)
|
|
395
|
-
let commentLines
|
|
396
|
-
let needComment = false
|
|
397
|
-
let sourceLogicalLineCount = -1
|
|
398
|
-
|
|
399
|
-
if (opt.setHighlight && md.options.highlight) {
|
|
400
|
-
if (lang && lang !== 'samp' ) {
|
|
401
|
-
content = md.options.highlight(content, lang)
|
|
402
|
-
} else {
|
|
403
|
-
content = md.utils.escapeHtml(token.content)
|
|
404
|
-
}
|
|
405
|
-
} else {
|
|
406
|
-
content = md.utils.escapeHtml(token.content)
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
let preAttrsFromHighlight
|
|
410
|
-
let hasHighlightPre = false
|
|
411
|
-
const hasPreTag = (content.indexOf('<pre') !== -1 || content.indexOf('<PRE') !== -1)
|
|
412
|
-
if (hasPreTag) {
|
|
413
|
-
const preMatch = content.match(preCodeWrapperReg)
|
|
414
|
-
if (preMatch) {
|
|
415
|
-
hasHighlightPre = true
|
|
416
|
-
preAttrsFromHighlight = parseHtmlAttrs(preMatch[1])
|
|
417
|
-
const codeAttrsFromHighlight = parseHtmlAttrs(preMatch[2])
|
|
418
|
-
content = preMatch[3]
|
|
419
|
-
if (codeAttrsFromHighlight.length) {
|
|
420
|
-
if (!token.attrs) token.attrs = []
|
|
421
|
-
mergeAttrSets(token.attrs, codeAttrsFromHighlight)
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
if (opt.useHighlightPre && hasPreTag && !hasHighlightPre) {
|
|
426
|
-
return content.endsWith('\n') ? content : content + '\n'
|
|
427
|
-
}
|
|
428
|
-
orderTokenAttrs(token, opt)
|
|
429
|
-
|
|
430
|
-
let preAttrs = preAttrsFromHighlight ? preAttrsFromHighlight.slice() : []
|
|
431
|
-
if (preWrapValue !== undefined) {
|
|
432
|
-
const idx = preAttrs.findIndex(attr => attr[0] === 'data-pre-wrap')
|
|
433
|
-
if (idx === -1) {
|
|
434
|
-
preAttrs.push(['data-pre-wrap', preWrapValue])
|
|
435
|
-
} else {
|
|
436
|
-
preAttrs[idx][1] = preWrapValue
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
if (wrapEnabled && opt.setPreWrapStyle !== false) {
|
|
440
|
-
const idx = preAttrs.findIndex(attr => attr[0] === 'style')
|
|
441
|
-
if (idx === -1) {
|
|
442
|
-
preAttrs.push(['style', preWrapStyle])
|
|
443
|
-
} else {
|
|
444
|
-
preAttrs[idx][1] = appendStyleValue(preAttrs[idx][1], preWrapStyle)
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
if (preAttrs.length) orderTokenAttrs({ attrs: preAttrs }, opt)
|
|
448
|
-
const preAttrsText = preAttrs.length ? slf.renderAttrs({ attrs: preAttrs }) : ''
|
|
449
|
-
|
|
450
|
-
const needLineNumber = opt.setLineNumber && startNumber >= 0
|
|
451
|
-
const needEmphasis = opt.setEmphasizeLines && emphasizeLines.length > 0
|
|
452
|
-
const needEndSpan = opt.lineEndSpanThreshold > 0
|
|
453
|
-
const useHighlightPre = opt.useHighlightPre && hasHighlightPre
|
|
454
|
-
if (!useHighlightPre && commentLineValue) {
|
|
455
|
-
const rawLines = token.content.split(lineBreakReg)
|
|
456
|
-
sourceLogicalLineCount = getLogicalLineCount(token.content)
|
|
457
|
-
commentLines = new Array(rawLines.length)
|
|
458
|
-
for (let i = 0; i < rawLines.length; i++) {
|
|
459
|
-
const isComment = rawLines[i].trimStart().startsWith(commentLineValue)
|
|
460
|
-
commentLines[i] = isComment
|
|
461
|
-
if (isComment) needComment = true
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
if (!useHighlightPre && (needLineNumber || needEmphasis || needEndSpan || needComment)) {
|
|
465
|
-
const nlIndex = content.indexOf('\n')
|
|
466
|
-
const br = nlIndex > 0 && content[nlIndex - 1] === '\r' ? '\r\n' : '\n'
|
|
467
|
-
if (needComment && sourceLogicalLineCount >= 0) {
|
|
468
|
-
const highlightedLogicalLineCount = getLogicalLineCount(content)
|
|
469
|
-
if (highlightedLogicalLineCount !== sourceLogicalLineCount) {
|
|
470
|
-
needComment = false
|
|
471
|
-
commentLines = undefined
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
content = splitFenceBlockToLines(content, emphasizeLines, needLineNumber, needEmphasis, needEndSpan, opt.lineEndSpanThreshold, opt.lineEndSpanClass, br, commentLines, commentLineClass)
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
const tag = isSamp ? 'samp' : 'code'
|
|
478
|
-
return `<pre${preAttrsText}><${tag}${slf.renderAttrs(token)}>${content}</${tag}></pre>\n`
|
|
1
|
+
import mditRendererFenceMarkup from './src/entry/markup-highlight.js'
|
|
2
|
+
import mditRendererFenceCustomHighlight, {
|
|
3
|
+
applyCustomHighlights,
|
|
4
|
+
clearCustomHighlights,
|
|
5
|
+
customHighlightPayloadSchemaVersion,
|
|
6
|
+
customHighlightPayloadSupportedVersions,
|
|
7
|
+
getCustomHighlightPayloadMap,
|
|
8
|
+
observeCustomHighlights,
|
|
9
|
+
renderCustomHighlightPayloadScript,
|
|
10
|
+
renderCustomHighlightScopeStyleTag,
|
|
11
|
+
shouldRuntimeFallback,
|
|
12
|
+
} from './src/entry/custom-highlight.js'
|
|
13
|
+
|
|
14
|
+
const normalizeHighlightRenderer = (value) => {
|
|
15
|
+
const key = String(value || '').trim().toLowerCase()
|
|
16
|
+
if (key === 'api' || key === 'custom-highlight-api') return 'api'
|
|
17
|
+
return 'markup'
|
|
479
18
|
}
|
|
480
19
|
|
|
481
20
|
const mditRendererFence = (md, option) => {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
opt._sampReg = new RegExp('^(?:samp|' + opt.sampLang.split(',').join('|') + ')$')
|
|
502
|
-
opt._langReg = new RegExp(opt.langPrefix + '([A-Za-z0-9-]+)')
|
|
503
|
-
|
|
504
|
-
md.renderer.rules['fence'] = (tokens, idx, options, env, slf) => {
|
|
505
|
-
return getFenceHtml(tokens, idx, md, opt, slf)
|
|
506
|
-
}
|
|
21
|
+
if (normalizeHighlightRenderer(option && option.highlightRenderer) === 'api') {
|
|
22
|
+
return mditRendererFenceCustomHighlight(md, option)
|
|
23
|
+
}
|
|
24
|
+
return mditRendererFenceMarkup(md, option)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export {
|
|
28
|
+
applyCustomHighlights,
|
|
29
|
+
clearCustomHighlights,
|
|
30
|
+
customHighlightPayloadSchemaVersion,
|
|
31
|
+
customHighlightPayloadSupportedVersions,
|
|
32
|
+
getCustomHighlightPayloadMap,
|
|
33
|
+
observeCustomHighlights,
|
|
34
|
+
renderCustomHighlightPayloadScript,
|
|
35
|
+
renderCustomHighlightScopeStyleTag,
|
|
36
|
+
shouldRuntimeFallback,
|
|
507
37
|
}
|
|
508
38
|
|
|
509
39
|
export default mditRendererFence
|
package/package.json
CHANGED
|
@@ -1,24 +1,48 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peaceroad/markdown-it-renderer-fence",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "In code blocks, the `<samp>` tag is used with the language keywords `samp`, `shell`, and `console`, and provides an option to display line numbers.",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./index.js",
|
|
8
|
+
"./custom-highlight": "./src/entry/custom-highlight.js",
|
|
9
|
+
"./custom-highlight-runtime": "./src/entry/custom-highlight-runtime.js",
|
|
10
|
+
"./markup-highlight": "./src/entry/markup-highlight.js"
|
|
11
|
+
},
|
|
6
12
|
"files": [
|
|
7
13
|
"index.js",
|
|
14
|
+
"src",
|
|
8
15
|
"LICENSE",
|
|
16
|
+
"THIRD_PARTY_NOTICES.md",
|
|
9
17
|
"README.md"
|
|
10
18
|
],
|
|
11
19
|
"type": "module",
|
|
20
|
+
"customHighlightPayload": {
|
|
21
|
+
"schemaVersion": 1,
|
|
22
|
+
"supportedVersions": [
|
|
23
|
+
1
|
|
24
|
+
]
|
|
25
|
+
},
|
|
12
26
|
"scripts": {
|
|
13
|
-
"test": "node test/test.js",
|
|
27
|
+
"test": "node test/test.js && node test/custom-highlight/provider-contract.test.js && node test/custom-highlight/provider-keyword-coverage.test.js && node test/custom-highlight/provider-keyword-holdout-parity.test.js && node -e \"console.log('Passed all test.')\"",
|
|
28
|
+
"test:provider:contract": "node test/custom-highlight/provider-contract.test.js",
|
|
29
|
+
"test:provider:keyword": "node test/custom-highlight/provider-keyword-coverage.test.js",
|
|
30
|
+
"test:provider:keyword:holdout": "node test/custom-highlight/provider-keyword-holdout-parity.test.js",
|
|
31
|
+
"test:provider:keyword:mismatch": "node test/custom-highlight/provider-keyword-mismatch-report.js",
|
|
32
|
+
"test:provider:matrix": "node test/custom-highlight/provider-matrix-audit.js",
|
|
33
|
+
"build:demo:provider:keyword": "node test/custom-highlight/build-provider-keyword-demos.js",
|
|
34
|
+
"build:example:custom-highlight": "node example/build-custom-highlight-compare.js",
|
|
14
35
|
"test:performance": "node test/performance/benchmark.js",
|
|
15
|
-
"test:performance:highlighter": "node test/performance/highlighter-benchmark.js"
|
|
36
|
+
"test:performance:highlighter": "node test/performance/highlighter-benchmark.js",
|
|
37
|
+
"test:performance:provider-modes": "node test/performance/provider-mode-benchmark.js",
|
|
38
|
+
"test:performance:runtime": "node test/performance/runtime-apply-benchmark.js",
|
|
39
|
+
"test:performance:keyword": "node test/performance/provider-mode-benchmark.js"
|
|
16
40
|
},
|
|
17
41
|
"author": "peaceroad <peaceroad@gmail.com>",
|
|
18
42
|
"repository": "https://github.com/peaceroad/p7d-markdown-it-renderer-fence",
|
|
19
43
|
"license": "MIT",
|
|
20
44
|
"devDependencies": {
|
|
21
|
-
"@peaceroad/markdown-it-figure-with-p-caption": "^0.
|
|
45
|
+
"@peaceroad/markdown-it-figure-with-p-caption": "^0.16.0",
|
|
22
46
|
"highlight.js": "^11.11.1",
|
|
23
47
|
"markdown-it": "^14.1.0",
|
|
24
48
|
"markdown-it-attrs": "^4.3.1",
|