@mdit-vue/shared 0.6.0 → 0.8.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 CHANGED
@@ -27,10 +27,7 @@ const htmlUnescapeMap = {
27
27
  const htmlUnescapeRegexp = /&(amp|#38|lt|#60|gt|#62|apos|#39|quot|#34);/g;
28
28
  const htmlUnescape = (str) => str.replace(htmlUnescapeRegexp, (char) => htmlUnescapeMap[char]);
29
29
 
30
- const resolveTitleFromToken = (token, {
31
- shouldAllowHtml,
32
- shouldEscapeText
33
- }) => {
30
+ const resolveTitleFromToken = (token, { shouldAllowHtml, shouldEscapeText }) => {
34
31
  const children = token.children ?? [];
35
32
  const titleTokenTypes = ["text", "emoji", "code_inline"];
36
33
  if (shouldAllowHtml) {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { MarkdownItHeader } from '@mdit-vue/types';
2
- import Token from 'markdown-it/lib/token';
2
+ import Token from 'markdown-it/lib/token.js';
3
3
 
4
4
  /**
5
5
  * Escape html chars
@@ -11,30 +11,53 @@ declare const htmlEscape: (str: string) => string;
11
11
  */
12
12
  declare const htmlUnescape: (str: string) => string;
13
13
 
14
- /**
15
- * Resolve headers from markdown-it tokens
16
- */
17
- declare const resolveHeadersFromTokens: (tokens: Token[], { level, shouldAllowHtml, shouldEscapeText, slugify, format, }: {
18
- level: number[];
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
+ */
19
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
+ */
20
28
  shouldEscapeText: boolean;
21
- slugify: (str: string) => string;
22
- format?: ((str: string) => string) | undefined;
23
- }) => MarkdownItHeader[];
24
-
29
+ }
25
30
  /**
26
31
  * Resolve header title from markdown-it token
27
32
  *
28
33
  * Typically using the next token of `heading_open` token
29
34
  */
30
- declare const resolveTitleFromToken: (token: Token, { shouldAllowHtml, shouldEscapeText, }: {
31
- shouldAllowHtml: boolean;
32
- shouldEscapeText: boolean;
33
- }) => string;
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
+ * A custom slugification function
44
+ *
45
+ * Would be ignored if the `id` attr of the token is set.
46
+ */
47
+ slugify: (str: string) => string;
48
+ /**
49
+ * A function for formatting headings
50
+ */
51
+ format?: (str: string) => string;
52
+ }
53
+ /**
54
+ * Resolve headers from markdown-it tokens
55
+ */
56
+ declare const resolveHeadersFromTokens: (tokens: Token[], { level, shouldAllowHtml, shouldEscapeText, slugify, format, }: ResolveHeadersOptions) => MarkdownItHeader[];
34
57
 
35
58
  /**
36
59
  * Default slugification function
37
60
  */
38
61
  declare const slugify: (str: string) => string;
39
62
 
40
- export { htmlEscape, htmlUnescape, resolveHeadersFromTokens, resolveTitleFromToken, slugify };
63
+ export { ResolveHeadersOptions, ResolveTitleOptions, htmlEscape, htmlUnescape, resolveHeadersFromTokens, resolveTitleFromToken, slugify };
package/dist/index.mjs CHANGED
@@ -23,10 +23,7 @@ const htmlUnescapeMap = {
23
23
  const htmlUnescapeRegexp = /&(amp|#38|lt|#60|gt|#62|apos|#39|quot|#34);/g;
24
24
  const htmlUnescape = (str) => str.replace(htmlUnescapeRegexp, (char) => htmlUnescapeMap[char]);
25
25
 
26
- const resolveTitleFromToken = (token, {
27
- shouldAllowHtml,
28
- shouldEscapeText
29
- }) => {
26
+ const resolveTitleFromToken = (token, { shouldAllowHtml, shouldEscapeText }) => {
30
27
  const children = token.children ?? [];
31
28
  const titleTokenTypes = ["text", "emoji", "code_inline"];
32
29
  if (shouldAllowHtml) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mdit-vue/shared",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "Shared utils and types of mdit-vue",
5
5
  "keywords": [
6
6
  "markdown-it",
@@ -17,6 +17,7 @@
17
17
  },
18
18
  "license": "MIT",
19
19
  "author": "meteorlxy <meteor.lxy@foxmail.com>",
20
+ "type": "module",
20
21
  "exports": {
21
22
  ".": {
22
23
  "types": "./dist/index.d.ts",
@@ -27,22 +28,25 @@
27
28
  "main": "./dist/index.cjs",
28
29
  "module": "./dist/index.mjs",
29
30
  "types": "./dist/index.d.ts",
31
+ "files": [
32
+ "./dist"
33
+ ],
30
34
  "scripts": {
31
35
  "build": "unbuild",
32
36
  "test": "vitest"
33
37
  },
34
38
  "dependencies": {
35
- "@mdit-vue/types": "0.6.0",
39
+ "@mdit-vue/types": "0.8.0",
36
40
  "@types/markdown-it": "^12.2.3",
37
41
  "markdown-it": "^13.0.1"
38
42
  },
39
43
  "devDependencies": {
40
- "c8": "^7.11.3",
41
- "unbuild": "^0.7.4",
42
- "vitest": "^0.18.0"
44
+ "c8": "^7.12.0",
45
+ "unbuild": "^0.7.6",
46
+ "vitest": "^0.18.1"
43
47
  },
44
48
  "publishConfig": {
45
49
  "access": "public"
46
50
  },
47
- "gitHead": "654a3a4d52f4fb9711bf5f7ba3674ff58ec663bf"
51
+ "gitHead": "7fd357a18b8bcc347cf17e2e78da3b3ed4242e58"
48
52
  }
package/CHANGELOG.md DELETED
@@ -1,31 +0,0 @@
1
- # Change Log
2
-
3
- All notable changes to this project will be documented in this file.
4
- See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
-
6
- # [0.6.0](https://github.com/mdit-vue/mdit-vue/compare/v0.5.0...v0.6.0) (2022-07-11)
7
-
8
- ### Features
9
-
10
- - **types:** extract types from shared package ([5fc56ce](https://github.com/mdit-vue/mdit-vue/commit/5fc56ce6439159584e09e13ca9a6e87abe8f4389))
11
-
12
- # [0.5.0](https://github.com/mdit-vue/mdit-vue/compare/v0.4.0...v0.5.0) (2022-07-06)
13
-
14
- **Note:** Version bump only for package @mdit-vue/shared
15
-
16
- # [0.4.0](https://github.com/mdit-vue/mdit-vue/compare/v0.3.1...v0.4.0) (2022-07-02)
17
-
18
- **Note:** Version bump only for package @mdit-vue/shared
19
-
20
- # [0.3.0](https://github.com/mdit-vue/mdit-vue/compare/v0.2.0...v0.3.0) (2022-06-25)
21
-
22
- ### Features
23
-
24
- - **plugin-toc:** add toc plugin ([e64cc2c](https://github.com/mdit-vue/mdit-vue/commit/e64cc2ce3bbc89999d373f8a00fb3a049d6af58f))
25
- - **shared:** add html escape and unescape utils ([e1103c2](https://github.com/mdit-vue/mdit-vue/commit/e1103c21998aec77c67cdefd3cbb4994c127124c))
26
-
27
- # [0.2.0](https://github.com/mdit-vue/mdit-vue/compare/v0.1.1...v0.2.0) (2022-06-23)
28
-
29
- ### Features
30
-
31
- - **shared:** add shared package ([9e36bdc](https://github.com/mdit-vue/mdit-vue/commit/9e36bdce8635ae048e8b0f2cc2d02cc0448ad09f))
package/build.config.ts DELETED
@@ -1,11 +0,0 @@
1
- import { defineBuildConfig } from 'unbuild';
2
-
3
- export default defineBuildConfig({
4
- clean: true,
5
- declaration: true,
6
- entries: ['src/index'],
7
- rollup: {
8
- emitCJS: true,
9
- inlineDependencies: false,
10
- },
11
- });
@@ -1,18 +0,0 @@
1
- const htmlEscapeMap = {
2
- '&': '&amp;',
3
- '<': '&lt;',
4
- '>': '&gt;',
5
- "'": '&#39;',
6
- '"': '&quot;',
7
- };
8
-
9
- const htmlEscapeRegexp = /[&<>'"]/g;
10
-
11
- /**
12
- * Escape html chars
13
- */
14
- export const htmlEscape = (str: string): string =>
15
- str.replace(
16
- htmlEscapeRegexp,
17
- (char) => htmlEscapeMap[char as keyof typeof htmlEscapeMap],
18
- );
@@ -1,23 +0,0 @@
1
- const htmlUnescapeMap = {
2
- '&amp;': '&',
3
- '&#38;': '&',
4
- '&lt;': '<',
5
- '&#60;': '<',
6
- '&gt;': '>',
7
- '&#62;': '>',
8
- '&apos;': "'",
9
- '&#39;': "'",
10
- '&quot;': '"',
11
- '&#34;': '"',
12
- };
13
-
14
- const htmlUnescapeRegexp = /&(amp|#38|lt|#60|gt|#62|apos|#39|quot|#34);/g;
15
-
16
- /**
17
- * Unescape html chars
18
- */
19
- export const htmlUnescape = (str: string): string =>
20
- str.replace(
21
- htmlUnescapeRegexp,
22
- (char) => htmlUnescapeMap[char as keyof typeof htmlUnescapeMap],
23
- );
package/src/index.ts DELETED
@@ -1,5 +0,0 @@
1
- export * from './html-escape';
2
- export * from './html-unescape';
3
- export * from './resolve-headers-from-tokens';
4
- export * from './resolve-title-from-token';
5
- export * from './slugify';
@@ -1,88 +0,0 @@
1
- import type { MarkdownItHeader } from '@mdit-vue/types';
2
- import type Token from 'markdown-it/lib/token';
3
- import { resolveTitleFromToken } from './resolve-title-from-token';
4
-
5
- /**
6
- * Resolve headers from markdown-it tokens
7
- */
8
- export const resolveHeadersFromTokens = (
9
- tokens: Token[],
10
- {
11
- level,
12
- shouldAllowHtml,
13
- shouldEscapeText,
14
- slugify,
15
- format,
16
- }: {
17
- level: number[];
18
- shouldAllowHtml: boolean;
19
- shouldEscapeText: boolean;
20
- slugify: (str: string) => string;
21
- format?: (str: string) => string;
22
- },
23
- ): MarkdownItHeader[] => {
24
- // store the result of headers
25
- const headers: MarkdownItHeader[] = [];
26
-
27
- // a temp headers stack for generating the headers tree
28
- const stack: MarkdownItHeader[] = [];
29
-
30
- // push a header to the headers tree
31
- const push = (header: MarkdownItHeader): void => {
32
- while (stack.length !== 0 && header.level <= stack[0].level) {
33
- stack.shift();
34
- }
35
-
36
- if (stack.length === 0) {
37
- headers.push(header);
38
- stack.push(header);
39
- } else {
40
- stack[0].children.push(header);
41
- stack.unshift(header);
42
- }
43
- };
44
-
45
- tokens.forEach((_, idx) => {
46
- const token = tokens[idx];
47
-
48
- // if the token type does not match, skip
49
- if (token?.type !== 'heading_open') {
50
- return;
51
- }
52
-
53
- // get the level from the tag, h1 -> 1
54
- const headerLevel = Number.parseInt(token.tag.slice(1), 10);
55
-
56
- // if the level should not be extracted, skip
57
- if (!level.includes(headerLevel)) {
58
- return;
59
- }
60
-
61
- // the next token of 'heading_open' contains the heading content
62
- const nextToken = tokens[idx + 1];
63
-
64
- // if the next token does not exist, skip
65
- if (!nextToken) {
66
- return;
67
- }
68
-
69
- const title = resolveTitleFromToken(nextToken, {
70
- shouldAllowHtml,
71
- shouldEscapeText,
72
- });
73
-
74
- // the id of the heading anchor is the slugify result of markdown-it-anchor
75
- // if the id does not exist, slugify the title ourselves
76
- const slug = token.attrGet('id') ?? slugify(title);
77
-
78
- // push the header to tree
79
- push({
80
- level: headerLevel,
81
- title: format?.(title) ?? title,
82
- slug,
83
- children: [],
84
- });
85
- });
86
-
87
- return headers;
88
- };
@@ -1,52 +0,0 @@
1
- import type Token from 'markdown-it/lib/token';
2
- import { htmlEscape } from './html-escape';
3
-
4
- /**
5
- * Resolve header title from markdown-it token
6
- *
7
- * Typically using the next token of `heading_open` token
8
- */
9
- export const resolveTitleFromToken = (
10
- token: Token,
11
- {
12
- shouldAllowHtml,
13
- shouldEscapeText,
14
- }: {
15
- shouldAllowHtml: boolean;
16
- shouldEscapeText: boolean;
17
- },
18
- ): string => {
19
- // children of the token contains the parsed result of the heading title
20
- const children = token.children ?? [];
21
-
22
- // type of tokens to be included in the heading title
23
- const titleTokenTypes = ['text', 'emoji', 'code_inline'];
24
-
25
- // include 'html_inline' or not
26
- if (shouldAllowHtml) {
27
- titleTokenTypes.push('html_inline');
28
- }
29
-
30
- // filter the token type to be included in the title
31
- const titleTokens = children.filter(
32
- (item) =>
33
- titleTokenTypes.includes(item.type) &&
34
- // filter permalink symbol that generated by markdown-it-anchor
35
- !item.meta?.isPermalinkSymbol,
36
- );
37
-
38
- // get title from tokens
39
- return titleTokens
40
- .reduce((result, item) => {
41
- if (shouldEscapeText) {
42
- // escape the content of 'code_inline' and 'text'
43
- if (item.type === 'code_inline' || item.type === 'text') {
44
- return `${result}${htmlEscape(item.content)}`;
45
- }
46
- }
47
-
48
- // keep the content of 'emoji' and 'html_inline'
49
- return `${result}${item.content}`;
50
- }, '')
51
- .trim();
52
- };
package/src/slugify.ts DELETED
@@ -1,25 +0,0 @@
1
- // eslint-disable-next-line no-control-regex
2
- const rControl = /[\u0000-\u001f]/g;
3
- const rSpecial = /[\s~`!@#$%^&*()\-_+=[\]{}|\\;:"'“”‘’<>,.?/]+/g;
4
- const rCombining = /[\u0300-\u036F]/g;
5
-
6
- /**
7
- * Default slugification function
8
- */
9
- export const slugify = (str: string): string =>
10
- str
11
- .normalize('NFKD')
12
- // Remove accents
13
- .replace(rCombining, '')
14
- // Remove control characters
15
- .replace(rControl, '')
16
- // Replace special characters
17
- .replace(rSpecial, '-')
18
- // Remove continuos separators
19
- .replace(/-{2,}/g, '-')
20
- // Remove prefixing and trailing separators
21
- .replace(/^-+|-+$/g, '')
22
- // ensure it doesn't start with a number (#121)
23
- .replace(/^(\d)/, '_$1')
24
- // lowercase
25
- .toLowerCase();
@@ -1,14 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { htmlEscape } from '../src';
3
-
4
- const testCases = [['&<>\'"', '&amp;&lt;&gt;&#39;&quot;']];
5
-
6
- describe('shared > html-escape', () => {
7
- describe('should escape special chars', () => {
8
- testCases.forEach(([source, expected]) => {
9
- it(source, () => {
10
- expect(htmlEscape(source)).toBe(expected);
11
- });
12
- });
13
- });
14
- });
@@ -1,21 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { htmlUnescape } from '../src';
3
-
4
- const testCases = [
5
- ['&amp;&#38;&lt;&#60;&gt;&#62;&apos;&#39;&quot;&#34;', '&&<<>>\'\'""'],
6
- ['&amp;lt;', '&lt;'],
7
- [
8
- '&amp;lt;script&amp;gt;&amp;lt;/script&amp;gt;',
9
- '&lt;script&gt;&lt;/script&gt;',
10
- ],
11
- ];
12
-
13
- describe('shared > html-unescape', () => {
14
- describe('should unescape special chars', () => {
15
- testCases.forEach(([source, expected]) => {
16
- it(source, () => {
17
- expect(htmlUnescape(source)).toBe(expected);
18
- });
19
- });
20
- });
21
- });
@@ -1,35 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { slugify } from '../src';
3
-
4
- const testCases: [string, string][] = [
5
- ['Привет', 'привет'],
6
- ['Лед üäöß', 'лед-uaoß'],
7
- ['hangul 가', 'hangul-가'],
8
- ['ع', 'ع'],
9
- ['džℍΩ', 'dzhω'],
10
- ['カi⁹', 'カi9'],
11
- // ㌀ -> アパート'
12
- ['㌀', decodeURIComponent('%E3%82%A2%E3%83%8F%E3%82%9A%E3%83%BC%E3%83%88')],
13
- ['¼', '_1⁄4'],
14
- ['džℍΩカi⁹¼', 'dzhωカi91⁄4'],
15
- ['Iлtèrnåtïonɑlíƶatï߀ԉ', 'iлternationɑliƶati߀ԉ'],
16
- [
17
- 'Båcòл ípѕùm ðoɭ߀r ѕït aϻèt âùþê aԉᏧ߀üïlɭê ƃëéf culρá fïlèt ϻiǥnòn cuρiᏧatat ut êлim tòлɢùê.',
18
- 'bacoл-ipѕum-ðoɭ߀r-ѕit-aϻet-auþe-aԉꮷ߀uilɭe-ƃeef-culρa-filet-ϻiǥnon-cuρiꮷatat-ut-eлim-toлɢue',
19
- ],
20
- ['ᴎᴑᴅᴇȷʂ', 'ᴎᴑᴅᴇȷʂ'],
21
- ['hambúrguer', 'hamburguer'],
22
- ['hŒllœ', 'hœllœ'],
23
- ['Fußball', 'fußball'],
24
- ['ABCDEFGHIJKLMNOPQRSTUVWXYZé', 'abcdefghijklmnopqrstuvwxyze'],
25
- ];
26
-
27
- describe('shared > slugify', () => {
28
- describe('should slugify string correctly', () => {
29
- testCases.forEach(([source, expected]) => {
30
- it(`${source} => ${expected}`, () => {
31
- expect(slugify(source)).toBe(expected);
32
- });
33
- });
34
- });
35
- });