@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,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown line scanner: splits input into typed block drafts whose inline
|
|
3
|
+
* content is parsed separately. Single-level only (no nested lists or
|
|
4
|
+
* quotes), matching the canonical block set.
|
|
5
|
+
*
|
|
6
|
+
* Documented behavior:
|
|
7
|
+
* - A single newline inside a paragraph is a CommonMark soft break and
|
|
8
|
+
* becomes a space (the same applies to consecutive `>` lines, which merge
|
|
9
|
+
* into ONE blockquote block — use a blank line for separate quotes).
|
|
10
|
+
* - Every list line is its own `list` block (one block per item).
|
|
11
|
+
* - An unterminated code fence runs to end of input.
|
|
12
|
+
*/
|
|
13
|
+
import type { Attrs } from '@rtif-sdk/core';
|
|
14
|
+
/** A scanned block before inline parsing. */
|
|
15
|
+
export interface MarkdownBlockDraft {
|
|
16
|
+
readonly type: string;
|
|
17
|
+
readonly attrs?: Attrs;
|
|
18
|
+
/** Inline markdown source, or literal text when `raw` is true. */
|
|
19
|
+
readonly text: string;
|
|
20
|
+
/** True for code blocks: `text` is taken verbatim, no inline parsing. */
|
|
21
|
+
readonly raw: boolean;
|
|
22
|
+
}
|
|
23
|
+
/** Scan markdown into block drafts. Never throws; garbage degrades to paragraphs. */
|
|
24
|
+
export declare function splitMarkdownBlocks(input: string): MarkdownBlockDraft[];
|
|
25
|
+
//# sourceMappingURL=parse-blocks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-blocks.d.ts","sourceRoot":"","sources":["../../src/markdown/parse-blocks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C,6CAA6C;AAC7C,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;IACvB,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;CACvB;AAoED,qFAAqF;AACrF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,kBAAkB,EAAE,CA+CvE"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown line scanner: splits input into typed block drafts whose inline
|
|
3
|
+
* content is parsed separately. Single-level only (no nested lists or
|
|
4
|
+
* quotes), matching the canonical block set.
|
|
5
|
+
*
|
|
6
|
+
* Documented behavior:
|
|
7
|
+
* - A single newline inside a paragraph is a CommonMark soft break and
|
|
8
|
+
* becomes a space (the same applies to consecutive `>` lines, which merge
|
|
9
|
+
* into ONE blockquote block — use a blank line for separate quotes).
|
|
10
|
+
* - Every list line is its own `list` block (one block per item).
|
|
11
|
+
* - An unterminated code fence runs to end of input.
|
|
12
|
+
*/
|
|
13
|
+
const FENCE_OPEN = /^(`{3,})\s*(\S*)\s*$/;
|
|
14
|
+
const HEADING = /^(#{1,6}) (.*)$/;
|
|
15
|
+
const HR = /^ {0,3}(-{3,}|\*{3,}|_{3,})\s*$/;
|
|
16
|
+
const BULLET = /^ {0,3}[-+*] (.*)$/;
|
|
17
|
+
const ORDERED = /^ {0,3}(\d{1,9})[.)] (.*)$/;
|
|
18
|
+
const isBlockStart = (line) => line.trim() === '' ||
|
|
19
|
+
FENCE_OPEN.test(line) ||
|
|
20
|
+
HEADING.test(line) ||
|
|
21
|
+
HR.test(line) ||
|
|
22
|
+
line.startsWith('>') ||
|
|
23
|
+
BULLET.test(line) ||
|
|
24
|
+
ORDERED.test(line);
|
|
25
|
+
const readFence = (lines, i, drafts) => {
|
|
26
|
+
const open = FENCE_OPEN.exec(lines[i]);
|
|
27
|
+
const fence = open[1];
|
|
28
|
+
const info = open[2].trim();
|
|
29
|
+
const content = [];
|
|
30
|
+
let j = i + 1;
|
|
31
|
+
while (j < lines.length) {
|
|
32
|
+
const line = lines[j].trim();
|
|
33
|
+
if (/^`{3,}$/.test(line) && line.length >= fence.length)
|
|
34
|
+
break;
|
|
35
|
+
content.push(lines[j]);
|
|
36
|
+
j++;
|
|
37
|
+
}
|
|
38
|
+
drafts.push({
|
|
39
|
+
type: 'code_block',
|
|
40
|
+
...(info !== '' ? { attrs: { language: info } } : {}),
|
|
41
|
+
text: content.join('\n'),
|
|
42
|
+
raw: true,
|
|
43
|
+
});
|
|
44
|
+
return j < lines.length ? j + 1 : j;
|
|
45
|
+
};
|
|
46
|
+
const readBlockquote = (lines, i, drafts) => {
|
|
47
|
+
const parts = [];
|
|
48
|
+
let j = i;
|
|
49
|
+
while (j < lines.length && lines[j].startsWith('>')) {
|
|
50
|
+
parts.push(lines[j].replace(/^> ?/, '').trim());
|
|
51
|
+
j++;
|
|
52
|
+
}
|
|
53
|
+
drafts.push({ type: 'blockquote', text: parts.join(' '), raw: false });
|
|
54
|
+
return j;
|
|
55
|
+
};
|
|
56
|
+
const readParagraph = (lines, i, drafts) => {
|
|
57
|
+
const parts = [lines[i].trim()];
|
|
58
|
+
let j = i + 1;
|
|
59
|
+
while (j < lines.length && !isBlockStart(lines[j])) {
|
|
60
|
+
parts.push(lines[j].trim()); // soft break → space
|
|
61
|
+
j++;
|
|
62
|
+
}
|
|
63
|
+
drafts.push({ type: 'paragraph', text: parts.join(' '), raw: false });
|
|
64
|
+
return j;
|
|
65
|
+
};
|
|
66
|
+
/** Scan markdown into block drafts. Never throws; garbage degrades to paragraphs. */
|
|
67
|
+
export function splitMarkdownBlocks(input) {
|
|
68
|
+
const lines = input.split(/\r\n|\r|\n/);
|
|
69
|
+
const drafts = [];
|
|
70
|
+
let i = 0;
|
|
71
|
+
while (i < lines.length) {
|
|
72
|
+
const line = lines[i];
|
|
73
|
+
if (line.trim() === '') {
|
|
74
|
+
i++;
|
|
75
|
+
}
|
|
76
|
+
else if (FENCE_OPEN.test(line)) {
|
|
77
|
+
i = readFence(lines, i, drafts);
|
|
78
|
+
}
|
|
79
|
+
else if (HEADING.test(line)) {
|
|
80
|
+
const match = HEADING.exec(line);
|
|
81
|
+
drafts.push({
|
|
82
|
+
type: 'heading',
|
|
83
|
+
attrs: { level: match[1].length },
|
|
84
|
+
text: match[2],
|
|
85
|
+
raw: false,
|
|
86
|
+
});
|
|
87
|
+
i++;
|
|
88
|
+
}
|
|
89
|
+
else if (HR.test(line)) {
|
|
90
|
+
drafts.push({ type: 'horizontal_rule', text: '', raw: true });
|
|
91
|
+
i++;
|
|
92
|
+
}
|
|
93
|
+
else if (line.startsWith('>')) {
|
|
94
|
+
i = readBlockquote(lines, i, drafts);
|
|
95
|
+
}
|
|
96
|
+
else if (BULLET.test(line)) {
|
|
97
|
+
const match = BULLET.exec(line);
|
|
98
|
+
drafts.push({
|
|
99
|
+
type: 'list',
|
|
100
|
+
attrs: { kind: 'bulleted' },
|
|
101
|
+
text: match[1],
|
|
102
|
+
raw: false,
|
|
103
|
+
});
|
|
104
|
+
i++;
|
|
105
|
+
}
|
|
106
|
+
else if (ORDERED.test(line)) {
|
|
107
|
+
const match = ORDERED.exec(line);
|
|
108
|
+
drafts.push({
|
|
109
|
+
type: 'list',
|
|
110
|
+
attrs: { kind: 'ordered' },
|
|
111
|
+
text: match[2],
|
|
112
|
+
raw: false,
|
|
113
|
+
});
|
|
114
|
+
i++;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
i = readParagraph(lines, i, drafts);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return drafts;
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=parse-blocks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-blocks.js","sourceRoot":"","sources":["../../src/markdown/parse-blocks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline markdown → spans. Pragmatic CommonMark subset: `**`/`__` bold,
|
|
3
|
+
* `*`/`_` italic (`***`/`___` bold+italic), `~~` strikethrough, backtick
|
|
4
|
+
* code spans (run-length aware), `[text](url)` links (destinations pass the
|
|
5
|
+
* shared protocol allowlist; unsafe links keep their text and drop the
|
|
6
|
+
* mark), and backslash escapes. Anything unparseable degrades to literal
|
|
7
|
+
* text — this module never throws.
|
|
8
|
+
*
|
|
9
|
+
* Deliberate simplifications vs full CommonMark: no flanking rules beyond
|
|
10
|
+
* an intraword guard for `_`, no reference links, no titles, no autolinks.
|
|
11
|
+
*/
|
|
12
|
+
import type { Span } from '@rtif-sdk/core';
|
|
13
|
+
/** Parse inline markdown into spans (possibly empty for empty input). Never throws. */
|
|
14
|
+
export declare function parseInline(text: string): Span[];
|
|
15
|
+
//# sourceMappingURL=parse-inline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-inline.d.ts","sourceRoot":"","sources":["../../src/markdown/parse-inline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAoB,IAAI,EAAE,MAAM,gBAAgB,CAAC;AA4J7D,uFAAuF;AACvF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,CAEhD"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline markdown → spans. Pragmatic CommonMark subset: `**`/`__` bold,
|
|
3
|
+
* `*`/`_` italic (`***`/`___` bold+italic), `~~` strikethrough, backtick
|
|
4
|
+
* code spans (run-length aware), `[text](url)` links (destinations pass the
|
|
5
|
+
* shared protocol allowlist; unsafe links keep their text and drop the
|
|
6
|
+
* mark), and backslash escapes. Anything unparseable degrades to literal
|
|
7
|
+
* text — this module never throws.
|
|
8
|
+
*
|
|
9
|
+
* Deliberate simplifications vs full CommonMark: no flanking rules beyond
|
|
10
|
+
* an intraword guard for `_`, no reference links, no titles, no autolinks.
|
|
11
|
+
*/
|
|
12
|
+
import { sanitizeUrl } from '../shared/url.js';
|
|
13
|
+
const PUNCTUATION = /[!-/:-@[-`{-~]/;
|
|
14
|
+
const withMark = (marks, name, value) => ({
|
|
15
|
+
...marks,
|
|
16
|
+
[name]: value,
|
|
17
|
+
});
|
|
18
|
+
const mkSpan = (text, marks) => marks !== undefined ? { text, marks } : { text };
|
|
19
|
+
/** Longest token first so `***` wins over `**` over `*`. */
|
|
20
|
+
const DELIMITERS = [
|
|
21
|
+
{ token: '***', markNames: ['bold', 'italic'] },
|
|
22
|
+
{ token: '___', markNames: ['bold', 'italic'] },
|
|
23
|
+
{ token: '**', markNames: ['bold'] },
|
|
24
|
+
{ token: '__', markNames: ['bold'] },
|
|
25
|
+
{ token: '~~', markNames: ['strikethrough'] },
|
|
26
|
+
{ token: '*', markNames: ['italic'] },
|
|
27
|
+
{ token: '_', markNames: ['italic'] },
|
|
28
|
+
];
|
|
29
|
+
const isWordChar = (ch) => ch !== undefined && /\w/.test(ch);
|
|
30
|
+
const tryDelimiter = (text, i, marks) => {
|
|
31
|
+
for (const { token, markNames } of DELIMITERS) {
|
|
32
|
+
if (!text.startsWith(token, i))
|
|
33
|
+
continue;
|
|
34
|
+
// underscore emphasis never opens/closes intraword: snake_case stays literal
|
|
35
|
+
if (token[0] === '_' && isWordChar(text[i - 1]))
|
|
36
|
+
continue;
|
|
37
|
+
const close = text.indexOf(token, i + token.length);
|
|
38
|
+
if (close === -1 || close === i + token.length)
|
|
39
|
+
continue; // unmatched or empty
|
|
40
|
+
if (token[0] === '_' && isWordChar(text[close + token.length]))
|
|
41
|
+
continue;
|
|
42
|
+
let inner = marks;
|
|
43
|
+
for (const name of markNames)
|
|
44
|
+
inner = withMark(inner, name, true);
|
|
45
|
+
return {
|
|
46
|
+
spans: parseSegment(text.slice(i + token.length, close), inner),
|
|
47
|
+
nextIndex: close + token.length,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
};
|
|
52
|
+
/** Backtick code span; content is raw (no escapes, no nested marks). */
|
|
53
|
+
const tryCode = (text, i, marks) => {
|
|
54
|
+
const run = /^`+/.exec(text.slice(i))[0];
|
|
55
|
+
const close = text.indexOf(run, i + run.length);
|
|
56
|
+
if (close === -1)
|
|
57
|
+
return null;
|
|
58
|
+
let content = text.slice(i + run.length, close);
|
|
59
|
+
if (content.startsWith(' ') && content.endsWith(' ') && content.trim() !== '') {
|
|
60
|
+
content = content.slice(1, -1); // CommonMark single-space stripping
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
spans: [mkSpan(content, withMark(marks, 'code', true))],
|
|
64
|
+
nextIndex: close + run.length,
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
const findUnescaped = (text, ch, from) => {
|
|
68
|
+
for (let j = from; j < text.length; j++) {
|
|
69
|
+
if (text[j] === '\\') {
|
|
70
|
+
j++;
|
|
71
|
+
}
|
|
72
|
+
else if (text[j] === ch) {
|
|
73
|
+
return j;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return -1;
|
|
77
|
+
};
|
|
78
|
+
const unescapeMd = (text) => text.replace(/\\([!-/:-@[-`{-~])/g, '$1');
|
|
79
|
+
/** Find the `)` closing a link destination, honoring escapes and nested parens. */
|
|
80
|
+
const findClosingParen = (text, from) => {
|
|
81
|
+
let depth = 0;
|
|
82
|
+
for (let j = from; j < text.length; j++) {
|
|
83
|
+
const ch = text[j];
|
|
84
|
+
if (ch === '\\')
|
|
85
|
+
j++;
|
|
86
|
+
else if (ch === '(')
|
|
87
|
+
depth++;
|
|
88
|
+
else if (ch === ')') {
|
|
89
|
+
if (depth === 0)
|
|
90
|
+
return j;
|
|
91
|
+
depth--;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return -1;
|
|
95
|
+
};
|
|
96
|
+
/** Take the first whitespace-delimited token (drops any title) and strip `<...>`. */
|
|
97
|
+
const parseDestination = (raw) => {
|
|
98
|
+
let url = raw.trim();
|
|
99
|
+
const space = url.search(/\s/);
|
|
100
|
+
if (space !== -1)
|
|
101
|
+
url = url.slice(0, space);
|
|
102
|
+
if (url.startsWith('<') && url.endsWith('>'))
|
|
103
|
+
url = url.slice(1, -1);
|
|
104
|
+
return unescapeMd(url);
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* `[label](destination)`; an unsafe destination keeps the label, drops the
|
|
108
|
+
* link. The allowlist gates on the FULL raw destination (whitespace included)
|
|
109
|
+
* so `java\tscript:` cannot smuggle a scheme past the title-splitting step.
|
|
110
|
+
*/
|
|
111
|
+
const tryLink = (text, i, marks) => {
|
|
112
|
+
const closeBracket = findUnescaped(text, ']', i + 1);
|
|
113
|
+
if (closeBracket === -1 || text[closeBracket + 1] !== '(')
|
|
114
|
+
return null;
|
|
115
|
+
const closeParen = findClosingParen(text, closeBracket + 2);
|
|
116
|
+
if (closeParen === -1)
|
|
117
|
+
return null;
|
|
118
|
+
const label = text.slice(i + 1, closeBracket);
|
|
119
|
+
const rawDest = text.slice(closeBracket + 2, closeParen);
|
|
120
|
+
const safe = sanitizeUrl(rawDest) !== null ? sanitizeUrl(parseDestination(rawDest)) : null;
|
|
121
|
+
const inner = safe !== null ? withMark(marks, 'link', { href: safe }) : marks;
|
|
122
|
+
return { spans: parseSegment(label, inner), nextIndex: closeParen + 1 };
|
|
123
|
+
};
|
|
124
|
+
const parseSegment = (text, marks) => {
|
|
125
|
+
const spans = [];
|
|
126
|
+
let literal = '';
|
|
127
|
+
const flushLiteral = () => {
|
|
128
|
+
if (literal !== '') {
|
|
129
|
+
spans.push(mkSpan(literal, marks));
|
|
130
|
+
literal = '';
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
let i = 0;
|
|
134
|
+
while (i < text.length) {
|
|
135
|
+
const ch = text[i];
|
|
136
|
+
if (ch === '\\' && i + 1 < text.length && PUNCTUATION.test(text[i + 1])) {
|
|
137
|
+
literal += text[i + 1];
|
|
138
|
+
i += 2;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const match = ch === '`'
|
|
142
|
+
? tryCode(text, i, marks)
|
|
143
|
+
: ch === '['
|
|
144
|
+
? tryLink(text, i, marks)
|
|
145
|
+
: ch === '*' || ch === '_' || ch === '~'
|
|
146
|
+
? tryDelimiter(text, i, marks)
|
|
147
|
+
: null;
|
|
148
|
+
if (match !== null) {
|
|
149
|
+
flushLiteral();
|
|
150
|
+
spans.push(...match.spans);
|
|
151
|
+
i = match.nextIndex;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
literal += ch;
|
|
155
|
+
i++;
|
|
156
|
+
}
|
|
157
|
+
flushLiteral();
|
|
158
|
+
return spans;
|
|
159
|
+
};
|
|
160
|
+
/** Parse inline markdown into spans (possibly empty for empty input). Never throws. */
|
|
161
|
+
export function parseInline(text) {
|
|
162
|
+
return parseSegment(text, undefined);
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=parse-inline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-inline.js","sourceRoot":"","sources":["../../src/markdown/parse-inline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document → CommonMark-subset markdown.
|
|
3
|
+
*
|
|
4
|
+
* Mapping: heading → `#{level}`, blockquote → `> `, code_block → fenced
|
|
5
|
+
* ``` (with `attrs.language`), bulleted list → `- `, ordered list →
|
|
6
|
+
* `1.`/`2.`/... (numbered per consecutive group), horizontal_rule → `---`.
|
|
7
|
+
* Marks: bold `**`, italic `*`, strikethrough `~~`, code backticks, link
|
|
8
|
+
* `[text](href)`. **Underline has no markdown representation and is emitted
|
|
9
|
+
* as plain text.** Blocks are separated by blank lines; consecutive list
|
|
10
|
+
* blocks of the same kind join with single newlines.
|
|
11
|
+
*/
|
|
12
|
+
import type { Document, Span } from '@rtif-sdk/core';
|
|
13
|
+
/** Serialize a block's spans as inline markdown. */
|
|
14
|
+
export declare const serializeInline: (spans: readonly Span[]) => string;
|
|
15
|
+
/** Serialize a document to markdown. */
|
|
16
|
+
export declare function serializeMarkdown(doc: Document): string;
|
|
17
|
+
//# sourceMappingURL=serialize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../../src/markdown/serialize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAS,QAAQ,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAwC5D,oDAAoD;AACpD,eAAO,MAAM,eAAe,GAAI,OAAO,SAAS,IAAI,EAAE,KAAG,MACtB,CAAC;AAoDpC,wCAAwC;AACxC,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,QAAQ,GAAG,MAAM,CAsBvD"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document → CommonMark-subset markdown.
|
|
3
|
+
*
|
|
4
|
+
* Mapping: heading → `#{level}`, blockquote → `> `, code_block → fenced
|
|
5
|
+
* ``` (with `attrs.language`), bulleted list → `- `, ordered list →
|
|
6
|
+
* `1.`/`2.`/... (numbered per consecutive group), horizontal_rule → `---`.
|
|
7
|
+
* Marks: bold `**`, italic `*`, strikethrough `~~`, code backticks, link
|
|
8
|
+
* `[text](href)`. **Underline has no markdown representation and is emitted
|
|
9
|
+
* as plain text.** Blocks are separated by blank lines; consecutive list
|
|
10
|
+
* blocks of the same kind join with single newlines.
|
|
11
|
+
*/
|
|
12
|
+
import { blockText } from '../shared/block-text.js';
|
|
13
|
+
/** Escape markdown specials in plain text (kept pragmatic, not exhaustive). */
|
|
14
|
+
const escapeMd = (text) => text.replace(/[\\*_`[~]/g, (ch) => `\\${ch}`);
|
|
15
|
+
/** Wrap inline code in a backtick run longer than any run inside it. */
|
|
16
|
+
const wrapInlineCode = (text) => {
|
|
17
|
+
const runs = text.match(/`+/g);
|
|
18
|
+
const max = runs === null ? 0 : Math.max(...runs.map((run) => run.length));
|
|
19
|
+
const fence = '`'.repeat(max + 1);
|
|
20
|
+
const pad = text.startsWith('`') || text.endsWith('`') ? ' ' : '';
|
|
21
|
+
return `${fence}${pad}${text}${pad}${fence}`;
|
|
22
|
+
};
|
|
23
|
+
const HREF_ESCAPES = { '(': '%28', ')': '%29', ' ': '%20' };
|
|
24
|
+
const escapeHref = (href) => href.replace(/[() ]/g, (ch) => HREF_ESCAPES[ch]);
|
|
25
|
+
const markHref = (span) => {
|
|
26
|
+
const link = span.marks?.['link'];
|
|
27
|
+
return typeof link === 'object' &&
|
|
28
|
+
link !== null &&
|
|
29
|
+
typeof link.href === 'string'
|
|
30
|
+
? link.href
|
|
31
|
+
: null;
|
|
32
|
+
};
|
|
33
|
+
/** Wrap order (inside → out): code, strikethrough, italic, bold, link — deterministic. */
|
|
34
|
+
const serializeSpan = (span) => {
|
|
35
|
+
const marks = span.marks ?? {};
|
|
36
|
+
let out = marks['code'] === true ? wrapInlineCode(span.text) : escapeMd(span.text);
|
|
37
|
+
if (marks['strikethrough'] === true)
|
|
38
|
+
out = `~~${out}~~`;
|
|
39
|
+
if (marks['italic'] === true)
|
|
40
|
+
out = `*${out}*`;
|
|
41
|
+
if (marks['bold'] === true)
|
|
42
|
+
out = `**${out}**`;
|
|
43
|
+
const href = markHref(span);
|
|
44
|
+
if (href !== null)
|
|
45
|
+
out = `[${out}](${escapeHref(href)})`;
|
|
46
|
+
return out; // underline (and unknown marks): plain text
|
|
47
|
+
};
|
|
48
|
+
/** Serialize a block's spans as inline markdown. */
|
|
49
|
+
export const serializeInline = (spans) => spans.map(serializeSpan).join('');
|
|
50
|
+
/** Escape a leading construct that would change the line's block type on re-parse. */
|
|
51
|
+
const escapeLineStart = (text) => {
|
|
52
|
+
if (/^#{1,6} /.test(text) || text.startsWith('> '))
|
|
53
|
+
return `\\${text}`;
|
|
54
|
+
if (/^[-+] /.test(text) || /^-{3,}\s*$/.test(text))
|
|
55
|
+
return `\\${text}`;
|
|
56
|
+
const ordered = /^(\d+)([.)]) /.exec(text);
|
|
57
|
+
if (ordered !== null) {
|
|
58
|
+
return `${ordered[1]}\\${ordered[2]}${text.slice(ordered[1].length + 1)}`;
|
|
59
|
+
}
|
|
60
|
+
return text;
|
|
61
|
+
};
|
|
62
|
+
const headingLevel = (block) => {
|
|
63
|
+
const level = block.attrs?.['level'];
|
|
64
|
+
return typeof level === 'number' && level >= 1 && level <= 6 ? Math.floor(level) : 1;
|
|
65
|
+
};
|
|
66
|
+
/** A fence longer than any backtick run in the content (minimum three). */
|
|
67
|
+
const fenceFor = (text) => {
|
|
68
|
+
const runs = text.match(/`{3,}/g);
|
|
69
|
+
const max = runs === null ? 2 : Math.max(...runs.map((run) => run.length));
|
|
70
|
+
return '`'.repeat(Math.max(3, max + 1));
|
|
71
|
+
};
|
|
72
|
+
const serializeCodeBlock = (block) => {
|
|
73
|
+
const text = blockText(block);
|
|
74
|
+
const language = block.attrs?.['language'];
|
|
75
|
+
const info = typeof language === 'string' ? language : '';
|
|
76
|
+
const fence = fenceFor(text);
|
|
77
|
+
return `${fence}${info}\n${text}\n${fence}`;
|
|
78
|
+
};
|
|
79
|
+
/** Serialize one non-list block; unknown block types degrade to paragraphs. */
|
|
80
|
+
const serializeBlock = (block) => {
|
|
81
|
+
switch (block.type) {
|
|
82
|
+
case 'heading':
|
|
83
|
+
return `${'#'.repeat(headingLevel(block))} ${serializeInline(block.spans)}`;
|
|
84
|
+
case 'blockquote':
|
|
85
|
+
return `> ${serializeInline(block.spans)}`;
|
|
86
|
+
case 'code_block':
|
|
87
|
+
return serializeCodeBlock(block);
|
|
88
|
+
case 'horizontal_rule':
|
|
89
|
+
return '---';
|
|
90
|
+
default:
|
|
91
|
+
return escapeLineStart(serializeInline(block.spans));
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
const listKind = (block) => block.attrs?.['kind'] === 'ordered' ? 'ordered' : 'bulleted';
|
|
95
|
+
/** Serialize a document to markdown. */
|
|
96
|
+
export function serializeMarkdown(doc) {
|
|
97
|
+
const chunks = [];
|
|
98
|
+
let i = 0;
|
|
99
|
+
while (i < doc.blocks.length) {
|
|
100
|
+
const block = doc.blocks[i];
|
|
101
|
+
if (block.type !== 'list') {
|
|
102
|
+
chunks.push(serializeBlock(block));
|
|
103
|
+
i++;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
const kind = listKind(block);
|
|
107
|
+
const items = [];
|
|
108
|
+
while (i < doc.blocks.length) {
|
|
109
|
+
const item = doc.blocks[i];
|
|
110
|
+
if (item.type !== 'list' || listKind(item) !== kind)
|
|
111
|
+
break;
|
|
112
|
+
const marker = kind === 'ordered' ? `${items.length + 1}.` : '-';
|
|
113
|
+
items.push(`${marker} ${serializeInline(item.spans)}`);
|
|
114
|
+
i++;
|
|
115
|
+
}
|
|
116
|
+
chunks.push(items.join('\n'));
|
|
117
|
+
}
|
|
118
|
+
return chunks.join('\n\n');
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=serialize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.js","sourceRoot":"","sources":["../../src/markdown/serialize.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plaintext codec: blocks joined by `'\n'` on serialize (code_block content
|
|
3
|
+
* emitted as-is, which may itself contain newlines), one paragraph per line
|
|
4
|
+
* on parse. All structure and marks are discarded — that is the format.
|
|
5
|
+
*/
|
|
6
|
+
import type { FormatCodec } from '@rtif-sdk/core';
|
|
7
|
+
/**
|
|
8
|
+
* Create the plaintext codec.
|
|
9
|
+
*
|
|
10
|
+
* Parsing never throws and always returns a valid document: each line becomes
|
|
11
|
+
* a paragraph with ids `'b1'`, `'b2'`, ... (fresh per call), and empty input
|
|
12
|
+
* yields a single empty paragraph.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createPlaintextCodec(): FormatCodec;
|
|
15
|
+
//# sourceMappingURL=codec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../../src/plaintext/codec.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAmB,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAanE;;;;;;GAMG;AACH,wBAAgB,oBAAoB,IAAI,WAAW,CAMlD"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plaintext codec: blocks joined by `'\n'` on serialize (code_block content
|
|
3
|
+
* emitted as-is, which may itself contain newlines), one paragraph per line
|
|
4
|
+
* on parse. All structure and marks are discarded — that is the format.
|
|
5
|
+
*/
|
|
6
|
+
import { blockText } from '../shared/block-text.js';
|
|
7
|
+
import { createIdGenerator } from '../shared/ids.js';
|
|
8
|
+
/** Split on LF, CRLF, or lone CR; `''.split` yields `['']`, so empty input becomes one empty paragraph. */
|
|
9
|
+
const parsePlaintext = (input) => {
|
|
10
|
+
const nextId = createIdGenerator();
|
|
11
|
+
const blocks = input
|
|
12
|
+
.split(/\r\n|\r|\n/)
|
|
13
|
+
.map((line) => ({ id: nextId(), type: 'paragraph', spans: [{ text: line }] }));
|
|
14
|
+
return { blocks };
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Create the plaintext codec.
|
|
18
|
+
*
|
|
19
|
+
* Parsing never throws and always returns a valid document: each line becomes
|
|
20
|
+
* a paragraph with ids `'b1'`, `'b2'`, ... (fresh per call), and empty input
|
|
21
|
+
* yields a single empty paragraph.
|
|
22
|
+
*/
|
|
23
|
+
export function createPlaintextCodec() {
|
|
24
|
+
return {
|
|
25
|
+
format: 'plaintext',
|
|
26
|
+
serialize: (doc) => doc.blocks.map(blockText).join('\n'),
|
|
27
|
+
parse: parsePlaintext,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=codec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codec.js","sourceRoot":"","sources":["../../src/plaintext/codec.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,2GAA2G;AAC3G,MAAM,cAAc,GAAG,CAAC,KAAa,EAAY,EAAE;IACjD,MAAM,MAAM,GAAG,iBAAiB,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,KAAK;SACjB,KAAK,CAAC,YAAY,CAAC;SACnB,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,CAAC;IACxF,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO;QACL,MAAM,EAAE,WAAW;QACnB,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QACxD,KAAK,EAAE,cAAc;KACtB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/plaintext/index.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAE1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/plaintext/index.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAE1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block-text.d.ts","sourceRoot":"","sources":["../../src/shared/block-text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C,4DAA4D;AAC5D,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAE9C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block-text.js","sourceRoot":"","sources":["../../src/shared/block-text.ts"],"names":[],"mappings":"AAEA,4DAA4D;AAC5D,MAAM,UAAU,SAAS,CAAC,KAAY;IACpC,OAAO,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sequential block-id generation for format parsers.
|
|
3
|
+
*
|
|
4
|
+
* Each `parse` call creates its own generator, so codecs hold no shared
|
|
5
|
+
* mutable state and identical inputs always produce identical documents.
|
|
6
|
+
*/
|
|
7
|
+
/** Create a counter-backed id generator yielding `'b1'`, `'b2'`, ... */
|
|
8
|
+
export declare function createIdGenerator(prefix?: string): () => string;
|
|
9
|
+
//# sourceMappingURL=ids.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../../src/shared/ids.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,MAAM,GAAE,MAAY,GAAG,MAAM,MAAM,CAGpE"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sequential block-id generation for format parsers.
|
|
3
|
+
*
|
|
4
|
+
* Each `parse` call creates its own generator, so codecs hold no shared
|
|
5
|
+
* mutable state and identical inputs always produce identical documents.
|
|
6
|
+
*/
|
|
7
|
+
/** Create a counter-backed id generator yielding `'b1'`, `'b2'`, ... */
|
|
8
|
+
export function createIdGenerator(prefix = 'b') {
|
|
9
|
+
let count = 0;
|
|
10
|
+
return () => `${prefix}${++count}`;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=ids.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ids.js","sourceRoot":"","sources":["../../src/shared/ids.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,wEAAwE;AACxE,MAAM,UAAU,iBAAiB,CAAC,SAAiB,GAAG;IACpD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,OAAO,GAAG,EAAE,CAAC,GAAG,MAAM,GAAG,EAAE,KAAK,EAAE,CAAC;AACrC,CAAC"}
|