@md-plugins/shared 0.1.0-rc.18 → 0.1.0-rc.19

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.mts CHANGED
@@ -1,65 +1,59 @@
1
- import Token from 'markdown-it/lib/token.mjs';
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
- plugins?: Record<string, unknown>;
11
+ plugins?: Record<string, unknown>;
15
12
  }
16
13
  interface MarkdownItHeader {
17
- /**
18
- * The slug of the header
19
- *
20
- * Typically the `id` attr of the header anchor
21
- */
22
- id: string;
23
- /**
24
- * The level of the header
25
- *
26
- * `1` to `6` for `<h1>` to `<h6>`
27
- */
28
- level: number;
29
- /**
30
- * The title of the header
31
- */
32
- title: string;
33
- /**
34
- * Link of the header
35
- *
36
- * Typically using `#${slug}` as the anchor hash
37
- */
38
- link: string;
39
- /**
40
- * The children of the header
41
- */
42
- children: MarkdownItHeader[];
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
- * Should allow inline HTML tags or not.
51
- *
52
- * If the result is going to be used as Vue template, it should allow inline
53
- * HTML tags so that Vue custom components would be kept.
54
- */
55
- shouldAllowHtml: boolean;
56
- /**
57
- * Should escape the text content or not.
58
- *
59
- * If the result is going to be used in HTML directly, it should be escaped
60
- * so that the text content won't be wrongly treated as HTML tags.
61
- */
62
- shouldEscapeText: boolean;
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.
@@ -68,29 +62,31 @@ interface ResolveTitleOptions {
68
62
  * `heading_open` token. Permalink marker tokens generated by markdown-it-anchor
69
63
  * are ignored so the title remains human-readable.
70
64
  */
71
- declare const resolveTitleFromToken: (token: Token, { shouldAllowHtml, shouldEscapeText }: ResolveTitleOptions) => string;
72
-
65
+ declare const resolveTitleFromToken: (token: Token, {
66
+ shouldAllowHtml,
67
+ shouldEscapeText
68
+ }: ResolveTitleOptions) => string;
73
69
  interface ResolveHeadersOptions extends ResolveTitleOptions {
74
- /**
75
- * Heading level that going to be resolved
76
- */
77
- level: number[];
78
- /**
79
- * Should allow headers inside nested blocks or not
80
- *
81
- * If set to `true`, headers inside blockquote, list, etc. would also be resolved.
82
- */
83
- shouldAllowNested: boolean;
84
- /**
85
- * A custom slugification function
86
- *
87
- * Would be ignored if the `id` attr of the token is set.
88
- */
89
- slugify?: (str: string) => string;
90
- /**
91
- * A function for formatting headings
92
- */
93
- format?: (str: string) => string | undefined;
70
+ /**
71
+ * Heading level that going to be resolved
72
+ */
73
+ level: number[];
74
+ /**
75
+ * Should allow headers inside nested blocks or not
76
+ *
77
+ * If set to `true`, headers inside blockquote, list, etc. would also be resolved.
78
+ */
79
+ shouldAllowNested: boolean;
80
+ /**
81
+ * A custom slugification function
82
+ *
83
+ * Would be ignored if the `id` attr of the token is set.
84
+ */
85
+ slugify?: (str: string) => string;
86
+ /**
87
+ * A function for formatting headings
88
+ */
89
+ format?: (str: string) => string | undefined;
94
90
  }
95
91
  /**
96
92
  * Builds a nested heading tree from markdown-it heading tokens.
@@ -98,16 +94,21 @@ interface ResolveHeadersOptions extends ResolveTitleOptions {
98
94
  * Existing heading `id` attributes are preserved. When a heading has no `id`,
99
95
  * the configured `slugify` function creates one from the resolved heading text.
100
96
  */
101
- declare const resolveHeadersFromTokens: (tokens: Token[], { level, shouldAllowHtml, shouldAllowNested, shouldEscapeText, slugify, format, }?: Partial<ResolveHeadersOptions>) => MarkdownItHeader[];
102
-
97
+ declare const resolveHeadersFromTokens: (tokens: Token[], {
98
+ level,
99
+ shouldAllowHtml,
100
+ shouldAllowNested,
101
+ shouldEscapeText,
102
+ slugify,
103
+ format
104
+ }?: Partial<ResolveHeadersOptions>) => MarkdownItHeader[];
103
105
  /**
104
106
  * Converts arbitrary heading text into a stable URL-friendly slug.
105
107
  *
106
108
  * The result is lowercase, accent-free, hyphen-separated, and safe to use as a
107
109
  * generated Markdown heading id.
108
110
  */
109
- declare const slugify: (str: string) => string;
110
-
111
+ declare const slugify$1: (str: string) => string;
111
112
  /**
112
113
  * Resolves plugin options from either a direct options object or a nested
113
114
  * package-level options bag.
@@ -116,9 +117,5 @@ declare const slugify: (str: string) => string;
116
117
  * or through a shared md-plugins config object keyed by plugin name. This helper
117
118
  * supports both shapes while applying default values.
118
119
  */
119
- declare function resolvePluginOptions<T extends object, K extends keyof any>(options: T | {
120
- [key in K]?: T;
121
- } | undefined, key: K, defaults: T): T;
122
-
123
- export { htmlEscape, htmlUnescape, resolveHeadersFromTokens, resolvePluginOptions, resolveTitleFromToken, slugify };
124
- export type { MarkdownItEnv, MarkdownItHeader, ResolveHeadersOptions, ResolvePluginOptionsFn, ResolveTitleOptions };
120
+ declare function resolvePluginOptions<T extends object, K extends keyof any>(options: T | { [key in K]?: T } | undefined, key: K, defaults: T): T;
121
+ 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 'markdown-it/lib/token.mjs';
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
- plugins?: Record<string, unknown>;
11
+ plugins?: Record<string, unknown>;
15
12
  }
16
13
  interface MarkdownItHeader {
17
- /**
18
- * The slug of the header
19
- *
20
- * Typically the `id` attr of the header anchor
21
- */
22
- id: string;
23
- /**
24
- * The level of the header
25
- *
26
- * `1` to `6` for `<h1>` to `<h6>`
27
- */
28
- level: number;
29
- /**
30
- * The title of the header
31
- */
32
- title: string;
33
- /**
34
- * Link of the header
35
- *
36
- * Typically using `#${slug}` as the anchor hash
37
- */
38
- link: string;
39
- /**
40
- * The children of the header
41
- */
42
- children: MarkdownItHeader[];
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
- * Should allow inline HTML tags or not.
51
- *
52
- * If the result is going to be used as Vue template, it should allow inline
53
- * HTML tags so that Vue custom components would be kept.
54
- */
55
- shouldAllowHtml: boolean;
56
- /**
57
- * Should escape the text content or not.
58
- *
59
- * If the result is going to be used in HTML directly, it should be escaped
60
- * so that the text content won't be wrongly treated as HTML tags.
61
- */
62
- shouldEscapeText: boolean;
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.
@@ -68,29 +62,31 @@ interface ResolveTitleOptions {
68
62
  * `heading_open` token. Permalink marker tokens generated by markdown-it-anchor
69
63
  * are ignored so the title remains human-readable.
70
64
  */
71
- declare const resolveTitleFromToken: (token: Token, { shouldAllowHtml, shouldEscapeText }: ResolveTitleOptions) => string;
72
-
65
+ declare const resolveTitleFromToken: (token: Token, {
66
+ shouldAllowHtml,
67
+ shouldEscapeText
68
+ }: ResolveTitleOptions) => string;
73
69
  interface ResolveHeadersOptions extends ResolveTitleOptions {
74
- /**
75
- * Heading level that going to be resolved
76
- */
77
- level: number[];
78
- /**
79
- * Should allow headers inside nested blocks or not
80
- *
81
- * If set to `true`, headers inside blockquote, list, etc. would also be resolved.
82
- */
83
- shouldAllowNested: boolean;
84
- /**
85
- * A custom slugification function
86
- *
87
- * Would be ignored if the `id` attr of the token is set.
88
- */
89
- slugify?: (str: string) => string;
90
- /**
91
- * A function for formatting headings
92
- */
93
- format?: (str: string) => string | undefined;
70
+ /**
71
+ * Heading level that going to be resolved
72
+ */
73
+ level: number[];
74
+ /**
75
+ * Should allow headers inside nested blocks or not
76
+ *
77
+ * If set to `true`, headers inside blockquote, list, etc. would also be resolved.
78
+ */
79
+ shouldAllowNested: boolean;
80
+ /**
81
+ * A custom slugification function
82
+ *
83
+ * Would be ignored if the `id` attr of the token is set.
84
+ */
85
+ slugify?: (str: string) => string;
86
+ /**
87
+ * A function for formatting headings
88
+ */
89
+ format?: (str: string) => string | undefined;
94
90
  }
95
91
  /**
96
92
  * Builds a nested heading tree from markdown-it heading tokens.
@@ -98,16 +94,21 @@ interface ResolveHeadersOptions extends ResolveTitleOptions {
98
94
  * Existing heading `id` attributes are preserved. When a heading has no `id`,
99
95
  * the configured `slugify` function creates one from the resolved heading text.
100
96
  */
101
- declare const resolveHeadersFromTokens: (tokens: Token[], { level, shouldAllowHtml, shouldAllowNested, shouldEscapeText, slugify, format, }?: Partial<ResolveHeadersOptions>) => MarkdownItHeader[];
102
-
97
+ declare const resolveHeadersFromTokens: (tokens: Token[], {
98
+ level,
99
+ shouldAllowHtml,
100
+ shouldAllowNested,
101
+ shouldEscapeText,
102
+ slugify,
103
+ format
104
+ }?: Partial<ResolveHeadersOptions>) => MarkdownItHeader[];
103
105
  /**
104
106
  * Converts arbitrary heading text into a stable URL-friendly slug.
105
107
  *
106
108
  * The result is lowercase, accent-free, hyphen-separated, and safe to use as a
107
109
  * generated Markdown heading id.
108
110
  */
109
- declare const slugify: (str: string) => string;
110
-
111
+ declare const slugify$1: (str: string) => string;
111
112
  /**
112
113
  * Resolves plugin options from either a direct options object or a nested
113
114
  * package-level options bag.
@@ -116,9 +117,5 @@ declare const slugify: (str: string) => string;
116
117
  * or through a shared md-plugins config object keyed by plugin name. This helper
117
118
  * supports both shapes while applying default values.
118
119
  */
119
- declare function resolvePluginOptions<T extends object, K extends keyof any>(options: T | {
120
- [key in K]?: T;
121
- } | undefined, key: K, defaults: T): T;
122
-
123
- export { htmlEscape, htmlUnescape, resolveHeadersFromTokens, resolvePluginOptions, resolveTitleFromToken, slugify };
124
- export type { MarkdownItEnv, MarkdownItHeader, ResolveHeadersOptions, ResolvePluginOptionsFn, ResolveTitleOptions };
120
+ declare function resolvePluginOptions<T extends object, K extends keyof any>(options: T | { [key in K]?: T } | undefined, key: K, defaults: T): T;
121
+ 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
- "&": "&amp;",
3
- "<": "&lt;",
4
- ">": "&gt;",
5
- "'": "&#39;",
6
- '"': "&quot;"
2
+ "&": "&amp;",
3
+ "<": "&lt;",
4
+ ">": "&gt;",
5
+ "'": "&#39;",
6
+ "\"": "&quot;"
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
- "&amp;": "&",
13
- "&#38;": "&",
14
- "&lt;": "<",
15
- "&#60;": "<",
16
- "&gt;": ">",
17
- "&#62;": ">",
18
- "&apos;": "'",
19
- "&#39;": "'",
20
- "&quot;": '"',
21
- "&#34;": '"'
13
+ "&amp;": "&",
14
+ "&#38;": "&",
15
+ "&lt;": "<",
16
+ "&#60;": "<",
17
+ "&gt;": ">",
18
+ "&#62;": ">",
19
+ "&apos;": "'",
20
+ "&#39;": "'",
21
+ "&quot;": "\"",
22
+ "&#34;": "\""
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
- const children = token.children ?? [];
28
- const titleTokenTypes = ["text", "emoji", "code_inline"];
29
- if (shouldAllowHtml) {
30
- titleTokenTypes.push("html_inline");
31
- }
32
- const titleTokens = children.filter(
33
- (item) => titleTokenTypes.includes(item.type) && // filter permalink symbol that generated by markdown-it-anchor
34
- !item.meta?.isPermalinkSymbol
35
- );
36
- return titleTokens.reduce((result, item) => {
37
- if (shouldEscapeText) {
38
- if (item.type === "code_inline" || item.type === "text") {
39
- return `${result}${htmlEscape(item.content)}`;
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
- const resolveHeadersFromTokens = (tokens, {
53
- level = [1, 2, 3],
54
- shouldAllowHtml = false,
55
- shouldAllowNested = false,
56
- shouldEscapeText = false,
57
- slugify: slugify$1 = slugify,
58
- format = (str) => str
59
- } = {}) => {
60
- const headers = [];
61
- const stack = [];
62
- const pushHeader = (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
- } else {
69
- stack[0].children.push(header);
70
- }
71
- stack.unshift(header);
72
- };
73
- tokens.forEach((token, i) => {
74
- if (token.type !== "heading_open") return;
75
- if (token.level !== 0 && !shouldAllowNested) return;
76
- const headerLevel = Number.parseInt(token.tag.slice(1), 10);
77
- if (!level.includes(headerLevel)) return;
78
- const nextToken = tokens[i + 1];
79
- if (!nextToken) return;
80
- const title = resolveTitleFromToken(nextToken, {
81
- shouldAllowHtml,
82
- shouldEscapeText
83
- });
84
- const slug = token.attrGet("id") ?? slugify$1(title);
85
- pushHeader({
86
- level: headerLevel,
87
- title: format(title) ?? title,
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
- if (options && typeof options === "object" && key in options) {
98
- return { ...defaults, ...options[key] };
99
- }
100
- return { ...defaults, ...options };
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": "0.1.0-rc.18",
3
+ "version": "0.1.0-rc.19",
4
4
  "description": "Shared functions and utilities for md-plugins.",
5
5
  "keywords": [
6
6
  "markdown-it",
@@ -43,7 +43,7 @@
43
43
  "markdown-it": "^14.2.0"
44
44
  },
45
45
  "scripts": {
46
- "build": "unbuild",
46
+ "build": "obuild && node ../../scripts/ensure-obuild-types.mjs",
47
47
  "clean": "rm -rf dist/ node_modules/",
48
48
  "test": "vitest"
49
49
  }