@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 CHANGED
@@ -1,70 +1,84 @@
1
- import { MarkdownItHeader } from '@mdit-vue/types';
2
- import Token from 'markdown-it/lib/token.mjs';
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
- * 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;
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, { shouldAllowHtml, shouldEscapeText }: ResolveTitleOptions) => string;
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
- * 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;
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[], { level, shouldAllowHtml, shouldAllowNested, shouldEscapeText, slugify, format, }: ResolveHeadersOptions) => MarkdownItHeader[];
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
+ "<": "&lt;",
5
+ ">": "&gt;",
6
+ "'": "&#39;",
7
+ "\"": "&quot;"
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
+ "&amp;": "&",
19
+ "&#38;": "&",
20
+ "&lt;": "<",
21
+ "&#60;": "<",
22
+ "&gt;": ">",
23
+ "&#62;": ">",
24
+ "&apos;": "'",
25
+ "&#39;": "'",
26
+ "&quot;": "\"",
27
+ "&#34;": "\""
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": "2.1.4",
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
- "import": {
24
- "types": "./dist/index.d.mts",
25
- "default": "./dist/index.mjs"
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": "unbuild",
32
+ "build": "tsdown",
41
33
  "test": "vitest"
42
34
  },
43
35
  "dependencies": {
44
- "@mdit-vue/types": "2.1.4",
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": "01a6daa37fff48ea3992becfd4ba8c0f97a605ad"
50
+ "gitHead": "cdffe386ef7b897f1bf878ce20e38bdd07908fb1"
52
51
  }
package/dist/index.cjs DELETED
@@ -1,118 +0,0 @@
1
- 'use strict';
2
-
3
- const htmlEscapeMap = {
4
- "&": "&amp;",
5
- "<": "&lt;",
6
- ">": "&gt;",
7
- "'": "&#39;",
8
- '"': "&quot;"
9
- };
10
- const htmlEscapeRegexp = /[&<>'"]/g;
11
- const htmlEscape = (str) => str.replace(
12
- htmlEscapeRegexp,
13
- (char) => htmlEscapeMap[char]
14
- );
15
-
16
- const htmlUnescapeMap = {
17
- "&amp;": "&",
18
- "&#38;": "&",
19
- "&lt;": "<",
20
- "&#60;": "<",
21
- "&gt;": ">",
22
- "&#62;": ">",
23
- "&apos;": "'",
24
- "&#39;": "'",
25
- "&quot;": '"',
26
- "&#34;": '"'
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
- "&": "&amp;",
3
- "<": "&lt;",
4
- ">": "&gt;",
5
- "'": "&#39;",
6
- '"': "&quot;"
7
- };
8
- const htmlEscapeRegexp = /[&<>'"]/g;
9
- const htmlEscape = (str) => str.replace(
10
- htmlEscapeRegexp,
11
- (char) => htmlEscapeMap[char]
12
- );
13
-
14
- const htmlUnescapeMap = {
15
- "&amp;": "&",
16
- "&#38;": "&",
17
- "&lt;": "<",
18
- "&#60;": "<",
19
- "&gt;": ">",
20
- "&#62;": ">",
21
- "&apos;": "'",
22
- "&#39;": "'",
23
- "&quot;": '"',
24
- "&#34;": '"'
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 };