@rtif-sdk/formats 3.0.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 +111 -0
- package/dist/html/codec.d.ts +22 -0
- package/dist/html/codec.d.ts.map +1 -0
- package/dist/html/codec.js +25 -0
- package/dist/html/codec.js.map +1 -0
- package/dist/html/entities.d.ts +14 -0
- package/dist/html/entities.d.ts.map +1 -0
- package/dist/html/entities.js +80 -0
- package/dist/html/entities.js.map +1 -0
- package/dist/html/index.d.ts +5 -0
- package/dist/html/index.d.ts.map +1 -0
- package/dist/html/index.js +3 -0
- package/dist/html/index.js.map +1 -0
- package/dist/html/parse-tree.d.ts +33 -0
- package/dist/html/parse-tree.d.ts.map +1 -0
- package/dist/html/parse-tree.js +191 -0
- package/dist/html/parse-tree.js.map +1 -0
- package/dist/html/parse.d.ts +28 -0
- package/dist/html/parse.d.ts.map +1 -0
- package/dist/html/parse.js +282 -0
- package/dist/html/parse.js.map +1 -0
- package/dist/html/rules.d.ts +51 -0
- package/dist/html/rules.d.ts.map +1 -0
- package/dist/html/rules.js +74 -0
- package/dist/html/rules.js.map +1 -0
- package/dist/html/serialize.d.ts +15 -0
- package/dist/html/serialize.d.ts.map +1 -0
- package/dist/html/serialize.js +68 -0
- package/dist/html/serialize.js.map +1 -0
- package/dist/markdown/codec.d.ts +15 -0
- package/dist/markdown/codec.d.ts.map +1 -0
- package/dist/markdown/codec.js +56 -0
- package/dist/markdown/codec.js.map +1 -0
- package/dist/markdown/index.d.ts +3 -0
- package/dist/markdown/index.d.ts.map +1 -0
- package/dist/markdown/index.js +3 -0
- package/dist/markdown/index.js.map +1 -0
- package/dist/markdown/parse-blocks.d.ts +25 -0
- package/dist/markdown/parse-blocks.d.ts.map +1 -0
- package/dist/markdown/parse-blocks.js +122 -0
- package/dist/markdown/parse-blocks.js.map +1 -0
- package/dist/markdown/parse-inline.d.ts +15 -0
- package/dist/markdown/parse-inline.d.ts.map +1 -0
- package/dist/markdown/parse-inline.js +164 -0
- package/dist/markdown/parse-inline.js.map +1 -0
- package/dist/markdown/serialize.d.ts +17 -0
- package/dist/markdown/serialize.d.ts.map +1 -0
- package/dist/markdown/serialize.js +120 -0
- package/dist/markdown/serialize.js.map +1 -0
- package/dist/plaintext/codec.d.ts +15 -0
- package/dist/plaintext/codec.d.ts.map +1 -0
- package/dist/plaintext/codec.js +30 -0
- package/dist/plaintext/codec.js.map +1 -0
- package/dist/plaintext/index.d.ts +3 -0
- package/dist/plaintext/index.d.ts.map +1 -0
- package/dist/plaintext/index.js +3 -0
- package/dist/plaintext/index.js.map +1 -0
- package/dist/shared/block-text.d.ts +4 -0
- package/dist/shared/block-text.d.ts.map +1 -0
- package/dist/shared/block-text.js +5 -0
- package/dist/shared/block-text.js.map +1 -0
- package/dist/shared/ids.d.ts +9 -0
- package/dist/shared/ids.d.ts.map +1 -0
- package/dist/shared/ids.js +12 -0
- package/dist/shared/ids.js.map +1 -0
- package/dist/shared/url.d.ts +20 -0
- package/dist/shared/url.d.ts.map +1 -0
- package/dist/shared/url.js +33 -0
- package/dist/shared/url.js.map +1 -0
- package/package.json +28 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTML → Document. Walks the sanitized tree from parse-tree.ts and
|
|
3
|
+
* accumulates normalized blocks. Best-effort: never throws, always returns
|
|
4
|
+
* a valid document with ≥ 1 block. No DOM dependency — SSR-safe.
|
|
5
|
+
*
|
|
6
|
+
* Documented behavior:
|
|
7
|
+
* - `<br>` ends the current block and starts a new one of the *same* type
|
|
8
|
+
* (so `<p>a<br>b</p>` yields two paragraphs; `<br><br>` keeps the empty
|
|
9
|
+
* block between them).
|
|
10
|
+
* - Nested `<ul>`/`<ol>` flatten to consecutive `list` blocks; nesting depth
|
|
11
|
+
* is recorded as `attrs.indent` (absent at the top level). `indent` is
|
|
12
|
+
* parse-only metadata — serialization ignores it.
|
|
13
|
+
* - Unknown elements are transparent (children are parsed in place); loose
|
|
14
|
+
* text at block level becomes a paragraph.
|
|
15
|
+
* - Inside `<blockquote>` and `<li>`, paragraph-ish children adopt the
|
|
16
|
+
* container's block type: `<blockquote><p>a</p><p>b</p></blockquote>`
|
|
17
|
+
* yields two blockquote blocks.
|
|
18
|
+
* - Whitespace collapses per HTML semantics except inside `<pre>`;
|
|
19
|
+
* block-edge whitespace is trimmed; whitespace-only text between blocks
|
|
20
|
+
* is dropped. ` ` (U+00A0) never collapses.
|
|
21
|
+
* - Styles are ignored: Google-Docs-style `<b style="font-weight:normal">`
|
|
22
|
+
* parses as bold.
|
|
23
|
+
*/
|
|
24
|
+
import { normalizeBlock } from '@rtif-sdk/core';
|
|
25
|
+
import { createIdGenerator } from '../shared/ids.js';
|
|
26
|
+
import { parseHtmlTree } from './parse-tree.js';
|
|
27
|
+
/** Elements dropped with their entire subtree (script/style/iframe died in the tokenizer). */
|
|
28
|
+
const DROPPED_TAGS = new Set([
|
|
29
|
+
'object',
|
|
30
|
+
'embed',
|
|
31
|
+
'img',
|
|
32
|
+
'picture',
|
|
33
|
+
'video',
|
|
34
|
+
'audio',
|
|
35
|
+
'svg',
|
|
36
|
+
'canvas',
|
|
37
|
+
]);
|
|
38
|
+
/** Unknown-but-block-level containers: force block boundaries, then recurse transparently. */
|
|
39
|
+
const BOUNDARY_TAGS = new Set([
|
|
40
|
+
'address',
|
|
41
|
+
'article',
|
|
42
|
+
'aside',
|
|
43
|
+
'caption',
|
|
44
|
+
'dd',
|
|
45
|
+
'details',
|
|
46
|
+
'dl',
|
|
47
|
+
'dt',
|
|
48
|
+
'fieldset',
|
|
49
|
+
'figcaption',
|
|
50
|
+
'figure',
|
|
51
|
+
'footer',
|
|
52
|
+
'form',
|
|
53
|
+
'header',
|
|
54
|
+
'main',
|
|
55
|
+
'nav',
|
|
56
|
+
'section',
|
|
57
|
+
'summary',
|
|
58
|
+
'table',
|
|
59
|
+
'tbody',
|
|
60
|
+
'td',
|
|
61
|
+
'tfoot',
|
|
62
|
+
'th',
|
|
63
|
+
'thead',
|
|
64
|
+
'tr',
|
|
65
|
+
]);
|
|
66
|
+
const collapseWs = (text) => text.replace(/[\t\n\r\f ]+/g, ' ');
|
|
67
|
+
const isWsOnly = (text) => /^[\t\n\r\f ]*$/.test(text);
|
|
68
|
+
/** Trim block-edge spaces and drop spaces duplicated across span boundaries. */
|
|
69
|
+
const trimBlockEdges = (spans) => {
|
|
70
|
+
const out = [];
|
|
71
|
+
let prevEndsWithSpace = true; // trims leading whitespace at the block edge
|
|
72
|
+
for (const span of spans) {
|
|
73
|
+
const text = prevEndsWithSpace ? span.text.replace(/^ +/, '') : span.text;
|
|
74
|
+
if (text === '')
|
|
75
|
+
continue;
|
|
76
|
+
prevEndsWithSpace = text.endsWith(' ');
|
|
77
|
+
out.push(span.marks !== undefined ? { text, marks: span.marks } : { text });
|
|
78
|
+
}
|
|
79
|
+
while (out.length > 0) {
|
|
80
|
+
const last = out[out.length - 1];
|
|
81
|
+
const trimmed = last.text.replace(/ +$/, '');
|
|
82
|
+
if (trimmed !== '') {
|
|
83
|
+
out[out.length - 1] =
|
|
84
|
+
last.marks !== undefined ? { text: trimmed, marks: last.marks } : { text: trimmed };
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
out.pop();
|
|
88
|
+
}
|
|
89
|
+
return out;
|
|
90
|
+
};
|
|
91
|
+
/** Close the open block; silently dropped when empty unless marked explicit. */
|
|
92
|
+
const flush = (acc) => {
|
|
93
|
+
const open = acc.open;
|
|
94
|
+
if (open === null)
|
|
95
|
+
return;
|
|
96
|
+
acc.open = null;
|
|
97
|
+
const spans = trimBlockEdges(open.spans);
|
|
98
|
+
if (spans.length === 0 && !open.explicit)
|
|
99
|
+
return;
|
|
100
|
+
pushBlock(acc, open.type, open.attrs, spans.length > 0 ? spans : [{ text: '' }]);
|
|
101
|
+
};
|
|
102
|
+
const pushBlock = (acc, type, attrs, spans) => {
|
|
103
|
+
acc.blocks.push(normalizeBlock({
|
|
104
|
+
id: acc.nextId(),
|
|
105
|
+
type,
|
|
106
|
+
...(attrs !== undefined ? { attrs } : {}),
|
|
107
|
+
spans,
|
|
108
|
+
}));
|
|
109
|
+
};
|
|
110
|
+
const appendText = (acc, ctx, raw) => {
|
|
111
|
+
if (acc.open === null) {
|
|
112
|
+
if (isWsOnly(raw))
|
|
113
|
+
return; // whitespace-only text between blocks
|
|
114
|
+
acc.open = { type: ctx.blockType, attrs: ctx.blockAttrs, spans: [], explicit: false };
|
|
115
|
+
}
|
|
116
|
+
const text = collapseWs(raw);
|
|
117
|
+
acc.open.spans.push(ctx.marks !== undefined ? { text, marks: ctx.marks } : { text });
|
|
118
|
+
};
|
|
119
|
+
const walk = (nodes, ctx, acc) => {
|
|
120
|
+
for (const node of nodes) {
|
|
121
|
+
if (node.kind === 'text')
|
|
122
|
+
appendText(acc, ctx, node.text);
|
|
123
|
+
else
|
|
124
|
+
walkElement(node, ctx, acc);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
const walkElement = (el, ctx, acc) => {
|
|
128
|
+
if (DROPPED_TAGS.has(el.tag))
|
|
129
|
+
return;
|
|
130
|
+
if (el.tag === 'br')
|
|
131
|
+
return handleBr(acc, ctx);
|
|
132
|
+
if (el.tag === 'hr') {
|
|
133
|
+
flush(acc);
|
|
134
|
+
return pushBlock(acc, 'horizontal_rule', undefined, [{ text: '' }]);
|
|
135
|
+
}
|
|
136
|
+
if (el.tag === 'pre')
|
|
137
|
+
return handlePre(el, acc);
|
|
138
|
+
if (el.tag === 'ul' || el.tag === 'ol')
|
|
139
|
+
return handleList(el, ctx, acc);
|
|
140
|
+
if (el.tag === 'li')
|
|
141
|
+
return handleListItem(el, ctx, acc);
|
|
142
|
+
if (el.tag === 'blockquote') {
|
|
143
|
+
return handleContainer(el, { ...ctx, blockType: 'blockquote', blockAttrs: undefined }, acc);
|
|
144
|
+
}
|
|
145
|
+
const mark = acc.markByTag.get(el.tag);
|
|
146
|
+
if (mark !== undefined)
|
|
147
|
+
return handleMark(el, ctx, acc, mark);
|
|
148
|
+
const block = acc.blockByTag.get(el.tag);
|
|
149
|
+
if (block !== undefined)
|
|
150
|
+
return handleBlock(el, ctx, acc, block);
|
|
151
|
+
if (BOUNDARY_TAGS.has(el.tag)) {
|
|
152
|
+
flush(acc);
|
|
153
|
+
walk(el.children, ctx, acc);
|
|
154
|
+
flush(acc);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
walk(el.children, ctx, acc); // unknown element → transparent
|
|
158
|
+
};
|
|
159
|
+
/** `<br>`: close the current block and open a new one of the same type/attrs. */
|
|
160
|
+
const handleBr = (acc, ctx) => {
|
|
161
|
+
const type = acc.open?.type ?? ctx.blockType;
|
|
162
|
+
const attrs = acc.open?.attrs ?? ctx.blockAttrs;
|
|
163
|
+
flush(acc);
|
|
164
|
+
acc.open = { type, attrs, spans: [], explicit: true };
|
|
165
|
+
};
|
|
166
|
+
/** Apply a mark to everything inside the element; `getValue() === null` ⇒ transparent. */
|
|
167
|
+
const handleMark = (el, ctx, acc, entry) => {
|
|
168
|
+
const value = entry.rule.parse?.getValue !== undefined ? entry.rule.parse.getValue(el.attrs) : true;
|
|
169
|
+
if (value === null)
|
|
170
|
+
return walk(el.children, ctx, acc);
|
|
171
|
+
walk(el.children, { ...ctx, marks: { ...ctx.marks, [entry.name]: value } }, acc);
|
|
172
|
+
};
|
|
173
|
+
/** Open a block element via its rule; paragraph-ish blocks adopt the container's type. */
|
|
174
|
+
const handleBlock = (el, ctx, acc, entry) => {
|
|
175
|
+
const getAttrs = entry.rule.parse?.getAttrs;
|
|
176
|
+
const attrs = getAttrs !== undefined ? getAttrs(el.attrs, el.tag) : undefined;
|
|
177
|
+
if (getAttrs !== undefined && attrs === null)
|
|
178
|
+
return walk(el.children, ctx, acc);
|
|
179
|
+
const inherit = entry.type === 'paragraph' && ctx.blockType !== 'paragraph';
|
|
180
|
+
const type = inherit ? ctx.blockType : entry.type;
|
|
181
|
+
const blockAttrs = inherit ? ctx.blockAttrs : (attrs ?? undefined);
|
|
182
|
+
handleContainer(el, { ...ctx, blockType: type, blockAttrs }, acc);
|
|
183
|
+
};
|
|
184
|
+
/**
|
|
185
|
+
* Walk a block element's children with `ctx` as the lazy block context.
|
|
186
|
+
* If the element produced no block at all (e.g. `<p></p>`), emit an empty one.
|
|
187
|
+
*/
|
|
188
|
+
const handleContainer = (el, ctx, acc) => {
|
|
189
|
+
flush(acc);
|
|
190
|
+
const before = acc.blocks.length;
|
|
191
|
+
walk(el.children, ctx, acc);
|
|
192
|
+
flush(acc);
|
|
193
|
+
if (acc.blocks.length === before)
|
|
194
|
+
pushBlock(acc, ctx.blockType, ctx.blockAttrs, [{ text: '' }]);
|
|
195
|
+
};
|
|
196
|
+
const handleList = (el, ctx, acc) => {
|
|
197
|
+
flush(acc);
|
|
198
|
+
const kind = el.tag === 'ol' ? 'ordered' : 'bulleted';
|
|
199
|
+
const attrs = ctx.listDepth > 0 ? { kind, indent: ctx.listDepth } : { kind };
|
|
200
|
+
walk(el.children, { ...ctx, blockType: 'list', blockAttrs: attrs, listDepth: ctx.listDepth + 1 }, acc);
|
|
201
|
+
flush(acc);
|
|
202
|
+
};
|
|
203
|
+
/** `<li>` inside a list becomes a `list` block; an orphan `<li>` degrades to the context type. */
|
|
204
|
+
const handleListItem = (el, ctx, acc) => {
|
|
205
|
+
handleContainer(el, ctx, acc);
|
|
206
|
+
};
|
|
207
|
+
/** `<pre>`: raw text (whitespace preserved, `<br>` → newline) becomes one code_block. */
|
|
208
|
+
const handlePre = (el, acc) => {
|
|
209
|
+
flush(acc);
|
|
210
|
+
const text = rawText(el).replace(/^\n/, '').replace(/\n$/, '');
|
|
211
|
+
const language = findCodeLanguage(el);
|
|
212
|
+
pushBlock(acc, 'code_block', language !== null ? { language } : undefined, [{ text }]);
|
|
213
|
+
};
|
|
214
|
+
const rawText = (node) => {
|
|
215
|
+
if (node.kind === 'text')
|
|
216
|
+
return node.text;
|
|
217
|
+
if (node.tag === 'br')
|
|
218
|
+
return '\n';
|
|
219
|
+
return node.children.map(rawText).join('');
|
|
220
|
+
};
|
|
221
|
+
const findCodeLanguage = (el) => {
|
|
222
|
+
for (const child of el.children) {
|
|
223
|
+
if (child.kind !== 'element' || child.tag !== 'code')
|
|
224
|
+
continue;
|
|
225
|
+
const cls = child.attrs['class'];
|
|
226
|
+
const match = cls !== undefined ? /language-([\w+-]+)/.exec(cls) : null;
|
|
227
|
+
return match !== null ? match[1] : null;
|
|
228
|
+
}
|
|
229
|
+
return null;
|
|
230
|
+
};
|
|
231
|
+
const buildMarkMap = (rules) => {
|
|
232
|
+
const map = new Map();
|
|
233
|
+
for (const [name, rule] of Object.entries(rules.marks)) {
|
|
234
|
+
for (const tag of rule.parse?.tags ?? [])
|
|
235
|
+
map.set(tag, { name, rule });
|
|
236
|
+
}
|
|
237
|
+
return map;
|
|
238
|
+
};
|
|
239
|
+
const buildBlockMap = (rules) => {
|
|
240
|
+
const map = new Map();
|
|
241
|
+
for (const [type, rule] of Object.entries(rules.blocks)) {
|
|
242
|
+
for (const tag of rule.parse?.tags ?? [])
|
|
243
|
+
map.set(tag, { type, rule });
|
|
244
|
+
}
|
|
245
|
+
return map;
|
|
246
|
+
};
|
|
247
|
+
/** Last-resort fallback when a user-supplied rule callback throws: plain text, line per paragraph. */
|
|
248
|
+
const plaintextFallback = (input) => {
|
|
249
|
+
const nextId = createIdGenerator();
|
|
250
|
+
return {
|
|
251
|
+
blocks: input
|
|
252
|
+
.split(/\r\n|\r|\n/)
|
|
253
|
+
.map((line) => ({ id: nextId(), type: 'paragraph', spans: [{ text: line }] })),
|
|
254
|
+
};
|
|
255
|
+
};
|
|
256
|
+
/** Parse an HTML string into a valid normalized document. Never throws. */
|
|
257
|
+
export function parseHtml(input, rules) {
|
|
258
|
+
try {
|
|
259
|
+
const acc = {
|
|
260
|
+
blocks: [],
|
|
261
|
+
open: null,
|
|
262
|
+
nextId: createIdGenerator(),
|
|
263
|
+
markByTag: buildMarkMap(rules),
|
|
264
|
+
blockByTag: buildBlockMap(rules),
|
|
265
|
+
};
|
|
266
|
+
const ctx = {
|
|
267
|
+
marks: undefined,
|
|
268
|
+
blockType: 'paragraph',
|
|
269
|
+
blockAttrs: undefined,
|
|
270
|
+
listDepth: 0,
|
|
271
|
+
};
|
|
272
|
+
walk(parseHtmlTree(input), ctx, acc);
|
|
273
|
+
flush(acc);
|
|
274
|
+
if (acc.blocks.length === 0)
|
|
275
|
+
acc.blocks.push({ id: acc.nextId(), type: 'paragraph', spans: [{ text: '' }] });
|
|
276
|
+
return { blocks: acc.blocks };
|
|
277
|
+
}
|
|
278
|
+
catch {
|
|
279
|
+
return plaintextFallback(input);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/html/parse.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HtmlRules — the typed extension point web features use to contribute
|
|
3
|
+
* serialize/parse behavior to the HTML codec. Defaults cover the canonical
|
|
4
|
+
* block and mark types; user rules merge over defaults per name.
|
|
5
|
+
*
|
|
6
|
+
* Structural tags are handled by the parser itself and cannot be remapped
|
|
7
|
+
* through parse rules: `<ul>`/`<ol>`/`<li>`, `<blockquote>`, `<pre>`,
|
|
8
|
+
* `<br>`, and `<hr>`.
|
|
9
|
+
*/
|
|
10
|
+
import type { Attrs, Block, MarkValue } from '@rtif-sdk/core';
|
|
11
|
+
/** Serialize/parse rule for one mark type. */
|
|
12
|
+
export interface HtmlMarkRule {
|
|
13
|
+
/** Tag emitted when serializing the mark. */
|
|
14
|
+
readonly tag: string;
|
|
15
|
+
/** Extra attributes for the serialized tag, derived from the mark value. */
|
|
16
|
+
readonly attrs?: (value: MarkValue) => Readonly<Record<string, string>>;
|
|
17
|
+
readonly parse?: {
|
|
18
|
+
/** Lowercase tag names that map to this mark when parsing. */
|
|
19
|
+
readonly tags: readonly string[];
|
|
20
|
+
/** Mark value from element attributes; return `null` to skip the mark (children still parse). Defaults to `true`. */
|
|
21
|
+
readonly getValue?: (attrs: Readonly<Record<string, string>>) => MarkValue | null;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/** Serialize/parse rule for one block type. */
|
|
25
|
+
export interface HtmlBlockRule {
|
|
26
|
+
/** Produce the block's HTML; `inner` is the already-serialized (and escaped) span content. */
|
|
27
|
+
readonly serialize: (block: Block, inner: string) => string;
|
|
28
|
+
readonly parse?: {
|
|
29
|
+
/** Lowercase tag names that map to this block type when parsing. */
|
|
30
|
+
readonly tags: readonly string[];
|
|
31
|
+
/** Block attrs from element attributes and tag name; return `null` to reject (element becomes transparent). */
|
|
32
|
+
readonly getAttrs?: (attrs: Readonly<Record<string, string>>, tag: string) => Attrs | null;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** Rule sets contributed by features; merged over the defaults per name. */
|
|
36
|
+
export interface HtmlRules {
|
|
37
|
+
readonly marks?: Readonly<Record<string, HtmlMarkRule>>;
|
|
38
|
+
readonly blocks?: Readonly<Record<string, HtmlBlockRule>>;
|
|
39
|
+
}
|
|
40
|
+
/** Fully-merged rules used internally by serialize/parse. */
|
|
41
|
+
export interface ResolvedHtmlRules {
|
|
42
|
+
readonly marks: Readonly<Record<string, HtmlMarkRule>>;
|
|
43
|
+
readonly blocks: Readonly<Record<string, HtmlBlockRule>>;
|
|
44
|
+
}
|
|
45
|
+
/** Default mark rules for the canonical mark set (architecture §3). */
|
|
46
|
+
export declare const defaultMarkRules: Readonly<Record<string, HtmlMarkRule>>;
|
|
47
|
+
/** Default block rules for the canonical block set (architecture §3). */
|
|
48
|
+
export declare const defaultBlockRules: Readonly<Record<string, HtmlBlockRule>>;
|
|
49
|
+
/** Merge user rules over the defaults (per mark/block name). */
|
|
50
|
+
export declare function resolveRules(rules?: HtmlRules): ResolvedHtmlRules;
|
|
51
|
+
//# sourceMappingURL=rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../src/html/rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAI9D,8CAA8C;AAC9C,MAAM,WAAW,YAAY;IAC3B,6CAA6C;IAC7C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACxE,QAAQ,CAAC,KAAK,CAAC,EAAE;QACf,8DAA8D;QAC9D,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;QACjC,qHAAqH;QACrH,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,KAAK,SAAS,GAAG,IAAI,CAAC;KACnF,CAAC;CACH;AAED,+CAA+C;AAC/C,MAAM,WAAW,aAAa;IAC5B,8FAA8F;IAC9F,QAAQ,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC5D,QAAQ,CAAC,KAAK,CAAC,EAAE;QACf,oEAAoE;QACpE,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;QACjC,+GAA+G;QAC/G,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,KAAK,KAAK,GAAG,IAAI,CAAC;KAC5F,CAAC;CACH;AAED,4EAA4E;AAC5E,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IACxD,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;CAC3D;AAED,6DAA6D;AAC7D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IACvD,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;CAC1D;AAwBD,uEAAuE;AACvE,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAenE,CAAC;AAEF,yEAAyE;AACzE,eAAO,MAAM,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAmBrE,CAAC;AAEF,gEAAgE;AAChE,wBAAgB,YAAY,CAAC,KAAK,CAAC,EAAE,SAAS,GAAG,iBAAiB,CAKjE"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HtmlRules — the typed extension point web features use to contribute
|
|
3
|
+
* serialize/parse behavior to the HTML codec. Defaults cover the canonical
|
|
4
|
+
* block and mark types; user rules merge over defaults per name.
|
|
5
|
+
*
|
|
6
|
+
* Structural tags are handled by the parser itself and cannot be remapped
|
|
7
|
+
* through parse rules: `<ul>`/`<ol>`/`<li>`, `<blockquote>`, `<pre>`,
|
|
8
|
+
* `<br>`, and `<hr>`.
|
|
9
|
+
*/
|
|
10
|
+
import { blockText } from '../shared/block-text.js';
|
|
11
|
+
import { escapeAttr, escapeText } from './entities.js';
|
|
12
|
+
const linkHref = (value) => typeof value === 'object' &&
|
|
13
|
+
value !== null &&
|
|
14
|
+
typeof value.href === 'string'
|
|
15
|
+
? value.href
|
|
16
|
+
: '';
|
|
17
|
+
/** Heading level from attrs, clamped to 1–6 (defaults to 1). */
|
|
18
|
+
const headingLevel = (block) => {
|
|
19
|
+
const level = block.attrs?.['level'];
|
|
20
|
+
return typeof level === 'number' && level >= 1 && level <= 6 ? Math.floor(level) : 1;
|
|
21
|
+
};
|
|
22
|
+
const codeBlockHtml = (block) => {
|
|
23
|
+
const language = block.attrs?.['language'];
|
|
24
|
+
const cls = typeof language === 'string' && language !== ''
|
|
25
|
+
? ` class="language-${escapeAttr(language)}"`
|
|
26
|
+
: '';
|
|
27
|
+
return `<pre><code${cls}>${escapeText(blockText(block))}</code></pre>`;
|
|
28
|
+
};
|
|
29
|
+
/** Default mark rules for the canonical mark set (architecture §3). */
|
|
30
|
+
export const defaultMarkRules = {
|
|
31
|
+
bold: { tag: 'strong', parse: { tags: ['strong', 'b'] } },
|
|
32
|
+
italic: { tag: 'em', parse: { tags: ['em', 'i'] } },
|
|
33
|
+
underline: { tag: 'u', parse: { tags: ['u'] } },
|
|
34
|
+
strikethrough: { tag: 's', parse: { tags: ['s', 'strike', 'del'] } },
|
|
35
|
+
code: { tag: 'code', parse: { tags: ['code'] } },
|
|
36
|
+
link: {
|
|
37
|
+
tag: 'a',
|
|
38
|
+
attrs: (value) => ({ href: linkHref(value) }),
|
|
39
|
+
parse: {
|
|
40
|
+
tags: ['a'],
|
|
41
|
+
// href is already protocol-allowlisted by the tokenizer; absent href ⇒ no mark.
|
|
42
|
+
getValue: (attrs) => (attrs['href'] !== undefined ? { href: attrs['href'] } : null),
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
/** Default block rules for the canonical block set (architecture §3). */
|
|
47
|
+
export const defaultBlockRules = {
|
|
48
|
+
paragraph: {
|
|
49
|
+
serialize: (_block, inner) => `<p>${inner}</p>`,
|
|
50
|
+
parse: { tags: ['p', 'div'] },
|
|
51
|
+
},
|
|
52
|
+
heading: {
|
|
53
|
+
serialize: (block, inner) => {
|
|
54
|
+
const level = headingLevel(block);
|
|
55
|
+
return `<h${level}>${inner}</h${level}>`;
|
|
56
|
+
},
|
|
57
|
+
parse: {
|
|
58
|
+
tags: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
|
|
59
|
+
getAttrs: (_attrs, tag) => ({ level: Number(tag.slice(1)) }),
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
blockquote: { serialize: (_block, inner) => `<blockquote><p>${inner}</p></blockquote>` },
|
|
63
|
+
code_block: { serialize: (block) => codeBlockHtml(block) },
|
|
64
|
+
list: { serialize: (_block, inner) => `<li>${inner}</li>` },
|
|
65
|
+
horizontal_rule: { serialize: () => '<hr>' },
|
|
66
|
+
};
|
|
67
|
+
/** Merge user rules over the defaults (per mark/block name). */
|
|
68
|
+
export function resolveRules(rules) {
|
|
69
|
+
return {
|
|
70
|
+
marks: { ...defaultMarkRules, ...rules?.marks },
|
|
71
|
+
blocks: { ...defaultBlockRules, ...rules?.blocks },
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/html/rules.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document → HTML string. Pure string building, no DOM.
|
|
3
|
+
*
|
|
4
|
+
* Determinism: a span's mark tags are nested in sorted mark-name order, so
|
|
5
|
+
* the same document always serializes to the same string. Adjacent spans are
|
|
6
|
+
* not merged — the document is already normalized, so adjacent spans always
|
|
7
|
+
* differ in marks. Consecutive `list` blocks of the same kind group into one
|
|
8
|
+
* `<ul>`/`<ol>` (the only block-grouping rule; `attrs.indent` from nested
|
|
9
|
+
* list parsing is intentionally ignored here).
|
|
10
|
+
*/
|
|
11
|
+
import type { Document } from '@rtif-sdk/core';
|
|
12
|
+
import type { ResolvedHtmlRules } from './rules.js';
|
|
13
|
+
/** Serialize a document to an HTML string using the resolved rules. */
|
|
14
|
+
export declare function serializeHtml(doc: Document, rules: ResolvedHtmlRules): string;
|
|
15
|
+
//# sourceMappingURL=serialize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../../src/html/serialize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAS,QAAQ,EAAmB,MAAM,gBAAgB,CAAC;AAEvE,OAAO,KAAK,EAAgB,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAyClE,uEAAuE;AACvE,wBAAgB,aAAa,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAsB7E"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document → HTML string. Pure string building, no DOM.
|
|
3
|
+
*
|
|
4
|
+
* Determinism: a span's mark tags are nested in sorted mark-name order, so
|
|
5
|
+
* the same document always serializes to the same string. Adjacent spans are
|
|
6
|
+
* not merged — the document is already normalized, so adjacent spans always
|
|
7
|
+
* differ in marks. Consecutive `list` blocks of the same kind group into one
|
|
8
|
+
* `<ul>`/`<ol>` (the only block-grouping rule; `attrs.indent` from nested
|
|
9
|
+
* list parsing is intentionally ignored here).
|
|
10
|
+
*/
|
|
11
|
+
import { escapeAttr, escapeText } from './entities.js';
|
|
12
|
+
const serializeTagAttrs = (attrs) => Object.keys(attrs)
|
|
13
|
+
.map((name) => ` ${name}="${escapeAttr(attrs[name])}"`)
|
|
14
|
+
.join('');
|
|
15
|
+
const openMarkTag = (rule, value) => `<${rule.tag}${rule.attrs !== undefined ? serializeTagAttrs(rule.attrs(value)) : ''}>`;
|
|
16
|
+
/** Serialize one span: escaped text wrapped in its mark tags (sorted mark-name order). */
|
|
17
|
+
const serializeSpan = (span, rules) => {
|
|
18
|
+
const text = escapeText(span.text);
|
|
19
|
+
const marks = span.marks;
|
|
20
|
+
if (marks === undefined)
|
|
21
|
+
return text;
|
|
22
|
+
const names = Object.keys(marks)
|
|
23
|
+
.sort()
|
|
24
|
+
.filter((name) => rules.marks[name] !== undefined); // unknown marks render as plain text
|
|
25
|
+
const open = names
|
|
26
|
+
.map((name) => openMarkTag(rules.marks[name], marks[name]))
|
|
27
|
+
.join('');
|
|
28
|
+
const close = names
|
|
29
|
+
.map((name) => `</${rules.marks[name].tag}>`)
|
|
30
|
+
.reverse()
|
|
31
|
+
.join('');
|
|
32
|
+
return open + text + close;
|
|
33
|
+
};
|
|
34
|
+
const serializeSpans = (block, rules) => block.spans.map((span) => serializeSpan(span, rules)).join('');
|
|
35
|
+
/** Serialize one block via its rule; unknown block types fall back to `<p>`. */
|
|
36
|
+
const serializeBlock = (block, rules) => {
|
|
37
|
+
const rule = rules.blocks[block.type] ?? rules.blocks['paragraph'];
|
|
38
|
+
if (rule === undefined)
|
|
39
|
+
return serializeSpans(block, rules);
|
|
40
|
+
return rule.serialize(block, serializeSpans(block, rules));
|
|
41
|
+
};
|
|
42
|
+
const listKind = (block) => block.attrs?.['kind'] === 'ordered' ? 'ordered' : 'bulleted';
|
|
43
|
+
/** Serialize a document to an HTML string using the resolved rules. */
|
|
44
|
+
export function serializeHtml(doc, rules) {
|
|
45
|
+
const out = [];
|
|
46
|
+
let i = 0;
|
|
47
|
+
while (i < doc.blocks.length) {
|
|
48
|
+
const block = doc.blocks[i];
|
|
49
|
+
if (block.type !== 'list') {
|
|
50
|
+
out.push(serializeBlock(block, rules));
|
|
51
|
+
i++;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const kind = listKind(block);
|
|
55
|
+
const items = [];
|
|
56
|
+
while (i < doc.blocks.length) {
|
|
57
|
+
const item = doc.blocks[i];
|
|
58
|
+
if (item.type !== 'list' || listKind(item) !== kind)
|
|
59
|
+
break;
|
|
60
|
+
items.push(serializeBlock(item, rules));
|
|
61
|
+
i++;
|
|
62
|
+
}
|
|
63
|
+
const tag = kind === 'ordered' ? 'ol' : 'ul';
|
|
64
|
+
out.push(`<${tag}>${items.join('')}</${tag}>`);
|
|
65
|
+
}
|
|
66
|
+
return out.join('');
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=serialize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.js","sourceRoot":"","sources":["../../src/html/serialize.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The markdown codec factory: a CommonMark subset matching the canonical
|
|
3
|
+
* block and mark types. Parse never throws — unparseable constructs degrade
|
|
4
|
+
* to plain text, and the result is always a valid normalized document.
|
|
5
|
+
*/
|
|
6
|
+
import type { FormatCodec } from '@rtif-sdk/core';
|
|
7
|
+
/**
|
|
8
|
+
* Create a markdown codec.
|
|
9
|
+
*
|
|
10
|
+
* Serialization notes: underline has no markdown form and is emitted as
|
|
11
|
+
* plain text; block ids are not preserved. Parsing sanitizes link
|
|
12
|
+
* destinations with the shared protocol allowlist.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createMarkdownCodec(): FormatCodec;
|
|
15
|
+
//# sourceMappingURL=codec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../../src/markdown/codec.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAmB,WAAW,EAAQ,MAAM,gBAAgB,CAAC;AAiCzE;;;;;;GAMG;AACH,wBAAgB,mBAAmB,IAAI,WAAW,CAYjD"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The markdown codec factory: a CommonMark subset matching the canonical
|
|
3
|
+
* block and mark types. Parse never throws — unparseable constructs degrade
|
|
4
|
+
* to plain text, and the result is always a valid normalized document.
|
|
5
|
+
*/
|
|
6
|
+
import { normalizeBlock } from '@rtif-sdk/core';
|
|
7
|
+
import { createIdGenerator } from '../shared/ids.js';
|
|
8
|
+
import { splitMarkdownBlocks } from './parse-blocks.js';
|
|
9
|
+
import { parseInline } from './parse-inline.js';
|
|
10
|
+
import { serializeMarkdown } from './serialize.js';
|
|
11
|
+
const parseMarkdown = (input) => {
|
|
12
|
+
const nextId = createIdGenerator();
|
|
13
|
+
const blocks = splitMarkdownBlocks(input).map((draft) => {
|
|
14
|
+
const spans = draft.raw ? [{ text: draft.text }] : parseInline(draft.text);
|
|
15
|
+
return normalizeBlock({
|
|
16
|
+
id: nextId(),
|
|
17
|
+
type: draft.type,
|
|
18
|
+
...(draft.attrs !== undefined ? { attrs: draft.attrs } : {}),
|
|
19
|
+
spans: spans.length > 0 ? spans : [{ text: '' }],
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
if (blocks.length === 0)
|
|
23
|
+
return { blocks: [{ id: nextId(), type: 'paragraph', spans: [{ text: '' }] }] };
|
|
24
|
+
return { blocks };
|
|
25
|
+
};
|
|
26
|
+
/** Last-resort fallback so `parse` upholds its never-throws contract. */
|
|
27
|
+
const plaintextFallback = (input) => {
|
|
28
|
+
const nextId = createIdGenerator();
|
|
29
|
+
return {
|
|
30
|
+
blocks: input
|
|
31
|
+
.split(/\r\n|\r|\n/)
|
|
32
|
+
.map((line) => ({ id: nextId(), type: 'paragraph', spans: [{ text: line }] })),
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Create a markdown codec.
|
|
37
|
+
*
|
|
38
|
+
* Serialization notes: underline has no markdown form and is emitted as
|
|
39
|
+
* plain text; block ids are not preserved. Parsing sanitizes link
|
|
40
|
+
* destinations with the shared protocol allowlist.
|
|
41
|
+
*/
|
|
42
|
+
export function createMarkdownCodec() {
|
|
43
|
+
return {
|
|
44
|
+
format: 'markdown',
|
|
45
|
+
serialize: serializeMarkdown,
|
|
46
|
+
parse: (input) => {
|
|
47
|
+
try {
|
|
48
|
+
return parseMarkdown(input);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return plaintextFallback(input);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=codec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codec.js","sourceRoot":"","sources":["../../src/markdown/codec.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD,MAAM,aAAa,GAAG,CAAC,KAAa,EAAY,EAAE;IAChD,MAAM,MAAM,GAAG,iBAAiB,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAS,EAAE;QAC7D,MAAM,KAAK,GAAoB,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5F,OAAO,cAAc,CAAC;YACpB,EAAE,EAAE,MAAM,EAAE;YACZ,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5D,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;SACjD,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QACrB,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IAClF,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC,CAAC;AAEF,yEAAyE;AACzE,MAAM,iBAAiB,GAAG,CAAC,KAAa,EAAY,EAAE;IACpD,MAAM,MAAM,GAAG,iBAAiB,EAAE,CAAC;IACnC,OAAO;QACL,MAAM,EAAE,KAAK;aACV,KAAK,CAAC,YAAY,CAAC;aACnB,GAAG,CAAC,CAAC,IAAI,EAAS,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;KACxF,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO;QACL,MAAM,EAAE,UAAU;QAClB,SAAS,EAAE,iBAAiB;QAC5B,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;YACf,IAAI,CAAC;gBACH,OAAO,aAAa,CAAC,KAAK,CAAC,CAAC;YAC9B,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,iBAAiB,CAAC,KAAK,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/markdown/index.ts"],"names":[],"mappings":"AAAA,oFAAoF;AAEpF,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/markdown/index.ts"],"names":[],"mappings":"AAAA,oFAAoF;AAEpF,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC"}
|