rapier-markdown-kit 1.1.54 → 1.1.56

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,829 @@
1
+ // SPDX-License-Identifier: MIT
2
+ const RAPIER_TABLE_CAPTION_PREFIX_RE = /^(?:Table:|:) /;
3
+ // The document's renderer. DOM, codecs and host state are explicit inputs.
4
+ function createMarkdownRenderer(runtime) {
5
+ const {RAPIER_HIGHLIGHT_COLOR_BY_MARKER, RAPIER_MARKDOWN_SPEC, RAPIER_RENDERED_HEADING_SELECTOR, _rapierApplyMarkdownSpec, _rapierBidiStrong, _rapierChromeOwnsId, _rapierCodeHtml, _rapierDeriveDarkColor, _rapierDormantHeadings, _rapierEmbedAssetSource, _rapierHeadingSlugBase, _rapierHighlightAdmitted, _rapierInstallMarkdownMath, _rapierMarkdownPreview, _rapierPlainLayout, _rapierProviders, _rapierRemoteContent, _rapierRemoteImagePlaceholder, _rapierRemoteSubresourceOrigin, _rapierRenderedAnchorOriginalIds, _rapierSourceCharEscaped, _rapierSplitOpeningFrontmatter, _rapierUiDiagram, _rapierUiMath, document, escapeRapierHtmlText, globalThis, sanitizeRapierHtml, window} = runtime;
6
+ let md = runtime.md;
7
+ function initMarkdownIt() {
8
+ if (typeof window.markdownit !== 'function') throw new Error('markdownit');
9
+ if (typeof _rapierMarkdownPreview === 'function') globalThis.rapierRenderPreview = _rapierMarkdownPreview; // Notes' cards read through here (R86i law 3); the Node witnesses that run this function alone have no such neighbour
10
+
11
+ md = window.markdownit({
12
+ ...RAPIER_MARKDOWN_SPEC.options,
13
+ // The first paint is coloured: the CPU reading, synchronously, for every admitted fence.
14
+ highlight: (code, lang) => _rapierHighlightAdmitted(code) ? _rapierCodeHtml(code, lang) : '',
15
+ });
16
+
17
+ _rapierApplyMarkdownSpec(md, window);
18
+ globalThis.RapierImageAssets.installMarkdownImages(md);
19
+ _rapierInstallSemanticProbe(md);
20
+ _rapierInstallMarkdownMath(md, RAPIER_MARKDOWN_SPEC.rules.mathBlock);
21
+
22
+ const markOpenDefault = md.renderer.rules.mark_open ||
23
+ ((tokens, idx, opts, _env, self) => self.renderToken(tokens, idx, opts));
24
+ md.renderer.rules.mark_open = (tokens, idx, opts, env, self) => {
25
+ const token = tokens[idx];
26
+ const first = tokens[idx + 1];
27
+ if (first && first.type === 'text') {
28
+ for (const [marker, color] of Object.entries(RAPIER_HIGHLIGHT_COLOR_BY_MARKER)) {
29
+ if (!first.content.startsWith(marker)) continue;
30
+ let hasContent = first.content.length > marker.length;
31
+ let depth = 1;
32
+ for (let cursor = idx + 2; !hasContent && cursor < tokens.length; cursor++) {
33
+ const candidate = tokens[cursor];
34
+ if (candidate.type === 'mark_open') depth++;
35
+ else if (candidate.type === 'mark_close' && --depth === 0) break;
36
+ else if (depth > 0 && String(candidate.content || '').length) hasContent = true;
37
+ }
38
+ if (!hasContent) break;
39
+ first.content = first.content.slice(marker.length);
40
+ token.attrSet('data-rapier-highlight', color);
41
+ break;
42
+ }
43
+ }
44
+ return markOpenDefault(tokens, idx, opts, env, self);
45
+ };
46
+
47
+ md.renderer.rules.rapier_color_open = (tokens, idx) => {
48
+ const hex = String(tokens[idx].attrGet('data-md-color') || '').toLowerCase();
49
+ if (!/^#[0-9a-f]{6}$/.test(hex)) return '<span>';
50
+ const dark = _rapierDeriveDarkColor(hex);
51
+ return '<span data-md-color="' + hex + '" style="--md-color:' + hex + ';--md-color-dark:' + dark + '">';
52
+ };
53
+ md.renderer.rules.rapier_color_close = () => '</span>';
54
+ // Ink: the span carries its opener's body (the grammar's inkOpenBody: a sanitizer drops an attribute holding the comment's
55
+ // close); the ink layer reads it back through the one grammar and draws the stroke over the words' own boxes
56
+ // (docs/briefs/ink.md §3). The span itself shows nothing.
57
+ md.renderer.rules.rapier_ink_open = (tokens, idx) => {
58
+ const body = String(tokens[idx].attrGet('data-rapier-ink') || '');
59
+ // The dark-page colour on the span, as the colour span's: an exported page draws its ink with no engine to ask (the
60
+ // rules run on this thread alone; the Worker plants the parser, not the renderer).
61
+ const spec = globalThis.RapierMarkdownSpec;
62
+ const mark = spec && typeof spec.parseInkBody === 'function' ? spec.parseInkBody(body) : null;
63
+ return '<span class="rapier-ink-mark" data-rapier-ink="' + md.utils.escapeHtml(body) + '"'
64
+ + (mark ? ' data-rapier-ink-dark="' + _rapierDeriveDarkColor(mark.hex || '#b32034') + '"' : '') + '>';
65
+ };
66
+ md.renderer.rules.rapier_ink_close = () => '</span>';
67
+
68
+ const sourceToken = (source, visible, className) =>
69
+ '<span class="rapier-source-token ' + className + '" data-rapier-source="' +
70
+ encodeURIComponent(source) + '" data-rapier-visible="' + encodeURIComponent(visible) + '">' + md.utils.escapeHtml(visible) + '</span>';
71
+ md.renderer.rules.emoji = (tokens, idx) => {
72
+ const token = tokens[idx];
73
+ const source = token.markup ? ':' + token.markup + ':' : token.content;
74
+ return sourceToken(source, token.content, 'rapier-source-token--emoji');
75
+ };
76
+ md.renderer.rules.softbreak = () =>
77
+ sourceToken('\n', '\u2060', 'rapier-source-token--softbreak');
78
+ // A backslash escape the edit surface's writer would not write itself (`https\://`, `www\.`, `a\@b`: an unlinked
79
+ // address, or a person's own escape) is carried through the edit projection as a source token, as a soft break and
80
+ // an emoji are; the parser joins escapes into plain text before rendering, so they are kept apart first. The
81
+ // characters the writer escapes on its own (\ * ` [ ] _) stay the writer's.
82
+ md.core.ruler.before('text_join', 'rapier_escape_token', state => {
83
+ for (const token of state.tokens) {
84
+ if (token.type !== 'inline' || !token.children) continue;
85
+ for (const child of token.children) {
86
+ if (child.type === 'text_special' && child.info === 'escape' && child.content.length === 1 && !/[\\*`[\]_]/.test(child.content)) child.type = 'rapier_escape';
87
+ }
88
+ }
89
+ });
90
+ md.renderer.rules.rapier_escape = (tokens, idx) =>
91
+ sourceToken('\\' + tokens[idx].content, tokens[idx].content, 'rapier-source-token--escape');
92
+
93
+ const linkOpenDefault = md.renderer.rules.link_open ||
94
+ ((tokens, idx, opts, _env, self) => self.renderToken(tokens, idx, opts));
95
+ md.renderer.rules.link_open = (tokens, idx, opts, env, self) => {
96
+ const token = tokens[idx];
97
+ if (token.info === 'auto' && /^(?:linkify|autolink)$/.test(token.markup || '')) {
98
+ token.attrSet('data-rapier-auto-link', token.markup);
99
+ }
100
+ return linkOpenDefault(tokens, idx, opts, env, self);
101
+ };
102
+
103
+ md.renderer.rules.image = (tokens, idx, opts, env, self) => {
104
+ const token = tokens[idx];
105
+ const src = token.attrGet('src') || '';
106
+ const title = token.attrGet('title') || '';
107
+ const rawAlt = String(token.content ?? token.attrGet('alt') ?? '');
108
+ const size = _rapierImageAltSize(rawAlt);
109
+ const semanticAlt = token.children ? self.renderInlineAsText(token.children, opts, env) : _rapierImageAltText(rawAlt, env);
110
+ const suffix = size ? rawAlt.slice(size.alt.length) : '';
111
+ const alt = suffix && semanticAlt.endsWith(suffix) ? semanticAlt.slice(0, -suffix.length) : semanticAlt;
112
+ const layout = token.meta?.mdLayout?.imageOnly ? token.meta.mdLayout.marker : '';
113
+ const asset = globalThis.RapierImageAssets.dataImage(src), reference = token.meta?.mdImage?.reference;
114
+ // A connected host's own asset (W/6); a host without one (the server) supplies no port.
115
+ if (_rapierEmbedAssetSource?.(src) || asset && (reference || asset.codec === 'image/jxl' || asset.codec === 'image/svg+xml')) return globalThis.RapierEmbeddedImages.imageHtml(
116
+ reference, alt, title, size, layout, rawAlt, token.meta?.mdImage?.source, src);
117
+ if (!_rapierRemoteContent.allowed && _rapierRemoteSubresourceOrigin(src)) {
118
+ const html = _rapierRemoteImagePlaceholder(src, alt, title, size, layout, rawAlt);
119
+ return html.replace('<span ', '<span data-rapier-markdown-image="" ' +
120
+ (token.meta?.mdImage?.source ? 'data-rapier-image-source="' + md.utils.escapeHtml(encodeURIComponent(token.meta.mdImage.source)) + '" ' : ''));
121
+ }
122
+ const attrs = [
123
+ 'data-rapier-markdown-image=""',
124
+ 'src="' + md.utils.escapeHtml(src) + '"',
125
+ 'alt="' + md.utils.escapeHtml(alt) + '"',
126
+ 'loading="lazy"',
127
+ 'decoding="async"',
128
+ ];
129
+ if (token.meta?.mdImage?.source && token.meta.mdImage.source.length <= 4096)
130
+ attrs.push('data-rapier-image-source="' + md.utils.escapeHtml(encodeURIComponent(token.meta.mdImage.source)) + '"');
131
+ if (title) attrs.push('title="' + md.utils.escapeHtml(title) + '"');
132
+ if (size && !token.meta?.mdLayout?.layout?.width) attrs.push('data-rapier-image-alt-source="' + md.utils.escapeHtml(rawAlt) + '"');
133
+ if (layout) attrs.push('data-rapier-image-layout="' + md.utils.escapeHtml(encodeURIComponent(layout)) + '"');
134
+ return '<img ' + attrs.join(' ') + _rapierImageSizeAttributes(size, layout) + '>';
135
+ };
136
+
137
+ md.renderer.rules.hr = function (tokens, idx) {
138
+ const m = (tokens[idx].markup || '---').charAt(0);
139
+ const style = m === '*' ? 'stars' : (m === '_' ? 'underscore' : 'dash');
140
+ return '<hr data-hr-style="' + style + '">\n';
141
+ };
142
+
143
+ md.renderer.rules.rapier_break = () =>
144
+ '<div class="rapier-page-break" data-md-break="page" contenteditable="false" role="separator" aria-label="Page break"></div>\n';
145
+
146
+ // Raw HTML carries no editor hooks. Keep its fragment boundaries until the complete Markdown
147
+ // markup reaches DOMPurify: sanitizing each HTML token closes containers before their body.
148
+ // The harness runs this installer alone for the parser's acceptance; without the page's sanitizer the tokens pass.
149
+ const inPage = typeof sanitizeRapierHtml === 'function' && typeof _rapierChromeOwnsId === 'function';
150
+ const rawAttribute = /\s+([A-Za-z_:][A-Za-z0-9_.:-]*)(?:\s*=\s*("[^"]*"|'[^']*'|[^"'=<>`\s]+))?/g;
151
+ // The id is read as HTML reads it: a numeric character reference (`&#115;ource-textarea` is `source-textarea`,
152
+ // `&#x73;` the same) and the named references that spell a character an id can hold are decoded before the
153
+ // chrome's ids are asked; every other name stays literal (no named reference spells a letter, a digit or a
154
+ // hyphen). A string walk, not a parser: the render pass is the one HTML parser this markup meets.
155
+ const RAW_ID_NAMED = { amp: '&', lt: '<', gt: '>', quot: '"', apos: "'", lowbar: '_', UnderBar: '_', num: '#', colon: ':',
156
+ period: '.', sol: '/', excl: '!', quest: '?', commat: '@', plus: '+', ast: '*', percnt: '%', dollar: '$', semi: ';',
157
+ equals: '=', comma: ',', lpar: '(', rpar: ')', lsqb: '[', lbrack: '[', rsqb: ']', rbrack: ']', lcub: '{', lbrace: '{',
158
+ rcub: '}', rbrace: '}', verbar: '|', vert: '|', VerticalLine: '|', bsol: '\\', Hat: '^', grave: '`', DiacriticalGrave: '`', Tab: '\t', NewLine: '\n' };
159
+ const attributeText = value => String(value || '').replace(/^["']|["']$/g, '')
160
+ .replace(/&(?:#(\d{1,7})|#[xX]([0-9a-fA-F]{1,6})|([A-Za-z][A-Za-z0-9]{0,31}));?/g, (whole, dec, hex, name) => {
161
+ const code = dec ? Number(dec) : hex ? parseInt(hex, 16) : -1;
162
+ if (code >= 0) return code > 0 && code <= 0x10ffff ? String.fromCodePoint(code) : '\ufffd';
163
+ return Object.hasOwn(RAW_ID_NAMED, name) ? RAW_ID_NAMED[name] : whole;
164
+ });
165
+ if (inPage) {
166
+ _rapierChromeOwnsId('');
167
+ const cleanTag = tag => /^<[A-Za-z]/.test(tag) ? tag.replace(rawAttribute, (whole, name, value) => {
168
+ const key = name.toLowerCase();
169
+ return key.startsWith('data-') || key === 'for' || key === 'id' && _rapierChromeOwnsId(attributeText(value)) ? '' : whole;
170
+ }) : tag;
171
+ md.renderer.rules.html_inline = (tokens, idx) => cleanTag(tokens[idx].content);
172
+ md.renderer.rules.html_block = (tokens, idx) => _rapierRawHtmlFragment(tokens[idx].content, cleanTag, md) + '\n';
173
+ }
174
+
175
+ const _ulOpenDefault = md.renderer.rules.bullet_list_open
176
+ || function (tokens, idx, opts, _env, self) { return self.renderToken(tokens, idx, opts); };
177
+ const _rapierMarkLooseList = (tokens, idx) => {
178
+ const token = tokens[idx], level = token.level;
179
+ for (let scan = idx + 1; scan < tokens.length; scan++) {
180
+ const next = tokens[scan];
181
+ if (next.level <= level) break;
182
+ if (next.type === 'paragraph_open' && !next.hidden && next.level === level + 2) {
183
+ token.attrSet('data-rapier-list-loose', '');
184
+ return;
185
+ }
186
+ }
187
+ };
188
+ md.renderer.rules.bullet_list_open = function (tokens, idx, opts, env, self) {
189
+ const token = tokens[idx];
190
+ token.attrSet('data-rapier-list-marker', token.markup || '-');
191
+ _rapierMarkLooseList(tokens, idx);
192
+ return _ulOpenDefault(tokens, idx, opts, env, self);
193
+ };
194
+
195
+ const _olOpenDefault = md.renderer.rules.ordered_list_open
196
+ || function (tokens, idx, opts, _env, self) { return self.renderToken(tokens, idx, opts); };
197
+ md.renderer.rules.ordered_list_open = function (tokens, idx, opts, env, self) {
198
+ const token = tokens[idx];
199
+ token.attrSet('data-rapier-list-delimiter', token.markup === ')' ? ')' : '.');
200
+ const startAttr = token.attrGet && token.attrGet('start');
201
+ const start = parseInt(startAttr, 10);
202
+ if (Number.isFinite(start) && start !== 1) {
203
+ const existing = token.attrGet('style') || '';
204
+ token.attrSet('style', (existing ? existing + ';' : '') + 'counter-reset:rapier-ol ' + (start - 1));
205
+ }
206
+ let generated = Number.isFinite(start) ? start : 1;
207
+ for (let scan = idx + 1; scan < tokens.length && tokens[scan].level > token.level; scan++) {
208
+ if (tokens[scan].type !== 'list_item_open' || tokens[scan].level !== token.level + 1) continue;
209
+ if (tokens[scan].info === String(generated)) { generated++; continue; }
210
+ token.attrSet('data-rapier-list-numbering', 'authored');
211
+ break;
212
+ }
213
+ _rapierMarkLooseList(tokens, idx);
214
+ return _olOpenDefault(tokens, idx, opts, env, self);
215
+ };
216
+
217
+ md.core.ruler.push('rapier_setext_rule', function (state) {
218
+ let lines = null;
219
+ for (const token of state.tokens) {
220
+ if (token.type !== 'heading_open') continue;
221
+ if (token.markup !== '=' && token.markup !== '-') continue;
222
+ if (!token.map) continue;
223
+ if (lines === null) lines = state.src.split('\n');
224
+ const underline = lines[token.map[1] - 1];
225
+ if (typeof underline === 'string' && /^ {0,3}(?:=+|-+)[ \t]*$/.test(underline)) {
226
+ token.attrSet('data-rapier-heading-rule', underline);
227
+ }
228
+ }
229
+ });
230
+
231
+ const _headingOpenDefault = md.renderer.rules.heading_open
232
+ || function (tokens, idx, opts, _env, self) { return self.renderToken(tokens, idx, opts); };
233
+ md.renderer.rules.heading_open = function (tokens, idx, opts, env, self) {
234
+ const token = tokens[idx];
235
+ if (token.markup === '=' || token.markup === '-') {
236
+ token.attrSet('data-rapier-heading-markup', token.markup);
237
+ }
238
+ return _headingOpenDefault(tokens, idx, opts, env, self);
239
+ };
240
+
241
+ const _fenceDefault = md.renderer.rules.fence;
242
+ {
243
+ let _diagramPromptedOnce = false;
244
+ md.renderer.rules.fence = function (tokens, idx, opts, env, self) {
245
+ const token = tokens[idx];
246
+ token.attrSet('data-rapier-fence', token.markup || '```');
247
+ token.attrSet('data-rapier-fence-info', token.info == null ? '' : String(token.info));
248
+ const lang = String(token.info || '').trim().split(/\s+/)[0].toLowerCase();
249
+ if (lang !== 'mermaid') return _fenceDefault(tokens, idx, opts, env, self);
250
+ const src = String(token.content || '').replace(/\n$/, '');
251
+ const fence = md.utils.escapeHtml(token.markup || '```');
252
+ const info = token.info == null ? '' : String(token.info);
253
+ const escapedSrc = md.utils.escapeHtml(src);
254
+ const sourceHtml = '<pre class="diagram-source"><code data-rapier-fence="' + fence +
255
+ '" data-rapier-fence-info="' + md.utils.escapeHtml(info) + '">' + escapedSrc + '</code></pre>';
256
+ const encoded = encodeURIComponent(src);
257
+ if (token.meta?.rapierFenceClosed === false) {
258
+ // No render request: even a valid diagram body must not conceal an unfinished fence.
259
+ return '<figure class="diagram-block diagram-block--error" data-diagram-state="error"' +
260
+ ' data-diagram-unclosed="" data-diagram-src="' + encoded + '">' +
261
+ '<p class="diagram-reason">Mermaid block may be missing its closing <code>' + fence +
262
+ '</code> fence. Text below is still inside the block.</p>' + sourceHtml + '</figure>\n';
263
+ }
264
+ const native = globalThis.RapierFlowchart?.parseFlowchart(src).ok === true;
265
+ const provider = _rapierProviders.mermaid;
266
+ const ready = native || !!(provider && provider.status === 'ready' && typeof provider.renderToString === 'function');
267
+ if (!ready && !_diagramPromptedOnce) {
268
+ _diagramPromptedOnce = true;
269
+ try { _rapierUiDiagram.request(); } catch (_) {}
270
+ }
271
+ const state = ready ? 'idle' : 'absent';
272
+ return '<figure class="diagram-block' + (ready ? '' : ' diagram-block--absent') +
273
+ '" data-diagram-src="' + encoded + '" data-diagram-state="' + state + '"' + (native ? ' data-diagram-native=""' : '') + '>' +
274
+ sourceHtml +
275
+ (ready ? '<div class="diagram-cache" hidden></div>' : '') +
276
+ '</figure>\n';
277
+ };
278
+ }
279
+
280
+ const _liOpenDefault = md.renderer.rules.list_item_open
281
+ || function (tokens, idx, opts, _env, self) { return self.renderToken(tokens, idx, opts); };
282
+ md.renderer.rules.list_item_open = function (tokens, idx, opts, env, self) {
283
+ const token = tokens[idx];
284
+ if (token.info) token.attrSet('data-rapier-list-ordinal', String(token.info));
285
+ return _liOpenDefault(tokens, idx, opts, env, self);
286
+ };
287
+
288
+ const preserveEmphasisMarkup = (ruleName, attrName) => {
289
+ const fallback = md.renderer.rules[ruleName]
290
+ || function (tokens, idx, opts, _env, self) { return self.renderToken(tokens, idx, opts); };
291
+ md.renderer.rules[ruleName] = function (tokens, idx, opts, env, self) {
292
+ const token = tokens[idx];
293
+ token.attrSet(attrName, token.markup || (ruleName === 'strong_open' ? '**' : '*'));
294
+ return fallback(tokens, idx, opts, env, self);
295
+ };
296
+ };
297
+ preserveEmphasisMarkup('em_open', 'data-rapier-emphasis');
298
+ preserveEmphasisMarkup('strong_open', 'data-rapier-strong');
299
+
300
+ {
301
+ let _mathPromptedOnce = false;
302
+ const _renderMath = (src, displayMode) => {
303
+ const marker = displayMode ? '$$' : '$';
304
+ const mathProvider = _rapierProviders.math;
305
+ if (!mathProvider || mathProvider.status !== 'ready' || typeof mathProvider.renderToString !== 'function') {
306
+ if (!_mathPromptedOnce) {
307
+ _mathPromptedOnce = true;
308
+ try { _rapierUiMath.request(); } catch (_) {}
309
+ }
310
+ return '<span class="math-placeholder" title="Install the math plug-in in Settings to show this equation.">'
311
+ + md.utils.escapeHtml(marker + src + marker) + '</span>';
312
+ }
313
+ try {
314
+ const rendered = mathProvider.renderToString(src, { displayMode });
315
+ return '<span class="math-rendered" data-math-src="'
316
+ + encodeURIComponent(marker + src + marker) + '">' + rendered + '</span>';
317
+ }
318
+ catch (_) { return md.utils.escapeHtml(marker + src + marker); }
319
+ };
320
+ md.renderer.rules.math_inline = (tokens, idx) => _renderMath(tokens[idx].content, false);
321
+ md.renderer.rules.math_block = (tokens, idx) => wrapDisplayMath(_renderMath(tokens[idx].content, true)) + '\n';
322
+ }
323
+ globalThis.RapierMarkdownLayout.installMarkdownLayout(md);
324
+ globalThis.RapierImageAssets.configureParser(md, _rapierSplitOpeningFrontmatter);
325
+ }
326
+
327
+ function _rapierRenderSemanticRoot(canonical, metadata) {
328
+ const root = document.createElement('div');
329
+ root.setAttribute('data-rapier-semantic-root', 'true');
330
+
331
+ if (metadata.docKind !== 'markdown') {
332
+ const pre = document.createElement('pre');
333
+ const code = document.createElement('code');
334
+ const lang = metadata.docKind === 'code'
335
+ ? String(metadata.codeLang || '').replace(/[^a-z0-9_-]/gi, '').toLowerCase()
336
+ : '';
337
+ if (lang) code.className = 'language-' + lang;
338
+ code.textContent = String(canonical || '');
339
+ pre.appendChild(code);
340
+ root.appendChild(pre);
341
+ return root;
342
+ }
343
+
344
+ const markdown = _rapierSplitOpeningFrontmatter(canonical).body;
345
+ const env = {};
346
+ let rendered = md
347
+ ? md.render(markdown, env)
348
+ : '<pre><code>' + escapeRapierHtmlText(markdown) + '</code></pre>';
349
+ if (md && env.footnotes && Array.isArray(env.footnotes.list) && env.footnotes.list.length) {
350
+ const labels = env.footnotes.list.map((item, index) =>
351
+ String(item && item.label || ('inline-' + (index + 1))));
352
+ rendered = _relabelFootnoteHtml(rendered, labels);
353
+ }
354
+ root.innerHTML = sanitizeRapierHtml(rendered, 'export');
355
+ _rapierApplyBlockDirection(root);
356
+
357
+ _rapierAssignHeadingSlugs(root, RAPIER_RENDERED_HEADING_SELECTOR, false);
358
+ _rapierDisambiguateRenderedAnchors(root);
359
+
360
+ root.querySelectorAll('pre > code').forEach(_rapierNormalizeCodeElement);
361
+ _rapierMarkTableCaptions(root);
362
+ _rapierMarkFigureCaptions(root);
363
+ _rapierMarkListContinuations(Array.from(root.children));
364
+ _rapierDecorateJumpLists(root);
365
+ return root;
366
+ }
367
+
368
+ function _rapierInstallSemanticProbe(instance) {
369
+ if (!instance || instance.__rapierSemanticProbeInstalled) return;
370
+ instance.__rapierSemanticProbeInstalled = true;
371
+ const originalParse = instance.inline.parse;
372
+ instance.inline.parse = function (source, parser, env, outTokens) {
373
+ const targetEnv = env || {};
374
+ const priorId = targetEnv.__rapierInlineProbeId || 0;
375
+ const nextId = (targetEnv.__rapierInlineProbeSeq || 0) + 1;
376
+ targetEnv.__rapierInlineProbeSeq = nextId;
377
+ targetEnv.__rapierInlineProbeId = nextId;
378
+ try {
379
+ Object.defineProperty(outTokens, '_rapierInlineProbeId', { value: nextId, configurable: true });
380
+ } catch (_) { outTokens._rapierInlineProbeId = nextId; }
381
+ try {
382
+ const result = originalParse.call(this, source, parser, targetEnv, outTokens);
383
+ for (const token of outTokens) {
384
+ try { Object.defineProperty(token, '_rapierInlineProbeId', { value: nextId, configurable: true }); }
385
+ catch (_) { token._rapierInlineProbeId = nextId; }
386
+ }
387
+ return result;
388
+ } finally { targetEnv.__rapierInlineProbeId = priorId; }
389
+ };
390
+
391
+ instance.inline.ruler.before('escape', 'rapier_semantic_probe', function (state, silent) {
392
+ if (silent || !state || !state.env) return false;
393
+ const inlineId = Number(state.env.__rapierInlineProbeId || 0);
394
+ if (!inlineId) return false;
395
+ const src = state.src;
396
+ const pos = state.pos;
397
+ const max = state.posMax;
398
+ const record = fact => {
399
+ if (!Array.isArray(state.env.__rapierInlineCandidates)) state.env.__rapierInlineCandidates = [];
400
+ state.env.__rapierInlineCandidates.push({ inlineId, ...fact });
401
+ };
402
+
403
+ if (src.charCodeAt(pos) === 0x5b && src.charCodeAt(pos + 1) === 0x5e) {
404
+ let end = pos + 2;
405
+ while (end < max) {
406
+ const code = src.charCodeAt(end);
407
+ if (code === 0x20 || code === 0x0a) return false;
408
+ if (code === 0x5d) break;
409
+ end++;
410
+ }
411
+ if (end > pos + 2 && end < max && src.charCodeAt(end) === 0x5d) {
412
+ const label = src.slice(pos + 2, end);
413
+ record({ kind: 'footnote-use', rawKey: label, localStart: pos, localEnd: end + 1, label: label.slice(0, 240), evidence: { syntax: 'footnote-reference' } });
414
+ }
415
+ return false;
416
+ }
417
+
418
+ let image = false;
419
+ let labelStart = pos;
420
+ if (src.charCodeAt(pos) === 0x21 && src.charCodeAt(pos + 1) === 0x5b) {
421
+ image = true;
422
+ labelStart = pos + 1;
423
+ } else if (src.charCodeAt(pos) !== 0x5b) {
424
+ return false;
425
+ } else if (pos > 0 && src.charCodeAt(pos - 1) === 0x21) {
426
+ return false;
427
+ }
428
+ const firstEnd = state.md.helpers.parseLinkLabel(state, labelStart, false);
429
+ if (firstEnd < 0) return false;
430
+ const firstLabel = src.slice(labelStart + 1, firstEnd);
431
+ const after = firstEnd + 1;
432
+
433
+ if (src.charCodeAt(after) === 0x5b) {
434
+ const secondEnd = state.md.helpers.parseLinkLabel(state, after, false);
435
+ if (secondEnd < 0) return false;
436
+ const explicitLabel = src.slice(after + 1, secondEnd);
437
+ const rawKey = explicitLabel.length ? explicitLabel : firstLabel;
438
+ record({
439
+ kind: image ? 'image-reference-use' : 'link-reference-use', rawKey,
440
+ localStart: pos, localEnd: secondEnd + 1,
441
+ label: rawKey.slice(0, 240),
442
+ evidence: { syntax: explicitLabel.length ? 'full-reference' : 'collapsed-reference' },
443
+ });
444
+ return false;
445
+ }
446
+
447
+ if (src.charCodeAt(after) === 0x28) {
448
+ let destinationPos = after + 1;
449
+ while (destinationPos < max && /[ \t\n]/.test(src.charAt(destinationPos))) destinationPos++;
450
+ const destination = state.md.helpers.parseLinkDestination(src, destinationPos, max);
451
+ if (!destination || !destination.ok || !String(destination.str || '').startsWith('#')) return false;
452
+ const rawDestination = String(destination.str || '');
453
+ const destinationSlice = src.slice(destinationPos, destination.pos);
454
+ const hashAt = destinationSlice.indexOf(rawDestination);
455
+ if (hashAt < 0 || destinationSlice.indexOf(rawDestination, hashAt + 1) >= 0) return false;
456
+ record({
457
+ kind: 'local-link-use', rawKey: rawDestination.slice(1),
458
+ localStart: destinationPos + hashAt, localEnd: destinationPos + hashAt + rawDestination.length,
459
+ label: rawDestination.slice(0, 240), evidence: { syntax: 'inline-destination' },
460
+ });
461
+ return false;
462
+ }
463
+
464
+ const normalize = state.md.utils && state.md.utils.normalizeReference;
465
+ const normalized = typeof normalize === 'function' ? normalize(firstLabel) : firstLabel.trim().replace(/\s+/g, ' ').toUpperCase();
466
+ if ((image || (state.env.references && state.env.references[normalized])) && firstLabel) {
467
+ record({
468
+ kind: image ? 'image-reference-use' : 'link-reference-use', rawKey: firstLabel,
469
+ localStart: pos, localEnd: firstEnd + 1,
470
+ label: firstLabel.slice(0, 240), evidence: { syntax: 'shortcut-reference' },
471
+ });
472
+ }
473
+ return false;
474
+ });
475
+
476
+ try {
477
+ instance.core.ruler.before('footnote_tail', 'rapier_footnote_definition_probe', function (state) {
478
+ const out = [];
479
+ const tokens = state && Array.isArray(state.tokens) ? state.tokens : [];
480
+ const signatureFor = values => {
481
+ let hash = 0x811c9dc5;
482
+ for (const value of values) {
483
+ const text = String(value == null ? '' : value);
484
+ for (let index = 0; index < text.length; index++) {
485
+ hash ^= text.charCodeAt(index);
486
+ hash = Math.imul(hash, 0x01000193) >>> 0;
487
+ }
488
+ hash ^= 0xff;
489
+ hash = Math.imul(hash, 0x01000193) >>> 0;
490
+ }
491
+ return hash.toString(16).padStart(8, '0');
492
+ };
493
+ for (let index = 0; index < tokens.length; index++) {
494
+ const open = tokens[index];
495
+ if (!open || open.type !== 'footnote_reference_open' || !open.meta || open.meta.label == null) continue;
496
+ let end = index + 1;
497
+ let startLine = Number.POSITIVE_INFINITY;
498
+ let endLine = -1;
499
+ const semantic = [];
500
+ for (; end < tokens.length; end++) {
501
+ const token = tokens[end];
502
+ if (!token) continue;
503
+ if (token.type === 'footnote_reference_close') break;
504
+ if (Array.isArray(token.map)) {
505
+ startLine = Math.min(startLine, Number(token.map[0]));
506
+ endLine = Math.max(endLine, Number(token.map[1]));
507
+ }
508
+ semantic.push(token.type, token.tag, token.nesting, token.markup, token.content);
509
+ }
510
+ if (Number.isFinite(startLine) && endLine >= startLine) {
511
+ out.push({
512
+ label: String(open.meta.label), startLine, endLine,
513
+ signature: signatureFor(semantic),
514
+ });
515
+ }
516
+ index = end;
517
+ }
518
+ state.env.__rapierFootnoteDefinitions = out;
519
+ });
520
+ } catch (_) {}
521
+ }
522
+
523
+ function _rapierImageAltSize(value) {
524
+ const parts = _rapierImageAltSourceParts(value);
525
+ return parts.width ? parts : null;
526
+ }
527
+
528
+ function _rapierImageAltSourceParts(value) {
529
+ const source = String(value || '');
530
+ const pipe = source.lastIndexOf('|');
531
+ if (pipe < 0 || _rapierSourceCharEscaped(source, pipe)) return { alt: source, width: 0 };
532
+ const widthText = source.slice(pipe + 1);
533
+ if (!/^[1-9]\d{1,3}$/.test(widthText)) return { alt: source, width: 0 };
534
+ const width = Math.max(32, Math.min(2400, Number(widthText)));
535
+ return { alt: source.slice(0, pipe), width };
536
+ }
537
+
538
+ function _rapierImageAltText(value, env = {}) {
539
+ const tokens = md.parseInline(String(value ?? ''), env);
540
+ return md.renderer.renderInlineAsText(tokens[0]?.children || [], md.options, env);
541
+ }
542
+
543
+ function _rapierImageSizeAttributes(size, marker) {
544
+ const layout = globalThis.RapierMarkdownLayout.parseLayout(marker || '');
545
+ // Plain (rung 0, docs/standard-adoption.md): every picture renders at its natural width, the
546
+ // same as a reader with no layout facts at all -- Obsidian's `![alt|N]` alt-text width (the
547
+ // `size` fallback below) is a different, established convention and is unaffected.
548
+ const style = layout && !_rapierPlainLayout() ? globalThis.RapierMarkdownLayout.imageStyle(layout) : '';
549
+ if (layout?.width != null && style) return ' data-md-image-width="' + layout.width + '" style="' + style + '"';
550
+ // A fade rides beside any width, the alt-text's own included.
551
+ return size ? ' width="' + size.width + '" data-rapier-image-size="' + size.width +
552
+ '" style="--md-image-width:' + size.width + 'px' + (style ? ';' + style : '') + '"' : style ? ' style="' + style + '"' : '';
553
+ }
554
+
555
+ function _rapierRawHtmlFragment(source, rewrite, parser) {
556
+ const state = new parser.inline.State(source, parser, {}, []);
557
+ const htmlRule = parser.inline.ruler.__rules__.find(rule => rule.name === 'html_inline').fn;
558
+ let out = '';
559
+ while (state.pos < state.posMax) {
560
+ const at = state.src.indexOf('<', state.pos);
561
+ if (at < 0) { out += state.src.slice(state.pos); break; }
562
+ out += state.src.slice(state.pos, at); state.pos = at;
563
+ if (htmlRule(state, false)) out += rewrite(state.tokens.pop().content);
564
+ else { out += '&lt;'; state.pos++; }
565
+ }
566
+ return out;
567
+ }
568
+
569
+ function _rapierApplyBlockDirection(root) {
570
+ if (!root || typeof root.querySelectorAll !== 'function') return;
571
+ for (const el of root.querySelectorAll(_RAPIER_DIR_BLOCKS)) {
572
+ if (el.closest('pre, code')) continue;
573
+ const dir = _rapierFirstStrongDir(el.textContent);
574
+ if (el.getAttribute('dir') !== dir) el.setAttribute('dir', dir);
575
+ }
576
+ }
577
+
578
+ function _rapierFirstStrongDir(text) {
579
+ const value = String(text || '');
580
+ for (let i = 0; i < value.length;) {
581
+ const cp = value.codePointAt(i);
582
+ i += cp > 0xFFFF ? 2 : 1;
583
+ const strong = _rapierBidiStrong(cp);
584
+ if (strong === 'L') return 'ltr';
585
+ if (strong === 'R') return 'rtl';
586
+ }
587
+ return 'ltr';
588
+ }
589
+
590
+ const _RAPIER_DIR_BLOCKS = 'p,h1,h2,h3,h4,h5,h6,li,blockquote,ul,ol,dt,dd,td,th';
591
+
592
+ function _rapierAssignHeadingSlugs(root, selector = RAPIER_RENDERED_HEADING_SELECTOR, reserveExisting = true) {
593
+ if (!root || !root.querySelectorAll) return;
594
+ const used = Object.create(null);
595
+ const headings = Array.from(root.querySelectorAll(selector)).concat(_rapierDormantHeadings(root, selector));
596
+ const headingSet = new Set(headings);
597
+ if (reserveExisting) (root.isConnected ? document : root).querySelectorAll('[id]').forEach(element => {
598
+ if (!headingSet.has(element) && element.id) used[element.id] = 1;
599
+ });
600
+ headings.forEach(heading => {
601
+ const base = _rapierHeadingSlugBase(heading.textContent);
602
+ let slug = base;
603
+ if (used[slug]) {
604
+ let ordinal = used[base];
605
+ do { slug = base + '-' + (++ordinal); } while (used[slug]);
606
+ used[base] = ordinal;
607
+ }
608
+ used[slug] = 1;
609
+ heading.id = slug;
610
+ });
611
+ }
612
+
613
+ function _rapierDisambiguateRenderedAnchors(root) {
614
+ if (!root || !root.querySelectorAll) return;
615
+ const headings = new Set(root.querySelectorAll(RAPIER_RENDERED_HEADING_SELECTOR));
616
+ const candidates = Array.from(root.querySelectorAll('[id]'))
617
+ .filter(element => !headings.has(element));
618
+ candidates.forEach(element => {
619
+ const original = _rapierRenderedAnchorOriginalIds.get(element);
620
+ if (original) element.id = original;
621
+ });
622
+
623
+ const groups = new Map();
624
+ candidates.forEach(element => {
625
+ if (!element.id) return;
626
+ if (!groups.has(element.id)) groups.set(element.id, []);
627
+ groups.get(element.id).push(element);
628
+ });
629
+ const used = new Set(Array.from(headings).map(heading => heading.id).filter(Boolean));
630
+ const allocate = original => {
631
+ const compact = String(original || '').replace(/[^a-z0-9_-]+/gi, '-')
632
+ .replace(/^-+|-+$/g, '') || 'anchor';
633
+ let next = 'rapier-anchor-' + compact;
634
+ let suffix = 2;
635
+ while (used.has(next) || groups.has(next)) {
636
+ next = 'rapier-anchor-' + compact + '-' + suffix++;
637
+ }
638
+ used.add(next);
639
+ return next;
640
+ };
641
+
642
+ groups.forEach((elements, original) => {
643
+ const explicitFootnotes = elements.filter(element =>
644
+ element.classList.contains('footnote-item') && element.hasAttribute('data-footnote-label'));
645
+ const footnoteRefs = elements.filter(element =>
646
+ element.closest && element.closest('.footnote-ref'));
647
+ const winner = explicitFootnotes.length
648
+ ? explicitFootnotes[explicitFootnotes.length - 1]
649
+ : (footnoteRefs[0] || elements[0]);
650
+ const winnerId = used.has(original) ? allocate(original) : original;
651
+ if (!used.has(winnerId)) used.add(winnerId);
652
+ winner.id = winnerId;
653
+ if (winnerId !== original) _rapierRenderedAnchorOriginalIds.set(winner, original);
654
+
655
+ elements.forEach(element => {
656
+ if (element === winner) return;
657
+ const alias = allocate(original);
658
+ element.id = alias;
659
+ _rapierRenderedAnchorOriginalIds.set(element, original);
660
+ });
661
+
662
+ const labels = new Set(elements.map(element => element.getAttribute('data-footnote-label'))
663
+ .filter(label => label != null));
664
+ const matchingHashLinks = selector => Array.from(root.querySelectorAll(selector))
665
+ .filter(link => _rapierDecodeHash(link.getAttribute('href')) === original ||
666
+ (labels.size && labels.has(link.getAttribute('data-footnote-label'))));
667
+ if (elements.some(element => element.classList.contains('footnote-item'))) {
668
+ matchingHashLinks('.footnote-ref a[href^="#"]')
669
+ .forEach(link => link.setAttribute('href', '#' + winnerId));
670
+ } else if (elements.some(element => element.closest && element.closest('.footnote-ref'))) {
671
+ matchingHashLinks('.footnote-backref[href^="#"]')
672
+ .forEach(link => link.setAttribute('href', '#' + winnerId));
673
+ }
674
+ });
675
+ }
676
+
677
+ function _rapierDecodeHash(hash) {
678
+ // A document's own address may carry a heading after it (`#d/<id>/<heading>`, task #413): the
679
+ // heading is the anchor, and an address with no heading names nothing to jump to. A view's
680
+ // (`#v/draw`, `#v/notes`) names no heading either (docs/agents.md "The address of a document").
681
+ let raw = String(hash || '').replace(/^#/, '');
682
+ const own = /^[dnv]\/[^/]*(?:\/(.*))?$/.exec(raw);
683
+ if (own) raw = own[1] || '';
684
+ try { return decodeURIComponent(raw); }
685
+ catch (_) { return raw; }
686
+ }
687
+
688
+ function _rapierDecorateJumpLists(root) {
689
+ root.querySelectorAll('ul').forEach(list => {
690
+ if (list.closest('li')) return;
691
+ const items = Array.from(list.children).filter(item => item.tagName === 'LI');
692
+ if (items.length < 2 || items.length !== list.children.length) return;
693
+ const isWayfinder = items.every(item => {
694
+ if (item.querySelector('ul,ol')) return false;
695
+ const links = Array.from(item.querySelectorAll(':scope > a[href^="#"]'));
696
+ if (links.length !== 1) return false;
697
+ const clone = item.cloneNode(true);
698
+ clone.querySelectorAll('a').forEach(link => link.replaceWith(...link.childNodes));
699
+ return String(clone.textContent || '').replace(/\s+/g, ' ').trim() ===
700
+ String(links[0].textContent || '').replace(/\s+/g, ' ').trim();
701
+ });
702
+ if (isWayfinder) {
703
+ list.classList.add('rapier-jump-list');
704
+ const label = list.previousElementSibling;
705
+ if (label && /^jump\s+to:?$/i.test(String(label.textContent || '').trim())) {
706
+ label.classList.add('rapier-jump-label');
707
+ }
708
+ }
709
+ });
710
+
711
+ const only = root.children && root.children.length === 1 ? root.firstElementChild : null;
712
+ if (only && only.tagName === 'P' && /^jump\s+to:?$/i.test(String(only.textContent || '').trim())) {
713
+ only.classList.add('rapier-jump-label-candidate');
714
+ }
715
+ }
716
+
717
+ function _rapierMarkFigureCaptions(root) {
718
+ // Same path as a table caption: an ordinary paragraph after the picture, still the source line.
719
+ const figureCaption = /^Figure: /;
720
+ root.querySelectorAll('p').forEach(paragraph => {
721
+ if (!figureCaption.test(paragraph.textContent || '')) return;
722
+ const previous = paragraph.previousElementSibling;
723
+ if (!previous || previous.tagName !== 'P') return;
724
+ const images = previous.querySelectorAll('img');
725
+ if (images.length !== 1 || previous.textContent.trim()) return;
726
+ paragraph.classList.add('rapier-figure-caption');
727
+ });
728
+ }
729
+
730
+ function _rapierMarkListContinuations(blocks) {
731
+ const isHeading = element => !!element && /^H[1-6]$/.test(element.tagName);
732
+ blocks.forEach((element, index) => {
733
+ if (!element || element.tagName !== 'OL') return;
734
+ const start = parseInt(element.getAttribute('start'), 10);
735
+ const last = (Number.isFinite(start) ? start : 1) + element.querySelectorAll(':scope > li').length - 1;
736
+ const headings = [];
737
+ let next = index + 1;
738
+ while (isHeading(blocks[next])) headings.push(blocks[next++]);
739
+ const following = blocks[next];
740
+ if (!headings.length || !following || following.tagName !== 'OL') return;
741
+ if (parseInt(following.getAttribute('start'), 10) !== last + 1) return;
742
+ element.setAttribute('data-rapier-list-continues', '');
743
+ headings.forEach(heading => heading.setAttribute('data-rapier-list-through', ''));
744
+ });
745
+ }
746
+
747
+ function _rapierMarkTableCaptions(root) {
748
+ // The source convention is untouched: the caption stays an ordinary trailing paragraph
749
+ // (docs/markdown-standard.md). Only this rendered projection associates it with its table —
750
+ // via a generated id plus aria-describedby, not a real <caption>, which would have to move the
751
+ // paragraph inside <table> and break the one-DOM-node-per-source-block correspondence other
752
+ // passes (heading slugs, portable export) rely on for this same root.
753
+ const used = new Set(Array.from(root.querySelectorAll('[id]'), element => element.id));
754
+ let ordinal = 0;
755
+ root.querySelectorAll('table').forEach(table => {
756
+ const sibling = table.nextElementSibling;
757
+ if (!sibling || sibling.tagName !== 'P') return;
758
+ if (!RAPIER_TABLE_CAPTION_PREFIX_RE.test(sibling.textContent || '')) return;
759
+ sibling.classList.add('rapier-table-caption');
760
+ let id;
761
+ do { id = 'rapier-table-caption-' + (++ordinal); } while (used.has(id));
762
+ used.add(id);
763
+ sibling.id = id;
764
+ const existing = (table.getAttribute('aria-describedby') || '').trim();
765
+ table.setAttribute('aria-describedby', existing ? existing + ' ' + id : id);
766
+ });
767
+ }
768
+
769
+
770
+
771
+ function _rapierNormalizeCodeElement(code) {
772
+ const lang = _rapierLanguageClass(code);
773
+ code.replaceChildren(document.createTextNode(code.textContent || ''));
774
+ code.removeAttribute('class');
775
+ if (lang) code.className = 'language-' + lang;
776
+ }
777
+
778
+ function _rapierLanguageClass(element) {
779
+ if (!element || !element.classList) return '';
780
+ const found = Array.from(element.classList).find(name => /^language-[a-z0-9_-]+$/i.test(name));
781
+ return found ? found.slice(9).toLowerCase() : '';
782
+ }
783
+
784
+ function _relabelFootnoteHtml(html, labels) {
785
+ if (!labels || !labels.length) return html;
786
+ const info = n => {
787
+ const label = labels[n - 1];
788
+ return label ? {
789
+ id: _footnoteIdFromLabel(label),
790
+ label: escapeRapierHtmlText(label),
791
+ } : null;
792
+ };
793
+ return html
794
+ .replace(/id="fnref(\d+)(:\d+)?"/g, (m0, n, dup) => {
795
+ const item = info(+n);
796
+ return item
797
+ ? 'id="fnref-' + item.id + (dup ? dup.replace(':', '-') : '') + '" data-footnote-label="' + item.label + '"'
798
+ : m0;
799
+ })
800
+ .replace(/href="#fnref(\d+)(:\d+)?"/g, (m0, n, dup) => {
801
+ const item = info(+n);
802
+ return item ? 'href="#fnref-' + item.id + (dup ? dup.replace(':', '-') : '') + '"' : m0;
803
+ })
804
+ .replace(/id="fn(\d+)"/g, (m0, n) => {
805
+ const item = info(+n);
806
+ return item
807
+ ? 'id="fn-' + item.id + '" data-footnote-label="' + item.label + '"'
808
+ : m0;
809
+ })
810
+ .replace(/href="#fn(\d+)"/g, (m0, n) => {
811
+ const item = info(+n);
812
+ return item ? 'href="#fn-' + item.id + '"' : m0;
813
+ });
814
+ }
815
+
816
+ function _footnoteIdFromLabel(label) {
817
+ return String(label).replace(/[^A-Za-z0-9_-]/g,
818
+ c => '_' + c.charCodeAt(0).toString(16));
819
+ }
820
+
821
+ function wrapDisplayMath(html) {
822
+ if (!html) return html;
823
+ if (/class=["'][^"']*\bmath-display-wrap\b/i.test(html)) return html;
824
+ return '<span class="math-display-wrap">' + html + '</span>';
825
+ }
826
+
827
+ return {render: (source, metadata = {}) => { if (!md) initMarkdownIt(); return _rapierRenderSemanticRoot(source, metadata).innerHTML; }, initMarkdownIt, _rapierRenderSemanticRoot, _rapierInstallSemanticProbe, _rapierImageAltSize, _rapierImageAltSourceParts, _rapierImageAltText, _rapierImageSizeAttributes, _rapierRawHtmlFragment, _rapierApplyBlockDirection, _rapierFirstStrongDir, _rapierAssignHeadingSlugs, _rapierDisambiguateRenderedAnchors, _rapierDecodeHash, _rapierDecorateJumpLists, _rapierMarkFigureCaptions, _rapierMarkListContinuations, _rapierMarkTableCaptions, _rapierNormalizeCodeElement, _rapierLanguageClass, _relabelFootnoteHtml, _footnoteIdFromLabel, wrapDisplayMath, parser: () => md};
828
+ }
829
+ export {RAPIER_TABLE_CAPTION_PREFIX_RE as tableCaptionPrefix, createMarkdownRenderer};