@md-plugins/shared 0.1.0-rc.9 → 1.1.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 +14 -3
- package/dist/index.d.mts +67 -80
- package/dist/index.d.ts +67 -80
- package/dist/index.mjs +78 -79
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
# @md-plugins/shared
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@md-plugins/shared)
|
|
4
|
+
[](https://www.npmjs.com/package/@md-plugins/shared)
|
|
5
|
+
[](https://www.npmjs.com/package/@md-plugins/shared)
|
|
6
|
+
[](https://www.npmjs.com/package/@md-plugins/shared)
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
<span class="badge-github-sponsors"><a href="https://github.com/sponsors/hawkeye64" title="Sponsor this project on GitHub"><img src="https://img.shields.io/badge/github-sponsors-ea4aaa.svg?logo=githubsponsors&logoColor=white" alt="GitHub Sponsors button" /></a></span>
|
|
9
|
+
<span class="badge-paypal"><a href="https://paypal.me/hawkeye64" title="Donate to this project using Paypal"><img src="https://img.shields.io/badge/paypal-donate-yellow.svg" alt="PayPal donate button" /></a></span>
|
|
10
|
+
|
|
11
|
+
[](https://chat.quasar.dev)
|
|
12
|
+
[](https://twitter.com/jgalbraith64)
|
|
13
|
+
|
|
14
|
+
The `@md-plugins/shared` package provides common utilities, types, and helpers used across the Markdown-it plugins in the md-plugins ecosystem. It keeps Q-Press and direct plugin usage on the same environment shape for frontmatter, table of contents, extracted titles, and page-level imports.
|
|
15
|
+
|
|
16
|
+
Q-Press applications and regular `@md-plugins/vite-md-plugin` users do not need to install this package directly. Use it only when building a custom Markdown-it plugin or contributing to the md-plugins packages.
|
|
6
17
|
|
|
7
18
|
## Features
|
|
8
19
|
|
|
9
20
|
- Shared TypeScript types for plugin environments.
|
|
10
|
-
- Common utility functions for Markdown-
|
|
21
|
+
- Common utility functions for Markdown-it processing.
|
|
11
22
|
- Centralized definitions for easier maintenance and reusability.
|
|
12
23
|
- Lightweight and dependency-free.
|
|
13
24
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,65 +1,59 @@
|
|
|
1
|
-
import Token from
|
|
2
|
-
|
|
1
|
+
import Token from "markdown-it/lib/token.mjs";
|
|
3
2
|
/**
|
|
4
3
|
* Escapes HTML-sensitive characters so text can be safely injected into markup.
|
|
5
4
|
*/
|
|
6
5
|
declare const htmlEscape: (str: string) => string;
|
|
7
|
-
|
|
8
6
|
/**
|
|
9
7
|
* Decodes the HTML entities emitted by {@link htmlEscape} and common numeric variants.
|
|
10
8
|
*/
|
|
11
9
|
declare const htmlUnescape: (str: string) => string;
|
|
12
|
-
|
|
13
10
|
interface MarkdownItEnv {
|
|
14
|
-
|
|
11
|
+
plugins?: Record<string, unknown>;
|
|
15
12
|
}
|
|
16
13
|
interface MarkdownItHeader {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
14
|
+
/**
|
|
15
|
+
* The slug of the header
|
|
16
|
+
*
|
|
17
|
+
* Typically the `id` attr of the header anchor
|
|
18
|
+
*/
|
|
19
|
+
id: string;
|
|
20
|
+
/**
|
|
21
|
+
* The level of the header
|
|
22
|
+
*
|
|
23
|
+
* `1` to `6` for `<h1>` to `<h6>`
|
|
24
|
+
*/
|
|
25
|
+
level: number;
|
|
26
|
+
/**
|
|
27
|
+
* The title of the header
|
|
28
|
+
*/
|
|
29
|
+
title: string;
|
|
30
|
+
/**
|
|
31
|
+
* Link of the header
|
|
32
|
+
*
|
|
33
|
+
* Typically using `#${slug}` as the anchor hash
|
|
34
|
+
*/
|
|
35
|
+
link: string;
|
|
36
|
+
/**
|
|
37
|
+
* The children of the header
|
|
38
|
+
*/
|
|
39
|
+
children: MarkdownItHeader[];
|
|
43
40
|
}
|
|
44
|
-
type ResolvePluginOptionsFn = <T extends object, K extends keyof any>(options: T | {
|
|
45
|
-
[P in K]?: T;
|
|
46
|
-
} | undefined, key: K, defaults: T) => T;
|
|
47
|
-
|
|
41
|
+
type ResolvePluginOptionsFn = <T extends object, K extends keyof any>(options: T | { [P in K]?: T; } | undefined, key: K, defaults: T) => T;
|
|
48
42
|
interface ResolveTitleOptions {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Should allow inline HTML tags or not.
|
|
45
|
+
*
|
|
46
|
+
* If the result is going to be used as Vue template, it should allow inline
|
|
47
|
+
* HTML tags so that Vue custom components would be kept.
|
|
48
|
+
*/
|
|
49
|
+
shouldAllowHtml: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Should escape the text content or not.
|
|
52
|
+
*
|
|
53
|
+
* If the result is going to be used in HTML directly, it should be escaped
|
|
54
|
+
* so that the text content won't be wrongly treated as HTML tags.
|
|
55
|
+
*/
|
|
56
|
+
shouldEscapeText: boolean;
|
|
63
57
|
}
|
|
64
58
|
/**
|
|
65
59
|
* Extracts plain heading text from a markdown-it inline token.
|
|
@@ -69,28 +63,27 @@ interface ResolveTitleOptions {
|
|
|
69
63
|
* are ignored so the title remains human-readable.
|
|
70
64
|
*/
|
|
71
65
|
declare const resolveTitleFromToken: (token: Token, { shouldAllowHtml, shouldEscapeText }: ResolveTitleOptions) => string;
|
|
72
|
-
|
|
73
66
|
interface ResolveHeadersOptions extends ResolveTitleOptions {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Heading level that going to be resolved
|
|
69
|
+
*/
|
|
70
|
+
level: number[];
|
|
71
|
+
/**
|
|
72
|
+
* Should allow headers inside nested blocks or not
|
|
73
|
+
*
|
|
74
|
+
* If set to `true`, headers inside blockquote, list, etc. would also be resolved.
|
|
75
|
+
*/
|
|
76
|
+
shouldAllowNested: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* A custom slugification function
|
|
79
|
+
*
|
|
80
|
+
* Would be ignored if the `id` attr of the token is set.
|
|
81
|
+
*/
|
|
82
|
+
slugify?: (str: string) => string;
|
|
83
|
+
/**
|
|
84
|
+
* A function for formatting headings
|
|
85
|
+
*/
|
|
86
|
+
format?: (str: string) => string | undefined;
|
|
94
87
|
}
|
|
95
88
|
/**
|
|
96
89
|
* Builds a nested heading tree from markdown-it heading tokens.
|
|
@@ -98,16 +91,14 @@ interface ResolveHeadersOptions extends ResolveTitleOptions {
|
|
|
98
91
|
* Existing heading `id` attributes are preserved. When a heading has no `id`,
|
|
99
92
|
* the configured `slugify` function creates one from the resolved heading text.
|
|
100
93
|
*/
|
|
101
|
-
declare const resolveHeadersFromTokens: (tokens: Token[], { level, shouldAllowHtml, shouldAllowNested, shouldEscapeText, slugify, format
|
|
102
|
-
|
|
94
|
+
declare const resolveHeadersFromTokens: (tokens: Token[], { level, shouldAllowHtml, shouldAllowNested, shouldEscapeText, slugify, format }?: Partial<ResolveHeadersOptions>) => MarkdownItHeader[];
|
|
103
95
|
/**
|
|
104
96
|
* Converts arbitrary heading text into a stable URL-friendly slug.
|
|
105
97
|
*
|
|
106
98
|
* The result is lowercase, accent-free, hyphen-separated, and safe to use as a
|
|
107
99
|
* generated Markdown heading id.
|
|
108
100
|
*/
|
|
109
|
-
declare const slugify: (str: string) => string;
|
|
110
|
-
|
|
101
|
+
declare const slugify$1: (str: string) => string;
|
|
111
102
|
/**
|
|
112
103
|
* Resolves plugin options from either a direct options object or a nested
|
|
113
104
|
* package-level options bag.
|
|
@@ -116,9 +107,5 @@ declare const slugify: (str: string) => string;
|
|
|
116
107
|
* or through a shared md-plugins config object keyed by plugin name. This helper
|
|
117
108
|
* supports both shapes while applying default values.
|
|
118
109
|
*/
|
|
119
|
-
declare function resolvePluginOptions<T extends object, K extends keyof any>(options: T | {
|
|
120
|
-
|
|
121
|
-
} | undefined, key: K, defaults: T): T;
|
|
122
|
-
|
|
123
|
-
export { htmlEscape, htmlUnescape, resolveHeadersFromTokens, resolvePluginOptions, resolveTitleFromToken, slugify };
|
|
124
|
-
export type { MarkdownItEnv, MarkdownItHeader, ResolveHeadersOptions, ResolvePluginOptionsFn, ResolveTitleOptions };
|
|
110
|
+
declare function resolvePluginOptions<T extends object, K extends keyof any>(options: T | { [key in K]?: T; } | undefined, key: K, defaults: T): T;
|
|
111
|
+
export { type MarkdownItEnv, type MarkdownItHeader, ResolveHeadersOptions, type ResolvePluginOptionsFn, ResolveTitleOptions, htmlEscape, htmlUnescape, resolveHeadersFromTokens, resolvePluginOptions, resolveTitleFromToken, slugify$1 as slugify };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,65 +1,59 @@
|
|
|
1
|
-
import Token from
|
|
2
|
-
|
|
1
|
+
import Token from "markdown-it/lib/token.mjs";
|
|
3
2
|
/**
|
|
4
3
|
* Escapes HTML-sensitive characters so text can be safely injected into markup.
|
|
5
4
|
*/
|
|
6
5
|
declare const htmlEscape: (str: string) => string;
|
|
7
|
-
|
|
8
6
|
/**
|
|
9
7
|
* Decodes the HTML entities emitted by {@link htmlEscape} and common numeric variants.
|
|
10
8
|
*/
|
|
11
9
|
declare const htmlUnescape: (str: string) => string;
|
|
12
|
-
|
|
13
10
|
interface MarkdownItEnv {
|
|
14
|
-
|
|
11
|
+
plugins?: Record<string, unknown>;
|
|
15
12
|
}
|
|
16
13
|
interface MarkdownItHeader {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
14
|
+
/**
|
|
15
|
+
* The slug of the header
|
|
16
|
+
*
|
|
17
|
+
* Typically the `id` attr of the header anchor
|
|
18
|
+
*/
|
|
19
|
+
id: string;
|
|
20
|
+
/**
|
|
21
|
+
* The level of the header
|
|
22
|
+
*
|
|
23
|
+
* `1` to `6` for `<h1>` to `<h6>`
|
|
24
|
+
*/
|
|
25
|
+
level: number;
|
|
26
|
+
/**
|
|
27
|
+
* The title of the header
|
|
28
|
+
*/
|
|
29
|
+
title: string;
|
|
30
|
+
/**
|
|
31
|
+
* Link of the header
|
|
32
|
+
*
|
|
33
|
+
* Typically using `#${slug}` as the anchor hash
|
|
34
|
+
*/
|
|
35
|
+
link: string;
|
|
36
|
+
/**
|
|
37
|
+
* The children of the header
|
|
38
|
+
*/
|
|
39
|
+
children: MarkdownItHeader[];
|
|
43
40
|
}
|
|
44
|
-
type ResolvePluginOptionsFn = <T extends object, K extends keyof any>(options: T | {
|
|
45
|
-
[P in K]?: T;
|
|
46
|
-
} | undefined, key: K, defaults: T) => T;
|
|
47
|
-
|
|
41
|
+
type ResolvePluginOptionsFn = <T extends object, K extends keyof any>(options: T | { [P in K]?: T; } | undefined, key: K, defaults: T) => T;
|
|
48
42
|
interface ResolveTitleOptions {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Should allow inline HTML tags or not.
|
|
45
|
+
*
|
|
46
|
+
* If the result is going to be used as Vue template, it should allow inline
|
|
47
|
+
* HTML tags so that Vue custom components would be kept.
|
|
48
|
+
*/
|
|
49
|
+
shouldAllowHtml: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Should escape the text content or not.
|
|
52
|
+
*
|
|
53
|
+
* If the result is going to be used in HTML directly, it should be escaped
|
|
54
|
+
* so that the text content won't be wrongly treated as HTML tags.
|
|
55
|
+
*/
|
|
56
|
+
shouldEscapeText: boolean;
|
|
63
57
|
}
|
|
64
58
|
/**
|
|
65
59
|
* Extracts plain heading text from a markdown-it inline token.
|
|
@@ -69,28 +63,27 @@ interface ResolveTitleOptions {
|
|
|
69
63
|
* are ignored so the title remains human-readable.
|
|
70
64
|
*/
|
|
71
65
|
declare const resolveTitleFromToken: (token: Token, { shouldAllowHtml, shouldEscapeText }: ResolveTitleOptions) => string;
|
|
72
|
-
|
|
73
66
|
interface ResolveHeadersOptions extends ResolveTitleOptions {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Heading level that going to be resolved
|
|
69
|
+
*/
|
|
70
|
+
level: number[];
|
|
71
|
+
/**
|
|
72
|
+
* Should allow headers inside nested blocks or not
|
|
73
|
+
*
|
|
74
|
+
* If set to `true`, headers inside blockquote, list, etc. would also be resolved.
|
|
75
|
+
*/
|
|
76
|
+
shouldAllowNested: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* A custom slugification function
|
|
79
|
+
*
|
|
80
|
+
* Would be ignored if the `id` attr of the token is set.
|
|
81
|
+
*/
|
|
82
|
+
slugify?: (str: string) => string;
|
|
83
|
+
/**
|
|
84
|
+
* A function for formatting headings
|
|
85
|
+
*/
|
|
86
|
+
format?: (str: string) => string | undefined;
|
|
94
87
|
}
|
|
95
88
|
/**
|
|
96
89
|
* Builds a nested heading tree from markdown-it heading tokens.
|
|
@@ -98,16 +91,14 @@ interface ResolveHeadersOptions extends ResolveTitleOptions {
|
|
|
98
91
|
* Existing heading `id` attributes are preserved. When a heading has no `id`,
|
|
99
92
|
* the configured `slugify` function creates one from the resolved heading text.
|
|
100
93
|
*/
|
|
101
|
-
declare const resolveHeadersFromTokens: (tokens: Token[], { level, shouldAllowHtml, shouldAllowNested, shouldEscapeText, slugify, format
|
|
102
|
-
|
|
94
|
+
declare const resolveHeadersFromTokens: (tokens: Token[], { level, shouldAllowHtml, shouldAllowNested, shouldEscapeText, slugify, format }?: Partial<ResolveHeadersOptions>) => MarkdownItHeader[];
|
|
103
95
|
/**
|
|
104
96
|
* Converts arbitrary heading text into a stable URL-friendly slug.
|
|
105
97
|
*
|
|
106
98
|
* The result is lowercase, accent-free, hyphen-separated, and safe to use as a
|
|
107
99
|
* generated Markdown heading id.
|
|
108
100
|
*/
|
|
109
|
-
declare const slugify: (str: string) => string;
|
|
110
|
-
|
|
101
|
+
declare const slugify$1: (str: string) => string;
|
|
111
102
|
/**
|
|
112
103
|
* Resolves plugin options from either a direct options object or a nested
|
|
113
104
|
* package-level options bag.
|
|
@@ -116,9 +107,5 @@ declare const slugify: (str: string) => string;
|
|
|
116
107
|
* or through a shared md-plugins config object keyed by plugin name. This helper
|
|
117
108
|
* supports both shapes while applying default values.
|
|
118
109
|
*/
|
|
119
|
-
declare function resolvePluginOptions<T extends object, K extends keyof any>(options: T | {
|
|
120
|
-
|
|
121
|
-
} | undefined, key: K, defaults: T): T;
|
|
122
|
-
|
|
123
|
-
export { htmlEscape, htmlUnescape, resolveHeadersFromTokens, resolvePluginOptions, resolveTitleFromToken, slugify };
|
|
124
|
-
export type { MarkdownItEnv, MarkdownItHeader, ResolveHeadersOptions, ResolvePluginOptionsFn, ResolveTitleOptions };
|
|
110
|
+
declare function resolvePluginOptions<T extends object, K extends keyof any>(options: T | { [key in K]?: T; } | undefined, key: K, defaults: T): T;
|
|
111
|
+
export { type MarkdownItEnv, type MarkdownItHeader, ResolveHeadersOptions, type ResolvePluginOptionsFn, ResolveTitleOptions, htmlEscape, htmlUnescape, resolveHeadersFromTokens, resolvePluginOptions, resolveTitleFromToken, slugify$1 as slugify };
|
package/dist/index.mjs
CHANGED
|
@@ -1,103 +1,102 @@
|
|
|
1
1
|
const htmlEscapeMap = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"&": "&",
|
|
3
|
+
"<": "<",
|
|
4
|
+
">": ">",
|
|
5
|
+
"'": "'",
|
|
6
|
+
"\"": """
|
|
7
7
|
};
|
|
8
8
|
const htmlEscapeRegexp = /[&<>'"]/g;
|
|
9
|
+
|
|
9
10
|
const htmlEscape = (str) => str.replace(htmlEscapeRegexp, (char) => htmlEscapeMap[char]);
|
|
10
11
|
|
|
11
12
|
const htmlUnescapeMap = {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
"&": "&",
|
|
14
|
+
"&": "&",
|
|
15
|
+
"<": "<",
|
|
16
|
+
"<": "<",
|
|
17
|
+
">": ">",
|
|
18
|
+
">": ">",
|
|
19
|
+
"'": "'",
|
|
20
|
+
"'": "'",
|
|
21
|
+
""": "\"",
|
|
22
|
+
""": "\""
|
|
22
23
|
};
|
|
23
24
|
const htmlUnescapeRegexp = /&(amp|#38|lt|#60|gt|#62|apos|#39|quot|#34);/g;
|
|
25
|
+
|
|
24
26
|
const htmlUnescape = (str) => str.replace(htmlUnescapeRegexp, (char) => htmlUnescapeMap[char]);
|
|
25
27
|
|
|
28
|
+
|
|
26
29
|
const resolveTitleFromToken = (token, { shouldAllowHtml, shouldEscapeText }) => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return `${result}${item.content}`;
|
|
43
|
-
}, "").trim();
|
|
30
|
+
const children = token.children ?? [];
|
|
31
|
+
const titleTokenTypes = [
|
|
32
|
+
"text",
|
|
33
|
+
"emoji",
|
|
34
|
+
"code_inline"
|
|
35
|
+
];
|
|
36
|
+
if (shouldAllowHtml) titleTokenTypes.push("html_inline");
|
|
37
|
+
return children.filter((item) => titleTokenTypes.includes(item.type) && !item.meta?.isPermalinkSymbol).reduce((result, item) => {
|
|
38
|
+
if (shouldEscapeText) {
|
|
39
|
+
if (item.type === "code_inline" || item.type === "text") return `${result}${htmlEscape(item.content)}`;
|
|
40
|
+
}
|
|
41
|
+
return `${result}${item.content}`;
|
|
42
|
+
}, "").trim();
|
|
44
43
|
};
|
|
45
44
|
|
|
46
45
|
const andRE = /&/g;
|
|
47
46
|
const rCombining = /[\u0300-\u036F]/g;
|
|
48
47
|
const rControl = /[\u0000-\u001f]/g;
|
|
49
48
|
const rSpecial = /[\s~`!@#$%^&*()\-_+=[\]{}|\\;:"'“”‘’<>,.?/]+/g;
|
|
49
|
+
|
|
50
50
|
const slugify = (str) => str.trim().replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase().normalize("NFKD").replace(rCombining, "").replace(andRE, "-and-").replace(rControl, "-").replace(rSpecial, "-").replace(/[^a-z0-9-]+/g, "").replace(/([a-z])(\d)/g, "$1-$2").replace(/(\d)([a-z])/g, "$1-$2").replace(/-{2,}/g, "-").replace(/(^-|-$)/g, "").replace(/^(\d)/, "_$1");
|
|
51
51
|
|
|
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
|
-
id: slug,
|
|
89
|
-
link: `#${slug}`,
|
|
90
|
-
children: []
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
return headers;
|
|
52
|
+
|
|
53
|
+
const resolveHeadersFromTokens = (tokens, { level = [
|
|
54
|
+
1,
|
|
55
|
+
2,
|
|
56
|
+
3
|
|
57
|
+
], shouldAllowHtml = false, shouldAllowNested = false, shouldEscapeText = false, slugify: slugify$1 = slugify, format = (str) => str } = {}) => {
|
|
58
|
+
const headers = [];
|
|
59
|
+
const stack = [];
|
|
60
|
+
|
|
61
|
+
const pushHeader = (header) => {
|
|
62
|
+
while (stack.length > 0 && header.level <= stack[0].level) stack.shift();
|
|
63
|
+
if (stack.length === 0) headers.push(header);
|
|
64
|
+
else stack[0].children.push(header);
|
|
65
|
+
stack.unshift(header);
|
|
66
|
+
};
|
|
67
|
+
tokens.forEach((token, i) => {
|
|
68
|
+
if (token.type !== "heading_open") return;
|
|
69
|
+
if (token.level !== 0 && !shouldAllowNested) return;
|
|
70
|
+
const headerLevel = Number.parseInt(token.tag.slice(1), 10);
|
|
71
|
+
if (!level.includes(headerLevel)) return;
|
|
72
|
+
const nextToken = tokens[i + 1];
|
|
73
|
+
if (!nextToken) return;
|
|
74
|
+
const title = resolveTitleFromToken(nextToken, {
|
|
75
|
+
shouldAllowHtml,
|
|
76
|
+
shouldEscapeText
|
|
77
|
+
});
|
|
78
|
+
const slug = token.attrGet("id") ?? slugify$1(title);
|
|
79
|
+
pushHeader({
|
|
80
|
+
level: headerLevel,
|
|
81
|
+
title: format(title) ?? title,
|
|
82
|
+
id: slug,
|
|
83
|
+
link: `#${slug}`,
|
|
84
|
+
children: []
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
return headers;
|
|
94
88
|
};
|
|
95
89
|
|
|
90
|
+
|
|
96
91
|
function resolvePluginOptions(options, key, defaults) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
92
|
+
if (options && typeof options === "object" && key in options) return {
|
|
93
|
+
...defaults,
|
|
94
|
+
...options[key]
|
|
95
|
+
};
|
|
96
|
+
return {
|
|
97
|
+
...defaults,
|
|
98
|
+
...options
|
|
99
|
+
};
|
|
101
100
|
}
|
|
102
101
|
|
|
103
|
-
export { htmlEscape, htmlUnescape, resolveHeadersFromTokens, resolvePluginOptions, resolveTitleFromToken, slugify };
|
|
102
|
+
export { htmlEscape, htmlUnescape, resolveHeadersFromTokens, resolvePluginOptions, resolveTitleFromToken, slugify };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@md-plugins/shared",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Shared functions and utilities for md-plugins.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"markdown-it",
|
|
@@ -37,13 +37,13 @@
|
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/markdown-it": "^14.1.2",
|
|
40
|
-
"markdown-it": "^14.
|
|
40
|
+
"markdown-it": "^14.3.0"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"markdown-it": "^14.2.0"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
|
-
"build": "
|
|
46
|
+
"build": "obuild && node ../../scripts/ensure-obuild-types.mjs",
|
|
47
47
|
"clean": "rm -rf dist/ node_modules/",
|
|
48
48
|
"test": "vitest"
|
|
49
49
|
}
|