rapier-markdown-kit 1.1.90 → 1.1.92

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.
@@ -4,7 +4,7 @@ function createRenderStyles(runtime) {
4
4
  const {_rapierArtifactAccent, _rapierStyleText} = runtime;
5
5
  function _rapierArtifactThemeCss(houseDefaults = false) {
6
6
  // Geometry and the selected accent belong to this page; palette and type belong to the
7
- // MIT reference sheet. Only the optional code lexer still reads the app token names.
7
+ // MIT reference sheet. Static code highlighting reads the app token names.
8
8
  const accent = houseDefaults ? '' : ':root,.md-render{--md-color-accent:' + _rapierArtifactAccent() + '}';
9
9
  return `
10
10
  ${accent}
@@ -71,9 +71,10 @@ function _rapierDocumentPrintCss(hostSelector) {
71
71
  }`;
72
72
  }
73
73
 
74
- function _rapierArtifactStyles(theme, includeFonts, printMode, houseDefaults = false) {
74
+ function _rapierArtifactStyles(theme, includeFonts, printMode, houseDefaults = false, fontCss = null) {
75
75
  const parts = [];
76
- if (includeFonts) parts.push(_rapierStyleText('rapier-font-style'));
76
+ if (fontCss !== null) parts.push(fontCss);
77
+ else if (includeFonts) parts.push(_rapierStyleText('rapier-font-style'));
77
78
  parts.push(_rapierStyleText('rapier-content-style'));
78
79
  parts.push(_rapierArtifactThemeCss(houseDefaults));
79
80
  // Where the faces do not ride (the written page's policy carries no font-src), the reader's own sans is
@@ -86,7 +87,7 @@ function _rapierArtifactStyles(theme, includeFonts, printMode, houseDefaults = f
86
87
  // The family list walks the platforms: Roboto (Android), Helvetica Neue (Apple), Segoe UI (Windows),
87
88
  // Arial, then Linux's Noto Sans, Ubuntu, Liberation Sans, DejaVu Sans; a face that is not installed fails
88
89
  // to load and the browser moves to the next family. font-size-adjust was tried and rescaled Geist itself.
89
- if (!includeFonts) parts.push(`@font-face{font-family:'Geist/Roboto';src:local('Roboto');font-weight:400 500;size-adjust:105%;ascent-override:95.7%;descent-override:28.1%;line-gap-override:0%}
90
+ if (!includeFonts && fontCss === null) parts.push(`@font-face{font-family:'Geist/Roboto';src:local('Roboto');font-weight:400 500;size-adjust:105%;ascent-override:95.7%;descent-override:28.1%;line-gap-override:0%}
90
91
  @font-face{font-family:'Geist/Roboto';src:local('Roboto Bold');font-weight:600 700;size-adjust:105%;ascent-override:95.7%;descent-override:28.1%;line-gap-override:0%}
91
92
  @font-face{font-family:'Geist/Helvetica Neue';src:local('Helvetica Neue');font-weight:400 500;size-adjust:103.8%;ascent-override:96.8%;descent-override:28.4%;line-gap-override:0%}
92
93
  @font-face{font-family:'Geist/Helvetica Neue';src:local('Helvetica Neue Bold');font-weight:600 700;size-adjust:103.8%;ascent-override:96.8%;descent-override:28.4%;line-gap-override:0%}
@@ -0,0 +1,145 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // The synchronous and cooperative writers consume the same document transformations.
3
+ export function finish(iterator) {
4
+ let next;
5
+ do { next = iterator.next(); } while (!next.done);
6
+ return next.value;
7
+ }
8
+
9
+ export function check(work) {
10
+ if (work?.signal?.aborted) throw Object.assign(new Error('The operation was cancelled.'), {name: 'AbortError', code: 'cancelled'});
11
+ }
12
+
13
+ export async function pause(work, fraction, label) {
14
+ check(work);
15
+ if (fraction !== undefined || label !== undefined) work?.onProgress?.(fraction, label);
16
+ if (work?.yield) await work.yield(fraction, label);
17
+ else await new Promise(resolve => setTimeout(resolve, 0));
18
+ check(work);
19
+ }
20
+
21
+ // This locates complete fragments; the existing HTML parser and sanitizer still admit
22
+ // every byte. Uncertain nesting stays together instead of guessing a new boundary.
23
+ export function htmlBoundary() {
24
+ const stack = [], voids = new Set('area base br col embed hr img input link meta param source track wbr'.split(' '));
25
+ const rawTags = new Set('script style textarea title xmp iframe noembed noframes'.split(' '));
26
+ let pending = '', raw = '', uncertain = false;
27
+ return fragment => {
28
+ if (uncertain) return false;
29
+ pending += fragment;
30
+ let at = 0;
31
+ while (at < pending.length) {
32
+ if (raw) {
33
+ const close = new RegExp('</' + raw + '(?=[\\t\\n\\f\\r />])', 'i').exec(pending.slice(at));
34
+ if (!close) { pending = pending.slice(Math.max(at, pending.length - raw.length - 3)); return false; }
35
+ at += close.index; raw = '';
36
+ }
37
+ const open = pending.indexOf('<', at);
38
+ if (open < 0) { pending = ''; return stack.length === 0; }
39
+ if (pending.startsWith('<!--', open)) {
40
+ const close = pending.indexOf('-->', open + 4);
41
+ if (close < 0) { pending = pending.slice(open); return false; }
42
+ at = close + 3; continue;
43
+ }
44
+ if (open + 1 === pending.length) { pending = '<'; return false; }
45
+ const match = /^<\/?([A-Za-z][A-Za-z0-9:.-]*)/.exec(pending.slice(open));
46
+ if (!match) { uncertain = true; return false; }
47
+ const name = match[1].toLowerCase();
48
+ if (['html', 'head', 'body', 'noscript', 'plaintext', 'template'].includes(name)) { uncertain = true; return false; }
49
+ let end = open + match[0].length, quote = '';
50
+ for (; end < pending.length; end++) {
51
+ const character = pending[end];
52
+ if (quote) { if (character === quote) quote = ''; }
53
+ else if (character === '"' || character === "'") quote = character;
54
+ else if (character === '>') break;
55
+ }
56
+ if (end === pending.length) { pending = pending.slice(open); return false; }
57
+ const closing = pending[open + 1] === '/';
58
+ if (closing) {
59
+ if (stack.at(-1) !== name) { uncertain = true; return false; }
60
+ stack.pop();
61
+ } else {
62
+ const foreign = name === 'svg' || name === 'math' || stack.includes('svg') || stack.includes('math');
63
+ if (!(foreign && pending[end - 1] === '/') && !(voids.has(name) && !foreign)) stack.push(name);
64
+ if (rawTags.has(name)) raw = name;
65
+ }
66
+ at = end + 1;
67
+ }
68
+ pending = '';
69
+ return stack.length === 0 && !raw;
70
+ };
71
+ }
72
+
73
+ export async function finishAsync(iterator, work) {
74
+ let began = performance.now(), next;
75
+ check(work);
76
+ do {
77
+ next = iterator.next();
78
+ if (!next.done && performance.now() - began >= 8) {
79
+ await pause(work);
80
+ began = performance.now();
81
+ }
82
+ } while (!next.done);
83
+ check(work);
84
+ return next.value;
85
+ }
86
+
87
+ export function* cloneTree(root) {
88
+ const copy = root.cloneNode(false), stack = [{source: root, target: copy, at: 0}];
89
+ while (stack.length) {
90
+ const top = stack[stack.length - 1], source = top.source.childNodes[top.at++];
91
+ if (!source) { stack.pop(); continue; }
92
+ const node = source.cloneNode(false);
93
+ top.target.appendChild(node);
94
+ const children = source.content || source, target = node.content || node;
95
+ if (children.childNodes.length) stack.push({source: children, target, at: 0});
96
+ yield;
97
+ }
98
+ return copy;
99
+ }
100
+
101
+ export function* htmlParts(root, limit = 16384) {
102
+ const text = root.ownerDocument.createElement('div');
103
+ let part = '';
104
+ for (let node = root.firstChild; node; node = node.nextSibling) {
105
+ let html;
106
+ if (node.nodeType === 1) html = node.outerHTML;
107
+ else { text.replaceChildren(node.cloneNode(false)); html = text.innerHTML; }
108
+ if (part && part.length + html.length > limit) { yield part; part = ''; }
109
+ part += html;
110
+ }
111
+ if (part) yield part;
112
+ }
113
+
114
+ export function* cleanTree(root, sanitize, context = 'export') {
115
+ const clean = root.ownerDocument.createElement('div');
116
+ const part = root.ownerDocument.createElement('div');
117
+ for (const html of htmlParts(root)) {
118
+ part.innerHTML = sanitize(html, context);
119
+ while (part.firstChild) clean.appendChild(part.firstChild);
120
+ yield;
121
+ }
122
+ return clean;
123
+ }
124
+
125
+ export function* serializeTree(root, sanitize = null, trim = false) {
126
+ const parts = [];
127
+ for (const html of htmlParts(root)) { parts.push(sanitize ? sanitize(html, 'export') : html); yield; }
128
+ const result = parts.join('');
129
+ return trim ? result.trim() : result;
130
+ }
131
+
132
+ // Chunk boundaries never split a UTF-16 pair; TextEncoder remains the byte authority.
133
+ export function* encodeUtf8Steps(source, size = 65536) {
134
+ const encoder = new TextEncoder(), parts = [];
135
+ let length = 0;
136
+ for (let at = 0; at < source.length;) {
137
+ let end = Math.min(source.length, at + size);
138
+ if (end < source.length && source.charCodeAt(end - 1) >= 0xd800 && source.charCodeAt(end - 1) <= 0xdbff) end--;
139
+ const part = encoder.encode(source.slice(at, end));
140
+ parts.push(part); length += part.length; at = end; yield;
141
+ }
142
+ const bytes = new Uint8Array(length); let at = 0;
143
+ for (const part of parts) { bytes.set(part, at); at += part.length; yield; }
144
+ return bytes;
145
+ }