pd-markdown 1.0.0 → 1.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/README.md +293 -0
- package/package.json +68 -1
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/index.d.ts +0 -4
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/index.d.ts.map +0 -1
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/index.js +0 -5
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/index.js.map +0 -1
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/index.d.ts +0 -4
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/index.d.ts.map +0 -1
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/index.js +0 -4
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/index.js.map +0 -1
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/heading.d.ts +0 -6
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/heading.d.ts.map +0 -1
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/heading.js +0 -36
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/heading.js.map +0 -1
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/list.d.ts +0 -14
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/list.d.ts.map +0 -1
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/list.js +0 -18
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/list.js.map +0 -1
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/table.d.ts +0 -27
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/table.d.ts.map +0 -1
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/table.js +0 -37
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/table.js.map +0 -1
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/processor.d.ts +0 -22
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/processor.d.ts.map +0 -1
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/processor.js +0 -95
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/processor.js.map +0 -1
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/types/index.d.ts +0 -55
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/types/index.d.ts.map +0 -1
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/types/index.js +0 -2
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/types/index.js.map +0 -1
- package/packages/parser/__tests__/frontmatter.test.ts +0 -69
- package/packages/parser/__tests__/gfm.test.ts +0 -83
- package/packages/parser/__tests__/processor.test.ts +0 -136
- package/packages/parser/__tests__/transform/heading.test.ts +0 -56
- package/packages/parser/__tests__/transform/list.test.ts +0 -67
- package/packages/parser/__tests__/transform/table.test.ts +0 -85
- package/packages/parser/node_modules/.bin/yaml +0 -17
- package/packages/parser/package.json +0 -38
- package/packages/parser/rollup.config.ts +0 -38
- package/packages/parser/src/index.ts +0 -15
- package/packages/parser/src/plugins/index.ts +0 -3
- package/packages/parser/src/plugins/transform/heading.ts +0 -40
- package/packages/parser/src/plugins/transform/list.ts +0 -29
- package/packages/parser/src/plugins/transform/table.ts +0 -62
- package/packages/parser/src/processor.ts +0 -119
- package/packages/parser/src/types/index.ts +0 -60
- package/packages/parser/tsconfig.json +0 -9
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/ast/query.d.ts +0 -36
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/ast/query.d.ts.map +0 -1
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/ast/query.js +0 -99
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/ast/query.js.map +0 -1
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/ast/traverse.d.ts +0 -22
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/ast/traverse.d.ts.map +0 -1
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/ast/traverse.js +0 -46
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/ast/traverse.js.map +0 -1
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/index.d.ts +0 -7
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/index.d.ts.map +0 -1
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/index.js +0 -8
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/index.js.map +0 -1
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/string/sanitize.d.ts +0 -22
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/string/sanitize.d.ts.map +0 -1
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/string/sanitize.js +0 -140
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/string/sanitize.js.map +0 -1
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/string/slugify.d.ts +0 -16
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/string/slugify.d.ts.map +0 -1
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/string/slugify.js +0 -39
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/string/slugify.js.map +0 -1
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/types/index.d.ts +0 -49
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/types/index.d.ts.map +0 -1
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/types/index.js +0 -19
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/types/index.js.map +0 -1
- package/packages/utils/__tests__/query.test.ts +0 -155
- package/packages/utils/__tests__/sanitize.test.ts +0 -96
- package/packages/utils/__tests__/slugify.test.ts +0 -71
- package/packages/utils/__tests__/traverse.test.ts +0 -131
- package/packages/utils/package.json +0 -27
- package/packages/utils/rollup.config.ts +0 -26
- package/packages/utils/src/ast/query.ts +0 -127
- package/packages/utils/src/ast/traverse.ts +0 -73
- package/packages/utils/src/index.ts +0 -20
- package/packages/utils/src/string/sanitize.ts +0 -155
- package/packages/utils/src/string/slugify.ts +0 -43
- package/packages/utils/src/types/index.ts +0 -72
- package/packages/utils/tsconfig.json +0 -8
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/MarkdownRenderer.d.ts +0 -27
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/MarkdownRenderer.d.ts.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/MarkdownRenderer.js +0 -39
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/MarkdownRenderer.js.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/NodeRenderer.d.ts +0 -10
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/NodeRenderer.d.ts.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/NodeRenderer.js +0 -130
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/NodeRenderer.js.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/context.d.ts +0 -17
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/context.d.ts.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/context.js +0 -14
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/context.js.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Blockquote.d.ts +0 -8
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Blockquote.d.ts.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Blockquote.js +0 -5
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Blockquote.js.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Code.d.ts +0 -13
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Code.d.ts.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Code.js +0 -9
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Code.js.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Heading.d.ts +0 -8
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Heading.d.ts.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Heading.js +0 -7
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Heading.js.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Image.d.ts +0 -7
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Image.d.ts.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Image.js +0 -5
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Image.js.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Link.d.ts +0 -8
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Link.d.ts.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Link.js +0 -7
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Link.js.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/List.d.ts +0 -13
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/List.d.ts.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/List.js +0 -14
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/List.js.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Paragraph.d.ts +0 -8
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Paragraph.d.ts.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Paragraph.js +0 -5
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Paragraph.js.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Table.d.ts +0 -19
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Table.d.ts.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Table.js +0 -18
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Table.js.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/index.d.ts +0 -34
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/index.d.ts.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/index.js +0 -28
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/index.js.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/hooks/useMarkdown.d.ts +0 -11
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/hooks/useMarkdown.d.ts.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/hooks/useMarkdown.js +0 -28
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/hooks/useMarkdown.js.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/index.d.ts +0 -6
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/index.d.ts.map +0 -1
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/index.js +0 -9
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/index.js.map +0 -1
- package/packages/web/__tests__/MarkdownRenderer.test.tsx +0 -89
- package/packages/web/__tests__/NodeRenderer.test.tsx +0 -97
- package/packages/web/__tests__/components/Code.test.tsx +0 -71
- package/packages/web/__tests__/components/Heading.test.tsx +0 -65
- package/packages/web/__tests__/components/List.test.tsx +0 -100
- package/packages/web/__tests__/components/Table.test.tsx +0 -105
- package/packages/web/__tests__/useMarkdown.test.ts +0 -63
- package/packages/web/package.json +0 -40
- package/packages/web/rollup.config.ts +0 -36
- package/packages/web/src/components/MarkdownRenderer.tsx +0 -70
- package/packages/web/src/components/NodeRenderer.tsx +0 -205
- package/packages/web/src/components/context.ts +0 -24
- package/packages/web/src/components/defaults/Blockquote.tsx +0 -11
- package/packages/web/src/components/defaults/Code.tsx +0 -26
- package/packages/web/src/components/defaults/Heading.tsx +0 -14
- package/packages/web/src/components/defaults/Image.tsx +0 -10
- package/packages/web/src/components/defaults/Link.tsx +0 -18
- package/packages/web/src/components/defaults/List.tsx +0 -33
- package/packages/web/src/components/defaults/Paragraph.tsx +0 -11
- package/packages/web/src/components/defaults/Table.tsx +0 -50
- package/packages/web/src/components/defaults/index.tsx +0 -80
- package/packages/web/src/hooks/useMarkdown.ts +0 -32
- package/packages/web/src/index.ts +0 -37
- package/packages/web/tsconfig.json +0 -11
- package/packages/web/vitest.config.ts +0 -9
- package/pnpm-workspace.yaml +0 -2
- package/tsconfig.base.json +0 -26
- package/tsconfig.json +0 -8
- package/vitest.config.ts +0 -28
- package/vitest.setup.ts +0 -1
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Escape HTML special characters
|
|
3
|
-
*
|
|
4
|
-
* @param text - Text to escape
|
|
5
|
-
* @returns Escaped text safe for HTML insertion
|
|
6
|
-
*/
|
|
7
|
-
export declare function escapeHtml(text: string): string;
|
|
8
|
-
/**
|
|
9
|
-
* Sanitize HTML string by removing dangerous content
|
|
10
|
-
*
|
|
11
|
-
* @param html - HTML string to sanitize
|
|
12
|
-
* @returns Sanitized HTML string
|
|
13
|
-
*/
|
|
14
|
-
export declare function sanitizeHtml(html: string): string;
|
|
15
|
-
/**
|
|
16
|
-
* Strip all HTML tags from a string
|
|
17
|
-
*
|
|
18
|
-
* @param html - HTML string to strip
|
|
19
|
-
* @returns Plain text without HTML tags
|
|
20
|
-
*/
|
|
21
|
-
export declare function stripHtml(html: string): string;
|
|
22
|
-
//# sourceMappingURL=sanitize.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/string/sanitize.ts"],"names":[],"mappings":"AAWA;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/C;AAwED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA+CjD;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C"}
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* HTML entities that need escaping
|
|
3
|
-
*/
|
|
4
|
-
const HTML_ESCAPE_MAP = {
|
|
5
|
-
'&': '&',
|
|
6
|
-
'<': '<',
|
|
7
|
-
'>': '>',
|
|
8
|
-
'"': '"',
|
|
9
|
-
"'": ''',
|
|
10
|
-
};
|
|
11
|
-
/**
|
|
12
|
-
* Escape HTML special characters
|
|
13
|
-
*
|
|
14
|
-
* @param text - Text to escape
|
|
15
|
-
* @returns Escaped text safe for HTML insertion
|
|
16
|
-
*/
|
|
17
|
-
export function escapeHtml(text) {
|
|
18
|
-
return text.replace(/[&<>"']/g, (char) => HTML_ESCAPE_MAP[char] || char);
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Allowed HTML tags for sanitization
|
|
22
|
-
*/
|
|
23
|
-
const ALLOWED_TAGS = new Set([
|
|
24
|
-
'a',
|
|
25
|
-
'abbr',
|
|
26
|
-
'b',
|
|
27
|
-
'blockquote',
|
|
28
|
-
'br',
|
|
29
|
-
'code',
|
|
30
|
-
'dd',
|
|
31
|
-
'del',
|
|
32
|
-
'div',
|
|
33
|
-
'dl',
|
|
34
|
-
'dt',
|
|
35
|
-
'em',
|
|
36
|
-
'h1',
|
|
37
|
-
'h2',
|
|
38
|
-
'h3',
|
|
39
|
-
'h4',
|
|
40
|
-
'h5',
|
|
41
|
-
'h6',
|
|
42
|
-
'hr',
|
|
43
|
-
'i',
|
|
44
|
-
'img',
|
|
45
|
-
'ins',
|
|
46
|
-
'kbd',
|
|
47
|
-
'li',
|
|
48
|
-
'ol',
|
|
49
|
-
'p',
|
|
50
|
-
'pre',
|
|
51
|
-
'q',
|
|
52
|
-
's',
|
|
53
|
-
'samp',
|
|
54
|
-
'small',
|
|
55
|
-
'span',
|
|
56
|
-
'strong',
|
|
57
|
-
'sub',
|
|
58
|
-
'sup',
|
|
59
|
-
'table',
|
|
60
|
-
'tbody',
|
|
61
|
-
'td',
|
|
62
|
-
'tfoot',
|
|
63
|
-
'th',
|
|
64
|
-
'thead',
|
|
65
|
-
'tr',
|
|
66
|
-
'u',
|
|
67
|
-
'ul',
|
|
68
|
-
]);
|
|
69
|
-
/**
|
|
70
|
-
* Allowed attributes for sanitization
|
|
71
|
-
*/
|
|
72
|
-
const ALLOWED_ATTRS = new Set([
|
|
73
|
-
'href',
|
|
74
|
-
'src',
|
|
75
|
-
'alt',
|
|
76
|
-
'title',
|
|
77
|
-
'class',
|
|
78
|
-
'id',
|
|
79
|
-
'name',
|
|
80
|
-
'target',
|
|
81
|
-
'rel',
|
|
82
|
-
'width',
|
|
83
|
-
'height',
|
|
84
|
-
'align',
|
|
85
|
-
'colspan',
|
|
86
|
-
'rowspan',
|
|
87
|
-
]);
|
|
88
|
-
/**
|
|
89
|
-
* Sanitize HTML string by removing dangerous content
|
|
90
|
-
*
|
|
91
|
-
* @param html - HTML string to sanitize
|
|
92
|
-
* @returns Sanitized HTML string
|
|
93
|
-
*/
|
|
94
|
-
export function sanitizeHtml(html) {
|
|
95
|
-
let result = html;
|
|
96
|
-
// Remove script tags first
|
|
97
|
-
result = result.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
|
|
98
|
-
// Remove event handlers
|
|
99
|
-
result = result.replace(/\s+on\w+\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]*)/gi, '');
|
|
100
|
-
// Remove disallowed tags (keep content) and sanitize attributes
|
|
101
|
-
result = result.replace(/<\/?(\w+)([^>]*)>/g, (match, tagName, attrs) => {
|
|
102
|
-
const tag = tagName.toLowerCase();
|
|
103
|
-
if (!ALLOWED_TAGS.has(tag)) {
|
|
104
|
-
return '';
|
|
105
|
-
}
|
|
106
|
-
// For closing tags, just return them
|
|
107
|
-
if (match.startsWith('</')) {
|
|
108
|
-
return `</${tag}>`;
|
|
109
|
-
}
|
|
110
|
-
// Sanitize attributes
|
|
111
|
-
const sanitizedAttrs = [];
|
|
112
|
-
const attrRegex = /\s+([\w-]+)\s*=\s*(?:"([^"]*)"|'([^']*)'|(\S+))/g;
|
|
113
|
-
let attrMatch;
|
|
114
|
-
while ((attrMatch = attrRegex.exec(attrs)) !== null) {
|
|
115
|
-
const [, attrName, v1, v2, v3] = attrMatch;
|
|
116
|
-
const attr = attrName.toLowerCase();
|
|
117
|
-
if (ALLOWED_ATTRS.has(attr)) {
|
|
118
|
-
let value = v1 ?? v2 ?? v3 ?? '';
|
|
119
|
-
// Check for dangerous URLs in href/src
|
|
120
|
-
if ((attr === 'href' || attr === 'src') && /^\s*javascript\s*:/i.test(value)) {
|
|
121
|
-
value = '';
|
|
122
|
-
}
|
|
123
|
-
sanitizedAttrs.push(`${attr}="${value}"`);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
const attrStr = sanitizedAttrs.length > 0 ? ' ' + sanitizedAttrs.join(' ') : '';
|
|
127
|
-
return `<${tag}${attrStr}>`;
|
|
128
|
-
});
|
|
129
|
-
return result;
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Strip all HTML tags from a string
|
|
133
|
-
*
|
|
134
|
-
* @param html - HTML string to strip
|
|
135
|
-
* @returns Plain text without HTML tags
|
|
136
|
-
*/
|
|
137
|
-
export function stripHtml(html) {
|
|
138
|
-
return html.replace(/<[^>]*>/g, '');
|
|
139
|
-
}
|
|
140
|
-
//# sourceMappingURL=sanitize.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sanitize.js","sourceRoot":"","sources":["../../src/string/sanitize.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Convert text to URL-safe slug
|
|
3
|
-
*
|
|
4
|
-
* @param text - Text to slugify
|
|
5
|
-
* @returns URL-safe slug
|
|
6
|
-
*/
|
|
7
|
-
export declare function slugify(text: string): string;
|
|
8
|
-
/**
|
|
9
|
-
* Generate unique slug with counter suffix for duplicates
|
|
10
|
-
*
|
|
11
|
-
* @param text - Text to slugify
|
|
12
|
-
* @param existingSlugs - Set of existing slugs to check against
|
|
13
|
-
* @returns Unique slug
|
|
14
|
-
*/
|
|
15
|
-
export declare function uniqueSlugify(text: string, existingSlugs: Set<string>): string;
|
|
16
|
-
//# sourceMappingURL=slugify.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"slugify.d.ts","sourceRoot":"","sources":["../../src/string/slugify.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAe5C;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,CAY9E"}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Convert text to URL-safe slug
|
|
3
|
-
*
|
|
4
|
-
* @param text - Text to slugify
|
|
5
|
-
* @returns URL-safe slug
|
|
6
|
-
*/
|
|
7
|
-
export function slugify(text) {
|
|
8
|
-
return (text
|
|
9
|
-
// Convert to lowercase
|
|
10
|
-
.toLowerCase()
|
|
11
|
-
// Replace Chinese characters with pinyin-like representation (keep as-is for simplicity)
|
|
12
|
-
// Replace spaces and special chars with hyphens
|
|
13
|
-
.replace(/[\s_]+/g, '-')
|
|
14
|
-
// Remove characters that aren't alphanumeric, hyphens, or common CJK
|
|
15
|
-
.replace(/[^\w\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff-]/g, '')
|
|
16
|
-
// Replace multiple consecutive hyphens with single hyphen
|
|
17
|
-
.replace(/-+/g, '-')
|
|
18
|
-
// Remove leading/trailing hyphens
|
|
19
|
-
.replace(/^-+|-+$/g, ''));
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Generate unique slug with counter suffix for duplicates
|
|
23
|
-
*
|
|
24
|
-
* @param text - Text to slugify
|
|
25
|
-
* @param existingSlugs - Set of existing slugs to check against
|
|
26
|
-
* @returns Unique slug
|
|
27
|
-
*/
|
|
28
|
-
export function uniqueSlugify(text, existingSlugs) {
|
|
29
|
-
const baseSlug = slugify(text);
|
|
30
|
-
let slug = baseSlug;
|
|
31
|
-
let counter = 1;
|
|
32
|
-
while (existingSlugs.has(slug)) {
|
|
33
|
-
slug = `${baseSlug}-${counter}`;
|
|
34
|
-
counter++;
|
|
35
|
-
}
|
|
36
|
-
existingSlugs.add(slug);
|
|
37
|
-
return slug;
|
|
38
|
-
}
|
|
39
|
-
//# sourceMappingURL=slugify.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"slugify.js","sourceRoot":"","sources":["../../src/string/slugify.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,OAAO,CACL,IAAI;QACF,uBAAuB;SACtB,WAAW,EAAE;QACd,yFAAyF;QACzF,gDAAgD;SAC/C,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;QACxB,qEAAqE;SACpE,OAAO,CAAC,gDAAgD,EAAE,EAAE,CAAC;QAC9D,0DAA0D;SACzD,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;QACpB,kCAAkC;SACjC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAC3B,CAAA;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,aAA0B;IACpE,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9B,IAAI,IAAI,GAAG,QAAQ,CAAA;IACnB,IAAI,OAAO,GAAG,CAAC,CAAA;IAEf,OAAO,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/B,IAAI,GAAG,GAAG,QAAQ,IAAI,OAAO,EAAE,CAAA;QAC/B,OAAO,EAAE,CAAA;IACX,CAAC;IAED,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACvB,OAAO,IAAI,CAAA;AACb,CAAC"}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import type { Root, Content, Parent, Literal } from 'mdast';
|
|
2
|
-
import type { Node as UnistNode } from 'unist';
|
|
3
|
-
export type { Root, Content, Parent, Literal };
|
|
4
|
-
/**
|
|
5
|
-
* All possible markdown node types
|
|
6
|
-
*/
|
|
7
|
-
export type MdNode = Root | Content;
|
|
8
|
-
/**
|
|
9
|
-
* Root node of markdown AST
|
|
10
|
-
*/
|
|
11
|
-
export type MdRoot = Root;
|
|
12
|
-
/**
|
|
13
|
-
* Visitor function for AST traversal
|
|
14
|
-
*/
|
|
15
|
-
export type Visitor<T extends UnistNode = MdNode> = (node: T, index: number | undefined, parent: Parent | undefined) => void | boolean;
|
|
16
|
-
/**
|
|
17
|
-
* Plugin options base interface
|
|
18
|
-
*/
|
|
19
|
-
export interface PluginOptions {
|
|
20
|
-
[key: string]: unknown;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Position information in source
|
|
24
|
-
*/
|
|
25
|
-
export interface Position {
|
|
26
|
-
line: number;
|
|
27
|
-
column: number;
|
|
28
|
-
offset?: number;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Location in source
|
|
32
|
-
*/
|
|
33
|
-
export interface Location {
|
|
34
|
-
start: Position;
|
|
35
|
-
end: Position;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Type guard to check if node is a parent node
|
|
39
|
-
*/
|
|
40
|
-
export declare function isParent(node: UnistNode): node is Parent;
|
|
41
|
-
/**
|
|
42
|
-
* Type guard to check if node is a literal node
|
|
43
|
-
*/
|
|
44
|
-
export declare function isLiteral(node: UnistNode): node is Literal;
|
|
45
|
-
/**
|
|
46
|
-
* Type guard to check if node has specific type
|
|
47
|
-
*/
|
|
48
|
-
export declare function isNodeType<T extends MdNode>(node: UnistNode, type: T['type']): node is T;
|
|
49
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAC3D,OAAO,KAAK,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,OAAO,CAAA;AAG9C,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAA;AAE9C;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG,IAAI,GAAG,OAAO,CAAA;AAEnC;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG,IAAI,CAAA;AAEzB;;GAEG;AACH,MAAM,MAAM,OAAO,CAAC,CAAC,SAAS,SAAS,GAAG,MAAM,IAAI,CAClD,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,MAAM,EAAE,MAAM,GAAG,SAAS,KACvB,IAAI,GAAG,OAAO,CAAA;AAEnB;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,QAAQ,CAAA;IACf,GAAG,EAAE,QAAQ,CAAA;CACd;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,IAAI,MAAM,CAExD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,IAAI,OAAO,CAE1D;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EACzC,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,GACd,IAAI,IAAI,CAAC,CAEX"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Type guard to check if node is a parent node
|
|
3
|
-
*/
|
|
4
|
-
export function isParent(node) {
|
|
5
|
-
return 'children' in node && Array.isArray(node.children);
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* Type guard to check if node is a literal node
|
|
9
|
-
*/
|
|
10
|
-
export function isLiteral(node) {
|
|
11
|
-
return 'value' in node && typeof node.value === 'string';
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Type guard to check if node has specific type
|
|
15
|
-
*/
|
|
16
|
-
export function isNodeType(node, type) {
|
|
17
|
-
return node.type === type;
|
|
18
|
-
}
|
|
19
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAiDA;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAe;IACtC,OAAO,UAAU,IAAI,IAAI,IAAI,KAAK,CAAC,OAAO,CAAE,IAAe,CAAC,QAAQ,CAAC,CAAA;AACvE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,IAAe;IACvC,OAAO,OAAO,IAAI,IAAI,IAAI,OAAQ,IAAgB,CAAC,KAAK,KAAK,QAAQ,CAAA;AACvE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CACxB,IAAe,EACf,IAAe;IAEf,OAAO,IAAI,CAAC,IAAI,KAAK,IAAI,CAAA;AAC3B,CAAC"}
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import { findNodes, findNode, findNodesBy, findParent } from '../src/ast/query'
|
|
3
|
-
import type { Root, Paragraph, Text, Heading, Strong } from 'mdast'
|
|
4
|
-
|
|
5
|
-
describe('findNodes', () => {
|
|
6
|
-
const createAst = (): Root => ({
|
|
7
|
-
type: 'root',
|
|
8
|
-
children: [
|
|
9
|
-
{
|
|
10
|
-
type: 'heading',
|
|
11
|
-
depth: 1,
|
|
12
|
-
children: [{ type: 'text', value: 'Title' }],
|
|
13
|
-
} as Heading,
|
|
14
|
-
{
|
|
15
|
-
type: 'paragraph',
|
|
16
|
-
children: [
|
|
17
|
-
{ type: 'text', value: 'Hello ' },
|
|
18
|
-
{
|
|
19
|
-
type: 'strong',
|
|
20
|
-
children: [{ type: 'text', value: 'world' }],
|
|
21
|
-
} as Strong,
|
|
22
|
-
],
|
|
23
|
-
} as Paragraph,
|
|
24
|
-
{
|
|
25
|
-
type: 'heading',
|
|
26
|
-
depth: 2,
|
|
27
|
-
children: [{ type: 'text', value: 'Subtitle' }],
|
|
28
|
-
} as Heading,
|
|
29
|
-
],
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
it('should find all nodes of specified type', () => {
|
|
33
|
-
const ast = createAst()
|
|
34
|
-
const headings = findNodes<Heading>(ast, 'heading')
|
|
35
|
-
|
|
36
|
-
expect(headings).toHaveLength(2)
|
|
37
|
-
expect(headings[0].depth).toBe(1)
|
|
38
|
-
expect(headings[1].depth).toBe(2)
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
it('should find nested nodes', () => {
|
|
42
|
-
const ast = createAst()
|
|
43
|
-
const texts = findNodes<Text>(ast, 'text')
|
|
44
|
-
|
|
45
|
-
expect(texts).toHaveLength(4)
|
|
46
|
-
expect(texts.map((t) => t.value)).toEqual([
|
|
47
|
-
'Title',
|
|
48
|
-
'Hello ',
|
|
49
|
-
'world',
|
|
50
|
-
'Subtitle',
|
|
51
|
-
])
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
it('should return empty array when no matches', () => {
|
|
55
|
-
const ast = createAst()
|
|
56
|
-
const codes = findNodes(ast, 'code')
|
|
57
|
-
|
|
58
|
-
expect(codes).toEqual([])
|
|
59
|
-
})
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
describe('findNode', () => {
|
|
63
|
-
const createAst = (): Root => ({
|
|
64
|
-
type: 'root',
|
|
65
|
-
children: [
|
|
66
|
-
{
|
|
67
|
-
type: 'heading',
|
|
68
|
-
depth: 1,
|
|
69
|
-
children: [{ type: 'text', value: 'First' }],
|
|
70
|
-
} as Heading,
|
|
71
|
-
{
|
|
72
|
-
type: 'heading',
|
|
73
|
-
depth: 2,
|
|
74
|
-
children: [{ type: 'text', value: 'Second' }],
|
|
75
|
-
} as Heading,
|
|
76
|
-
],
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
it('should find first matching node', () => {
|
|
80
|
-
const ast = createAst()
|
|
81
|
-
const heading = findNode<Heading>(ast, 'heading')
|
|
82
|
-
|
|
83
|
-
expect(heading).toBeDefined()
|
|
84
|
-
expect(heading!.depth).toBe(1)
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
it('should return undefined when no match', () => {
|
|
88
|
-
const ast = createAst()
|
|
89
|
-
const code = findNode(ast, 'code')
|
|
90
|
-
|
|
91
|
-
expect(code).toBeUndefined()
|
|
92
|
-
})
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
describe('findNodesBy', () => {
|
|
96
|
-
const createAst = (): Root => ({
|
|
97
|
-
type: 'root',
|
|
98
|
-
children: [
|
|
99
|
-
{
|
|
100
|
-
type: 'heading',
|
|
101
|
-
depth: 1,
|
|
102
|
-
children: [{ type: 'text', value: 'H1' }],
|
|
103
|
-
} as Heading,
|
|
104
|
-
{
|
|
105
|
-
type: 'heading',
|
|
106
|
-
depth: 2,
|
|
107
|
-
children: [{ type: 'text', value: 'H2' }],
|
|
108
|
-
} as Heading,
|
|
109
|
-
{
|
|
110
|
-
type: 'heading',
|
|
111
|
-
depth: 1,
|
|
112
|
-
children: [{ type: 'text', value: 'Another H1' }],
|
|
113
|
-
} as Heading,
|
|
114
|
-
],
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
it('should find nodes matching predicate', () => {
|
|
118
|
-
const ast = createAst()
|
|
119
|
-
const h1s = findNodesBy<Heading>(
|
|
120
|
-
ast,
|
|
121
|
-
(node) => node.type === 'heading' && (node as Heading).depth === 1
|
|
122
|
-
)
|
|
123
|
-
|
|
124
|
-
expect(h1s).toHaveLength(2)
|
|
125
|
-
expect(h1s[0].children[0]).toHaveProperty('value', 'H1')
|
|
126
|
-
expect(h1s[1].children[0]).toHaveProperty('value', 'Another H1')
|
|
127
|
-
})
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
describe('findParent', () => {
|
|
131
|
-
it('should find parent of a node', () => {
|
|
132
|
-
const textNode: Text = { type: 'text', value: 'Hello' }
|
|
133
|
-
const paragraph: Paragraph = {
|
|
134
|
-
type: 'paragraph',
|
|
135
|
-
children: [textNode],
|
|
136
|
-
}
|
|
137
|
-
const ast: Root = {
|
|
138
|
-
type: 'root',
|
|
139
|
-
children: [paragraph],
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const parent = findParent(ast, textNode)
|
|
143
|
-
expect(parent).toBe(paragraph)
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
it('should return undefined for root node', () => {
|
|
147
|
-
const ast: Root = {
|
|
148
|
-
type: 'root',
|
|
149
|
-
children: [],
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const parent = findParent(ast, ast)
|
|
153
|
-
expect(parent).toBeUndefined()
|
|
154
|
-
})
|
|
155
|
-
})
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import { escapeHtml, sanitizeHtml, stripHtml } from '../src/string/sanitize'
|
|
3
|
-
|
|
4
|
-
describe('escapeHtml', () => {
|
|
5
|
-
it('should escape ampersand', () => {
|
|
6
|
-
expect(escapeHtml('foo & bar')).toBe('foo & bar')
|
|
7
|
-
})
|
|
8
|
-
|
|
9
|
-
it('should escape less than', () => {
|
|
10
|
-
expect(escapeHtml('a < b')).toBe('a < b')
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
it('should escape greater than', () => {
|
|
14
|
-
expect(escapeHtml('a > b')).toBe('a > b')
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
it('should escape double quotes', () => {
|
|
18
|
-
expect(escapeHtml('say "hello"')).toBe('say "hello"')
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
it('should escape single quotes', () => {
|
|
22
|
-
expect(escapeHtml("it's")).toBe('it's')
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
it('should escape multiple characters', () => {
|
|
26
|
-
expect(escapeHtml('<script>alert("xss")</script>')).toBe(
|
|
27
|
-
'<script>alert("xss")</script>'
|
|
28
|
-
)
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
it('should preserve safe text', () => {
|
|
32
|
-
expect(escapeHtml('Hello World 123')).toBe('Hello World 123')
|
|
33
|
-
})
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
describe('sanitizeHtml', () => {
|
|
37
|
-
it('should remove script tags', () => {
|
|
38
|
-
expect(sanitizeHtml('<script>alert("xss")</script>')).toBe('')
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
it('should remove event handlers', () => {
|
|
42
|
-
expect(sanitizeHtml('<div onclick="alert(1)">text</div>')).toBe(
|
|
43
|
-
'<div>text</div>'
|
|
44
|
-
)
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
it('should remove javascript: URLs', () => {
|
|
48
|
-
expect(sanitizeHtml('<a href="javascript:alert(1)">click</a>')).toBe(
|
|
49
|
-
'<a href="">click</a>'
|
|
50
|
-
)
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
it('should preserve allowed tags', () => {
|
|
54
|
-
expect(sanitizeHtml('<p>Hello <strong>world</strong></p>')).toBe(
|
|
55
|
-
'<p>Hello <strong>world</strong></p>'
|
|
56
|
-
)
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
it('should preserve allowed attributes', () => {
|
|
60
|
-
expect(sanitizeHtml('<a href="https://example.com" title="link">text</a>')).toBe(
|
|
61
|
-
'<a href="https://example.com" title="link">text</a>'
|
|
62
|
-
)
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
it('should remove disallowed tags', () => {
|
|
66
|
-
expect(sanitizeHtml('<iframe src="evil.com"></iframe>')).toBe('')
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
it('should remove disallowed attributes', () => {
|
|
70
|
-
expect(sanitizeHtml('<div data-evil="bad">text</div>')).toBe('<div>text</div>')
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
it('should handle nested script content', () => {
|
|
74
|
-
expect(
|
|
75
|
-
sanitizeHtml('<div><script>bad()</script>safe</div>')
|
|
76
|
-
).toBe('<div>safe</div>')
|
|
77
|
-
})
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
describe('stripHtml', () => {
|
|
81
|
-
it('should remove all HTML tags', () => {
|
|
82
|
-
expect(stripHtml('<p>Hello <strong>world</strong></p>')).toBe('Hello world')
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
it('should handle self-closing tags', () => {
|
|
86
|
-
expect(stripHtml('Hello<br/>World')).toBe('HelloWorld')
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
it('should preserve text content', () => {
|
|
90
|
-
expect(stripHtml('No tags here')).toBe('No tags here')
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
it('should handle nested tags', () => {
|
|
94
|
-
expect(stripHtml('<div><p><span>Deep</span></p></div>')).toBe('Deep')
|
|
95
|
-
})
|
|
96
|
-
})
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import { slugify, uniqueSlugify } from '../src/string/slugify'
|
|
3
|
-
|
|
4
|
-
describe('slugify', () => {
|
|
5
|
-
it('should convert text to lowercase', () => {
|
|
6
|
-
expect(slugify('Hello World')).toBe('hello-world')
|
|
7
|
-
})
|
|
8
|
-
|
|
9
|
-
it('should replace spaces with hyphens', () => {
|
|
10
|
-
expect(slugify('hello world')).toBe('hello-world')
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
it('should replace underscores with hyphens', () => {
|
|
14
|
-
expect(slugify('hello_world')).toBe('hello-world')
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
it('should remove special characters', () => {
|
|
18
|
-
expect(slugify('Hello! World?')).toBe('hello-world')
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
it('should handle multiple consecutive spaces', () => {
|
|
22
|
-
expect(slugify('hello world')).toBe('hello-world')
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
it('should remove leading and trailing hyphens', () => {
|
|
26
|
-
expect(slugify(' hello world ')).toBe('hello-world')
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
it('should preserve Chinese characters', () => {
|
|
30
|
-
expect(slugify('你好世界')).toBe('你好世界')
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
it('should handle mixed Chinese and English', () => {
|
|
34
|
-
expect(slugify('Hello 你好 World')).toBe('hello-你好-world')
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
it('should handle Japanese characters', () => {
|
|
38
|
-
expect(slugify('こんにちは')).toBe('こんにちは')
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
it('should return empty string for only special characters', () => {
|
|
42
|
-
expect(slugify('!@#$%')).toBe('')
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
it('should handle numbers', () => {
|
|
46
|
-
expect(slugify('Chapter 1')).toBe('chapter-1')
|
|
47
|
-
})
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
describe('uniqueSlugify', () => {
|
|
51
|
-
it('should return base slug when no duplicates', () => {
|
|
52
|
-
const existing = new Set<string>()
|
|
53
|
-
expect(uniqueSlugify('Hello World', existing)).toBe('hello-world')
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
it('should add counter for duplicates', () => {
|
|
57
|
-
const existing = new Set(['hello-world'])
|
|
58
|
-
expect(uniqueSlugify('Hello World', existing)).toBe('hello-world-1')
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
it('should increment counter for multiple duplicates', () => {
|
|
62
|
-
const existing = new Set(['hello-world', 'hello-world-1', 'hello-world-2'])
|
|
63
|
-
expect(uniqueSlugify('Hello World', existing)).toBe('hello-world-3')
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
it('should add generated slug to existing set', () => {
|
|
67
|
-
const existing = new Set<string>()
|
|
68
|
-
uniqueSlugify('Hello World', existing)
|
|
69
|
-
expect(existing.has('hello-world')).toBe(true)
|
|
70
|
-
})
|
|
71
|
-
})
|