@mdit-vue/shared 2.1.4 → 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/dist/index.cjs +95 -95
- package/dist/index.d.cts +60 -46
- package/dist/index.d.mts +60 -46
- package/dist/index.mjs +95 -94
- package/package.json +16 -14
package/dist/index.cjs
CHANGED
|
@@ -1,118 +1,118 @@
|
|
|
1
|
-
'use strict';
|
|
2
1
|
|
|
2
|
+
//#region src/html-escape.ts
|
|
3
3
|
const htmlEscapeMap = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
"&": "&",
|
|
5
|
+
"<": "<",
|
|
6
|
+
">": ">",
|
|
7
|
+
"'": "'",
|
|
8
|
+
"\"": """
|
|
9
9
|
};
|
|
10
10
|
const htmlEscapeRegexp = /[&<>'"]/g;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
);
|
|
11
|
+
/**
|
|
12
|
+
* Escape html chars
|
|
13
|
+
*/
|
|
14
|
+
const htmlEscape = (str) => str.replace(htmlEscapeRegexp, (char) => htmlEscapeMap[char]);
|
|
15
15
|
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/html-unescape.ts
|
|
16
18
|
const htmlUnescapeMap = {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
"&": "&",
|
|
20
|
+
"&": "&",
|
|
21
|
+
"<": "<",
|
|
22
|
+
"<": "<",
|
|
23
|
+
">": ">",
|
|
24
|
+
">": ">",
|
|
25
|
+
"'": "'",
|
|
26
|
+
"'": "'",
|
|
27
|
+
""": "\"",
|
|
28
|
+
""": "\""
|
|
27
29
|
};
|
|
28
30
|
const htmlUnescapeRegexp = /&(amp|#38|lt|#60|gt|#62|apos|#39|quot|#34);/g;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
);
|
|
31
|
+
/**
|
|
32
|
+
* Unescape html chars
|
|
33
|
+
*/
|
|
34
|
+
const htmlUnescape = (str) => str.replace(htmlUnescapeRegexp, (char) => htmlUnescapeMap[char]);
|
|
33
35
|
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/resolve-title-from-token.ts
|
|
38
|
+
/**
|
|
39
|
+
* Resolve header title from markdown-it token
|
|
40
|
+
*
|
|
41
|
+
* Typically using the next token of `heading_open` token
|
|
42
|
+
*/
|
|
34
43
|
const resolveTitleFromToken = (token, { shouldAllowHtml, shouldEscapeText }) => {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
return `${result}${item.content}`;
|
|
51
|
-
}, "").trim();
|
|
44
|
+
const children = token.children ?? [];
|
|
45
|
+
const titleTokenTypes = [
|
|
46
|
+
"text",
|
|
47
|
+
"emoji",
|
|
48
|
+
"code_inline"
|
|
49
|
+
];
|
|
50
|
+
if (shouldAllowHtml) titleTokenTypes.push("html_inline");
|
|
51
|
+
const titleTokens = children.filter((item) => titleTokenTypes.includes(item.type) && !item.meta?.isPermalinkSymbol);
|
|
52
|
+
return titleTokens.reduce((result, item) => {
|
|
53
|
+
if (shouldEscapeText) {
|
|
54
|
+
if (item.type === "code_inline" || item.type === "text") return `${result}${htmlEscape(item.content)}`;
|
|
55
|
+
}
|
|
56
|
+
return `${result}${item.content}`;
|
|
57
|
+
}, "").trim();
|
|
52
58
|
};
|
|
53
59
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
shouldEscapeText
|
|
96
|
-
});
|
|
97
|
-
const slug = token.attrGet("id") ?? slugify(title);
|
|
98
|
-
push({
|
|
99
|
-
level: headerLevel,
|
|
100
|
-
title: format?.(title) ?? title,
|
|
101
|
-
slug,
|
|
102
|
-
link: `#${slug}`,
|
|
103
|
-
children: []
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
return headers;
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/resolve-headers-from-tokens.ts
|
|
62
|
+
/**
|
|
63
|
+
* Resolve headers from markdown-it tokens
|
|
64
|
+
*/
|
|
65
|
+
const resolveHeadersFromTokens = (tokens, { level, shouldAllowHtml, shouldAllowNested, shouldEscapeText, slugify: slugify$1, format }) => {
|
|
66
|
+
const headers = [];
|
|
67
|
+
const stack = [];
|
|
68
|
+
const push = (header) => {
|
|
69
|
+
while (stack.length !== 0 && header.level <= stack[0].level) stack.shift();
|
|
70
|
+
if (stack.length === 0) {
|
|
71
|
+
headers.push(header);
|
|
72
|
+
stack.push(header);
|
|
73
|
+
} else {
|
|
74
|
+
stack[0].children.push(header);
|
|
75
|
+
stack.unshift(header);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
for (let i = 0; i < tokens.length; i += 1) {
|
|
79
|
+
const token = tokens[i];
|
|
80
|
+
if (token.type !== "heading_open") continue;
|
|
81
|
+
if (token.level !== 0 && !shouldAllowNested) continue;
|
|
82
|
+
const headerLevel = Number.parseInt(token.tag.slice(1), 10);
|
|
83
|
+
if (!level.includes(headerLevel)) continue;
|
|
84
|
+
const nextToken = tokens[i + 1];
|
|
85
|
+
/* istanbul ignore if -- @preserve */
|
|
86
|
+
if (!nextToken) continue;
|
|
87
|
+
const title = resolveTitleFromToken(nextToken, {
|
|
88
|
+
shouldAllowHtml,
|
|
89
|
+
shouldEscapeText
|
|
90
|
+
});
|
|
91
|
+
const slug = token.attrGet("id") ?? slugify$1(title);
|
|
92
|
+
push({
|
|
93
|
+
level: headerLevel,
|
|
94
|
+
title: format?.(title) ?? title,
|
|
95
|
+
slug,
|
|
96
|
+
link: `#${slug}`,
|
|
97
|
+
children: []
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return headers;
|
|
107
101
|
};
|
|
108
102
|
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region src/slugify.ts
|
|
109
105
|
const rControl = /[\u0000-\u001f]/g;
|
|
110
106
|
const rSpecial = /[\s~`!@#$%^&*()\-_+=[\]{}|\\;:"'“”‘’<>,.?/]+/g;
|
|
111
107
|
const rCombining = /[\u0300-\u036F]/g;
|
|
108
|
+
/**
|
|
109
|
+
* Default slugification function
|
|
110
|
+
*/
|
|
112
111
|
const slugify = (str) => str.normalize("NFKD").replace(rCombining, "").replace(rControl, "").replace(rSpecial, "-").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "").replace(/^(\d)/, "_$1").toLowerCase();
|
|
113
112
|
|
|
113
|
+
//#endregion
|
|
114
114
|
exports.htmlEscape = htmlEscape;
|
|
115
115
|
exports.htmlUnescape = htmlUnescape;
|
|
116
116
|
exports.resolveHeadersFromTokens = resolveHeadersFromTokens;
|
|
117
117
|
exports.resolveTitleFromToken = resolveTitleFromToken;
|
|
118
|
-
exports.slugify = slugify;
|
|
118
|
+
exports.slugify = slugify;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,70 +1,84 @@
|
|
|
1
|
-
import { MarkdownItHeader } from
|
|
2
|
-
import Token from
|
|
1
|
+
import { MarkdownItHeader } from "@mdit-vue/types";
|
|
2
|
+
import Token from "markdown-it/lib/token.mjs";
|
|
3
3
|
|
|
4
|
+
//#region src/html-escape.d.ts
|
|
4
5
|
/**
|
|
5
6
|
* Escape html chars
|
|
6
7
|
*/
|
|
7
8
|
declare const htmlEscape: (str: string) => string;
|
|
8
|
-
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/html-unescape.d.ts
|
|
9
11
|
/**
|
|
10
12
|
* Unescape html chars
|
|
11
13
|
*/
|
|
12
14
|
declare const htmlUnescape: (str: string) => string;
|
|
13
|
-
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/resolve-title-from-token.d.ts
|
|
14
17
|
interface ResolveTitleOptions {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Should allow inline HTML tags or not.
|
|
20
|
+
*
|
|
21
|
+
* If the result is going to be used as Vue template, it should allow inline
|
|
22
|
+
* HTML tags so that Vue custom components would be kept.
|
|
23
|
+
*/
|
|
24
|
+
shouldAllowHtml: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Should escape the text content or not.
|
|
27
|
+
*
|
|
28
|
+
* If the result is going to be used in HTML directly, it should be escaped
|
|
29
|
+
* so that the text content won't be wrongly treated as HTML tags.
|
|
30
|
+
*/
|
|
31
|
+
shouldEscapeText: boolean;
|
|
29
32
|
}
|
|
30
33
|
/**
|
|
31
34
|
* Resolve header title from markdown-it token
|
|
32
35
|
*
|
|
33
36
|
* Typically using the next token of `heading_open` token
|
|
34
37
|
*/
|
|
35
|
-
declare const resolveTitleFromToken: (token: Token, {
|
|
36
|
-
|
|
38
|
+
declare const resolveTitleFromToken: (token: Token, {
|
|
39
|
+
shouldAllowHtml,
|
|
40
|
+
shouldEscapeText
|
|
41
|
+
}: ResolveTitleOptions) => string;
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/resolve-headers-from-tokens.d.ts
|
|
37
44
|
interface ResolveHeadersOptions extends ResolveTitleOptions {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Heading level that going to be resolved
|
|
47
|
+
*/
|
|
48
|
+
level: number[];
|
|
49
|
+
/**
|
|
50
|
+
* Should allow headers inside nested blocks or not
|
|
51
|
+
*
|
|
52
|
+
* If set to `true`, headers inside blockquote, list, etc. would also be resolved.
|
|
53
|
+
*/
|
|
54
|
+
shouldAllowNested: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* A custom slugification function
|
|
57
|
+
*
|
|
58
|
+
* Would be ignored if the `id` attr of the token is set.
|
|
59
|
+
*/
|
|
60
|
+
slugify: (str: string) => string;
|
|
61
|
+
/**
|
|
62
|
+
* A function for formatting headings
|
|
63
|
+
*/
|
|
64
|
+
format?: (str: string) => string;
|
|
58
65
|
}
|
|
59
66
|
/**
|
|
60
67
|
* Resolve headers from markdown-it tokens
|
|
61
68
|
*/
|
|
62
|
-
declare const resolveHeadersFromTokens: (tokens: Token[], {
|
|
63
|
-
|
|
69
|
+
declare const resolveHeadersFromTokens: (tokens: Token[], {
|
|
70
|
+
level,
|
|
71
|
+
shouldAllowHtml,
|
|
72
|
+
shouldAllowNested,
|
|
73
|
+
shouldEscapeText,
|
|
74
|
+
slugify,
|
|
75
|
+
format
|
|
76
|
+
}: ResolveHeadersOptions) => MarkdownItHeader[];
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region src/slugify.d.ts
|
|
64
79
|
/**
|
|
65
80
|
* Default slugification function
|
|
66
81
|
*/
|
|
67
|
-
declare const slugify: (str: string) => string;
|
|
68
|
-
|
|
69
|
-
export { htmlEscape, htmlUnescape, resolveHeadersFromTokens, resolveTitleFromToken, slugify };
|
|
70
|
-
export type { ResolveHeadersOptions, ResolveTitleOptions };
|
|
82
|
+
declare const slugify$1: (str: string) => string;
|
|
83
|
+
//#endregion
|
|
84
|
+
export { ResolveHeadersOptions, ResolveTitleOptions, htmlEscape, htmlUnescape, resolveHeadersFromTokens, resolveTitleFromToken, slugify$1 as slugify };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,70 +1,84 @@
|
|
|
1
|
-
import { MarkdownItHeader } from
|
|
2
|
-
import Token from
|
|
1
|
+
import { MarkdownItHeader } from "@mdit-vue/types";
|
|
2
|
+
import Token from "markdown-it/lib/token.mjs";
|
|
3
3
|
|
|
4
|
+
//#region src/html-escape.d.ts
|
|
4
5
|
/**
|
|
5
6
|
* Escape html chars
|
|
6
7
|
*/
|
|
7
8
|
declare const htmlEscape: (str: string) => string;
|
|
8
|
-
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/html-unescape.d.ts
|
|
9
11
|
/**
|
|
10
12
|
* Unescape html chars
|
|
11
13
|
*/
|
|
12
14
|
declare const htmlUnescape: (str: string) => string;
|
|
13
|
-
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/resolve-title-from-token.d.ts
|
|
14
17
|
interface ResolveTitleOptions {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Should allow inline HTML tags or not.
|
|
20
|
+
*
|
|
21
|
+
* If the result is going to be used as Vue template, it should allow inline
|
|
22
|
+
* HTML tags so that Vue custom components would be kept.
|
|
23
|
+
*/
|
|
24
|
+
shouldAllowHtml: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Should escape the text content or not.
|
|
27
|
+
*
|
|
28
|
+
* If the result is going to be used in HTML directly, it should be escaped
|
|
29
|
+
* so that the text content won't be wrongly treated as HTML tags.
|
|
30
|
+
*/
|
|
31
|
+
shouldEscapeText: boolean;
|
|
29
32
|
}
|
|
30
33
|
/**
|
|
31
34
|
* Resolve header title from markdown-it token
|
|
32
35
|
*
|
|
33
36
|
* Typically using the next token of `heading_open` token
|
|
34
37
|
*/
|
|
35
|
-
declare const resolveTitleFromToken: (token: Token, {
|
|
36
|
-
|
|
38
|
+
declare const resolveTitleFromToken: (token: Token, {
|
|
39
|
+
shouldAllowHtml,
|
|
40
|
+
shouldEscapeText
|
|
41
|
+
}: ResolveTitleOptions) => string;
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/resolve-headers-from-tokens.d.ts
|
|
37
44
|
interface ResolveHeadersOptions extends ResolveTitleOptions {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Heading level that going to be resolved
|
|
47
|
+
*/
|
|
48
|
+
level: number[];
|
|
49
|
+
/**
|
|
50
|
+
* Should allow headers inside nested blocks or not
|
|
51
|
+
*
|
|
52
|
+
* If set to `true`, headers inside blockquote, list, etc. would also be resolved.
|
|
53
|
+
*/
|
|
54
|
+
shouldAllowNested: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* A custom slugification function
|
|
57
|
+
*
|
|
58
|
+
* Would be ignored if the `id` attr of the token is set.
|
|
59
|
+
*/
|
|
60
|
+
slugify: (str: string) => string;
|
|
61
|
+
/**
|
|
62
|
+
* A function for formatting headings
|
|
63
|
+
*/
|
|
64
|
+
format?: (str: string) => string;
|
|
58
65
|
}
|
|
59
66
|
/**
|
|
60
67
|
* Resolve headers from markdown-it tokens
|
|
61
68
|
*/
|
|
62
|
-
declare const resolveHeadersFromTokens: (tokens: Token[], {
|
|
63
|
-
|
|
69
|
+
declare const resolveHeadersFromTokens: (tokens: Token[], {
|
|
70
|
+
level,
|
|
71
|
+
shouldAllowHtml,
|
|
72
|
+
shouldAllowNested,
|
|
73
|
+
shouldEscapeText,
|
|
74
|
+
slugify,
|
|
75
|
+
format
|
|
76
|
+
}: ResolveHeadersOptions) => MarkdownItHeader[];
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region src/slugify.d.ts
|
|
64
79
|
/**
|
|
65
80
|
* Default slugification function
|
|
66
81
|
*/
|
|
67
|
-
declare const slugify: (str: string) => string;
|
|
68
|
-
|
|
69
|
-
export { htmlEscape, htmlUnescape, resolveHeadersFromTokens, resolveTitleFromToken, slugify };
|
|
70
|
-
export type { ResolveHeadersOptions, ResolveTitleOptions };
|
|
82
|
+
declare const slugify$1: (str: string) => string;
|
|
83
|
+
//#endregion
|
|
84
|
+
export { ResolveHeadersOptions, ResolveTitleOptions, htmlEscape, htmlUnescape, resolveHeadersFromTokens, resolveTitleFromToken, slugify$1 as slugify };
|
package/dist/index.mjs
CHANGED
|
@@ -1,112 +1,113 @@
|
|
|
1
|
+
//#region src/html-escape.ts
|
|
1
2
|
const htmlEscapeMap = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
"&": "&",
|
|
4
|
+
"<": "<",
|
|
5
|
+
">": ">",
|
|
6
|
+
"'": "'",
|
|
7
|
+
"\"": """
|
|
7
8
|
};
|
|
8
9
|
const htmlEscapeRegexp = /[&<>'"]/g;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
);
|
|
10
|
+
/**
|
|
11
|
+
* Escape html chars
|
|
12
|
+
*/
|
|
13
|
+
const htmlEscape = (str) => str.replace(htmlEscapeRegexp, (char) => htmlEscapeMap[char]);
|
|
13
14
|
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/html-unescape.ts
|
|
14
17
|
const htmlUnescapeMap = {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
"&": "&",
|
|
19
|
+
"&": "&",
|
|
20
|
+
"<": "<",
|
|
21
|
+
"<": "<",
|
|
22
|
+
">": ">",
|
|
23
|
+
">": ">",
|
|
24
|
+
"'": "'",
|
|
25
|
+
"'": "'",
|
|
26
|
+
""": "\"",
|
|
27
|
+
""": "\""
|
|
25
28
|
};
|
|
26
29
|
const htmlUnescapeRegexp = /&(amp|#38|lt|#60|gt|#62|apos|#39|quot|#34);/g;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
);
|
|
30
|
+
/**
|
|
31
|
+
* Unescape html chars
|
|
32
|
+
*/
|
|
33
|
+
const htmlUnescape = (str) => str.replace(htmlUnescapeRegexp, (char) => htmlUnescapeMap[char]);
|
|
31
34
|
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/resolve-title-from-token.ts
|
|
37
|
+
/**
|
|
38
|
+
* Resolve header title from markdown-it token
|
|
39
|
+
*
|
|
40
|
+
* Typically using the next token of `heading_open` token
|
|
41
|
+
*/
|
|
32
42
|
const resolveTitleFromToken = (token, { shouldAllowHtml, shouldEscapeText }) => {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
return `${result}${item.content}`;
|
|
49
|
-
}, "").trim();
|
|
43
|
+
const children = token.children ?? [];
|
|
44
|
+
const titleTokenTypes = [
|
|
45
|
+
"text",
|
|
46
|
+
"emoji",
|
|
47
|
+
"code_inline"
|
|
48
|
+
];
|
|
49
|
+
if (shouldAllowHtml) titleTokenTypes.push("html_inline");
|
|
50
|
+
const titleTokens = children.filter((item) => titleTokenTypes.includes(item.type) && !item.meta?.isPermalinkSymbol);
|
|
51
|
+
return titleTokens.reduce((result, item) => {
|
|
52
|
+
if (shouldEscapeText) {
|
|
53
|
+
if (item.type === "code_inline" || item.type === "text") return `${result}${htmlEscape(item.content)}`;
|
|
54
|
+
}
|
|
55
|
+
return `${result}${item.content}`;
|
|
56
|
+
}, "").trim();
|
|
50
57
|
};
|
|
51
58
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
shouldEscapeText
|
|
94
|
-
});
|
|
95
|
-
const slug = token.attrGet("id") ?? slugify(title);
|
|
96
|
-
push({
|
|
97
|
-
level: headerLevel,
|
|
98
|
-
title: format?.(title) ?? title,
|
|
99
|
-
slug,
|
|
100
|
-
link: `#${slug}`,
|
|
101
|
-
children: []
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
return headers;
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/resolve-headers-from-tokens.ts
|
|
61
|
+
/**
|
|
62
|
+
* Resolve headers from markdown-it tokens
|
|
63
|
+
*/
|
|
64
|
+
const resolveHeadersFromTokens = (tokens, { level, shouldAllowHtml, shouldAllowNested, shouldEscapeText, slugify: slugify$1, format }) => {
|
|
65
|
+
const headers = [];
|
|
66
|
+
const stack = [];
|
|
67
|
+
const push = (header) => {
|
|
68
|
+
while (stack.length !== 0 && header.level <= stack[0].level) stack.shift();
|
|
69
|
+
if (stack.length === 0) {
|
|
70
|
+
headers.push(header);
|
|
71
|
+
stack.push(header);
|
|
72
|
+
} else {
|
|
73
|
+
stack[0].children.push(header);
|
|
74
|
+
stack.unshift(header);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
for (let i = 0; i < tokens.length; i += 1) {
|
|
78
|
+
const token = tokens[i];
|
|
79
|
+
if (token.type !== "heading_open") continue;
|
|
80
|
+
if (token.level !== 0 && !shouldAllowNested) continue;
|
|
81
|
+
const headerLevel = Number.parseInt(token.tag.slice(1), 10);
|
|
82
|
+
if (!level.includes(headerLevel)) continue;
|
|
83
|
+
const nextToken = tokens[i + 1];
|
|
84
|
+
/* istanbul ignore if -- @preserve */
|
|
85
|
+
if (!nextToken) continue;
|
|
86
|
+
const title = resolveTitleFromToken(nextToken, {
|
|
87
|
+
shouldAllowHtml,
|
|
88
|
+
shouldEscapeText
|
|
89
|
+
});
|
|
90
|
+
const slug = token.attrGet("id") ?? slugify$1(title);
|
|
91
|
+
push({
|
|
92
|
+
level: headerLevel,
|
|
93
|
+
title: format?.(title) ?? title,
|
|
94
|
+
slug,
|
|
95
|
+
link: `#${slug}`,
|
|
96
|
+
children: []
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return headers;
|
|
105
100
|
};
|
|
106
101
|
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region src/slugify.ts
|
|
107
104
|
const rControl = /[\u0000-\u001f]/g;
|
|
108
105
|
const rSpecial = /[\s~`!@#$%^&*()\-_+=[\]{}|\\;:"'“”‘’<>,.?/]+/g;
|
|
109
106
|
const rCombining = /[\u0300-\u036F]/g;
|
|
107
|
+
/**
|
|
108
|
+
* Default slugification function
|
|
109
|
+
*/
|
|
110
110
|
const slugify = (str) => str.normalize("NFKD").replace(rCombining, "").replace(rControl, "").replace(rSpecial, "-").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "").replace(/^(\d)/, "_$1").toLowerCase();
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
//#endregion
|
|
113
|
+
export { htmlEscape, htmlUnescape, resolveHeadersFromTokens, resolveTitleFromToken, slugify };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mdit-vue/shared",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Shared utils and types of mdit-vue",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"markdown-it",
|
|
@@ -20,33 +20,35 @@
|
|
|
20
20
|
"type": "module",
|
|
21
21
|
"exports": {
|
|
22
22
|
".": {
|
|
23
|
-
"import":
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"require": {
|
|
28
|
-
"types": "./dist/index.d.cts",
|
|
29
|
-
"default": "./dist/index.cjs"
|
|
30
|
-
}
|
|
31
|
-
}
|
|
23
|
+
"import": "./dist/index.mjs",
|
|
24
|
+
"require": "./dist/index.cjs"
|
|
25
|
+
},
|
|
26
|
+
"./package.json": "./package.json"
|
|
32
27
|
},
|
|
33
28
|
"main": "./dist/index.cjs",
|
|
34
29
|
"module": "./dist/index.mjs",
|
|
35
|
-
"types": "./dist/index.d.
|
|
30
|
+
"types": "./dist/index.d.cts",
|
|
36
31
|
"files": [
|
|
37
32
|
"./dist"
|
|
38
33
|
],
|
|
39
34
|
"scripts": {
|
|
40
|
-
"build": "
|
|
35
|
+
"build": "tsdown",
|
|
41
36
|
"test": "vitest"
|
|
42
37
|
},
|
|
43
38
|
"dependencies": {
|
|
44
|
-
"@mdit-vue/types": "
|
|
39
|
+
"@mdit-vue/types": "3.0.0",
|
|
45
40
|
"@types/markdown-it": "^14.1.2",
|
|
46
41
|
"markdown-it": "^14.1.0"
|
|
47
42
|
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"tsdown": "^0.14.0",
|
|
45
|
+
"vitest": "^3.2.4"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=20.0.0"
|
|
49
|
+
},
|
|
48
50
|
"publishConfig": {
|
|
49
51
|
"access": "public"
|
|
50
52
|
},
|
|
51
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "bbb62a47109c2932505b3f570b963f70d590914f"
|
|
52
54
|
}
|