svelte-streamdown 1.0.7 → 1.0.9
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 +11 -5
- package/dist/Block.svelte +26 -10
- package/dist/Elements/Code.svelte +1 -1
- package/dist/Elements/Element.svelte +120 -37
- package/dist/Elements/FootnoteRef.svelte +113 -0
- package/dist/Elements/FootnoteRef.svelte.d.ts +7 -0
- package/dist/Elements/Image.svelte +3 -3
- package/dist/Elements/{A.svelte → Link.svelte} +3 -3
- package/dist/Elements/{A.svelte.d.ts → Link.svelte.d.ts} +3 -3
- package/dist/Elements/Math.svelte +3 -2
- package/dist/Elements/index.d.ts +5 -25
- package/dist/Elements/index.js +5 -25
- package/dist/Streamdown.d.ts +1 -1
- package/dist/Streamdown.svelte +7 -1
- package/dist/Streamdown.svelte.d.ts +6 -0
- package/dist/marked/index.d.ts +18 -5
- package/dist/marked/index.js +4 -0
- package/dist/marked/marked-alert.d.ts +2 -2
- package/dist/marked/marked-alert.js +18 -18
- package/dist/marked/marked-footnotes.d.ts +1 -0
- package/dist/marked/marked-footnotes.js +28 -8
- package/dist/marked/marked-list.d.ts +36 -0
- package/dist/marked/marked-list.js +215 -0
- package/dist/marked/marked-math.js +0 -3
- package/dist/marked/marked-subsup.d.ts +28 -0
- package/dist/marked/marked-subsup.js +44 -0
- package/dist/theme.d.ts +48 -42
- package/dist/theme.js +47 -43
- package/dist/utils/parse-incomplete-markdown.js +157 -0
- package/dist/utils/useClickOutside.svelte.d.ts +8 -0
- package/dist/utils/useClickOutside.svelte.js +42 -0
- package/dist/utils/useKeyDown.svelte.d.ts +5 -0
- package/dist/utils/useKeyDown.svelte.js +20 -0
- package/package.json +3 -1
- package/dist/Elements/Blockquote.svelte +0 -28
- package/dist/Elements/Blockquote.svelte.d.ts +0 -9
- package/dist/Elements/Del.svelte +0 -28
- package/dist/Elements/Del.svelte.d.ts +0 -9
- package/dist/Elements/Em.svelte +0 -28
- package/dist/Elements/Em.svelte.d.ts +0 -9
- package/dist/Elements/Heading.svelte +0 -25
- package/dist/Elements/Heading.svelte.d.ts +0 -9
- package/dist/Elements/Hr.svelte +0 -26
- package/dist/Elements/Hr.svelte.d.ts +0 -9
- package/dist/Elements/InlineCode.svelte +0 -28
- package/dist/Elements/InlineCode.svelte.d.ts +0 -9
- package/dist/Elements/Li.svelte +0 -28
- package/dist/Elements/Li.svelte.d.ts +0 -9
- package/dist/Elements/Ol.svelte +0 -30
- package/dist/Elements/Ol.svelte.d.ts +0 -9
- package/dist/Elements/P.svelte +0 -28
- package/dist/Elements/P.svelte.d.ts +0 -9
- package/dist/Elements/Strong.svelte +0 -28
- package/dist/Elements/Strong.svelte.d.ts +0 -9
- package/dist/Elements/Sub.svelte +0 -27
- package/dist/Elements/Sub.svelte.d.ts +0 -8
- package/dist/Elements/Sup.svelte +0 -28
- package/dist/Elements/Sup.svelte.d.ts +0 -8
- package/dist/Elements/Tbody.svelte +0 -24
- package/dist/Elements/Tbody.svelte.d.ts +0 -7
- package/dist/Elements/Td.svelte +0 -28
- package/dist/Elements/Td.svelte.d.ts +0 -9
- package/dist/Elements/Th.svelte +0 -28
- package/dist/Elements/Th.svelte.d.ts +0 -9
- package/dist/Elements/Thead.svelte +0 -27
- package/dist/Elements/Thead.svelte.d.ts +0 -9
- package/dist/Elements/Tr.svelte +0 -27
- package/dist/Elements/Tr.svelte.d.ts +0 -9
- package/dist/Elements/Ul.svelte +0 -28
- package/dist/Elements/Ul.svelte.d.ts +0 -9
- /package/dist/{hightlighter.svelte.d.ts → utils/hightlighter.svelte.d.ts} +0 -0
- /package/dist/{hightlighter.svelte.js → utils/hightlighter.svelte.js} +0 -0
package/dist/marked/index.js
CHANGED
|
@@ -2,6 +2,8 @@ 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
|
+
import markedSubSup, {} from './marked-subsup.js';
|
|
6
|
+
import { markedList } from './marked-list.js';
|
|
5
7
|
export const lex = (markdown) => {
|
|
6
8
|
return marked
|
|
7
9
|
.use({
|
|
@@ -10,6 +12,8 @@ export const lex = (markdown) => {
|
|
|
10
12
|
.use(markedAlert())
|
|
11
13
|
.use(markedFootnote())
|
|
12
14
|
.use(markedMath())
|
|
15
|
+
.use(markedSubSup())
|
|
16
|
+
.use(markedList())
|
|
13
17
|
.lexer(markdown)
|
|
14
18
|
.filter((token) => token.type !== 'space' && token.type !== 'footnote');
|
|
15
19
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Token } from 'marked';
|
|
1
|
+
import type { Token, Tokenizer } 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: Token): void;
|
|
12
|
+
export declare function processAlertToken(token: Token, tokenizer: Tokenizer): void;
|
|
13
13
|
export type AlertToken = {
|
|
14
14
|
type: 'alert';
|
|
15
15
|
variant: variantType;
|
|
@@ -15,7 +15,7 @@ export default function markedAlert() {
|
|
|
15
15
|
const cap = defaultTokenizer.rules.block.blockquote.exec(src);
|
|
16
16
|
if (cap) {
|
|
17
17
|
const blockquoteToken = defaultTokenizer.blockquote(src);
|
|
18
|
-
blockquoteToken && processAlertToken(blockquoteToken);
|
|
18
|
+
blockquoteToken && processAlertToken(blockquoteToken, this.lexer.options.tokenizer);
|
|
19
19
|
return blockquoteToken;
|
|
20
20
|
}
|
|
21
21
|
}
|
|
@@ -23,7 +23,7 @@ export default function markedAlert() {
|
|
|
23
23
|
]
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
|
-
export function processAlertToken(token) {
|
|
26
|
+
export function processAlertToken(token, tokenizer) {
|
|
27
27
|
const matchedVariant = variants.find((type) => new RegExp(createSyntaxPattern(type)).test(('text' in token && token.text) || ''));
|
|
28
28
|
if (!matchedVariant)
|
|
29
29
|
return;
|
|
@@ -35,20 +35,20 @@ export function processAlertToken(token) {
|
|
|
35
35
|
});
|
|
36
36
|
const firstLine = ('tokens' in token && token.tokens?.[0]);
|
|
37
37
|
const firstLineText = firstLine.raw?.replace(typeRegexp, '').trim();
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
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
|
+
};
|
|
47
|
+
});
|
|
48
|
+
// Transform the token into an alert token
|
|
49
|
+
Object.assign(token, {
|
|
50
|
+
type: 'alert',
|
|
51
|
+
variant: matchedVariant,
|
|
52
|
+
tokens
|
|
53
|
+
});
|
|
54
54
|
}
|
|
@@ -1,14 +1,30 @@
|
|
|
1
1
|
import { lex } from './index.js';
|
|
2
|
+
import { StreamdownContext } from '../Streamdown.svelte';
|
|
3
|
+
import { getContext } from 'svelte';
|
|
4
|
+
const safeGetContext = () => {
|
|
5
|
+
try {
|
|
6
|
+
return getContext('streamdown');
|
|
7
|
+
}
|
|
8
|
+
catch (e) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
2
12
|
export default function markedFootnote() {
|
|
3
13
|
const ensureMaps = (tokenizer) => {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
footnotes
|
|
8
|
-
|
|
9
|
-
|
|
14
|
+
const streamdown = safeGetContext();
|
|
15
|
+
if (!streamdown) {
|
|
16
|
+
if (!tokenizer.lexer.hasFootnotes) {
|
|
17
|
+
tokenizer.lexer.footnotes = {
|
|
18
|
+
refs: new Map(),
|
|
19
|
+
footnotes: new Map()
|
|
20
|
+
};
|
|
21
|
+
tokenizer.lexer.hasFootnotes = true;
|
|
22
|
+
}
|
|
23
|
+
return tokenizer.lexer.footnotes;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
return streamdown.footnotes;
|
|
10
27
|
}
|
|
11
|
-
return tokenizer.lexer.footnotes;
|
|
12
28
|
};
|
|
13
29
|
return {
|
|
14
30
|
extensions: [
|
|
@@ -30,11 +46,13 @@ export default function markedFootnote() {
|
|
|
30
46
|
/^[ \t]*?[>\-*][ ]|[`]{3,}$|^[ \t]*?[|].+[|]$/.test(contentLastLine)
|
|
31
47
|
? '\n\n'
|
|
32
48
|
: '';
|
|
49
|
+
const lines = content.split('\n');
|
|
33
50
|
const token = {
|
|
34
51
|
type: 'footnote',
|
|
35
52
|
raw,
|
|
36
53
|
label,
|
|
37
|
-
|
|
54
|
+
lines,
|
|
55
|
+
tokens: []
|
|
38
56
|
};
|
|
39
57
|
maps.footnotes.set(label, token);
|
|
40
58
|
const ref = maps.refs.get(label);
|
|
@@ -54,6 +72,7 @@ export default function markedFootnote() {
|
|
|
54
72
|
if (match) {
|
|
55
73
|
const [raw, label] = match;
|
|
56
74
|
const footnote = maps.footnotes.get(label);
|
|
75
|
+
console.log({ footnote });
|
|
57
76
|
const token = {
|
|
58
77
|
type: 'footnoteRef',
|
|
59
78
|
raw,
|
|
@@ -62,6 +81,7 @@ export default function markedFootnote() {
|
|
|
62
81
|
type: 'footnote',
|
|
63
82
|
raw,
|
|
64
83
|
label,
|
|
84
|
+
lines: [],
|
|
65
85
|
tokens: []
|
|
66
86
|
}
|
|
67
87
|
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { TokenizerExtensionFunction } from 'marked';
|
|
2
|
+
export declare function letterToInt(letter: string): number;
|
|
3
|
+
export declare function romanToInt(roman: string): number;
|
|
4
|
+
export declare const romanUpper = "(?:C|XC|L?X{0,3}(?:IX|IV|V?I{0,3}))";
|
|
5
|
+
export declare const romanLower = "(?:c|xc|l?x{0,3}(?:ix|iv|v?i{0,3}))";
|
|
6
|
+
export declare const bulletPattern = "(?:[*+-]|(?:\\d{1,9}|[a-zA-Z]|(?:C|XC|L?X{0,3}(?:IX|IV|V?I{0,3}))|(?:c|xc|l?x{0,3}(?:ix|iv|v?i{0,3})))[.)])";
|
|
7
|
+
export declare const rule = "^( {0,3}(?:[*+-]|(?:\\d{1,9}|[a-zA-Z]|(?:C|XC|L?X{0,3}(?:IX|IV|V?I{0,3}))|(?:c|xc|l?x{0,3}(?:ix|iv|v?i{0,3})))[.)]))([ \\t][^\\n]+?)?(?:\\n|$)";
|
|
8
|
+
export declare function markedList(): {
|
|
9
|
+
extensions: Array<{
|
|
10
|
+
name: string;
|
|
11
|
+
level: 'block' | 'inline';
|
|
12
|
+
tokenizer: TokenizerExtensionFunction;
|
|
13
|
+
}>;
|
|
14
|
+
};
|
|
15
|
+
export interface ListToken {
|
|
16
|
+
type: 'list';
|
|
17
|
+
raw: string;
|
|
18
|
+
ordered: boolean;
|
|
19
|
+
listType: 'decimal' | 'lower-alpha' | 'upper-alpha' | 'lower-roman' | 'upper-roman';
|
|
20
|
+
loose: boolean;
|
|
21
|
+
items: ListItemToken[];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Token representing an item in an extended list.
|
|
25
|
+
*/
|
|
26
|
+
export interface ListItemToken {
|
|
27
|
+
type: 'list_item';
|
|
28
|
+
raw: string;
|
|
29
|
+
task: boolean;
|
|
30
|
+
checked: boolean;
|
|
31
|
+
loose: boolean;
|
|
32
|
+
text: string;
|
|
33
|
+
value: number | null;
|
|
34
|
+
skipped: boolean;
|
|
35
|
+
tokens: unknown[];
|
|
36
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
export function letterToInt(letter) {
|
|
2
|
+
return letter.toLowerCase().charCodeAt(0) - 96;
|
|
3
|
+
}
|
|
4
|
+
const romanMap = {
|
|
5
|
+
I: 1,
|
|
6
|
+
V: 5,
|
|
7
|
+
X: 10,
|
|
8
|
+
L: 50,
|
|
9
|
+
C: 100,
|
|
10
|
+
D: 500,
|
|
11
|
+
M: 1000
|
|
12
|
+
};
|
|
13
|
+
export function romanToInt(roman) {
|
|
14
|
+
roman = roman.toUpperCase();
|
|
15
|
+
let total = 0;
|
|
16
|
+
for (let i = 0; i < roman.length; i++) {
|
|
17
|
+
const current = romanMap[roman[i]];
|
|
18
|
+
const next = romanMap[roman[i + 1]];
|
|
19
|
+
total += next && current < next ? -current : current;
|
|
20
|
+
}
|
|
21
|
+
return total;
|
|
22
|
+
}
|
|
23
|
+
// Regular expression patterns for list detection
|
|
24
|
+
export const romanUpper = '(?:C|XC|L?X{0,3}(?:IX|IV|V?I{0,3}))';
|
|
25
|
+
export const romanLower = '(?:c|xc|l?x{0,3}(?:ix|iv|v?i{0,3}))';
|
|
26
|
+
// Fixed regex pattern - carefully balanced parentheses
|
|
27
|
+
export const bulletPattern = `(?:[*+-]|(?:\\d{1,9}|[a-zA-Z]|${romanUpper}|${romanLower})[.)])`;
|
|
28
|
+
export const rule = `^( {0,3}${bulletPattern})([ \\t][^\\n]+?)?(?:\\n|$)`;
|
|
29
|
+
function finalizeList(list, lexer) {
|
|
30
|
+
if (list.items.length === 0)
|
|
31
|
+
return;
|
|
32
|
+
// Trim trailing newline from last item
|
|
33
|
+
const lastItem = list.items[list.items.length - 1];
|
|
34
|
+
lastItem.raw = lastItem.raw.trimEnd();
|
|
35
|
+
lastItem.text = lastItem.text.trimEnd();
|
|
36
|
+
list.raw = list.raw.trimEnd();
|
|
37
|
+
// Handle child tokens
|
|
38
|
+
for (const item of list.items) {
|
|
39
|
+
lexer.state.top = false;
|
|
40
|
+
item.tokens = lexer.blockTokens(item.text, []);
|
|
41
|
+
}
|
|
42
|
+
// Mark list as loose if needed
|
|
43
|
+
if (list.loose) {
|
|
44
|
+
for (const item of list.items) {
|
|
45
|
+
item.loose = true;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export function markedList() {
|
|
50
|
+
return {
|
|
51
|
+
extensions: [
|
|
52
|
+
{
|
|
53
|
+
name: 'list',
|
|
54
|
+
level: 'block',
|
|
55
|
+
tokenizer(src) {
|
|
56
|
+
let cap = new RegExp(rule).exec(src);
|
|
57
|
+
if (!cap)
|
|
58
|
+
return null;
|
|
59
|
+
const bullet = cap[1].trim();
|
|
60
|
+
const isOrdered = bullet !== '*' && bullet !== '-' && bullet !== '+';
|
|
61
|
+
let bull;
|
|
62
|
+
let type = '';
|
|
63
|
+
let expectedValue = 1;
|
|
64
|
+
// Detect list type (Roman, alphabetic, numeric)
|
|
65
|
+
if (isOrdered) {
|
|
66
|
+
if (bullet.match(new RegExp(`^${romanUpper}[.)]$`))) {
|
|
67
|
+
type = 'upper-roman';
|
|
68
|
+
bull = `${romanUpper}\\${bullet.slice(-1)}`;
|
|
69
|
+
}
|
|
70
|
+
else if (bullet.match(new RegExp(`^${romanLower}[.)]$`))) {
|
|
71
|
+
type = 'lower-roman';
|
|
72
|
+
bull = `${romanLower}\\${bullet.slice(-1)}`;
|
|
73
|
+
}
|
|
74
|
+
else if (bullet.match(/^[a-z][.)]$/)) {
|
|
75
|
+
type = 'lower-alpha';
|
|
76
|
+
bull = `[a-z]\\${bullet.slice(-1)}`;
|
|
77
|
+
}
|
|
78
|
+
else if (bullet.match(/^[A-Z][.)]$/)) {
|
|
79
|
+
type = 'upper-alpha';
|
|
80
|
+
bull = `[A-Z]\\${bullet.slice(-1)}`;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
type = 'decimal';
|
|
84
|
+
bull = `\\d{1,9}\\${bullet.slice(-1)}`;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
bull = this.lexer.options.pedantic ? bullet : '[*+-]';
|
|
89
|
+
}
|
|
90
|
+
const list = {
|
|
91
|
+
type: 'list',
|
|
92
|
+
raw: '',
|
|
93
|
+
ordered: isOrdered,
|
|
94
|
+
listType: type,
|
|
95
|
+
loose: false,
|
|
96
|
+
items: []
|
|
97
|
+
};
|
|
98
|
+
// Get next list item
|
|
99
|
+
const itemRegex = new RegExp(`^( {0,3}${bull})((?:[\t ][^\\n]*)?(?:\\n|$))`);
|
|
100
|
+
let endsWithBlankLine = false;
|
|
101
|
+
// Check if current bullet point can start a new List Item
|
|
102
|
+
while (src) {
|
|
103
|
+
let raw = '';
|
|
104
|
+
let itemContents = '';
|
|
105
|
+
let endEarly = false;
|
|
106
|
+
if (!(cap = itemRegex.exec(src)))
|
|
107
|
+
break;
|
|
108
|
+
raw = cap[0];
|
|
109
|
+
const bullet = cap[1].trim();
|
|
110
|
+
src = src.substring(raw.length);
|
|
111
|
+
const line = cap[2].split('\n', 1)[0].replace(/^\t+/, (t) => ' '.repeat(3 * t.length));
|
|
112
|
+
const nextLine = src.split('\n', 1)[0];
|
|
113
|
+
const blankLine = !line.trim();
|
|
114
|
+
let indent = 0;
|
|
115
|
+
if (this.lexer.options.pedantic) {
|
|
116
|
+
indent = 2;
|
|
117
|
+
itemContents = line.trimStart();
|
|
118
|
+
}
|
|
119
|
+
else if (blankLine) {
|
|
120
|
+
indent = cap[1].length + 1;
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
indent = cap[2].search(/[^ ]/); // Find first non-space char
|
|
124
|
+
indent = indent > 4 ? 1 : indent; // Treat indented code blocks (> 4 spaces) as having only 1 indent
|
|
125
|
+
itemContents = line.slice(indent);
|
|
126
|
+
indent += cap[1].length;
|
|
127
|
+
}
|
|
128
|
+
if (blankLine && /^[ \t]*$/.test(nextLine)) {
|
|
129
|
+
// Items begin with at most one blank line
|
|
130
|
+
raw += nextLine + '\n';
|
|
131
|
+
src = src.substring(nextLine.length + 1);
|
|
132
|
+
endEarly = true;
|
|
133
|
+
}
|
|
134
|
+
if (!endEarly) {
|
|
135
|
+
const nextBulletRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:[*+-]|(?:\\d{1,9}|[a-zA-Z]|${romanUpper}|${romanLower})[.)])((?:[ \t][^\\n]*)?(?:\\n|$))`);
|
|
136
|
+
const hrRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`);
|
|
137
|
+
const fencesBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:\`\`\`|~~~)`);
|
|
138
|
+
const headingBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}#`);
|
|
139
|
+
const htmlBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}<[a-z].*>`, 'i');
|
|
140
|
+
// Check if following lines should be included in List Item
|
|
141
|
+
while (src) {
|
|
142
|
+
const rawLine = src.split('\n', 1)[0];
|
|
143
|
+
const nextLineWithoutTabs = rawLine.replace(/\t/g, ' ');
|
|
144
|
+
if (fencesBeginRegex.test(nextLineWithoutTabs) ||
|
|
145
|
+
headingBeginRegex.test(nextLineWithoutTabs) ||
|
|
146
|
+
htmlBeginRegex.test(nextLineWithoutTabs) ||
|
|
147
|
+
nextBulletRegex.test(nextLineWithoutTabs) ||
|
|
148
|
+
hrRegex.test(nextLineWithoutTabs))
|
|
149
|
+
break;
|
|
150
|
+
if (nextLineWithoutTabs.search(/[^ ]/) >= indent || !nextLineWithoutTabs.trim()) {
|
|
151
|
+
itemContents += '\n' + nextLineWithoutTabs.slice(indent);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
itemContents += '\n' + nextLineWithoutTabs;
|
|
155
|
+
}
|
|
156
|
+
raw += rawLine + '\n';
|
|
157
|
+
src = src.substring(rawLine.length + 1);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (!list.loose) {
|
|
161
|
+
// If the previous item ended with a blank line, the list is loose
|
|
162
|
+
if (endsWithBlankLine) {
|
|
163
|
+
list.loose = true;
|
|
164
|
+
}
|
|
165
|
+
else if (/\n[ \t]*\n[ \t]*$/.test(raw)) {
|
|
166
|
+
endsWithBlankLine = true;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
let isTask = null;
|
|
170
|
+
let isChecked = false;
|
|
171
|
+
// Check for task list items
|
|
172
|
+
if (this.lexer.options.gfm) {
|
|
173
|
+
isTask = /^\[[ xX]] /.exec(itemContents);
|
|
174
|
+
if (isTask) {
|
|
175
|
+
isChecked = isTask[0] !== '[ ] ';
|
|
176
|
+
itemContents = itemContents.replace(/^\[[ xX]] +/, '');
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
let value = null;
|
|
180
|
+
if (!isOrdered) {
|
|
181
|
+
// Do nothing for unordered lists
|
|
182
|
+
}
|
|
183
|
+
else if (type === 'decimal') {
|
|
184
|
+
value = parseInt(bullet.slice(0, -1), 10);
|
|
185
|
+
}
|
|
186
|
+
else if (type === 'lower-alpha' || type === 'upper-alpha') {
|
|
187
|
+
value = letterToInt(bullet.slice(0, -1));
|
|
188
|
+
}
|
|
189
|
+
else if (type === 'lower-roman' || type === 'upper-roman') {
|
|
190
|
+
value = romanToInt(bullet.slice(0, -1));
|
|
191
|
+
}
|
|
192
|
+
list.items.push({
|
|
193
|
+
type: 'list_item',
|
|
194
|
+
raw,
|
|
195
|
+
task: !!isTask,
|
|
196
|
+
checked: isChecked,
|
|
197
|
+
loose: false,
|
|
198
|
+
text: itemContents,
|
|
199
|
+
value,
|
|
200
|
+
skipped: isOrdered && value !== expectedValue,
|
|
201
|
+
tokens: []
|
|
202
|
+
});
|
|
203
|
+
expectedValue = (value ?? 0) + 1;
|
|
204
|
+
list.raw += raw;
|
|
205
|
+
}
|
|
206
|
+
if (list.items.length === 0)
|
|
207
|
+
return null;
|
|
208
|
+
// Finalize the list
|
|
209
|
+
finalizeList(list, this.lexer);
|
|
210
|
+
return list;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
]
|
|
214
|
+
};
|
|
215
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { TokenizerExtensionFunction } from 'marked';
|
|
2
|
+
export default function markedSubSup(): {
|
|
3
|
+
extensions: {
|
|
4
|
+
name: string;
|
|
5
|
+
level: 'inline';
|
|
6
|
+
tokenizer: TokenizerExtensionFunction;
|
|
7
|
+
start?: (src: string) => number | void;
|
|
8
|
+
}[];
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Represents a subscript token.
|
|
12
|
+
*/
|
|
13
|
+
export type SubToken = {
|
|
14
|
+
type: 'sub';
|
|
15
|
+
raw: string;
|
|
16
|
+
text: string;
|
|
17
|
+
tokens: any[];
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Represents a superscript token.
|
|
21
|
+
*/
|
|
22
|
+
export type SupToken = {
|
|
23
|
+
type: 'sup';
|
|
24
|
+
raw: string;
|
|
25
|
+
text: string;
|
|
26
|
+
tokens: any[];
|
|
27
|
+
};
|
|
28
|
+
export type SubSupToken = SubToken | SupToken;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const subRule = /^~([^~\s](?:[^~]*[^~\s])?)~/; // ~text~
|
|
2
|
+
const supRule = /^\^([^\^\s](?:[^\^]*[^\^\s])?)\^/; // ^text^
|
|
3
|
+
export default function markedSubSup() {
|
|
4
|
+
return {
|
|
5
|
+
extensions: [
|
|
6
|
+
{
|
|
7
|
+
name: 'sub',
|
|
8
|
+
level: 'inline',
|
|
9
|
+
start(src) {
|
|
10
|
+
return src.indexOf('~');
|
|
11
|
+
},
|
|
12
|
+
tokenizer(src) {
|
|
13
|
+
const match = src.match(subRule);
|
|
14
|
+
if (match) {
|
|
15
|
+
return {
|
|
16
|
+
type: 'sub',
|
|
17
|
+
raw: match[0],
|
|
18
|
+
text: match[1],
|
|
19
|
+
tokens: this.lexer.inlineTokens(match[1])
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: 'sup',
|
|
26
|
+
level: 'inline',
|
|
27
|
+
start(src) {
|
|
28
|
+
return src.indexOf('^');
|
|
29
|
+
},
|
|
30
|
+
tokenizer(src) {
|
|
31
|
+
const match = src.match(supRule);
|
|
32
|
+
if (match) {
|
|
33
|
+
return {
|
|
34
|
+
type: 'sup',
|
|
35
|
+
raw: match[0],
|
|
36
|
+
text: match[1],
|
|
37
|
+
tokens: this.lexer.inlineTokens(match[1])
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
};
|
|
44
|
+
}
|