svelte-streamdown 1.0.9 → 2.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 +144 -135
- package/dist/Block.svelte +14 -54
- package/dist/Elements/Alert.svelte +1 -2
- package/dist/Elements/Code.svelte +2 -4
- package/dist/Elements/Code.svelte.d.ts +0 -2
- package/dist/Elements/Element.svelte +70 -25
- package/dist/Elements/FootnoteRef.svelte +19 -6
- package/dist/Elements/Image.svelte +1 -1
- package/dist/Elements/Link.svelte +1 -1
- package/dist/Elements/Math.svelte +13 -25
- package/dist/Elements/Math.svelte.d.ts +0 -2
- package/dist/Elements/Mermaid.svelte +105 -115
- package/dist/Elements/Mermaid.svelte.d.ts +0 -2
- package/dist/Elements/Table.svelte +1 -1
- package/dist/Streamdown.d.ts +52 -10
- package/dist/Streamdown.js +19 -1
- package/dist/Streamdown.svelte +3 -41
- package/dist/Streamdown.svelte.d.ts +1 -20
- package/dist/marked/index.d.ts +3 -20
- package/dist/marked/index.js +27 -19
- package/dist/marked/marked-alert.d.ts +2 -2
- package/dist/marked/marked-alert.js +6 -19
- package/dist/marked/marked-footnotes.js +1 -2
- package/dist/marked/marked-list.d.ts +2 -2
- package/dist/marked/marked-list.js +28 -11
- package/dist/marked/marked-math.js +1 -1
- package/dist/marked/marked-subsup.d.ts +1 -1
- package/dist/marked/marked-subsup.js +2 -1
- package/dist/marked/marked-table.d.ts +59 -0
- package/dist/marked/marked-table.js +495 -0
- package/dist/theme.d.ts +24 -6
- package/dist/theme.js +22 -10
- package/dist/utils/panzoom.svelte.d.ts +17 -18
- package/dist/utils/panzoom.svelte.js +0 -2
- package/dist/utils/useClickOutside.svelte.js +0 -1
- package/dist/utils/useKeyDown.svelte.js +4 -1
- package/package.json +1 -2
package/dist/marked/index.js
CHANGED
|
@@ -1,32 +1,40 @@
|
|
|
1
|
-
import { Lexer,
|
|
1
|
+
import { Lexer, Marked } from 'marked';
|
|
2
2
|
import markedAlert, {} from './marked-alert.js';
|
|
3
3
|
import markedFootnote, {} from './marked-footnotes.js';
|
|
4
4
|
import { markedMath } from './marked-math.js';
|
|
5
5
|
import markedSubSup, {} from './marked-subsup.js';
|
|
6
6
|
import { markedList } from './marked-list.js';
|
|
7
|
+
import { markedTable } from './marked-table.js';
|
|
8
|
+
const completeLexer = new Marked({
|
|
9
|
+
// Enable GFM features but disable built-in tables
|
|
10
|
+
gfm: true,
|
|
11
|
+
tokenizer: {
|
|
12
|
+
table: () => {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
.use(markedAlert())
|
|
18
|
+
.use(markedFootnote())
|
|
19
|
+
.use(markedMath())
|
|
20
|
+
.use(markedSubSup())
|
|
21
|
+
.use(markedList())
|
|
22
|
+
.use(markedTable());
|
|
23
|
+
const blockLexer = new Lexer({
|
|
24
|
+
gfm: true,
|
|
25
|
+
extensions: {
|
|
26
|
+
childTokens: {},
|
|
27
|
+
renderers: {},
|
|
28
|
+
block: [markedFootnote().extensions[0].tokenizer, markedTable().extensions[0].tokenizer]
|
|
29
|
+
}
|
|
30
|
+
});
|
|
7
31
|
export const lex = (markdown) => {
|
|
8
|
-
return
|
|
9
|
-
.use({
|
|
10
|
-
gfm: true
|
|
11
|
-
})
|
|
12
|
-
.use(markedAlert())
|
|
13
|
-
.use(markedFootnote())
|
|
14
|
-
.use(markedMath())
|
|
15
|
-
.use(markedSubSup())
|
|
16
|
-
.use(markedList())
|
|
32
|
+
return completeLexer
|
|
17
33
|
.lexer(markdown)
|
|
18
34
|
.filter((token) => token.type !== 'space' && token.type !== 'footnote');
|
|
19
35
|
};
|
|
20
36
|
export const parseBlocks = (markdown) => {
|
|
21
|
-
|
|
22
|
-
gfm: true,
|
|
23
|
-
extensions: {
|
|
24
|
-
childTokens: {},
|
|
25
|
-
renderers: {},
|
|
26
|
-
block: [markedFootnote().extensions[0].tokenizer]
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
return lexer.blockTokens(markdown, []).reduce((acc, block) => {
|
|
37
|
+
return blockLexer.blockTokens(markdown, []).reduce((acc, block) => {
|
|
30
38
|
if (block.type === 'space' || block.type === 'footnote') {
|
|
31
39
|
return acc;
|
|
32
40
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Tokenizer, Tokens } from 'marked';
|
|
2
2
|
import type { TokenizerExtensionFunction } from 'marked';
|
|
3
3
|
type variantType = 'note' | 'tip' | 'important' | 'warning' | 'caution';
|
|
4
4
|
export declare function createSyntaxPattern(type: variantType): string;
|
|
@@ -9,7 +9,7 @@ export default function markedAlert(): {
|
|
|
9
9
|
tokenizer: TokenizerExtensionFunction;
|
|
10
10
|
}>;
|
|
11
11
|
};
|
|
12
|
-
export declare function processAlertToken(token:
|
|
12
|
+
export declare function processAlertToken(token: Tokens.Blockquote, tokenizer: Tokenizer): void;
|
|
13
13
|
export type AlertToken = {
|
|
14
14
|
type: 'alert';
|
|
15
15
|
variant: variantType;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { Lexer } from 'marked';
|
|
2
2
|
const variants = ['note', 'tip', 'important', 'warning', 'caution'];
|
|
3
|
+
// export function createSyntaxPattern(type: variantType): string {
|
|
4
|
+
// return `^(?:\\[!${type.toUpperCase()}])\\s*?\n*`;
|
|
5
|
+
// }
|
|
3
6
|
export function createSyntaxPattern(type) {
|
|
4
|
-
return
|
|
7
|
+
return `^\\s*\\[!${type.toUpperCase()}\\]\\s+`;
|
|
5
8
|
}
|
|
6
9
|
export default function markedAlert() {
|
|
7
10
|
const defaultLexer = new Lexer({ gfm: true });
|
|
@@ -27,25 +30,9 @@ export function processAlertToken(token, tokenizer) {
|
|
|
27
30
|
const matchedVariant = variants.find((type) => new RegExp(createSyntaxPattern(type)).test(('text' in token && token.text) || ''));
|
|
28
31
|
if (!matchedVariant)
|
|
29
32
|
return;
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
Object.assign(token, {
|
|
33
|
-
type: 'alert',
|
|
34
|
-
variant: matchedVariant
|
|
35
|
-
});
|
|
36
|
-
const firstLine = ('tokens' in token && token.tokens?.[0]);
|
|
37
|
-
const firstLineText = firstLine.raw?.replace(typeRegexp, '').trim();
|
|
38
|
-
const lines = token.raw
|
|
39
|
-
.split('>')
|
|
40
|
-
.filter((line) => line.trim().replace(typeRegexp, '').length > 0);
|
|
41
|
-
const tokens = lines.map((line) => {
|
|
42
|
-
const lineTokens = tokenizer.lexer.inlineTokens(line);
|
|
43
|
-
return {
|
|
44
|
-
type: 'paragraph',
|
|
45
|
-
tokens: lineTokens
|
|
46
|
-
};
|
|
33
|
+
const tokens = token.tokens.map((token) => {
|
|
34
|
+
return tokenizer.lexer.blockTokens(token.raw.replaceAll(`[!${matchedVariant.toUpperCase()}]`, '').trim(), [])[0];
|
|
47
35
|
});
|
|
48
|
-
// Transform the token into an alert token
|
|
49
36
|
Object.assign(token, {
|
|
50
37
|
type: 'alert',
|
|
51
38
|
variant: matchedVariant,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { lex } from './index.js';
|
|
2
|
-
import { StreamdownContext } from '../Streamdown.
|
|
2
|
+
import { StreamdownContext } from '../Streamdown.js';
|
|
3
3
|
import { getContext } from 'svelte';
|
|
4
4
|
const safeGetContext = () => {
|
|
5
5
|
try {
|
|
@@ -72,7 +72,6 @@ export default function markedFootnote() {
|
|
|
72
72
|
if (match) {
|
|
73
73
|
const [raw, label] = match;
|
|
74
74
|
const footnote = maps.footnotes.get(label);
|
|
75
|
-
console.log({ footnote });
|
|
76
75
|
const token = {
|
|
77
76
|
type: 'footnoteRef',
|
|
78
77
|
raw,
|
|
@@ -16,9 +16,9 @@ export interface ListToken {
|
|
|
16
16
|
type: 'list';
|
|
17
17
|
raw: string;
|
|
18
18
|
ordered: boolean;
|
|
19
|
-
listType: 'decimal' | 'lower-alpha' | 'upper-alpha' | 'lower-roman' | 'upper-roman';
|
|
19
|
+
listType: 'decimal' | 'lower-alpha' | 'upper-alpha' | 'lower-roman' | 'upper-roman' | null;
|
|
20
20
|
loose: boolean;
|
|
21
|
-
|
|
21
|
+
tokens: ListItemToken[];
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
24
|
* Token representing an item in an extended list.
|
|
@@ -27,25 +27,28 @@ export const romanLower = '(?:c|xc|l?x{0,3}(?:ix|iv|v?i{0,3}))';
|
|
|
27
27
|
export const bulletPattern = `(?:[*+-]|(?:\\d{1,9}|[a-zA-Z]|${romanUpper}|${romanLower})[.)])`;
|
|
28
28
|
export const rule = `^( {0,3}${bulletPattern})([ \\t][^\\n]+?)?(?:\\n|$)`;
|
|
29
29
|
function finalizeList(list, lexer) {
|
|
30
|
-
if (list.
|
|
30
|
+
if (list.tokens.length === 0)
|
|
31
31
|
return;
|
|
32
32
|
// Trim trailing newline from last item
|
|
33
|
-
const lastItem = list.
|
|
33
|
+
const lastItem = list.tokens[list.tokens.length - 1];
|
|
34
34
|
lastItem.raw = lastItem.raw.trimEnd();
|
|
35
35
|
lastItem.text = lastItem.text.trimEnd();
|
|
36
36
|
list.raw = list.raw.trimEnd();
|
|
37
37
|
// Handle child tokens
|
|
38
|
-
for (const item of list.
|
|
38
|
+
for (const item of list.tokens) {
|
|
39
39
|
lexer.state.top = false;
|
|
40
40
|
item.tokens = lexer.blockTokens(item.text, []);
|
|
41
41
|
}
|
|
42
42
|
// Mark list as loose if needed
|
|
43
43
|
if (list.loose) {
|
|
44
|
-
for (const item of list.
|
|
44
|
+
for (const item of list.tokens) {
|
|
45
45
|
item.loose = true;
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
+
function escapeForRegex(s) {
|
|
50
|
+
return s.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&');
|
|
51
|
+
}
|
|
49
52
|
export function markedList() {
|
|
50
53
|
return {
|
|
51
54
|
extensions: [
|
|
@@ -60,7 +63,7 @@ export function markedList() {
|
|
|
60
63
|
const isOrdered = bullet !== '*' && bullet !== '-' && bullet !== '+';
|
|
61
64
|
let bull;
|
|
62
65
|
let type = '';
|
|
63
|
-
let expectedValue =
|
|
66
|
+
let expectedValue = null;
|
|
64
67
|
// Detect list type (Roman, alphabetic, numeric)
|
|
65
68
|
if (isOrdered) {
|
|
66
69
|
if (bullet.match(new RegExp(`^${romanUpper}[.)]$`))) {
|
|
@@ -86,14 +89,15 @@ export function markedList() {
|
|
|
86
89
|
}
|
|
87
90
|
else {
|
|
88
91
|
bull = this.lexer.options.pedantic ? bullet : '[*+-]';
|
|
92
|
+
bull = this.lexer.options.pedantic ? escapeForRegex(bullet) : '[*+-]';
|
|
89
93
|
}
|
|
90
94
|
const list = {
|
|
91
95
|
type: 'list',
|
|
92
96
|
raw: '',
|
|
93
97
|
ordered: isOrdered,
|
|
94
|
-
listType: type,
|
|
98
|
+
listType: isOrdered ? type : null,
|
|
95
99
|
loose: false,
|
|
96
|
-
|
|
100
|
+
tokens: []
|
|
97
101
|
};
|
|
98
102
|
// Get next list item
|
|
99
103
|
const itemRegex = new RegExp(`^( {0,3}${bull})((?:[\t ][^\\n]*)?(?:\\n|$))`);
|
|
@@ -189,7 +193,21 @@ export function markedList() {
|
|
|
189
193
|
else if (type === 'lower-roman' || type === 'upper-roman') {
|
|
190
194
|
value = romanToInt(bullet.slice(0, -1));
|
|
191
195
|
}
|
|
192
|
-
|
|
196
|
+
// Handle expectedValue initialization and validation
|
|
197
|
+
let skipped = false;
|
|
198
|
+
if (isOrdered) {
|
|
199
|
+
if (expectedValue === null) {
|
|
200
|
+
// First item: set expectedValue to this item's value (or 1 if parsing failed)
|
|
201
|
+
expectedValue = value ?? 1;
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
// Subsequent items: check if value matches expected
|
|
205
|
+
skipped = value !== null && value !== expectedValue;
|
|
206
|
+
// Increment expectedValue for next item
|
|
207
|
+
expectedValue += 1;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
list.tokens.push({
|
|
193
211
|
type: 'list_item',
|
|
194
212
|
raw,
|
|
195
213
|
task: !!isTask,
|
|
@@ -197,13 +215,12 @@ export function markedList() {
|
|
|
197
215
|
loose: false,
|
|
198
216
|
text: itemContents,
|
|
199
217
|
value,
|
|
200
|
-
skipped
|
|
218
|
+
skipped,
|
|
201
219
|
tokens: []
|
|
202
220
|
});
|
|
203
|
-
expectedValue = (value ?? 0) + 1;
|
|
204
221
|
list.raw += raw;
|
|
205
222
|
}
|
|
206
|
-
if (list.
|
|
223
|
+
if (list.tokens.length === 0)
|
|
207
224
|
return null;
|
|
208
225
|
// Finalize the list
|
|
209
226
|
finalizeList(list, this.lexer);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const inlineRule = /^(\${1,2})(?!\$)((?:\\.|[^\\\n])*?(?:\\.|[^\\\n\$]))\1(?=[\s?!\.,:?!。,:]|$)/;
|
|
2
2
|
const inlineRuleNonStandard = /^(\${1,2})(?!\$)((?:\\.|[^\\\n])*?(?:\\.|[^\\\n\$]))\1/; // Non-standard, even if there are no spaces before and after $ or $$, try to parse
|
|
3
|
-
const blockRule = /^(\${1,2})\n((?:\\[
|
|
3
|
+
const blockRule = /^(\${1,2})\n((?:\\[\s\S]|[^\\])+?)\n\1(?:\n|$)/;
|
|
4
4
|
export function markedMath() {
|
|
5
5
|
return {
|
|
6
6
|
extensions: [
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { MarkedExtension } from 'marked';
|
|
2
|
+
export interface SpanTableOptions {
|
|
3
|
+
useTheadTbody?: boolean;
|
|
4
|
+
useTfoot?: boolean;
|
|
5
|
+
detectFooter?: boolean;
|
|
6
|
+
maxColspan?: number | null;
|
|
7
|
+
handleComplexSpans?: boolean;
|
|
8
|
+
}
|
|
9
|
+
interface BaseCell {
|
|
10
|
+
rowspan: number;
|
|
11
|
+
colspan: number;
|
|
12
|
+
text: string;
|
|
13
|
+
position?: number;
|
|
14
|
+
tokens?: unknown[];
|
|
15
|
+
rowSpanTarget?: BaseCell;
|
|
16
|
+
complexRowSpan?: boolean;
|
|
17
|
+
relatedCell?: BaseCell;
|
|
18
|
+
align?: string | null;
|
|
19
|
+
}
|
|
20
|
+
export interface TH extends BaseCell {
|
|
21
|
+
type: 'th';
|
|
22
|
+
}
|
|
23
|
+
export interface TD extends BaseCell {
|
|
24
|
+
type: 'td';
|
|
25
|
+
}
|
|
26
|
+
export interface THeadRow {
|
|
27
|
+
type: 'tr';
|
|
28
|
+
tokens: TH[];
|
|
29
|
+
}
|
|
30
|
+
export interface TRow {
|
|
31
|
+
type: 'tr';
|
|
32
|
+
tokens: TD[];
|
|
33
|
+
}
|
|
34
|
+
export interface THead {
|
|
35
|
+
type: 'thead';
|
|
36
|
+
tokens: THeadRow[];
|
|
37
|
+
}
|
|
38
|
+
export interface TBody {
|
|
39
|
+
type: 'tbody';
|
|
40
|
+
tokens: TRow[];
|
|
41
|
+
}
|
|
42
|
+
export interface TFoot {
|
|
43
|
+
type: 'tfoot';
|
|
44
|
+
tokens: TRow[];
|
|
45
|
+
}
|
|
46
|
+
export type TableSection = THead | TBody | TFoot;
|
|
47
|
+
export interface TableToken {
|
|
48
|
+
type: 'table';
|
|
49
|
+
tokens: TableSection[];
|
|
50
|
+
raw: string;
|
|
51
|
+
}
|
|
52
|
+
interface WorkingCell extends BaseCell {
|
|
53
|
+
}
|
|
54
|
+
type WorkingRow = WorkingCell[];
|
|
55
|
+
export declare const DEFAULT_OPTIONS: Required<SpanTableOptions>;
|
|
56
|
+
export declare const getTableCell: (text: string, cell: BaseCell, type: "th" | "td", align: string | null) => string;
|
|
57
|
+
export declare const splitCells: (tableRow: string, count: number | null, prevRow?: WorkingRow | null, maxColspan?: number | null) => WorkingRow;
|
|
58
|
+
export declare function markedTable(options?: SpanTableOptions): MarkedExtension;
|
|
59
|
+
export {};
|