pd-markdown 1.0.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/package.json +26 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/index.d.ts +4 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/index.d.ts.map +1 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/index.js +5 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/index.js.map +1 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/index.d.ts +4 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/index.d.ts.map +1 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/index.js +4 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/index.js.map +1 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/heading.d.ts +6 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/heading.d.ts.map +1 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/heading.js +36 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/heading.js.map +1 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/list.d.ts +14 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/list.d.ts.map +1 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/list.js +18 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/list.js.map +1 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/table.d.ts +27 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/table.d.ts.map +1 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/table.js +37 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/plugins/transform/table.js.map +1 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/processor.d.ts +22 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/processor.d.ts.map +1 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/processor.js +95 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/processor.js.map +1 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/types/index.d.ts +55 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/types/index.d.ts.map +1 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/types/index.js +2 -0
- package/packages/parser/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/parser/dist/types/index.js.map +1 -0
- package/packages/parser/__tests__/frontmatter.test.ts +69 -0
- package/packages/parser/__tests__/gfm.test.ts +83 -0
- package/packages/parser/__tests__/processor.test.ts +136 -0
- package/packages/parser/__tests__/transform/heading.test.ts +56 -0
- package/packages/parser/__tests__/transform/list.test.ts +67 -0
- package/packages/parser/__tests__/transform/table.test.ts +85 -0
- package/packages/parser/dist/index.cjs +191 -0
- package/packages/parser/dist/index.cjs.map +1 -0
- package/packages/parser/dist/index.d.ts +4 -0
- package/packages/parser/dist/index.d.ts.map +1 -0
- package/packages/parser/dist/index.mjs +185 -0
- package/packages/parser/dist/index.mjs.map +1 -0
- package/packages/parser/dist/plugins/index.d.ts +4 -0
- package/packages/parser/dist/plugins/index.d.ts.map +1 -0
- package/packages/parser/dist/plugins/transform/heading.d.ts +6 -0
- package/packages/parser/dist/plugins/transform/heading.d.ts.map +1 -0
- package/packages/parser/dist/plugins/transform/list.d.ts +14 -0
- package/packages/parser/dist/plugins/transform/list.d.ts.map +1 -0
- package/packages/parser/dist/plugins/transform/table.d.ts +27 -0
- package/packages/parser/dist/plugins/transform/table.d.ts.map +1 -0
- package/packages/parser/dist/processor.d.ts +22 -0
- package/packages/parser/dist/processor.d.ts.map +1 -0
- package/packages/parser/dist/types/index.d.ts +55 -0
- package/packages/parser/dist/types/index.d.ts.map +1 -0
- package/packages/parser/node_modules/.bin/yaml +17 -0
- package/packages/parser/package.json +38 -0
- package/packages/parser/rollup.config.ts +38 -0
- package/packages/parser/src/index.ts +15 -0
- package/packages/parser/src/plugins/index.ts +3 -0
- package/packages/parser/src/plugins/transform/heading.ts +40 -0
- package/packages/parser/src/plugins/transform/list.ts +29 -0
- package/packages/parser/src/plugins/transform/table.ts +62 -0
- package/packages/parser/src/processor.ts +119 -0
- package/packages/parser/src/types/index.ts +60 -0
- package/packages/parser/tsconfig.json +9 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/ast/query.d.ts +36 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/ast/query.d.ts.map +1 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/ast/query.js +99 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/ast/query.js.map +1 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/ast/traverse.d.ts +22 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/ast/traverse.d.ts.map +1 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/ast/traverse.js +46 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/ast/traverse.js.map +1 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/index.d.ts +7 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/index.d.ts.map +1 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/index.js +8 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/index.js.map +1 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/string/sanitize.d.ts +22 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/string/sanitize.d.ts.map +1 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/string/sanitize.js +140 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/string/sanitize.js.map +1 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/string/slugify.d.ts +16 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/string/slugify.d.ts.map +1 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/string/slugify.js +39 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/string/slugify.js.map +1 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/types/index.d.ts +49 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/types/index.d.ts.map +1 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/types/index.js +19 -0
- package/packages/utils/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/utils/dist/types/index.js.map +1 -0
- package/packages/utils/__tests__/query.test.ts +155 -0
- package/packages/utils/__tests__/sanitize.test.ts +96 -0
- package/packages/utils/__tests__/slugify.test.ts +71 -0
- package/packages/utils/__tests__/traverse.test.ts +131 -0
- package/packages/utils/dist/ast/query.d.ts +36 -0
- package/packages/utils/dist/ast/query.d.ts.map +1 -0
- package/packages/utils/dist/ast/traverse.d.ts +22 -0
- package/packages/utils/dist/ast/traverse.d.ts.map +1 -0
- package/packages/utils/dist/index.cjs +358 -0
- package/packages/utils/dist/index.cjs.map +1 -0
- package/packages/utils/dist/index.d.ts +7 -0
- package/packages/utils/dist/index.d.ts.map +1 -0
- package/packages/utils/dist/index.mjs +343 -0
- package/packages/utils/dist/index.mjs.map +1 -0
- package/packages/utils/dist/string/sanitize.d.ts +22 -0
- package/packages/utils/dist/string/sanitize.d.ts.map +1 -0
- package/packages/utils/dist/string/slugify.d.ts +16 -0
- package/packages/utils/dist/string/slugify.d.ts.map +1 -0
- package/packages/utils/dist/types/index.d.ts +49 -0
- package/packages/utils/dist/types/index.d.ts.map +1 -0
- package/packages/utils/package.json +27 -0
- package/packages/utils/rollup.config.ts +26 -0
- package/packages/utils/src/ast/query.ts +127 -0
- package/packages/utils/src/ast/traverse.ts +73 -0
- package/packages/utils/src/index.ts +20 -0
- package/packages/utils/src/string/sanitize.ts +155 -0
- package/packages/utils/src/string/slugify.ts +43 -0
- package/packages/utils/src/types/index.ts +72 -0
- package/packages/utils/tsconfig.json +8 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/MarkdownRenderer.d.ts +27 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/MarkdownRenderer.d.ts.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/MarkdownRenderer.js +39 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/MarkdownRenderer.js.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/NodeRenderer.d.ts +10 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/NodeRenderer.d.ts.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/NodeRenderer.js +130 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/NodeRenderer.js.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/context.d.ts +17 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/context.d.ts.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/context.js +14 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/context.js.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Blockquote.d.ts +8 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Blockquote.d.ts.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Blockquote.js +5 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Blockquote.js.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Code.d.ts +13 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Code.d.ts.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Code.js +9 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Code.js.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Heading.d.ts +8 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Heading.d.ts.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Heading.js +7 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Heading.js.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Image.d.ts +7 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Image.d.ts.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Image.js +5 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Image.js.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Link.d.ts +8 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Link.d.ts.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Link.js +7 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Link.js.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/List.d.ts +13 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/List.d.ts.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/List.js +14 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/List.js.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Paragraph.d.ts +8 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Paragraph.d.ts.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Paragraph.js +5 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Paragraph.js.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Table.d.ts +19 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Table.d.ts.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Table.js +18 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/Table.js.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/index.d.ts +34 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/index.d.ts.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/index.js +28 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/components/defaults/index.js.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/hooks/useMarkdown.d.ts +11 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/hooks/useMarkdown.d.ts.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/hooks/useMarkdown.js +28 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/hooks/useMarkdown.js.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/index.d.ts +6 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/index.d.ts.map +1 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/index.js +9 -0
- package/packages/web/.rollup.cache/Users/pidan/Work/Learn/pd-markdown/packages/web/dist/index.js.map +1 -0
- package/packages/web/__tests__/MarkdownRenderer.test.tsx +89 -0
- package/packages/web/__tests__/NodeRenderer.test.tsx +97 -0
- package/packages/web/__tests__/components/Code.test.tsx +71 -0
- package/packages/web/__tests__/components/Heading.test.tsx +65 -0
- package/packages/web/__tests__/components/List.test.tsx +100 -0
- package/packages/web/__tests__/components/Table.test.tsx +105 -0
- package/packages/web/__tests__/useMarkdown.test.ts +63 -0
- package/packages/web/dist/components/MarkdownRenderer.d.ts +27 -0
- package/packages/web/dist/components/MarkdownRenderer.d.ts.map +1 -0
- package/packages/web/dist/components/NodeRenderer.d.ts +10 -0
- package/packages/web/dist/components/NodeRenderer.d.ts.map +1 -0
- package/packages/web/dist/components/context.d.ts +17 -0
- package/packages/web/dist/components/context.d.ts.map +1 -0
- package/packages/web/dist/components/defaults/Blockquote.d.ts +8 -0
- package/packages/web/dist/components/defaults/Blockquote.d.ts.map +1 -0
- package/packages/web/dist/components/defaults/Code.d.ts +13 -0
- package/packages/web/dist/components/defaults/Code.d.ts.map +1 -0
- package/packages/web/dist/components/defaults/Heading.d.ts +8 -0
- package/packages/web/dist/components/defaults/Heading.d.ts.map +1 -0
- package/packages/web/dist/components/defaults/Image.d.ts +7 -0
- package/packages/web/dist/components/defaults/Image.d.ts.map +1 -0
- package/packages/web/dist/components/defaults/Link.d.ts +8 -0
- package/packages/web/dist/components/defaults/Link.d.ts.map +1 -0
- package/packages/web/dist/components/defaults/List.d.ts +13 -0
- package/packages/web/dist/components/defaults/List.d.ts.map +1 -0
- package/packages/web/dist/components/defaults/Paragraph.d.ts +8 -0
- package/packages/web/dist/components/defaults/Paragraph.d.ts.map +1 -0
- package/packages/web/dist/components/defaults/Table.d.ts +19 -0
- package/packages/web/dist/components/defaults/Table.d.ts.map +1 -0
- package/packages/web/dist/components/defaults/index.d.ts +34 -0
- package/packages/web/dist/components/defaults/index.d.ts.map +1 -0
- package/packages/web/dist/hooks/useMarkdown.d.ts +11 -0
- package/packages/web/dist/hooks/useMarkdown.d.ts.map +1 -0
- package/packages/web/dist/index.cjs +306 -0
- package/packages/web/dist/index.cjs.map +1 -0
- package/packages/web/dist/index.d.ts +6 -0
- package/packages/web/dist/index.d.ts.map +1 -0
- package/packages/web/dist/index.mjs +287 -0
- package/packages/web/dist/index.mjs.map +1 -0
- package/packages/web/package.json +40 -0
- package/packages/web/rollup.config.ts +36 -0
- package/packages/web/src/components/MarkdownRenderer.tsx +70 -0
- package/packages/web/src/components/NodeRenderer.tsx +205 -0
- package/packages/web/src/components/context.ts +24 -0
- package/packages/web/src/components/defaults/Blockquote.tsx +11 -0
- package/packages/web/src/components/defaults/Code.tsx +26 -0
- package/packages/web/src/components/defaults/Heading.tsx +14 -0
- package/packages/web/src/components/defaults/Image.tsx +10 -0
- package/packages/web/src/components/defaults/Link.tsx +18 -0
- package/packages/web/src/components/defaults/List.tsx +33 -0
- package/packages/web/src/components/defaults/Paragraph.tsx +11 -0
- package/packages/web/src/components/defaults/Table.tsx +50 -0
- package/packages/web/src/components/defaults/index.tsx +80 -0
- package/packages/web/src/hooks/useMarkdown.ts +32 -0
- package/packages/web/src/index.ts +37 -0
- package/packages/web/tsconfig.json +11 -0
- package/packages/web/vitest.config.ts +9 -0
- package/pnpm-workspace.yaml +2 -0
- package/tsconfig.base.json +26 -0
- package/tsconfig.json +8 -0
- package/vitest.config.ts +28 -0
- package/vitest.setup.ts +1 -0
|
@@ -0,0 +1,39 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,155 @@
|
|
|
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
|
+
})
|
|
@@ -0,0 +1,96 @@
|
|
|
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
|
+
})
|
|
@@ -0,0 +1,71 @@
|
|
|
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
|
+
})
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
2
|
+
import { traverseAst, traverseAstWithCallbacks } from '../src/ast/traverse'
|
|
3
|
+
import type { Root, Paragraph, Text, Heading } from 'mdast'
|
|
4
|
+
|
|
5
|
+
describe('traverseAst', () => {
|
|
6
|
+
const createSimpleAst = (): 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: [{ type: 'text', value: 'Content' }],
|
|
17
|
+
} as Paragraph,
|
|
18
|
+
],
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('should visit all nodes in depth-first order', () => {
|
|
22
|
+
const ast = createSimpleAst()
|
|
23
|
+
const visited: string[] = []
|
|
24
|
+
|
|
25
|
+
traverseAst(ast, (node) => {
|
|
26
|
+
visited.push(node.type)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
expect(visited).toEqual(['root', 'heading', 'text', 'paragraph', 'text'])
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('should skip children when visitor returns false', () => {
|
|
33
|
+
const ast = createSimpleAst()
|
|
34
|
+
const visited: string[] = []
|
|
35
|
+
|
|
36
|
+
traverseAst(ast, (node) => {
|
|
37
|
+
visited.push(node.type)
|
|
38
|
+
if (node.type === 'heading') {
|
|
39
|
+
return false // Skip children of heading
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
expect(visited).toEqual(['root', 'heading', 'paragraph', 'text'])
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('should provide correct index and parent', () => {
|
|
47
|
+
const ast = createSimpleAst()
|
|
48
|
+
const visitor = vi.fn()
|
|
49
|
+
|
|
50
|
+
traverseAst(ast, visitor)
|
|
51
|
+
|
|
52
|
+
// Root has no index and no parent
|
|
53
|
+
expect(visitor).toHaveBeenNthCalledWith(1, ast, undefined, undefined)
|
|
54
|
+
|
|
55
|
+
// Heading is at index 0 with root as parent
|
|
56
|
+
expect(visitor).toHaveBeenNthCalledWith(2, ast.children[0], 0, ast)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('should handle empty children', () => {
|
|
60
|
+
const ast: Root = {
|
|
61
|
+
type: 'root',
|
|
62
|
+
children: [],
|
|
63
|
+
}
|
|
64
|
+
const visited: string[] = []
|
|
65
|
+
|
|
66
|
+
traverseAst(ast, (node) => {
|
|
67
|
+
visited.push(node.type)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
expect(visited).toEqual(['root'])
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
describe('traverseAstWithCallbacks', () => {
|
|
75
|
+
const createSimpleAst = (): Root => ({
|
|
76
|
+
type: 'root',
|
|
77
|
+
children: [
|
|
78
|
+
{
|
|
79
|
+
type: 'paragraph',
|
|
80
|
+
children: [{ type: 'text', value: 'Hello' }],
|
|
81
|
+
} as Paragraph,
|
|
82
|
+
],
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('should call enter and leave in correct order', () => {
|
|
86
|
+
const ast = createSimpleAst()
|
|
87
|
+
const events: string[] = []
|
|
88
|
+
|
|
89
|
+
traverseAstWithCallbacks(ast, {
|
|
90
|
+
enter: (node) => {
|
|
91
|
+
events.push(`enter:${node.type}`)
|
|
92
|
+
},
|
|
93
|
+
leave: (node) => {
|
|
94
|
+
events.push(`leave:${node.type}`)
|
|
95
|
+
},
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
expect(events).toEqual([
|
|
99
|
+
'enter:root',
|
|
100
|
+
'enter:paragraph',
|
|
101
|
+
'enter:text',
|
|
102
|
+
'leave:text',
|
|
103
|
+
'leave:paragraph',
|
|
104
|
+
'leave:root',
|
|
105
|
+
])
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('should skip children when enter returns false', () => {
|
|
109
|
+
const ast = createSimpleAst()
|
|
110
|
+
const events: string[] = []
|
|
111
|
+
|
|
112
|
+
traverseAstWithCallbacks(ast, {
|
|
113
|
+
enter: (node) => {
|
|
114
|
+
events.push(`enter:${node.type}`)
|
|
115
|
+
if (node.type === 'paragraph') {
|
|
116
|
+
return false
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
leave: (node) => {
|
|
120
|
+
events.push(`leave:${node.type}`)
|
|
121
|
+
},
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
expect(events).toEqual([
|
|
125
|
+
'enter:root',
|
|
126
|
+
'enter:paragraph',
|
|
127
|
+
'leave:paragraph',
|
|
128
|
+
'leave:root',
|
|
129
|
+
])
|
|
130
|
+
})
|
|
131
|
+
})
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Node } from 'unist';
|
|
2
|
+
import type { MdNode, Parent } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Find all nodes of a specific type in the AST
|
|
5
|
+
*
|
|
6
|
+
* @param node - Root node to search from
|
|
7
|
+
* @param type - Node type to find
|
|
8
|
+
* @returns Array of matching nodes
|
|
9
|
+
*/
|
|
10
|
+
export declare function findNodes<T extends Node = MdNode>(node: Node, type: string): T[];
|
|
11
|
+
/**
|
|
12
|
+
* Find the first node of a specific type in the AST
|
|
13
|
+
*
|
|
14
|
+
* @param node - Root node to search from
|
|
15
|
+
* @param type - Node type to find
|
|
16
|
+
* @returns The first matching node or undefined
|
|
17
|
+
*/
|
|
18
|
+
export declare function findNode<T extends Node = MdNode>(node: Node, type: string): T | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Find all nodes matching a predicate
|
|
21
|
+
*
|
|
22
|
+
* @param node - Root node to search from
|
|
23
|
+
* @param predicate - Function to test each node
|
|
24
|
+
* @returns Array of matching nodes
|
|
25
|
+
*/
|
|
26
|
+
export declare function findNodesBy<T extends Node = MdNode>(node: Node, predicate: (node: Node) => boolean): T[];
|
|
27
|
+
/**
|
|
28
|
+
* Get the parent of a node in the AST
|
|
29
|
+
* Note: This requires traversing from root, use sparingly
|
|
30
|
+
*
|
|
31
|
+
* @param root - Root node of the AST
|
|
32
|
+
* @param target - Node to find parent of
|
|
33
|
+
* @returns Parent node or undefined if not found or is root
|
|
34
|
+
*/
|
|
35
|
+
export declare function findParent(root: Node, target: Node): Parent | undefined;
|
|
36
|
+
//# sourceMappingURL=query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/ast/query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AACjC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAG9C;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,IAAI,GAAG,MAAM,EAC/C,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,MAAM,GACX,CAAC,EAAE,CAiBL;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,IAAI,GAAG,MAAM,EAC9C,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,MAAM,GACX,CAAC,GAAG,SAAS,CAsBf;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,IAAI,GAAG,MAAM,EACjD,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,GACjC,CAAC,EAAE,CAiBL;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAsBvE"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Node } from 'unist';
|
|
2
|
+
import type { MdNode, Visitor } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Traverse AST in depth-first order
|
|
5
|
+
*
|
|
6
|
+
* @param node - Root node to start traversal
|
|
7
|
+
* @param visitor - Visitor function called for each node
|
|
8
|
+
* Return `false` to skip children of current node
|
|
9
|
+
* Return `true` or `undefined` to continue
|
|
10
|
+
*/
|
|
11
|
+
export declare function traverseAst<T extends Node = MdNode>(node: T, visitor: Visitor<T>): void;
|
|
12
|
+
/**
|
|
13
|
+
* Traverse AST with enter and leave callbacks
|
|
14
|
+
*
|
|
15
|
+
* @param node - Root node to start traversal
|
|
16
|
+
* @param callbacks - Object with optional enter and leave functions
|
|
17
|
+
*/
|
|
18
|
+
export declare function traverseAstWithCallbacks<T extends Node = MdNode>(node: T, callbacks: {
|
|
19
|
+
enter?: Visitor<T>;
|
|
20
|
+
leave?: Visitor<T>;
|
|
21
|
+
}): void;
|
|
22
|
+
//# sourceMappingURL=traverse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traverse.d.ts","sourceRoot":"","sources":["../../src/ast/traverse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AACjC,OAAO,KAAK,EAAU,MAAM,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAGvD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,IAAI,GAAG,MAAM,EACjD,IAAI,EAAE,CAAC,EACP,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAClB,IAAI,CAsBN;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,IAAI,GAAG,MAAM,EAC9D,IAAI,EAAE,CAAC,EACP,SAAS,EAAE;IACT,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;CACnB,GACA,IAAI,CAqBN"}
|