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