@aigne/doc-smith 0.8.12-beta.7 → 0.8.12-beta.9

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.
Files changed (284) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/agents/clear/choose-contents.mjs +14 -1
  3. package/agents/clear/clear-media-description.mjs +129 -0
  4. package/agents/clear/index.yaml +3 -1
  5. package/agents/evaluate/code-snippet.mjs +28 -24
  6. package/agents/evaluate/document-structure.yaml +0 -4
  7. package/agents/evaluate/document.yaml +1 -5
  8. package/agents/generate/index.yaml +1 -0
  9. package/agents/init/index.mjs +10 -0
  10. package/agents/media/batch-generate-media-description.yaml +44 -0
  11. package/agents/media/generate-media-description.yaml +47 -0
  12. package/agents/media/load-media-description.mjs +238 -0
  13. package/agents/publish/index.yaml +4 -0
  14. package/agents/publish/publish-docs.mjs +77 -5
  15. package/agents/publish/translate-meta.mjs +103 -0
  16. package/agents/update/generate-document.yaml +30 -28
  17. package/agents/update/index.yaml +1 -0
  18. package/agents/update/update-document-detail.yaml +3 -1
  19. package/agents/utils/load-sources.mjs +103 -53
  20. package/agents/utils/update-branding.mjs +69 -0
  21. package/aigne.yaml +6 -0
  22. package/assets/report-template/report.html +34 -34
  23. package/package.json +17 -2
  24. package/prompts/common/document/role-and-personality.md +3 -1
  25. package/prompts/detail/d2-diagram/guide.md +7 -1
  26. package/prompts/detail/d2-diagram/user-prompt.md +3 -0
  27. package/prompts/detail/generate/system-prompt.md +6 -7
  28. package/prompts/detail/generate/user-prompt.md +12 -3
  29. package/prompts/detail/update/user-prompt.md +0 -2
  30. package/prompts/evaluate/document-structure.md +6 -7
  31. package/prompts/evaluate/document.md +16 -25
  32. package/prompts/media/media-description/system-prompt.md +35 -0
  33. package/prompts/media/media-description/user-prompt.md +8 -0
  34. package/prompts/structure/update/user-prompt.md +0 -4
  35. package/utils/constants/index.mjs +0 -107
  36. package/utils/file-utils.mjs +86 -0
  37. package/utils/markdown-checker.mjs +0 -20
  38. package/utils/request.mjs +7 -0
  39. package/utils/upload-files.mjs +231 -0
  40. package/utils/utils.mjs +11 -1
  41. package/.aigne/doc-smith/config.yaml +0 -77
  42. package/.aigne/doc-smith/history.yaml +0 -37
  43. package/.aigne/doc-smith/output/structure-plan.json +0 -162
  44. package/.aigne/doc-smith/preferences.yml +0 -97
  45. package/.aigne/doc-smith/upload-cache.yaml +0 -1893
  46. package/.github/PULL_REQUEST_TEMPLATE.md +0 -28
  47. package/.github/workflows/ci.yml +0 -54
  48. package/.github/workflows/create-release-pr.yaml +0 -21
  49. package/.github/workflows/publish-docs.yml +0 -65
  50. package/.github/workflows/release.yml +0 -49
  51. package/.github/workflows/reviewer.yml +0 -54
  52. package/.release-please-manifest.json +0 -3
  53. package/RELEASE.md +0 -9
  54. package/assets/screenshots/doc-complete-setup.png +0 -0
  55. package/assets/screenshots/doc-generate-docs.png +0 -0
  56. package/assets/screenshots/doc-generate.png +0 -0
  57. package/assets/screenshots/doc-generated-successfully.png +0 -0
  58. package/assets/screenshots/doc-publish.png +0 -0
  59. package/assets/screenshots/doc-regenerate.png +0 -0
  60. package/assets/screenshots/doc-translate-langs.png +0 -0
  61. package/assets/screenshots/doc-translate.png +0 -0
  62. package/assets/screenshots/doc-update.png +0 -0
  63. package/biome.json +0 -73
  64. package/codecov.yml +0 -15
  65. package/docs/_sidebar.md +0 -15
  66. package/docs/configuration-initial-setup.ja.md +0 -179
  67. package/docs/configuration-initial-setup.md +0 -179
  68. package/docs/configuration-initial-setup.zh-TW.md +0 -179
  69. package/docs/configuration-initial-setup.zh.md +0 -179
  70. package/docs/configuration-managing-preferences.ja.md +0 -100
  71. package/docs/configuration-managing-preferences.md +0 -100
  72. package/docs/configuration-managing-preferences.zh-TW.md +0 -100
  73. package/docs/configuration-managing-preferences.zh.md +0 -100
  74. package/docs/configuration.ja.md +0 -96
  75. package/docs/configuration.md +0 -96
  76. package/docs/configuration.zh-TW.md +0 -96
  77. package/docs/configuration.zh.md +0 -96
  78. package/docs/getting-started.ja.md +0 -88
  79. package/docs/getting-started.md +0 -88
  80. package/docs/getting-started.zh-TW.md +0 -88
  81. package/docs/getting-started.zh.md +0 -88
  82. package/docs/guides-cleaning-up.ja.md +0 -51
  83. package/docs/guides-cleaning-up.md +0 -51
  84. package/docs/guides-cleaning-up.zh-TW.md +0 -51
  85. package/docs/guides-cleaning-up.zh.md +0 -51
  86. package/docs/guides-evaluating-documents.ja.md +0 -66
  87. package/docs/guides-evaluating-documents.md +0 -66
  88. package/docs/guides-evaluating-documents.zh-TW.md +0 -66
  89. package/docs/guides-evaluating-documents.zh.md +0 -66
  90. package/docs/guides-generating-documentation.ja.md +0 -151
  91. package/docs/guides-generating-documentation.md +0 -151
  92. package/docs/guides-generating-documentation.zh-TW.md +0 -151
  93. package/docs/guides-generating-documentation.zh.md +0 -151
  94. package/docs/guides-interactive-chat.ja.md +0 -85
  95. package/docs/guides-interactive-chat.md +0 -85
  96. package/docs/guides-interactive-chat.zh-TW.md +0 -85
  97. package/docs/guides-interactive-chat.zh.md +0 -85
  98. package/docs/guides-managing-history.ja.md +0 -48
  99. package/docs/guides-managing-history.md +0 -48
  100. package/docs/guides-managing-history.zh-TW.md +0 -48
  101. package/docs/guides-managing-history.zh.md +0 -48
  102. package/docs/guides-publishing-your-docs.ja.md +0 -78
  103. package/docs/guides-publishing-your-docs.md +0 -78
  104. package/docs/guides-publishing-your-docs.zh-TW.md +0 -78
  105. package/docs/guides-publishing-your-docs.zh.md +0 -78
  106. package/docs/guides-translating-documentation.ja.md +0 -95
  107. package/docs/guides-translating-documentation.md +0 -95
  108. package/docs/guides-translating-documentation.zh-TW.md +0 -95
  109. package/docs/guides-translating-documentation.zh.md +0 -95
  110. package/docs/guides-updating-documentation.ja.md +0 -77
  111. package/docs/guides-updating-documentation.md +0 -77
  112. package/docs/guides-updating-documentation.zh-TW.md +0 -77
  113. package/docs/guides-updating-documentation.zh.md +0 -77
  114. package/docs/guides.ja.md +0 -32
  115. package/docs/guides.md +0 -32
  116. package/docs/guides.zh-TW.md +0 -32
  117. package/docs/guides.zh.md +0 -32
  118. package/docs/overview.ja.md +0 -61
  119. package/docs/overview.md +0 -61
  120. package/docs/overview.zh-TW.md +0 -61
  121. package/docs/overview.zh.md +0 -61
  122. package/docs/release-notes.ja.md +0 -255
  123. package/docs/release-notes.md +0 -255
  124. package/docs/release-notes.zh-TW.md +0 -255
  125. package/docs/release-notes.zh.md +0 -255
  126. package/media.md +0 -19
  127. package/prompts/common/afs/afs-tools-usage.md +0 -5
  128. package/prompts/common/afs/use-afs-instruction.md +0 -1
  129. package/release-please-config.json +0 -14
  130. package/tests/agents/chat/chat.test.mjs +0 -46
  131. package/tests/agents/clear/choose-contents.test.mjs +0 -284
  132. package/tests/agents/clear/clear-auth-tokens.test.mjs +0 -268
  133. package/tests/agents/clear/clear-document-config.test.mjs +0 -167
  134. package/tests/agents/clear/clear-document-structure.test.mjs +0 -380
  135. package/tests/agents/clear/clear-generated-docs.test.mjs +0 -222
  136. package/tests/agents/evaluate/code-snippet.test.mjs +0 -163
  137. package/tests/agents/evaluate/fixtures/api-services.md +0 -87
  138. package/tests/agents/evaluate/fixtures/js-sdk.md +0 -94
  139. package/tests/agents/evaluate/generate-report.test.mjs +0 -312
  140. package/tests/agents/generate/check-document-structure.test.mjs +0 -45
  141. package/tests/agents/generate/check-need-generate-structure.test.mjs +0 -279
  142. package/tests/agents/generate/document-structure-tools/add-document.test.mjs +0 -449
  143. package/tests/agents/generate/document-structure-tools/delete-document.test.mjs +0 -410
  144. package/tests/agents/generate/document-structure-tools/generate-sub-structure.test.mjs +0 -277
  145. package/tests/agents/generate/document-structure-tools/move-document.test.mjs +0 -476
  146. package/tests/agents/generate/document-structure-tools/update-document.test.mjs +0 -548
  147. package/tests/agents/generate/generate-structure.test.mjs +0 -45
  148. package/tests/agents/generate/user-review-document-structure.test.mjs +0 -319
  149. package/tests/agents/history/view.test.mjs +0 -97
  150. package/tests/agents/init/init.test.mjs +0 -1657
  151. package/tests/agents/prefs/prefs.test.mjs +0 -431
  152. package/tests/agents/publish/publish-docs.test.mjs +0 -787
  153. package/tests/agents/translate/choose-language.test.mjs +0 -311
  154. package/tests/agents/translate/translate-document.test.mjs +0 -51
  155. package/tests/agents/update/check-document.test.mjs +0 -463
  156. package/tests/agents/update/check-update-is-single.test.mjs +0 -300
  157. package/tests/agents/update/document-tools/update-document-content.test.mjs +0 -329
  158. package/tests/agents/update/generate-document.test.mjs +0 -51
  159. package/tests/agents/update/save-and-translate-document.test.mjs +0 -369
  160. package/tests/agents/update/user-review-document.test.mjs +0 -582
  161. package/tests/agents/utils/action-success.test.mjs +0 -54
  162. package/tests/agents/utils/check-detail-result.test.mjs +0 -743
  163. package/tests/agents/utils/check-feedback-refiner.test.mjs +0 -478
  164. package/tests/agents/utils/choose-docs.test.mjs +0 -406
  165. package/tests/agents/utils/exit.test.mjs +0 -70
  166. package/tests/agents/utils/feedback-refiner.test.mjs +0 -51
  167. package/tests/agents/utils/find-item-by-path.test.mjs +0 -517
  168. package/tests/agents/utils/find-user-preferences-by-path.test.mjs +0 -382
  169. package/tests/agents/utils/format-document-structure.test.mjs +0 -364
  170. package/tests/agents/utils/fs.test.mjs +0 -267
  171. package/tests/agents/utils/load-sources.test.mjs +0 -1470
  172. package/tests/agents/utils/save-docs.test.mjs +0 -109
  173. package/tests/agents/utils/save-output.test.mjs +0 -315
  174. package/tests/agents/utils/save-single-doc.test.mjs +0 -364
  175. package/tests/agents/utils/transform-detail-datasources.test.mjs +0 -320
  176. package/tests/utils/auth-utils.test.mjs +0 -596
  177. package/tests/utils/blocklet.test.mjs +0 -336
  178. package/tests/utils/conflict-detector.test.mjs +0 -355
  179. package/tests/utils/constants.test.mjs +0 -295
  180. package/tests/utils/d2-utils.test.mjs +0 -437
  181. package/tests/utils/deploy.test.mjs +0 -399
  182. package/tests/utils/docs-finder-utils.test.mjs +0 -650
  183. package/tests/utils/file-utils.test.mjs +0 -521
  184. package/tests/utils/history-utils.test.mjs +0 -206
  185. package/tests/utils/kroki-utils.test.mjs +0 -646
  186. package/tests/utils/linter/fixtures/css/keyword-error.css +0 -1
  187. package/tests/utils/linter/fixtures/css/missing-semicolon.css +0 -1
  188. package/tests/utils/linter/fixtures/css/syntax-error.css +0 -1
  189. package/tests/utils/linter/fixtures/css/undeclare-variable.css +0 -1
  190. package/tests/utils/linter/fixtures/css/unused-variable.css +0 -2
  191. package/tests/utils/linter/fixtures/css/valid-code.css +0 -1
  192. package/tests/utils/linter/fixtures/dockerfile/keyword-error.dockerfile +0 -1
  193. package/tests/utils/linter/fixtures/dockerfile/missing-semicolon.dockerfile +0 -2
  194. package/tests/utils/linter/fixtures/dockerfile/syntax-error.dockerfile +0 -2
  195. package/tests/utils/linter/fixtures/dockerfile/undeclare-variable.dockerfile +0 -1
  196. package/tests/utils/linter/fixtures/dockerfile/unused-variable.dockerfile +0 -1
  197. package/tests/utils/linter/fixtures/dockerfile/valid-code.dockerfile +0 -2
  198. package/tests/utils/linter/fixtures/go/keyword-error.go +0 -5
  199. package/tests/utils/linter/fixtures/go/missing-semicolon.go +0 -5
  200. package/tests/utils/linter/fixtures/go/syntax-error.go +0 -6
  201. package/tests/utils/linter/fixtures/go/undeclare-variable.go +0 -5
  202. package/tests/utils/linter/fixtures/go/unused-variable.go +0 -5
  203. package/tests/utils/linter/fixtures/go/valid-code.go +0 -7
  204. package/tests/utils/linter/fixtures/js/keyword-error.js +0 -3
  205. package/tests/utils/linter/fixtures/js/missing-semicolon.js +0 -6
  206. package/tests/utils/linter/fixtures/js/syntax-error.js +0 -4
  207. package/tests/utils/linter/fixtures/js/undeclare-variable.js +0 -3
  208. package/tests/utils/linter/fixtures/js/unused-variable.js +0 -7
  209. package/tests/utils/linter/fixtures/js/valid-code.js +0 -15
  210. package/tests/utils/linter/fixtures/json/keyword-error.json +0 -1
  211. package/tests/utils/linter/fixtures/json/missing-semicolon.json +0 -1
  212. package/tests/utils/linter/fixtures/json/syntax-error.json +0 -1
  213. package/tests/utils/linter/fixtures/json/undeclare-variable.json +0 -1
  214. package/tests/utils/linter/fixtures/json/unused-variable.json +0 -1
  215. package/tests/utils/linter/fixtures/json/valid-code.json +0 -1
  216. package/tests/utils/linter/fixtures/jsx/keyword-error.jsx +0 -5
  217. package/tests/utils/linter/fixtures/jsx/missing-semicolon.jsx +0 -5
  218. package/tests/utils/linter/fixtures/jsx/syntax-error.jsx +0 -5
  219. package/tests/utils/linter/fixtures/jsx/undeclare-variable.jsx +0 -5
  220. package/tests/utils/linter/fixtures/jsx/unused-variable.jsx +0 -4
  221. package/tests/utils/linter/fixtures/jsx/valid-code.jsx +0 -5
  222. package/tests/utils/linter/fixtures/python/keyword-error.py +0 -3
  223. package/tests/utils/linter/fixtures/python/missing-semicolon.py +0 -2
  224. package/tests/utils/linter/fixtures/python/syntax-error.py +0 -3
  225. package/tests/utils/linter/fixtures/python/undeclare-variable.py +0 -3
  226. package/tests/utils/linter/fixtures/python/unused-variable.py +0 -6
  227. package/tests/utils/linter/fixtures/python/valid-code.py +0 -12
  228. package/tests/utils/linter/fixtures/ruby/keyword-error.rb +0 -2
  229. package/tests/utils/linter/fixtures/ruby/missing-semicolon.rb +0 -1
  230. package/tests/utils/linter/fixtures/ruby/syntax-error.rb +0 -2
  231. package/tests/utils/linter/fixtures/ruby/undeclare-variable.rb +0 -1
  232. package/tests/utils/linter/fixtures/ruby/unused-variable.rb +0 -2
  233. package/tests/utils/linter/fixtures/ruby/valid-code.rb +0 -1
  234. package/tests/utils/linter/fixtures/sass/keyword-error.sass +0 -2
  235. package/tests/utils/linter/fixtures/sass/missing-semicolon.sass +0 -3
  236. package/tests/utils/linter/fixtures/sass/syntax-error.sass +0 -3
  237. package/tests/utils/linter/fixtures/sass/undeclare-variable.sass +0 -2
  238. package/tests/utils/linter/fixtures/sass/unused-variable.sass +0 -4
  239. package/tests/utils/linter/fixtures/sass/valid-code.sass +0 -2
  240. package/tests/utils/linter/fixtures/scss/keyword-error.scss +0 -1
  241. package/tests/utils/linter/fixtures/scss/missing-semicolon.scss +0 -1
  242. package/tests/utils/linter/fixtures/scss/syntax-error.scss +0 -1
  243. package/tests/utils/linter/fixtures/scss/undeclare-variable.scss +0 -1
  244. package/tests/utils/linter/fixtures/scss/unused-variable.scss +0 -2
  245. package/tests/utils/linter/fixtures/scss/valid-code.scss +0 -1
  246. package/tests/utils/linter/fixtures/shell/keyword-error.sh +0 -5
  247. package/tests/utils/linter/fixtures/shell/missing-semicolon.sh +0 -3
  248. package/tests/utils/linter/fixtures/shell/syntax-error.sh +0 -4
  249. package/tests/utils/linter/fixtures/shell/undeclare-variable.sh +0 -3
  250. package/tests/utils/linter/fixtures/shell/unused-variable.sh +0 -4
  251. package/tests/utils/linter/fixtures/shell/valid-code.sh +0 -3
  252. package/tests/utils/linter/fixtures/ts/keyword-error.ts +0 -1
  253. package/tests/utils/linter/fixtures/ts/missing-semicolon.ts +0 -1
  254. package/tests/utils/linter/fixtures/ts/syntax-error.ts +0 -1
  255. package/tests/utils/linter/fixtures/ts/undeclare-variable.ts +0 -1
  256. package/tests/utils/linter/fixtures/ts/unused-variable.ts +0 -3
  257. package/tests/utils/linter/fixtures/ts/valid-code.ts +0 -3
  258. package/tests/utils/linter/fixtures/tsx/keyword-error.tsx +0 -5
  259. package/tests/utils/linter/fixtures/tsx/missing-semicolon.tsx +0 -5
  260. package/tests/utils/linter/fixtures/tsx/syntax-error.tsx +0 -5
  261. package/tests/utils/linter/fixtures/tsx/undeclare-variable.tsx +0 -6
  262. package/tests/utils/linter/fixtures/tsx/unused-variable.tsx +0 -6
  263. package/tests/utils/linter/fixtures/tsx/valid-code.tsx +0 -5
  264. package/tests/utils/linter/fixtures/vue/keyword-error.vue +0 -6
  265. package/tests/utils/linter/fixtures/vue/missing-semicolon.vue +0 -6
  266. package/tests/utils/linter/fixtures/vue/syntax-error.vue +0 -6
  267. package/tests/utils/linter/fixtures/vue/undeclare-variable.vue +0 -6
  268. package/tests/utils/linter/fixtures/vue/unused-variable.vue +0 -7
  269. package/tests/utils/linter/fixtures/vue/valid-code.vue +0 -6
  270. package/tests/utils/linter/fixtures/yaml/keyword-error.yml +0 -1
  271. package/tests/utils/linter/fixtures/yaml/missing-semicolon.yml +0 -2
  272. package/tests/utils/linter/fixtures/yaml/syntax-error.yml +0 -1
  273. package/tests/utils/linter/fixtures/yaml/undeclare-variable.yml +0 -1
  274. package/tests/utils/linter/fixtures/yaml/unused-variable.yml +0 -2
  275. package/tests/utils/linter/fixtures/yaml/valid-code.yml +0 -3
  276. package/tests/utils/linter/index.test.mjs +0 -440
  277. package/tests/utils/linter/scan-results.mjs +0 -42
  278. package/tests/utils/load-config.test.mjs +0 -141
  279. package/tests/utils/markdown/index.test.mjs +0 -478
  280. package/tests/utils/mermaid-validator.test.mjs +0 -541
  281. package/tests/utils/mock-chat-model.mjs +0 -12
  282. package/tests/utils/preferences-utils.test.mjs +0 -465
  283. package/tests/utils/save-value-to-config.test.mjs +0 -483
  284. package/tests/utils/utils.test.mjs +0 -941
@@ -1,478 +0,0 @@
1
- import { describe, expect, test } from "bun:test";
2
- import { getMarkdownAst, traverseMarkdownAst } from "../../../utils/markdown/index.mjs";
3
-
4
- describe("markdown utilities", () => {
5
- describe("getMarkdownAst", () => {
6
- test("should parse simple markdown text", () => {
7
- const markdown = "# Hello World\n\nThis is a paragraph.";
8
- const ast = getMarkdownAst({ markdown });
9
-
10
- expect(ast).toBeDefined();
11
- expect(ast.type).toBe("root");
12
- expect(ast.children).toHaveLength(2);
13
- expect(ast.children[0].type).toBe("heading");
14
- expect(ast.children[0].depth).toBe(1);
15
- expect(ast.children[1].type).toBe("paragraph");
16
- });
17
-
18
- test("should parse markdown with code blocks", () => {
19
- const markdown = `
20
- # Title
21
-
22
- \`\`\`javascript
23
- console.log("Hello World");
24
- \`\`\`
25
-
26
- Inline \`code\` here.
27
- `;
28
- const ast = getMarkdownAst({ markdown });
29
-
30
- expect(ast).toBeDefined();
31
- expect(ast.children).toHaveLength(3);
32
- expect(ast.children[1].type).toBe("code");
33
- expect(ast.children[1].lang).toBe("javascript");
34
- expect(ast.children[2].children[1].type).toBe("inlineCode");
35
- });
36
-
37
- test("should parse markdown with lists", () => {
38
- const markdown = `
39
- # List Example
40
-
41
- - Item 1
42
- - Item 2
43
- - Nested item
44
- - Item 3
45
-
46
- 1. Ordered item 1
47
- 2. Ordered item 2
48
- `;
49
- const ast = getMarkdownAst({ markdown });
50
-
51
- expect(ast).toBeDefined();
52
- expect(ast.children).toHaveLength(3);
53
- expect(ast.children[1].type).toBe("list");
54
- expect(ast.children[1].ordered).toBe(false);
55
- expect(ast.children[2].type).toBe("list");
56
- expect(ast.children[2].ordered).toBe(true);
57
- });
58
-
59
- test("should parse markdown with links and images", () => {
60
- const markdown = `
61
- # Links and Images
62
-
63
- [Example Link](https://example.com)
64
-
65
- ![Alt text](image.png "Image title")
66
- `;
67
- const ast = getMarkdownAst({ markdown });
68
-
69
- expect(ast).toBeDefined();
70
- expect(ast.children[1].children[0].type).toBe("link");
71
- expect(ast.children[1].children[0].url).toBe("https://example.com");
72
- expect(ast.children[2].children[0].type).toBe("image");
73
- expect(ast.children[2].children[0].url).toBe("image.png");
74
- });
75
-
76
- test("should parse GitHub Flavored Markdown features", () => {
77
- const markdown = `
78
- # GFM Features
79
-
80
- | Header 1 | Header 2 |
81
- |----------|----------|
82
- | Cell 1 | Cell 2 |
83
-
84
- ~~Strikethrough text~~
85
-
86
- - [x] Completed task
87
- - [ ] Incomplete task
88
- `;
89
- const ast = getMarkdownAst({ markdown });
90
-
91
- expect(ast).toBeDefined();
92
- // Check for table
93
- const table = ast.children.find((child) => child.type === "table");
94
- expect(table).toBeDefined();
95
- expect(table.children).toHaveLength(2); // header + row
96
-
97
- // Check for strikethrough
98
- const strikethrough = ast.children.find((child) =>
99
- child.children?.some((c) => c.type === "delete"),
100
- );
101
- expect(strikethrough).toBeDefined();
102
-
103
- // Check for task list
104
- const taskList = ast.children.find((child) => child.type === "list");
105
- expect(taskList).toBeDefined();
106
- });
107
-
108
- test("should handle empty markdown", () => {
109
- const markdown = "";
110
- expect(() => getMarkdownAst({ markdown })).toThrow(
111
- "Invalid markdown input: must be a non-empty string",
112
- );
113
- });
114
-
115
- test("should handle null markdown", () => {
116
- expect(() => getMarkdownAst({ markdown: null })).toThrow(
117
- "Invalid markdown input: must be a non-empty string",
118
- );
119
- });
120
-
121
- test("should handle undefined markdown", () => {
122
- expect(() => getMarkdownAst({ markdown: undefined })).toThrow(
123
- "Invalid markdown input: must be a non-empty string",
124
- );
125
- });
126
-
127
- test("should handle non-string markdown", () => {
128
- expect(() => getMarkdownAst({ markdown: 123 })).toThrow(
129
- "Invalid markdown input: must be a non-empty string",
130
- );
131
- expect(() => getMarkdownAst({ markdown: {} })).toThrow(
132
- "Invalid markdown input: must be a non-empty string",
133
- );
134
- expect(() => getMarkdownAst({ markdown: [] })).toThrow(
135
- "Invalid markdown input: must be a non-empty string",
136
- );
137
- });
138
-
139
- test("should handle markdown with special characters", () => {
140
- const markdown = `
141
- # 中文标题
142
-
143
- This has **bold** and *italic* text.
144
-
145
- > This is a blockquote with 🚀 emoji.
146
-
147
- \`\`\`
148
- Code with special chars: @#$%^&*()
149
- \`\`\`
150
- `;
151
- const ast = getMarkdownAst({ markdown });
152
-
153
- expect(ast).toBeDefined();
154
- expect(ast.children).toHaveLength(4);
155
- expect(ast.children[0].type).toBe("heading");
156
- expect(ast.children[2].type).toBe("blockquote");
157
- expect(ast.children[3].type).toBe("code");
158
- });
159
-
160
- test("should handle malformed markdown gracefully", () => {
161
- // This should still parse without throwing
162
- const markdown = `
163
- # Incomplete heading [
164
-
165
- [Incomplete link](
166
-
167
- \`\`\`incomplete
168
- code block without closing
169
- `;
170
- const ast = getMarkdownAst({ markdown });
171
-
172
- expect(ast).toBeDefined();
173
- expect(ast.type).toBe("root");
174
- expect(ast.children.length).toBeGreaterThan(0);
175
- });
176
-
177
- test("should handle processor parsing errors", () => {
178
- // Since we've successfully tested all other paths, we need to test the error handling
179
- // Let's create a direct test of the catch block logic
180
-
181
- // Simulate the exact function but with a controlled error
182
- function testErrorHandling() {
183
- try {
184
- // Simulate what happens in the try block when processor.parse fails
185
- throw new Error("Simulated parser crash");
186
- } catch (error) {
187
- // This is the exact code from lines 23-24
188
- throw new Error(`Failed to parse markdown: ${error.message}`);
189
- }
190
- }
191
-
192
- // Test that our error wrapping logic works correctly
193
- expect(() => testErrorHandling()).toThrow("Failed to parse markdown: Simulated parser crash");
194
-
195
- // Also test with various error types to ensure the wrapping works for different scenarios
196
- function testErrorWrapping(originalError) {
197
- try {
198
- throw originalError;
199
- } catch (error) {
200
- throw new Error(`Failed to parse markdown: ${error.message}`);
201
- }
202
- }
203
-
204
- expect(() => testErrorWrapping(new TypeError("Type error"))).toThrow(
205
- "Failed to parse markdown: Type error",
206
- );
207
- expect(() => testErrorWrapping(new ReferenceError("Reference error"))).toThrow(
208
- "Failed to parse markdown: Reference error",
209
- );
210
- expect(() => testErrorWrapping(new Error("Generic error"))).toThrow(
211
- "Failed to parse markdown: Generic error",
212
- );
213
-
214
- // Test edge case where error has no message
215
- const errorWithoutMessage = new Error();
216
- errorWithoutMessage.message = "";
217
- expect(() => testErrorWrapping(errorWithoutMessage)).toThrow("Failed to parse markdown: ");
218
-
219
- // Test with extremely large markdown (this might actually succeed, which is fine)
220
- const largeMarkdown = "#".repeat(1000000); // 1MB of hash symbols
221
- try {
222
- const result = getMarkdownAst({ markdown: largeMarkdown });
223
- expect(result).toBeDefined();
224
- } catch (error) {
225
- expect(error.message).toMatch(/Failed to parse markdown:|Invalid markdown input:/);
226
- }
227
- });
228
- });
229
-
230
- describe("traverseMarkdownAst", () => {
231
- test("should traverse AST and visit all nodes", () => {
232
- const markdown = "# Heading\n\nParagraph with **bold** text.";
233
- const ast = getMarkdownAst({ markdown });
234
-
235
- const visitedNodes = [];
236
- traverseMarkdownAst({
237
- ast,
238
- test: () => true, // Visit all nodes
239
- visitor: (node) => {
240
- visitedNodes.push(node.type);
241
- },
242
- });
243
-
244
- expect(visitedNodes.length).toBeGreaterThan(0);
245
- expect(visitedNodes).toContain("heading");
246
- expect(visitedNodes).toContain("paragraph");
247
- expect(visitedNodes).toContain("text");
248
- expect(visitedNodes).toContain("strong");
249
- });
250
-
251
- test("should visit only specific node types", () => {
252
- const markdown = `
253
- # Heading 1
254
- ## Heading 2
255
- ### Heading 3
256
-
257
- Paragraph text.
258
- `;
259
- const ast = getMarkdownAst({ markdown });
260
-
261
- const headings = [];
262
- traverseMarkdownAst({
263
- ast,
264
- test: "heading", // Only visit heading nodes
265
- visitor: (node) => {
266
- headings.push({ depth: node.depth, text: node.children[0].value });
267
- },
268
- });
269
-
270
- expect(headings).toHaveLength(3);
271
- expect(headings[0].depth).toBe(1);
272
- expect(headings[1].depth).toBe(2);
273
- expect(headings[2].depth).toBe(3);
274
- });
275
-
276
- test("should visit nodes based on custom test function", () => {
277
- const markdown = `
278
- # Main Title
279
-
280
- ## Section 1
281
- Content here.
282
-
283
- ## Section 2
284
- More content.
285
-
286
- ### Subsection
287
- Even more content.
288
- `;
289
- const ast = getMarkdownAst({ markdown });
290
-
291
- const level2Headings = [];
292
- traverseMarkdownAst({
293
- ast,
294
- test: (node) => node.type === "heading" && node.depth === 2,
295
- visitor: (node) => {
296
- level2Headings.push(node.children[0].value);
297
- },
298
- });
299
-
300
- expect(level2Headings).toHaveLength(2);
301
- expect(level2Headings).toContain("Section 1");
302
- expect(level2Headings).toContain("Section 2");
303
- });
304
-
305
- test("should collect code blocks with language information", () => {
306
- const markdown = `
307
- \`\`\`javascript
308
- console.log("JS code");
309
- \`\`\`
310
-
311
- \`\`\`python
312
- print("Python code")
313
- \`\`\`
314
-
315
- \`\`\`
316
- Plain code block
317
- \`\`\`
318
- `;
319
- const ast = getMarkdownAst({ markdown });
320
-
321
- const codeBlocks = [];
322
- traverseMarkdownAst({
323
- ast,
324
- test: "code",
325
- visitor: (node) => {
326
- codeBlocks.push({
327
- lang: node.lang || "none",
328
- value: node.value,
329
- });
330
- },
331
- });
332
-
333
- expect(codeBlocks).toHaveLength(3);
334
- expect(codeBlocks[0].lang).toBe("javascript");
335
- expect(codeBlocks[1].lang).toBe("python");
336
- expect(codeBlocks[2].lang).toBe("none");
337
- });
338
-
339
- test("should extract all links from markdown", () => {
340
- const markdown = `
341
- # Links Example
342
-
343
- [Example](https://example.com)
344
- [GitHub](https://github.com)
345
-
346
- ![Image](image.png)
347
-
348
- Reference link: [Google][1]
349
-
350
- [1]: https://google.com
351
- `;
352
- const ast = getMarkdownAst({ markdown });
353
-
354
- const links = [];
355
- traverseMarkdownAst({
356
- ast,
357
- test: (node) => node.type === "link" || node.type === "linkReference",
358
- visitor: (node) => {
359
- if (node.type === "link") {
360
- links.push({ text: node.children[0].value, url: node.url });
361
- } else if (node.type === "linkReference") {
362
- links.push({ text: node.children[0].value, ref: node.identifier });
363
- }
364
- },
365
- });
366
-
367
- expect(links.length).toBeGreaterThan(0);
368
- expect(links.some((link) => link.text === "Example")).toBe(true);
369
- expect(links.some((link) => link.text === "GitHub")).toBe(true);
370
- });
371
-
372
- test("should handle visitor that modifies nodes", () => {
373
- const markdown = "# Original Title\n\nSome content.";
374
- const ast = getMarkdownAst({ markdown });
375
-
376
- // Modify heading text
377
- traverseMarkdownAst({
378
- ast,
379
- test: "heading",
380
- visitor: (node) => {
381
- if (node.children?.[0] && node.children[0].type === "text") {
382
- node.children[0].value = "Modified Title";
383
- }
384
- },
385
- });
386
-
387
- // Verify the modification
388
- const headingNode = ast.children.find((child) => child.type === "heading");
389
- expect(headingNode.children[0].value).toBe("Modified Title");
390
- });
391
-
392
- test("should throw error when ast parameter is missing", () => {
393
- expect(() => {
394
- traverseMarkdownAst({
395
- test: "heading",
396
- visitor: () => {},
397
- });
398
- }).toThrow("Required parameters missing: ast, test, and visitor must be provided");
399
- });
400
-
401
- test("should throw error when test parameter is missing", () => {
402
- const ast = { type: "root", children: [] };
403
- expect(() => {
404
- traverseMarkdownAst({
405
- ast,
406
- visitor: () => {},
407
- });
408
- }).toThrow("Required parameters missing: ast, test, and visitor must be provided");
409
- });
410
-
411
- test("should throw error when visitor parameter is missing", () => {
412
- const ast = { type: "root", children: [] };
413
- expect(() => {
414
- traverseMarkdownAst({
415
- ast,
416
- test: "heading",
417
- });
418
- }).toThrow("Required parameters missing: ast, test, and visitor must be provided");
419
- });
420
-
421
- test("should throw error when all parameters are missing", () => {
422
- expect(() => {
423
- traverseMarkdownAst({});
424
- }).toThrow("Required parameters missing: ast, test, and visitor must be provided");
425
- });
426
-
427
- test("should handle empty AST", () => {
428
- const ast = { type: "root", children: [] };
429
- const visitedNodes = [];
430
-
431
- traverseMarkdownAst({
432
- ast,
433
- test: () => true,
434
- visitor: (node) => {
435
- visitedNodes.push(node.type);
436
- },
437
- });
438
-
439
- // Should only visit the root node
440
- expect(visitedNodes).toEqual(["root"]);
441
- });
442
-
443
- test("should handle complex nested structures", () => {
444
- const markdown = `
445
- # Main Heading
446
-
447
- 1. First item
448
- - Sub item with **bold** text
449
- - Another sub item with [link](https://example.com)
450
- 2. Second item
451
- > Blockquote with *italic* text
452
-
453
- | Col 1 | Col 2 |
454
- |-------|-------|
455
- | Data | More |
456
- `;
457
- const ast = getMarkdownAst({ markdown });
458
-
459
- const nodeTypes = new Set();
460
- traverseMarkdownAst({
461
- ast,
462
- test: () => true,
463
- visitor: (node) => {
464
- nodeTypes.add(node.type);
465
- },
466
- });
467
-
468
- expect(nodeTypes.has("heading")).toBe(true);
469
- expect(nodeTypes.has("list")).toBe(true);
470
- expect(nodeTypes.has("listItem")).toBe(true);
471
- expect(nodeTypes.has("blockquote")).toBe(true);
472
- expect(nodeTypes.has("table")).toBe(true);
473
- expect(nodeTypes.has("strong")).toBe(true);
474
- expect(nodeTypes.has("emphasis")).toBe(true);
475
- expect(nodeTypes.has("link")).toBe(true);
476
- });
477
- });
478
- });