rapier-markdown-kit 1.2.45 → 1.2.46
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/LICENSE +12 -5
- package/README.md +131 -10
- package/dist/agent/vendor/BROWSER-ENTITIES.json +36 -0
- package/dist/agent/vendor/MARKDOWN-RUNTIME.json +136 -0
- package/dist/agent/vendor/MARKDOWNIT.json +582 -0
- package/dist/agent/vendor/NOTICE.txt +60 -0
- package/dist/agent/vendor/markdown-licenses/entities-LICENSE.txt +11 -0
- package/dist/agent/vendor/markdown-licenses/linkify-it-LICENSE.txt +22 -0
- package/dist/agent/vendor/markdown-licenses/markdown-it-LICENSE.txt +22 -0
- package/dist/agent/vendor/markdown-licenses/mdurl-LICENSE.txt +45 -0
- package/dist/agent/vendor/markdown-licenses/punycode.js-LICENSE-MIT.txt +20 -0
- package/dist/agent/vendor/markdown-licenses/uc.micro-LICENSE.txt +20 -0
- package/dist/agent/vendor/markdown-plugins.json +46 -0
- package/dist/agent/vendor/markdown-plugins.mjs +27 -0
- package/dist/agent/vendor/markdown-runtime.mjs +13 -0
- package/dist/kit/assets.d.mts +106 -0
- package/dist/kit/index.d.mts +151 -0
- package/dist/kit/layout.d.mts +61 -0
- package/dist/kit/ledger/carried.d.mts +12 -6
- package/dist/kit/ledger/carried.mjs +1 -1
- package/dist/kit/ledger/format.mjs +5 -3
- package/dist/kit/ledger/text-merge.mjs +33 -0
- package/dist/kit/ledger/transport.mjs +61 -2
- package/dist/kit/ledger.d.mts +137 -31
- package/dist/kit/markdown-it.d.mts +2 -2
- package/dist/kit/marks.d.mts +241 -0
- package/dist/kit/marks.mjs +39 -1
- package/dist/kit/model.d.mts +191 -0
- package/dist/kit/render-entry.d.mts +654 -0
- package/dist/kit/render.mjs +8 -7
- package/dist/kit/typography.d.mts +42 -0
- package/dist/kit/will.d.mts +26 -3
- package/dist/math/delimiters.mjs +38 -0
- package/dist/math/markdown-rules.mjs +103 -0
- package/dist/spec/document-fonts.mjs +2 -10
- package/dist/spec/md-assets.mjs +1 -0
- package/dist/spec/md-comments.mjs +384 -0
- package/dist/spec/md-marks.mjs +9 -0
- package/dist/spec/md-parser-config.mjs +463 -0
- package/dist/spec/md-parser-runtime.mjs +23 -0
- package/package.json +30 -8
package/dist/kit/render.mjs
CHANGED
|
@@ -49,8 +49,7 @@ async function _rapierBuildArtifact(options, providedContext) {
|
|
|
49
49
|
const opts = options || {};
|
|
50
50
|
const context = providedContext || _rapierBuildInterchangeContext(opts);
|
|
51
51
|
const preference = _rapierArtifactPreference('theme', ['system', 'light', 'dark']);
|
|
52
|
-
const theme = opts.print ? 'light' : preference
|
|
53
|
-
? (globalThis.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : preference;
|
|
52
|
+
const theme = opts.print ? 'light' : preference;
|
|
54
53
|
const metadata = context.metadata;
|
|
55
54
|
const base = context.baseName;
|
|
56
55
|
const work = context.work || opts.work;
|
|
@@ -113,8 +112,8 @@ async function _rapierBuildArtifact(options, providedContext) {
|
|
|
113
112
|
const styledRoot = work ? await _rapierProjectStyledRootAsync(context.semanticRoot, styledOptions)
|
|
114
113
|
: _rapierProjectStyledRoot(context.semanticRoot, styledOptions);
|
|
115
114
|
styledRoot.setAttribute('lang', language);
|
|
116
|
-
const
|
|
117
|
-
const templatePage = _rapierTemplatePage(context.canonical, settings, styledRoot,
|
|
115
|
+
const paperTheme = _rapierArtifactPreference('invertImageAlpha', ['true', 'false']) !== 'false' ? theme : 'light';
|
|
116
|
+
const templatePage = _rapierTemplatePage(context.canonical, settings, styledRoot, paperTheme);
|
|
118
117
|
if (completePage && typeof _rapierFinalizeExportCode === 'function') await _rapierFinalizeExportCode(styledRoot);
|
|
119
118
|
if (!opts.print) _rapierAnnotateExportBoxPolygons(styledRoot);
|
|
120
119
|
if (completePage || opts.print) {
|
|
@@ -204,7 +203,7 @@ async function _rapierBuildArtifact(options, providedContext) {
|
|
|
204
203
|
};
|
|
205
204
|
}
|
|
206
205
|
|
|
207
|
-
function _rapierTemplatePage(canonical, settings, root,
|
|
206
|
+
function _rapierTemplatePage(canonical, settings, root, paperTheme = 'light') {
|
|
208
207
|
if (!isTemplatePage(canonical)) return null;
|
|
209
208
|
const paper = pageSizeOf(settings);
|
|
210
209
|
let url = '';
|
|
@@ -219,9 +218,11 @@ function _rapierTemplatePage(canonical, settings, root, darkPaper = false) {
|
|
|
219
218
|
const margins = ['top', 'right', 'bottom', 'left'].map(side => (settings?.geometry?.[side] ?? 1440) / 15);
|
|
220
219
|
const padding = margins.map(value => value + 'px').join(' ');
|
|
221
220
|
const ground = 'background:var(--rapier-template-border) 0 0/100% 100% no-repeat';
|
|
222
|
-
const shown =
|
|
221
|
+
const shown = paperTheme !== 'light' && globalThis.RapierImageAssets.dataImage(url)?.codec === 'image/svg+xml' ? _rapierDarkPaperSvgUrl(url, '#fafafa') : url;
|
|
222
|
+
const screenInk = shown !== url ? '@media screen' + (paperTheme === 'system' ? ' and (prefers-color-scheme:dark)' : '')
|
|
223
|
+
+ '{:root{--rapier-template-border:url("' + shown + '")}}\n' : '';
|
|
223
224
|
const css = ':root{--rapier-template-border:url("' + url + '")}\n'
|
|
224
|
-
+ '@media screen{
|
|
225
|
+
+ screenInk + '@media screen{.rapier-template-border{display:none}body{background:var(--md-color-inset)}.rapier-page{box-sizing:border-box;width:min(100%,' + width + 'px);min-height:' + height + 'px;margin:0 auto;padding:' + padding
|
|
225
226
|
+ ';background:var(--rapier-template-border) 0 0/100% ' + height + 'px repeat-y,var(--md-color-bg);color:var(--md-color-text)}}\n'
|
|
226
227
|
+ '@media screen and (max-width:' + width + 'px){.rapier-page{min-height:auto;aspect-ratio:' + width + '/' + height + ';padding:'
|
|
227
228
|
+ margins.map(value => 'min(' + value + 'px,' + Number((value / width * 100).toFixed(4)) + '%)').join(' ') + ';background-size:100% auto,auto}}\n'
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
import type {RichTextItem, PreparationOptions, Rect, SlotsForBand, SlotSequence, FlowPlan,
|
|
3
|
+
FlowFragment, FlowSlot} from './model.mjs';
|
|
4
|
+
|
|
5
|
+
export interface TypographyApplyResult {
|
|
6
|
+
changed: number;
|
|
7
|
+
released: number;
|
|
8
|
+
pending: boolean;
|
|
9
|
+
prepared: number;
|
|
10
|
+
}
|
|
11
|
+
export interface InitialRange {start: number; end: number; text: string}
|
|
12
|
+
export interface TypographySlotInput {
|
|
13
|
+
width: number;
|
|
14
|
+
top: number;
|
|
15
|
+
obstacles: readonly Rect[];
|
|
16
|
+
lineHeight: number;
|
|
17
|
+
minWidth: number;
|
|
18
|
+
slotsForBand: SlotsForBand;
|
|
19
|
+
slotSequence: SlotSequence;
|
|
20
|
+
columnsFilled(slots: readonly FlowSlot[], placed: readonly FlowSlot[]): boolean;
|
|
21
|
+
justify: boolean;
|
|
22
|
+
hyphenate: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface DerivedFlowFragment extends FlowFragment {
|
|
25
|
+
derive: true;
|
|
26
|
+
glyph?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface TypographyController {
|
|
29
|
+
/** Pending work requires a subsequent call after the host yields. */
|
|
30
|
+
apply(root: Element | Document | DocumentFragment, options?: {all?: boolean; editing?: boolean}): TypographyApplyResult;
|
|
31
|
+
clear(root: Element | Document | DocumentFragment, options?: {forget?: boolean; keepSelection?: boolean}): void;
|
|
32
|
+
clearSelection(root: Element | Document | DocumentFragment): number;
|
|
33
|
+
firstLineEnd(paragraph: Element | null | undefined): number | null;
|
|
34
|
+
initialRange(input: string | Pick<Node, 'textContent'> | null | undefined): InitialRange | null;
|
|
35
|
+
protectInitial(root: Element | Document | DocumentFragment): void;
|
|
36
|
+
invalidateFonts(document?: Document | null): number;
|
|
37
|
+
retire(root: Element | Document | DocumentFragment, options?: {documentChanged?: boolean}): void;
|
|
38
|
+
slotPlan(paragraph: Element, items: readonly RichTextItem[],
|
|
39
|
+
options: Pick<PreparationOptions, 'language' | 'wordBreak'>, input: TypographySlotInput): FlowPlan<DerivedFlowFragment> | null;
|
|
40
|
+
}
|
|
41
|
+
/** Creates an independent disposable DOM projection owner; it never changes Markdown source. */
|
|
42
|
+
export function createTypography(): TypographyController;
|
package/dist/kit/will.d.mts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Will/1: permissions a Markdown document gives agents, as HTML comments on their own lines.
|
|
3
3
|
// <!-- will/1 keep --> ... <!-- /will --> keep: no change; append: add after the region's text only; edit: any change
|
|
4
4
|
export type WillLaw = 'keep' | 'append' | 'edit';
|
|
5
|
-
export type WillFault = 'malformed_marker' | 'unpaired_marker';
|
|
5
|
+
export type WillFault = 'malformed_marker' | 'unpaired_marker' | 'unknown_version' | 'unknown_law' | 'intent_over_bound';
|
|
6
6
|
/** A paired region; `start` to `end` is its text between the marker lines (UTF-16 offsets). */
|
|
7
7
|
export interface WillRegion {
|
|
8
8
|
index: number; law: WillLaw; intent: string | null;
|
|
@@ -40,6 +40,29 @@ export function willMarkerOf(line: string): WillMarker | null;
|
|
|
40
40
|
export function terminatorWidth(last: number, prior: number): number;
|
|
41
41
|
/** The text without one trailing line terminator. */
|
|
42
42
|
export function stripOneTerminator(text: string): string;
|
|
43
|
+
/** A sequential source edit in UTF-16 coordinates; removed must match the current source. */
|
|
44
|
+
export interface WillSplice {pos: number; removed: string; inserted: string;}
|
|
45
|
+
export interface WillRestoreOptions {
|
|
46
|
+
/** Exact splice objects the host has proved undo its own earlier act; text equality is not authority. */
|
|
47
|
+
restores?: readonly WillSplice[] | null;
|
|
48
|
+
}
|
|
49
|
+
export interface WillTransitionOptions extends WillRestoreOptions {
|
|
50
|
+
/** Optional output map populated with admitted contiguous append-tail inverse rows. */
|
|
51
|
+
restored?: Map<number, WillSplice[]> | null;
|
|
52
|
+
}
|
|
53
|
+
export type WillTransitionRefusal =
|
|
54
|
+
| {law: 'keep'; rule: 'before_faulted' | 'result_faulted'; faults: {mode: WillFault; line: number}[]; start: number; end: number}
|
|
55
|
+
| {law: WillLaw; rule: 'marker_span_touched'; editIndex: number; region: number; start: number; end: number}
|
|
56
|
+
| {law: 'keep'; rule: 'marker_sequence_mismatch'; start: number; end: number}
|
|
57
|
+
| {law: 'keep' | 'append'; rule: 'law_violated'; region: number; start: number; end: number};
|
|
58
|
+
/** Maps a resulting UTF-16 offset back through sequential rows; -1 means it lies in inserted text. */
|
|
59
|
+
export function willOffsetBefore(rows: readonly WillSplice[], offset: number): number;
|
|
60
|
+
/** Checks marker identity and body laws after the host has proved the sequential splices. Null admits the transition. */
|
|
61
|
+
export function willTransition(beforeText: string, afterText: string, splices: readonly WillSplice[],
|
|
62
|
+
markerSplices?: readonly WillSplice[], options?: WillTransitionOptions): WillTransitionRefusal | null;
|
|
63
|
+
export type WillEvaluation =
|
|
64
|
+
| {outcome: 'applied'}
|
|
65
|
+
| {outcome: 'invalid'; reason: 'precondition'; rule: 'invalid_unicode' | 'malformed_splice' | 'out_of_range_splice' | 'source_mismatch'}
|
|
66
|
+
| ({outcome: 'refused'; reason: 'document_law'} & WillTransitionRefusal);
|
|
43
67
|
/** Judges sequential UTF-16 source splices, including the resulting marker identities and protected text. */
|
|
44
|
-
export function evaluateWill(beforeText: string, splices:
|
|
45
|
-
{outcome: 'applied'} | {outcome: 'invalid' | 'refused'; reason: string; rule: string; law?: WillLaw; region?: number};
|
|
68
|
+
export function evaluateWill(beforeText: string, splices: readonly WillSplice[], options?: WillRestoreOptions): WillEvaluation;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
export function createMathMatcher(source, {singleDollar = false, brackets = true} = {}) {
|
|
3
|
+
if (typeof source !== 'string') throw new TypeError('Math boundaries require source text.');
|
|
4
|
+
const markers = new Map(), next = Object.create(null);
|
|
5
|
+
let slashes = 0, line = 0;
|
|
6
|
+
for (let at = 0; at < source.length;) {
|
|
7
|
+
const char = source[at];
|
|
8
|
+
if (char === '\\') { slashes++; at++; continue; }
|
|
9
|
+
if (char === '\n' || char === '\r') line++;
|
|
10
|
+
if (char === '$') {
|
|
11
|
+
let end = at + 1;
|
|
12
|
+
while (source[end] === '$') end++;
|
|
13
|
+
const count = end - at;
|
|
14
|
+
if (!(slashes & 1) && (count === 2 || count === 1 && singleDollar))
|
|
15
|
+
markers.set(at, {at, marker: count === 2 ? '$$' : '$', line});
|
|
16
|
+
at = end;
|
|
17
|
+
} else {
|
|
18
|
+
if (brackets && slashes & 1 && '()[]'.includes(char))
|
|
19
|
+
markers.set(at - 1, {at: at - 1, marker: '\\' + char, line});
|
|
20
|
+
at++;
|
|
21
|
+
}
|
|
22
|
+
slashes = 0;
|
|
23
|
+
}
|
|
24
|
+
for (const entry of [...markers.values()].reverse()) {
|
|
25
|
+
const closing = entry.marker === '\\(' ? '\\)' : entry.marker === '\\[' ? '\\]' : entry.marker;
|
|
26
|
+
entry.close = next[closing];
|
|
27
|
+
next[entry.marker] = entry;
|
|
28
|
+
}
|
|
29
|
+
return function match(start, limit = source.length) {
|
|
30
|
+
const open = markers.get(start), close = open?.close;
|
|
31
|
+
if (!close || open.marker === '\\)' || open.marker === '\\]' || close.at + close.marker.length > limit) return null;
|
|
32
|
+
const bodyStart = start + open.marker.length, bodyEnd = close.at;
|
|
33
|
+
if (open.marker === '$' && (open.line !== close.line || bodyStart === bodyEnd ||
|
|
34
|
+
/\s/.test(source[bodyStart]) || /\s/.test(source[bodyEnd - 1]) || /[0-9]/.test(source[bodyEnd + 1] || ''))) return null;
|
|
35
|
+
return {start, end: bodyEnd + close.marker.length, bodyStart, bodyEnd,
|
|
36
|
+
open: open.marker, close: close.marker, displayMode: open.marker === '$$' || open.marker === '\\['};
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
import {createMathMatcher} from './delimiters.mjs';
|
|
3
|
+
|
|
4
|
+
export function installMathRules(md, {singleDollar = false, brackets = true, ruleName = 'rapier_math', inLink = false} = {}) {
|
|
5
|
+
const authored = new WeakMap();
|
|
6
|
+
md.core.ruler.before('normalize', ruleName + '_source', state => {
|
|
7
|
+
authored.set(state.tokens, {source: state.src});
|
|
8
|
+
});
|
|
9
|
+
md.core.ruler.after('block', ruleName + '_source_release', state => authored.delete(state.tokens));
|
|
10
|
+
const tokenize = md.block.tokenize;
|
|
11
|
+
md.block.tokenize = function(state, startLine, endLine) {
|
|
12
|
+
const first = state.tokens.length;
|
|
13
|
+
try { return tokenize.call(this, state, startLine, endLine); }
|
|
14
|
+
finally {
|
|
15
|
+
for (let index = first; index < state.tokens.length; index++) {
|
|
16
|
+
const token = state.tokens[index];
|
|
17
|
+
if (token.type !== 'fence' || !token.map || token.meta?.mathSource !== undefined ||
|
|
18
|
+
String(token.info || '').trim().split(/\s+/)[0].toLowerCase() !== 'math') continue;
|
|
19
|
+
const held = authored.get(state.tokens), source = held?.source ?? state.src;
|
|
20
|
+
let value;
|
|
21
|
+
if (!state.rapierSourceSlice && source === state.src) value = state.getLines(token.map[0], token.map[1], state.blkIndent, false);
|
|
22
|
+
else {
|
|
23
|
+
if (!state.rapierSourceSlice) {
|
|
24
|
+
const starts = text => [0, ...Array.from(text.matchAll(/\r\n?|\n/g), match => match.index + match[0].length)];
|
|
25
|
+
held.rawLines ||= starts(source);
|
|
26
|
+
held.lines ||= starts(state.src);
|
|
27
|
+
}
|
|
28
|
+
const view = Object.create(state), parts = [];
|
|
29
|
+
view.bMarks = []; view.eMarks = [];
|
|
30
|
+
for (let line = token.map[0]; line < token.map[1]; line++) {
|
|
31
|
+
const shift = state.rapierSourceSlice ? 0 : held.rawLines[line] - held.lines[line];
|
|
32
|
+
view.src = state.rapierSourceSlice
|
|
33
|
+
? state.rapierSourceSlice(state.bMarks[line], state.eMarks[line])
|
|
34
|
+
: source.slice(state.bMarks[line] + shift, state.eMarks[line] + shift);
|
|
35
|
+
view.bMarks[line] = 0; view.eMarks[line] = view.src.length;
|
|
36
|
+
parts.push(view.getLines(line, line + 1, state.blkIndent, false));
|
|
37
|
+
if (line + 1 < token.map[1]) parts.push(state.rapierSourceSlice
|
|
38
|
+
? state.rapierSourceSlice(state.eMarks[line], state.eMarks[line] + 1)
|
|
39
|
+
: source.slice(state.eMarks[line] + shift, held.rawLines[line + 1]));
|
|
40
|
+
}
|
|
41
|
+
value = parts.join('');
|
|
42
|
+
}
|
|
43
|
+
token.meta = {...token.meta, mathSource: value};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const renderText = md.renderer.renderInlineAsText;
|
|
48
|
+
md.renderer.renderInlineAsText = function(tokens, options, env) {
|
|
49
|
+
return renderText.call(this, tokens.map(token =>
|
|
50
|
+
token.type === 'math_inline' || token.type === 'math_block'
|
|
51
|
+
? {...token, type: 'text', content: token.meta?.mathSource ?? token.content}
|
|
52
|
+
: token), options, env);
|
|
53
|
+
};
|
|
54
|
+
const matchers = new WeakMap();
|
|
55
|
+
function match(state, at, limit) {
|
|
56
|
+
let entry = matchers.get(state);
|
|
57
|
+
if (!entry || entry.source !== state.src) {
|
|
58
|
+
entry = {source: state.src, match: createMathMatcher(state.src, {singleDollar, brackets})};
|
|
59
|
+
matchers.set(state, entry);
|
|
60
|
+
}
|
|
61
|
+
return entry.match(at, limit);
|
|
62
|
+
}
|
|
63
|
+
md.inline.ruler.before('escape', ruleName, (state, silent) => {
|
|
64
|
+
if (!inLink && state.linkLevel > 0) return false;
|
|
65
|
+
if (state.src[state.pos] !== '$' && state.src[state.pos] !== '\\') return false;
|
|
66
|
+
const span = match(state, state.pos, state.posMax);
|
|
67
|
+
if (!span) return false;
|
|
68
|
+
if (!silent) {
|
|
69
|
+
const token = state.push(span.displayMode ? 'math_block' : 'math_inline', '', 0);
|
|
70
|
+
token.markup = span.open;
|
|
71
|
+
token.content = state.src.slice(span.bodyStart, span.bodyEnd);
|
|
72
|
+
token.meta = {mathSource: state.src.slice(span.start, span.end)};
|
|
73
|
+
}
|
|
74
|
+
state.pos = span.end;
|
|
75
|
+
return true;
|
|
76
|
+
});
|
|
77
|
+
md.block.ruler.before('fence', ruleName, (state, startLine, endLine, silent) => {
|
|
78
|
+
if (state.sCount[startLine] - state.blkIndent >= 4) return false;
|
|
79
|
+
const start = state.bMarks[startLine] + state.tShift[startLine];
|
|
80
|
+
if (state.src.slice(start, start + 2) !== '$$' && (!brackets || state.src.slice(start, start + 2) !== '\\[')) return false;
|
|
81
|
+
const span = match(state, start, state.eMarks[endLine - 1]);
|
|
82
|
+
if (!span?.displayMode) return false;
|
|
83
|
+
let last = startLine;
|
|
84
|
+
while (last < endLine && state.eMarks[last] < span.end) last++;
|
|
85
|
+
if (last >= endLine || span.bodyEnd < state.bMarks[last] + state.tShift[last] ||
|
|
86
|
+
state.src.slice(span.end, state.eMarks[last]).trim()) return false;
|
|
87
|
+
if (silent) return true;
|
|
88
|
+
const parts = [];
|
|
89
|
+
for (let line = startLine; line <= last; line++) {
|
|
90
|
+
const from = line === startLine ? span.bodyStart : state.bMarks[line] + state.tShift[line];
|
|
91
|
+
const to = line === last ? span.bodyEnd : state.eMarks[line];
|
|
92
|
+
parts.push(state.src.slice(from, to));
|
|
93
|
+
}
|
|
94
|
+
const token = state.push('math_block', 'math', 0);
|
|
95
|
+
token.block = true;
|
|
96
|
+
token.markup = span.open;
|
|
97
|
+
token.content = parts.join('\n');
|
|
98
|
+
token.meta = {mathSource: span.open + token.content + span.close};
|
|
99
|
+
token.map = [startLine, last + 1];
|
|
100
|
+
state.line = last + 1;
|
|
101
|
+
return true;
|
|
102
|
+
}, {alt: ['paragraph', 'reference', 'blockquote', 'list']});
|
|
103
|
+
}
|
|
@@ -2,20 +2,12 @@
|
|
|
2
2
|
import {markdownParser, installMarkdownImages, normalizeLabel} from './md-assets.mjs';
|
|
3
3
|
import {splitOpeningFrontmatter} from './frontmatter.mjs';
|
|
4
4
|
import {readDocumentSettings, documentFont} from './document-settings.mjs';
|
|
5
|
-
import {normalizeFontFamily, fontFamilyCss, FONT_STACKS, typography} from './md-marks.mjs';
|
|
5
|
+
import {normalizeFontFamily, fontFamilyCss, FONT_STACKS, typography, fontDataUrl} from './md-marks.mjs';
|
|
6
|
+
export {fontDataUrl};
|
|
6
7
|
|
|
7
8
|
export const CSS_GENERIC_FONT_FAMILIES = Object.freeze(['serif', 'sans-serif', 'monospace', 'cursive', 'fantasy', 'system-ui',
|
|
8
9
|
'ui-serif', 'ui-sans-serif', 'ui-monospace', 'ui-rounded', 'emoji', 'math', 'fangsong', 'initial', 'revert', 'revert-layer']);
|
|
9
10
|
|
|
10
|
-
export function fontDataUrl(url) {
|
|
11
|
-
if (typeof url !== 'string') return null;
|
|
12
|
-
const match = /^data:font\/(woff2|woff|ttf|otf);base64,([A-Za-z0-9+/]+={0,2})$/i.exec(url);
|
|
13
|
-
if (!match || match[2].length % 4) return null;
|
|
14
|
-
const padding = match[2].endsWith('==') ? 2 : match[2].endsWith('=') ? 1 : 0;
|
|
15
|
-
const byteLength = match[2].length / 4 * 3 - padding;
|
|
16
|
-
return byteLength >= 12 ? {format: match[1].toLowerCase(), byteLength, data: match[2]} : null;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
11
|
function parserFor(parser) {
|
|
20
12
|
const md = installMarkdownImages(markdownParser(parser));
|
|
21
13
|
if (!md.__rapierFontsInstalled) {
|
package/dist/spec/md-assets.mjs
CHANGED
|
@@ -9,6 +9,7 @@ const cached = [];
|
|
|
9
9
|
let preparedDefinitions = [];
|
|
10
10
|
let configured = null, splitSource = null;
|
|
11
11
|
export function configureParser(parser, split) { configured = parser; splitSource = split; cached.length = 0; preparedDefinitions = []; }
|
|
12
|
+
export const configuredMarkdownParser = () => configured;
|
|
12
13
|
function fail(reason) { throw new Error(reason); }
|
|
13
14
|
export const normalizeLabel = label => String(label).trim().replace(/\s+/g, ' ').toLowerCase().toUpperCase();
|
|
14
15
|
export const assetTitle = value => String(value || '').replace(/[\r\n]/g, ' ').replace(/\0/g, '\ufffd');
|