@mdit-vue/shared 0.7.0 → 0.9.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 +11 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +11 -3
- package/package.json +10 -6
- package/CHANGELOG.md +0 -35
- package/build.config.ts +0 -11
- package/src/html-escape.ts +0 -18
- package/src/html-unescape.ts +0 -23
- package/src/index.ts +0 -5
- package/src/resolve-headers-from-tokens.ts +0 -102
- package/src/resolve-title-from-token.ts +0 -64
- package/src/slugify.ts +0 -25
- package/tests/html-escape.spec.ts +0 -14
- package/tests/html-unescape.spec.ts +0 -21
- package/tests/slugify.spec.ts +0 -35
package/dist/index.cjs
CHANGED
|
@@ -10,7 +10,10 @@ const htmlEscapeMap = {
|
|
|
10
10
|
'"': """
|
|
11
11
|
};
|
|
12
12
|
const htmlEscapeRegexp = /[&<>'"]/g;
|
|
13
|
-
const htmlEscape = (str) => str.replace(
|
|
13
|
+
const htmlEscape = (str) => str.replace(
|
|
14
|
+
htmlEscapeRegexp,
|
|
15
|
+
(char) => htmlEscapeMap[char]
|
|
16
|
+
);
|
|
14
17
|
|
|
15
18
|
const htmlUnescapeMap = {
|
|
16
19
|
"&": "&",
|
|
@@ -25,7 +28,10 @@ const htmlUnescapeMap = {
|
|
|
25
28
|
""": '"'
|
|
26
29
|
};
|
|
27
30
|
const htmlUnescapeRegexp = /&(amp|#38|lt|#60|gt|#62|apos|#39|quot|#34);/g;
|
|
28
|
-
const htmlUnescape = (str) => str.replace(
|
|
31
|
+
const htmlUnescape = (str) => str.replace(
|
|
32
|
+
htmlUnescapeRegexp,
|
|
33
|
+
(char) => htmlUnescapeMap[char]
|
|
34
|
+
);
|
|
29
35
|
|
|
30
36
|
const resolveTitleFromToken = (token, { shouldAllowHtml, shouldEscapeText }) => {
|
|
31
37
|
const children = token.children ?? [];
|
|
@@ -33,7 +39,9 @@ const resolveTitleFromToken = (token, { shouldAllowHtml, shouldEscapeText }) =>
|
|
|
33
39
|
if (shouldAllowHtml) {
|
|
34
40
|
titleTokenTypes.push("html_inline");
|
|
35
41
|
}
|
|
36
|
-
const titleTokens = children.filter(
|
|
42
|
+
const titleTokens = children.filter(
|
|
43
|
+
(item) => titleTokenTypes.includes(item.type) && !item.meta?.isPermalinkSymbol
|
|
44
|
+
);
|
|
37
45
|
return titleTokens.reduce((result, item) => {
|
|
38
46
|
if (shouldEscapeText) {
|
|
39
47
|
if (item.type === "code_inline" || item.type === "text") {
|
package/dist/index.d.ts
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -6,7 +6,10 @@ const htmlEscapeMap = {
|
|
|
6
6
|
'"': """
|
|
7
7
|
};
|
|
8
8
|
const htmlEscapeRegexp = /[&<>'"]/g;
|
|
9
|
-
const htmlEscape = (str) => str.replace(
|
|
9
|
+
const htmlEscape = (str) => str.replace(
|
|
10
|
+
htmlEscapeRegexp,
|
|
11
|
+
(char) => htmlEscapeMap[char]
|
|
12
|
+
);
|
|
10
13
|
|
|
11
14
|
const htmlUnescapeMap = {
|
|
12
15
|
"&": "&",
|
|
@@ -21,7 +24,10 @@ const htmlUnescapeMap = {
|
|
|
21
24
|
""": '"'
|
|
22
25
|
};
|
|
23
26
|
const htmlUnescapeRegexp = /&(amp|#38|lt|#60|gt|#62|apos|#39|quot|#34);/g;
|
|
24
|
-
const htmlUnescape = (str) => str.replace(
|
|
27
|
+
const htmlUnescape = (str) => str.replace(
|
|
28
|
+
htmlUnescapeRegexp,
|
|
29
|
+
(char) => htmlUnescapeMap[char]
|
|
30
|
+
);
|
|
25
31
|
|
|
26
32
|
const resolveTitleFromToken = (token, { shouldAllowHtml, shouldEscapeText }) => {
|
|
27
33
|
const children = token.children ?? [];
|
|
@@ -29,7 +35,9 @@ const resolveTitleFromToken = (token, { shouldAllowHtml, shouldEscapeText }) =>
|
|
|
29
35
|
if (shouldAllowHtml) {
|
|
30
36
|
titleTokenTypes.push("html_inline");
|
|
31
37
|
}
|
|
32
|
-
const titleTokens = children.filter(
|
|
38
|
+
const titleTokens = children.filter(
|
|
39
|
+
(item) => titleTokenTypes.includes(item.type) && !item.meta?.isPermalinkSymbol
|
|
40
|
+
);
|
|
33
41
|
return titleTokens.reduce((result, item) => {
|
|
34
42
|
if (shouldEscapeText) {
|
|
35
43
|
if (item.type === "code_inline" || item.type === "text") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mdit-vue/shared",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.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.
|
|
39
|
+
"@mdit-vue/types": "0.9.0",
|
|
36
40
|
"@types/markdown-it": "^12.2.3",
|
|
37
41
|
"markdown-it": "^13.0.1"
|
|
38
42
|
},
|
|
39
43
|
"devDependencies": {
|
|
40
|
-
"c8": "^7.
|
|
41
|
-
"unbuild": "^0.7.
|
|
42
|
-
"vitest": "^0.
|
|
44
|
+
"c8": "^7.12.0",
|
|
45
|
+
"unbuild": "^0.7.6",
|
|
46
|
+
"vitest": "^0.19.1"
|
|
43
47
|
},
|
|
44
48
|
"publishConfig": {
|
|
45
49
|
"access": "public"
|
|
46
50
|
},
|
|
47
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "4279fc7ac1db0b585ffb395f55a07038af2a7263"
|
|
48
52
|
}
|
package/CHANGELOG.md
DELETED
|
@@ -1,35 +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.7.0](https://github.com/mdit-vue/mdit-vue/compare/v0.6.0...v0.7.0) (2022-07-18)
|
|
7
|
-
|
|
8
|
-
**Note:** Version bump only for package @mdit-vue/shared
|
|
9
|
-
|
|
10
|
-
# [0.6.0](https://github.com/mdit-vue/mdit-vue/compare/v0.5.0...v0.6.0) (2022-07-11)
|
|
11
|
-
|
|
12
|
-
### Features
|
|
13
|
-
|
|
14
|
-
- **types:** extract types from shared package ([5fc56ce](https://github.com/mdit-vue/mdit-vue/commit/5fc56ce6439159584e09e13ca9a6e87abe8f4389))
|
|
15
|
-
|
|
16
|
-
# [0.5.0](https://github.com/mdit-vue/mdit-vue/compare/v0.4.0...v0.5.0) (2022-07-06)
|
|
17
|
-
|
|
18
|
-
**Note:** Version bump only for package @mdit-vue/shared
|
|
19
|
-
|
|
20
|
-
# [0.4.0](https://github.com/mdit-vue/mdit-vue/compare/v0.3.1...v0.4.0) (2022-07-02)
|
|
21
|
-
|
|
22
|
-
**Note:** Version bump only for package @mdit-vue/shared
|
|
23
|
-
|
|
24
|
-
# [0.3.0](https://github.com/mdit-vue/mdit-vue/compare/v0.2.0...v0.3.0) (2022-06-25)
|
|
25
|
-
|
|
26
|
-
### Features
|
|
27
|
-
|
|
28
|
-
- **plugin-toc:** add toc plugin ([e64cc2c](https://github.com/mdit-vue/mdit-vue/commit/e64cc2ce3bbc89999d373f8a00fb3a049d6af58f))
|
|
29
|
-
- **shared:** add html escape and unescape utils ([e1103c2](https://github.com/mdit-vue/mdit-vue/commit/e1103c21998aec77c67cdefd3cbb4994c127124c))
|
|
30
|
-
|
|
31
|
-
# [0.2.0](https://github.com/mdit-vue/mdit-vue/compare/v0.1.1...v0.2.0) (2022-06-23)
|
|
32
|
-
|
|
33
|
-
### Features
|
|
34
|
-
|
|
35
|
-
- **shared:** add shared package ([9e36bdc](https://github.com/mdit-vue/mdit-vue/commit/9e36bdce8635ae048e8b0f2cc2d02cc0448ad09f))
|
package/build.config.ts
DELETED
package/src/html-escape.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
const htmlEscapeMap = {
|
|
2
|
-
'&': '&',
|
|
3
|
-
'<': '<',
|
|
4
|
-
'>': '>',
|
|
5
|
-
"'": ''',
|
|
6
|
-
'"': '"',
|
|
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
|
-
);
|
package/src/html-unescape.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
const htmlUnescapeMap = {
|
|
2
|
-
'&': '&',
|
|
3
|
-
'&': '&',
|
|
4
|
-
'<': '<',
|
|
5
|
-
'<': '<',
|
|
6
|
-
'>': '>',
|
|
7
|
-
'>': '>',
|
|
8
|
-
''': "'",
|
|
9
|
-
''': "'",
|
|
10
|
-
'"': '"',
|
|
11
|
-
'"': '"',
|
|
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,102 +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
|
-
import type { ResolveTitleOptions } from './resolve-title-from-token';
|
|
5
|
-
|
|
6
|
-
export interface ResolveHeadersOptions extends ResolveTitleOptions {
|
|
7
|
-
/**
|
|
8
|
-
* Heading level that going to be resolved
|
|
9
|
-
*/
|
|
10
|
-
level: number[];
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* A custom slugification function
|
|
14
|
-
*
|
|
15
|
-
* Would be ignored if the `id` attr of the token is set.
|
|
16
|
-
*/
|
|
17
|
-
slugify: (str: string) => string;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* A function for formatting headings
|
|
21
|
-
*/
|
|
22
|
-
format?: (str: string) => string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Resolve headers from markdown-it tokens
|
|
27
|
-
*/
|
|
28
|
-
export const resolveHeadersFromTokens = (
|
|
29
|
-
tokens: Token[],
|
|
30
|
-
{
|
|
31
|
-
level,
|
|
32
|
-
shouldAllowHtml,
|
|
33
|
-
shouldEscapeText,
|
|
34
|
-
slugify,
|
|
35
|
-
format,
|
|
36
|
-
}: ResolveHeadersOptions,
|
|
37
|
-
): MarkdownItHeader[] => {
|
|
38
|
-
// store the result of headers
|
|
39
|
-
const headers: MarkdownItHeader[] = [];
|
|
40
|
-
|
|
41
|
-
// a temp headers stack for generating the headers tree
|
|
42
|
-
const stack: MarkdownItHeader[] = [];
|
|
43
|
-
|
|
44
|
-
// push a header to the headers tree
|
|
45
|
-
const push = (header: MarkdownItHeader): void => {
|
|
46
|
-
while (stack.length !== 0 && header.level <= stack[0].level) {
|
|
47
|
-
stack.shift();
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (stack.length === 0) {
|
|
51
|
-
headers.push(header);
|
|
52
|
-
stack.push(header);
|
|
53
|
-
} else {
|
|
54
|
-
stack[0].children.push(header);
|
|
55
|
-
stack.unshift(header);
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
tokens.forEach((_, idx) => {
|
|
60
|
-
const token = tokens[idx];
|
|
61
|
-
|
|
62
|
-
// if the token type does not match, skip
|
|
63
|
-
if (token?.type !== 'heading_open') {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// get the level from the tag, h1 -> 1
|
|
68
|
-
const headerLevel = Number.parseInt(token.tag.slice(1), 10);
|
|
69
|
-
|
|
70
|
-
// if the level should not be extracted, skip
|
|
71
|
-
if (!level.includes(headerLevel)) {
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// the next token of 'heading_open' contains the heading content
|
|
76
|
-
const nextToken = tokens[idx + 1];
|
|
77
|
-
|
|
78
|
-
// if the next token does not exist, skip
|
|
79
|
-
if (!nextToken) {
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const title = resolveTitleFromToken(nextToken, {
|
|
84
|
-
shouldAllowHtml,
|
|
85
|
-
shouldEscapeText,
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
// the id of the heading anchor is the slugify result of markdown-it-anchor
|
|
89
|
-
// if the id does not exist, slugify the title ourselves
|
|
90
|
-
const slug = token.attrGet('id') ?? slugify(title);
|
|
91
|
-
|
|
92
|
-
// push the header to tree
|
|
93
|
-
push({
|
|
94
|
-
level: headerLevel,
|
|
95
|
-
title: format?.(title) ?? title,
|
|
96
|
-
slug,
|
|
97
|
-
children: [],
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
return headers;
|
|
102
|
-
};
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import type Token from 'markdown-it/lib/token';
|
|
2
|
-
import { htmlEscape } from './html-escape';
|
|
3
|
-
|
|
4
|
-
export interface ResolveTitleOptions {
|
|
5
|
-
/**
|
|
6
|
-
* Should allow inline HTML tags or not.
|
|
7
|
-
*
|
|
8
|
-
* If the result is going to be used as Vue template, it should allow inline
|
|
9
|
-
* HTML tags so that Vue custom components would be kept.
|
|
10
|
-
*/
|
|
11
|
-
shouldAllowHtml: boolean;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Should escape the text content or not.
|
|
15
|
-
*
|
|
16
|
-
* If the result is going to be used in HTML directly, it should be escaped
|
|
17
|
-
* so that the text content won't be wrongly treated as HTML tags.
|
|
18
|
-
*/
|
|
19
|
-
shouldEscapeText: boolean;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Resolve header title from markdown-it token
|
|
24
|
-
*
|
|
25
|
-
* Typically using the next token of `heading_open` token
|
|
26
|
-
*/
|
|
27
|
-
export const resolveTitleFromToken = (
|
|
28
|
-
token: Token,
|
|
29
|
-
{ shouldAllowHtml, shouldEscapeText }: ResolveTitleOptions,
|
|
30
|
-
): string => {
|
|
31
|
-
// children of the token contains the parsed result of the heading title
|
|
32
|
-
const children = token.children ?? [];
|
|
33
|
-
|
|
34
|
-
// type of tokens to be included in the heading title
|
|
35
|
-
const titleTokenTypes = ['text', 'emoji', 'code_inline'];
|
|
36
|
-
|
|
37
|
-
// include 'html_inline' or not
|
|
38
|
-
if (shouldAllowHtml) {
|
|
39
|
-
titleTokenTypes.push('html_inline');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// filter the token type to be included in the title
|
|
43
|
-
const titleTokens = children.filter(
|
|
44
|
-
(item) =>
|
|
45
|
-
titleTokenTypes.includes(item.type) &&
|
|
46
|
-
// filter permalink symbol that generated by markdown-it-anchor
|
|
47
|
-
!item.meta?.isPermalinkSymbol,
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
// get title from tokens
|
|
51
|
-
return titleTokens
|
|
52
|
-
.reduce((result, item) => {
|
|
53
|
-
if (shouldEscapeText) {
|
|
54
|
-
// escape the content of 'code_inline' and 'text'
|
|
55
|
-
if (item.type === 'code_inline' || item.type === 'text') {
|
|
56
|
-
return `${result}${htmlEscape(item.content)}`;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// keep the content of 'emoji' and 'html_inline'
|
|
61
|
-
return `${result}${item.content}`;
|
|
62
|
-
}, '')
|
|
63
|
-
.trim();
|
|
64
|
-
};
|
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 = [['&<>\'"', '&<>'"']];
|
|
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
|
-
['&&<<>>''""', '&&<<>>\'\'""'],
|
|
6
|
-
['&lt;', '<'],
|
|
7
|
-
[
|
|
8
|
-
'&lt;script&gt;&lt;/script&gt;',
|
|
9
|
-
'<script></script>',
|
|
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
|
-
});
|
package/tests/slugify.spec.ts
DELETED
|
@@ -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
|
-
});
|