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