@peaceroad/markdown-it-renderer-fence 0.4.0 → 0.5.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 +440 -112
- package/THIRD_PARTY_NOTICES.md +56 -0
- package/index.js +33 -479
- package/package.json +29 -3
- 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 +40 -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 +136 -0
- package/src/fence/render-api-runtime.js +712 -0
- package/src/fence/render-api.js +117 -0
- package/src/fence/render-markup.js +161 -0
- package/src/fence/render-shared.js +428 -0
- package/src/utils/attr-utils.js +120 -0
- package/src/utils/pre-code-wrapper-parser.js +114 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import {
|
|
2
|
+
escapeJsonForScript,
|
|
3
|
+
} from '../custom-highlight/payload-utils.js'
|
|
4
|
+
import {
|
|
5
|
+
addTimingMs,
|
|
6
|
+
commentLineClass,
|
|
7
|
+
emitFenceDecision,
|
|
8
|
+
finalizeFenceTimings,
|
|
9
|
+
getNowMs,
|
|
10
|
+
orderTokenAttrs,
|
|
11
|
+
preWrapStyle,
|
|
12
|
+
splitFenceBlockToLines,
|
|
13
|
+
} from './render-shared.js'
|
|
14
|
+
import {
|
|
15
|
+
createApiPayloadForFence,
|
|
16
|
+
shouldApplyApiFallbackForReason,
|
|
17
|
+
} from './render-api-provider.js'
|
|
18
|
+
import {
|
|
19
|
+
customHighlightDataEnvKey,
|
|
20
|
+
customHighlightPreAttr,
|
|
21
|
+
customHighlightSeqEnvKey,
|
|
22
|
+
} from './render-api-constants.js'
|
|
23
|
+
import {
|
|
24
|
+
renderFenceMarkup,
|
|
25
|
+
} from './render-markup.js'
|
|
26
|
+
|
|
27
|
+
let fallbackCustomHighlightSeq = 0
|
|
28
|
+
|
|
29
|
+
const nextCustomHighlightId = (env, prefix) => {
|
|
30
|
+
if (env && typeof env === 'object') {
|
|
31
|
+
const n = Number.isSafeInteger(env[customHighlightSeqEnvKey]) ? env[customHighlightSeqEnvKey] + 1 : 1
|
|
32
|
+
env[customHighlightSeqEnvKey] = n
|
|
33
|
+
return `${prefix}${n}`
|
|
34
|
+
}
|
|
35
|
+
fallbackCustomHighlightSeq += 1
|
|
36
|
+
return `${prefix}${fallbackCustomHighlightSeq}`
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const buildApiPreAttrs = (preWrapValue, wrapEnabled, opt) => {
|
|
40
|
+
const preAttrs = []
|
|
41
|
+
if (preWrapValue !== undefined) preAttrs.push(['data-pre-wrap', preWrapValue])
|
|
42
|
+
if (wrapEnabled && opt.setPreWrapStyle !== false) preAttrs.push(['style', preWrapStyle])
|
|
43
|
+
return preAttrs
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const renderFenceApiOrPlain = (token, lang, md, opt, slf, env, startNumber, emphasizeLines, wrapEnabled, preWrapValue, commentMarkValue, includePayload, timings) => {
|
|
47
|
+
const isSamp = opt._sampReg.test(lang)
|
|
48
|
+
const tag = isSamp ? 'samp' : 'code'
|
|
49
|
+
let content = md.utils.escapeHtml(token.content)
|
|
50
|
+
const lineStrategy = opt.customHighlight.lineFeatureStrategy
|
|
51
|
+
const needLineNumber = lineStrategy === 'hybrid' && opt.setLineNumber && startNumber >= 0
|
|
52
|
+
const needEndSpan = lineStrategy === 'hybrid' && opt.lineEndSpanThreshold > 0
|
|
53
|
+
if (needLineNumber || needEndSpan) {
|
|
54
|
+
const splitStartedAt = timings ? getNowMs() : 0
|
|
55
|
+
const nlIndex = content.indexOf('\n')
|
|
56
|
+
const br = nlIndex > 0 && content[nlIndex - 1] === '\r' ? '\r\n' : '\n'
|
|
57
|
+
content = splitFenceBlockToLines(content, [], needLineNumber, false, needEndSpan, opt.lineEndSpanThreshold, opt.lineEndSpanClass, br, undefined, commentLineClass)
|
|
58
|
+
if (timings) addTimingMs(timings, 'lineSplitMs', getNowMs() - splitStartedAt)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
orderTokenAttrs(token, opt)
|
|
62
|
+
const preAttrs = buildApiPreAttrs(preWrapValue, wrapEnabled, opt)
|
|
63
|
+
let inlinePayloadScript = ''
|
|
64
|
+
|
|
65
|
+
if (includePayload) {
|
|
66
|
+
const providerStartedAt = timings ? getNowMs() : 0
|
|
67
|
+
const payload = createApiPayloadForFence(token, lang, opt, md, env, emphasizeLines, commentMarkValue)
|
|
68
|
+
if (timings) addTimingMs(timings, 'providerMs', getNowMs() - providerStartedAt)
|
|
69
|
+
const id = nextCustomHighlightId(env, opt.customHighlight.idPrefix)
|
|
70
|
+
preAttrs.push([customHighlightPreAttr, id])
|
|
71
|
+
|
|
72
|
+
if (opt.customHighlight.transport === 'env' && env && typeof env === 'object') {
|
|
73
|
+
if (!env[customHighlightDataEnvKey] || typeof env[customHighlightDataEnvKey] !== 'object') env[customHighlightDataEnvKey] = {}
|
|
74
|
+
env[customHighlightDataEnvKey][id] = payload
|
|
75
|
+
} else {
|
|
76
|
+
const payloadJson = escapeJsonForScript(payload)
|
|
77
|
+
const scriptId = `pre-highlight-data-${id}`
|
|
78
|
+
inlinePayloadScript = `<script type="application/json" id="${scriptId}" ${customHighlightPreAttr}="${id}">${payloadJson}</script>\n`
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (preAttrs.length) orderTokenAttrs({ attrs: preAttrs }, opt)
|
|
83
|
+
const preAttrsText = preAttrs.length ? slf.renderAttrs({ attrs: preAttrs }) : ''
|
|
84
|
+
const html = `<pre${preAttrsText}><${tag}${slf.renderAttrs(token)}>${content}</${tag}></pre>\n`
|
|
85
|
+
return inlinePayloadScript ? html + inlinePayloadScript : html
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const getFenceHtml = (context, md, opt, slf, env) => {
|
|
89
|
+
const token = context.token
|
|
90
|
+
const lang = context.lang
|
|
91
|
+
const timingEnabled = context.timingEnabled
|
|
92
|
+
const timings = context.timings
|
|
93
|
+
const fenceStartedAt = context.fenceStartedAt
|
|
94
|
+
const startNumber = context.startNumber
|
|
95
|
+
const emphasizeLines = context.emphasizeLines
|
|
96
|
+
const wrapEnabled = context.wrapEnabled
|
|
97
|
+
const preWrapValue = context.preWrapValue
|
|
98
|
+
const commentMarkValue = context.commentMarkValue
|
|
99
|
+
|
|
100
|
+
const apiDecisionBase = {
|
|
101
|
+
renderer: 'api',
|
|
102
|
+
includePayload: true,
|
|
103
|
+
fallbackUsed: false,
|
|
104
|
+
lineFeatureStrategy: opt.customHighlight.lineFeatureStrategy,
|
|
105
|
+
disabledFeatures: opt.customHighlight.lineFeatureStrategy === 'disable'
|
|
106
|
+
? ['setLineNumber', 'lineEndSpanThreshold']
|
|
107
|
+
: [],
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
const html = renderFenceApiOrPlain(token, lang, md, opt, slf, env, startNumber, emphasizeLines, wrapEnabled, preWrapValue, commentMarkValue, true, timings)
|
|
111
|
+
if (timingEnabled) apiDecisionBase.timings = finalizeFenceTimings(timings, fenceStartedAt)
|
|
112
|
+
emitFenceDecision(opt, apiDecisionBase)
|
|
113
|
+
return html
|
|
114
|
+
} catch (err) {
|
|
115
|
+
if (opt.customHighlight.fallback === 'plain' && shouldApplyApiFallbackForReason(opt.customHighlight, 'provider-error')) {
|
|
116
|
+
const fallbackDecision = {
|
|
117
|
+
renderer: 'api',
|
|
118
|
+
includePayload: false,
|
|
119
|
+
fallbackUsed: true,
|
|
120
|
+
fallback: 'plain',
|
|
121
|
+
reason: 'provider-error',
|
|
122
|
+
lineFeatureStrategy: opt.customHighlight.lineFeatureStrategy,
|
|
123
|
+
}
|
|
124
|
+
const html = renderFenceApiOrPlain(token, lang, md, opt, slf, env, startNumber, emphasizeLines, wrapEnabled, preWrapValue, commentMarkValue, false, timings)
|
|
125
|
+
if (timingEnabled) fallbackDecision.timings = finalizeFenceTimings(timings, fenceStartedAt)
|
|
126
|
+
emitFenceDecision(opt, fallbackDecision)
|
|
127
|
+
return html
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return renderFenceMarkup(context, md, opt, slf)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export {
|
|
135
|
+
getFenceHtml,
|
|
136
|
+
}
|