@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,364 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test";
2
- import saveSingleDoc from "../../../agents/utils/save-single-doc.mjs";
3
- import * as mermaidWorkerPool from "../../../utils/mermaid-worker-pool.mjs";
4
- import * as utils from "../../../utils/utils.mjs";
5
-
6
- describe("saveSingleDoc utility", () => {
7
- let consoleWarnSpy;
8
- let shutdownMermaidWorkerPoolSpy;
9
- let saveDocWithTranslationsSpy;
10
-
11
- beforeEach(() => {
12
- shutdownMermaidWorkerPoolSpy = spyOn(
13
- mermaidWorkerPool,
14
- "shutdownMermaidWorkerPool",
15
- ).mockResolvedValue();
16
- saveDocWithTranslationsSpy = spyOn(utils, "saveDocWithTranslations").mockResolvedValue({
17
- success: true,
18
- });
19
- consoleWarnSpy = spyOn(console, "warn").mockImplementation(() => {});
20
- });
21
-
22
- afterEach(() => {
23
- // Restore all spies
24
- shutdownMermaidWorkerPoolSpy?.mockRestore();
25
- saveDocWithTranslationsSpy?.mockRestore();
26
- consoleWarnSpy?.mockRestore();
27
- });
28
-
29
- // BASIC FUNCTIONALITY TESTS
30
- test("should save document without showing message", async () => {
31
- const options = {
32
- path: "/docs/guide.md",
33
- content: "# User Guide\n\nThis is a guide.",
34
- docsDir: "/project/docs",
35
- translates: [],
36
- labels: {},
37
- locale: "en",
38
- isTranslate: false,
39
- isShowMessage: false,
40
- };
41
-
42
- const result = await saveSingleDoc(options);
43
-
44
- expect(saveDocWithTranslationsSpy).toHaveBeenCalledWith({
45
- path: "/docs/guide.md",
46
- content: "# User Guide\n\nThis is a guide.",
47
- docsDir: "/project/docs",
48
- translates: [],
49
- labels: {},
50
- locale: "en",
51
- isTranslate: false,
52
- });
53
- expect(shutdownMermaidWorkerPoolSpy).not.toHaveBeenCalled();
54
- expect(result).toEqual({});
55
- });
56
-
57
- test("should save document with success message for regular update", async () => {
58
- const options = {
59
- path: "/docs/api.md",
60
- content: "# API Reference",
61
- docsDir: "/project/docs",
62
- translates: ["zh", "ja"],
63
- labels: { api: "API" },
64
- locale: "en",
65
- isTranslate: false,
66
- isShowMessage: true,
67
- };
68
-
69
- const result = await saveSingleDoc(options);
70
-
71
- expect(saveDocWithTranslationsSpy).toHaveBeenCalledWith({
72
- path: "/docs/api.md",
73
- content: "# API Reference",
74
- docsDir: "/project/docs",
75
- translates: ["zh", "ja"],
76
- labels: { api: "API" },
77
- locale: "en",
78
- isTranslate: false,
79
- });
80
- expect(shutdownMermaidWorkerPoolSpy).toHaveBeenCalled();
81
- expect(result).toEqual({
82
- message: "✅ Document updated successfully",
83
- });
84
- });
85
-
86
- test("should save document with success message for translation", async () => {
87
- const options = {
88
- path: "/docs/zh/guide.md",
89
- content: "# 用户指南\n\n这是一个指南。",
90
- docsDir: "/project/docs",
91
- translates: ["zh", "ja"],
92
- labels: { guide: "指南" },
93
- locale: "zh",
94
- isTranslate: true,
95
- isShowMessage: true,
96
- };
97
-
98
- const result = await saveSingleDoc(options);
99
-
100
- expect(saveDocWithTranslationsSpy).toHaveBeenCalledWith({
101
- path: "/docs/zh/guide.md",
102
- content: "# 用户指南\n\n这是一个指南。",
103
- docsDir: "/project/docs",
104
- translates: ["zh", "ja"],
105
- labels: { guide: "指南" },
106
- locale: "zh",
107
- isTranslate: true,
108
- });
109
- expect(shutdownMermaidWorkerPoolSpy).toHaveBeenCalled();
110
- expect(result).toEqual({
111
- message: "✅ Translation completed successfully",
112
- });
113
- });
114
-
115
- // DEFAULT VALUES TESTS
116
- test("should use default values for optional parameters", async () => {
117
- const options = {
118
- path: "/docs/minimal.md",
119
- content: "# Minimal",
120
- docsDir: "/docs",
121
- translates: [],
122
- labels: {},
123
- locale: "en",
124
- };
125
-
126
- const result = await saveSingleDoc(options);
127
-
128
- expect(saveDocWithTranslationsSpy).toHaveBeenCalledWith({
129
- path: "/docs/minimal.md",
130
- content: "# Minimal",
131
- docsDir: "/docs",
132
- translates: [],
133
- labels: {},
134
- locale: "en",
135
- isTranslate: false, // Default value
136
- });
137
- expect(shutdownMermaidWorkerPoolSpy).not.toHaveBeenCalled();
138
- expect(result).toEqual({});
139
- });
140
-
141
- test("should handle explicit false values", async () => {
142
- const options = {
143
- path: "/docs/explicit.md",
144
- content: "# Explicit",
145
- docsDir: "/docs",
146
- translates: [],
147
- labels: {},
148
- locale: "en",
149
- isTranslate: false,
150
- isShowMessage: false,
151
- };
152
-
153
- const result = await saveSingleDoc(options);
154
-
155
- expect(saveDocWithTranslationsSpy).toHaveBeenCalledWith(
156
- expect.objectContaining({
157
- isTranslate: false,
158
- }),
159
- );
160
- expect(result).toEqual({});
161
- });
162
-
163
- // MERMAID WORKER POOL SHUTDOWN TESTS
164
- test("should handle mermaid worker pool shutdown error gracefully", async () => {
165
- const shutdownError = new Error("Worker pool shutdown failed");
166
- shutdownMermaidWorkerPoolSpy.mockRejectedValue(shutdownError);
167
-
168
- const options = {
169
- path: "/docs/with-error.md",
170
- content: "# Document with shutdown error",
171
- docsDir: "/docs",
172
- translates: [],
173
- labels: {},
174
- locale: "en",
175
- isTranslate: false,
176
- isShowMessage: true,
177
- };
178
-
179
- const result = await saveSingleDoc(options);
180
-
181
- expect(shutdownMermaidWorkerPoolSpy).toHaveBeenCalled();
182
- expect(consoleWarnSpy).toHaveBeenCalledWith(
183
- "Failed to shutdown mermaid worker pool:",
184
- "Worker pool shutdown failed",
185
- );
186
- expect(result).toEqual({
187
- message: "✅ Document updated successfully",
188
- });
189
- });
190
-
191
- test("should handle mermaid worker pool shutdown error for translation", async () => {
192
- const shutdownError = new Error("Pool cleanup failed");
193
- shutdownMermaidWorkerPoolSpy.mockRejectedValue(shutdownError);
194
-
195
- const options = {
196
- path: "/docs/zh/with-error.md",
197
- content: "# 带错误的文档",
198
- docsDir: "/docs",
199
- translates: ["zh"],
200
- labels: {},
201
- locale: "zh",
202
- isTranslate: true,
203
- isShowMessage: true,
204
- };
205
-
206
- const result = await saveSingleDoc(options);
207
-
208
- expect(consoleWarnSpy).toHaveBeenCalledWith(
209
- "Failed to shutdown mermaid worker pool:",
210
- "Pool cleanup failed",
211
- );
212
- expect(result).toEqual({
213
- message: "✅ Translation completed successfully",
214
- });
215
- });
216
-
217
- // COMPREHENSIVE PARAMETER TESTS
218
- test("should pass all parameters correctly to saveDocWithTranslations", async () => {
219
- const complexOptions = {
220
- path: "/docs/complex/nested/file.md",
221
- content: "# Complex Document\n\nWith multiple sections.",
222
- docsDir: "/project/documentation",
223
- translates: ["zh-CN", "ja-JP", "ko-KR"],
224
- labels: {
225
- title: "标题",
226
- section: "部分",
227
- example: "例子",
228
- },
229
- locale: "zh-CN",
230
- isTranslate: true,
231
- isShowMessage: false,
232
- };
233
-
234
- await saveSingleDoc(complexOptions);
235
-
236
- expect(saveDocWithTranslationsSpy).toHaveBeenCalledWith({
237
- path: "/docs/complex/nested/file.md",
238
- content: "# Complex Document\n\nWith multiple sections.",
239
- docsDir: "/project/documentation",
240
- translates: ["zh-CN", "ja-JP", "ko-KR"],
241
- labels: {
242
- title: "标题",
243
- section: "部分",
244
- example: "例子",
245
- },
246
- locale: "zh-CN",
247
- isTranslate: true,
248
- });
249
- });
250
-
251
- // EDGE CASES
252
- test("should handle empty content", async () => {
253
- const options = {
254
- path: "/docs/empty.md",
255
- content: "",
256
- docsDir: "/docs",
257
- translates: [],
258
- labels: {},
259
- locale: "en",
260
- isShowMessage: true,
261
- };
262
-
263
- const result = await saveSingleDoc(options);
264
-
265
- expect(saveDocWithTranslationsSpy).toHaveBeenCalledWith(
266
- expect.objectContaining({
267
- content: "",
268
- }),
269
- );
270
- expect(result).toEqual({
271
- message: "✅ Document updated successfully",
272
- });
273
- });
274
-
275
- test("should handle empty translations array", async () => {
276
- const options = {
277
- path: "/docs/no-translations.md",
278
- content: "# No Translations",
279
- docsDir: "/docs",
280
- translates: [],
281
- labels: {},
282
- locale: "en",
283
- };
284
-
285
- await saveSingleDoc(options);
286
-
287
- expect(saveDocWithTranslationsSpy).toHaveBeenCalledWith(
288
- expect.objectContaining({
289
- translates: [],
290
- }),
291
- );
292
- });
293
-
294
- test("should handle empty labels object", async () => {
295
- const options = {
296
- path: "/docs/no-labels.md",
297
- content: "# No Labels",
298
- docsDir: "/docs",
299
- translates: ["zh"],
300
- labels: {},
301
- locale: "en",
302
- };
303
-
304
- await saveSingleDoc(options);
305
-
306
- expect(saveDocWithTranslationsSpy).toHaveBeenCalledWith(
307
- expect.objectContaining({
308
- labels: {},
309
- }),
310
- );
311
- });
312
-
313
- // SPECIAL CHARACTERS AND PATHS
314
- test("should handle paths with special characters", async () => {
315
- const options = {
316
- path: "/docs/特殊字符/file with spaces.md",
317
- content: "# Special Characters 特殊字符",
318
- docsDir: "/project/docs",
319
- translates: ["zh-CN"],
320
- labels: { special: "特殊" },
321
- locale: "zh-CN",
322
- isTranslate: true,
323
- };
324
-
325
- await saveSingleDoc(options);
326
-
327
- expect(saveDocWithTranslationsSpy).toHaveBeenCalledWith(
328
- expect.objectContaining({
329
- path: "/docs/特殊字符/file with spaces.md",
330
- content: "# Special Characters 特殊字符",
331
- labels: { special: "特殊" },
332
- locale: "zh-CN",
333
- }),
334
- );
335
- });
336
-
337
- // RETURN VALUE CONSISTENCY
338
- test("should always return object structure", async () => {
339
- const withoutMessage = await saveSingleDoc({
340
- path: "/docs/test1.md",
341
- content: "Test",
342
- docsDir: "/docs",
343
- translates: [],
344
- labels: {},
345
- locale: "en",
346
- isShowMessage: false,
347
- });
348
-
349
- const withMessage = await saveSingleDoc({
350
- path: "/docs/test2.md",
351
- content: "Test",
352
- docsDir: "/docs",
353
- translates: [],
354
- labels: {},
355
- locale: "en",
356
- isShowMessage: true,
357
- });
358
-
359
- expect(typeof withoutMessage).toBe("object");
360
- expect(typeof withMessage).toBe("object");
361
- expect(withoutMessage).toEqual({});
362
- expect(withMessage).toHaveProperty("message");
363
- });
364
- });
@@ -1,320 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test";
2
- import { mkdir, rm, writeFile } from "node:fs/promises";
3
- import path, { dirname } from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- import transformDetailDatasources from "../../../agents/utils/transform-detail-datasources.mjs";
6
- import * as utils from "../../../utils/utils.mjs";
7
-
8
- const __dirname = dirname(fileURLToPath(import.meta.url));
9
-
10
- describe("transformDetailDatasources utility", () => {
11
- let normalizePathSpy;
12
- let toRelativePathSpy;
13
- let testDir;
14
-
15
- beforeEach(async () => {
16
- // Create test directory
17
- const uniqueId = `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
18
- testDir = path.join(__dirname, `test-transform-${uniqueId}`);
19
- await mkdir(testDir, { recursive: true });
20
-
21
- // Spy on utility functions
22
- normalizePathSpy = spyOn(utils, "normalizePath").mockImplementation((path) =>
23
- path?.replace(/\\/g, "/").replace(/^\.\//, ""),
24
- );
25
- toRelativePathSpy = spyOn(utils, "toRelativePath").mockImplementation((path) =>
26
- path?.startsWith("/") ? path.substring(1) : path,
27
- );
28
- });
29
-
30
- afterEach(async () => {
31
- // Restore all spies
32
- normalizePathSpy?.mockRestore();
33
- toRelativePathSpy?.mockRestore();
34
-
35
- // Clean up test directory
36
- try {
37
- await rm(testDir, { recursive: true, force: true });
38
- } catch {
39
- console.warn(`Warning: Could not clean up test directory: ${testDir}`);
40
- }
41
- });
42
-
43
- // BASIC FUNCTIONALITY TESTS
44
- test("should transform simple datasources correctly", async () => {
45
- // Create test files
46
- const guidePath = path.join(testDir, "guide.md");
47
- const apiPath = path.join(testDir, "api.md");
48
- await writeFile(guidePath, "# User Guide\n\nThis is a guide.");
49
- await writeFile(apiPath, "# API Reference\n\nAPI documentation.");
50
-
51
- // Mock normalizePath to return the actual file path
52
- normalizePathSpy.mockImplementation((p) => p);
53
-
54
- const input = {
55
- sourceIds: [guidePath, apiPath],
56
- };
57
-
58
- const result = transformDetailDatasources(input);
59
-
60
- expect(normalizePathSpy).toHaveBeenCalledWith(guidePath);
61
- expect(normalizePathSpy).toHaveBeenCalledWith(apiPath);
62
- expect(toRelativePathSpy).toHaveBeenCalledWith(guidePath);
63
- expect(toRelativePathSpy).toHaveBeenCalledWith(apiPath);
64
-
65
- expect(result.detailDataSources).toContain("# User Guide\n\nThis is a guide.");
66
- expect(result.detailDataSources).toContain("# API Reference\n\nAPI documentation.");
67
- });
68
-
69
- test("should handle single datasource", async () => {
70
- // Create test file
71
- const readmePath = path.join(testDir, "readme.md");
72
- await writeFile(readmePath, "# README\n\nProject documentation.");
73
-
74
- normalizePathSpy.mockImplementation((p) => p);
75
-
76
- const input = {
77
- sourceIds: [readmePath],
78
- };
79
-
80
- const result = transformDetailDatasources(input);
81
-
82
- expect(result.detailDataSources).toContain("# README\n\nProject documentation.");
83
- });
84
-
85
- test("should maintain order of sourceIds", async () => {
86
- // Create test files
87
- const cPath = path.join(testDir, "c.md");
88
- const aPath = path.join(testDir, "a.md");
89
- const bPath = path.join(testDir, "b.md");
90
- await writeFile(cPath, "Content C");
91
- await writeFile(aPath, "Content A");
92
- await writeFile(bPath, "Content B");
93
-
94
- normalizePathSpy.mockImplementation((p) => p);
95
-
96
- const input = {
97
- sourceIds: [cPath, aPath, bPath],
98
- };
99
-
100
- const result = transformDetailDatasources(input);
101
-
102
- // Check order by finding indices
103
- const indexC = result.detailDataSources.indexOf("Content C");
104
- const indexA = result.detailDataSources.indexOf("Content A");
105
- const indexB = result.detailDataSources.indexOf("Content B");
106
-
107
- expect(indexC).toBeLessThan(indexA);
108
- expect(indexA).toBeLessThan(indexB);
109
- });
110
-
111
- // PATH NORMALIZATION TESTS
112
- test("should normalize paths correctly", async () => {
113
- // Create test files
114
- const guidePath = path.join(testDir, "guide.md");
115
- const apiPath = path.join(testDir, "api.md");
116
- await writeFile(guidePath, "Guide content");
117
- await writeFile(apiPath, "API content");
118
-
119
- normalizePathSpy.mockImplementation((p) => p?.replace(/\\/g, "/"));
120
-
121
- const input = {
122
- sourceIds: [guidePath, apiPath],
123
- };
124
-
125
- const result = transformDetailDatasources(input);
126
-
127
- expect(normalizePathSpy).toHaveBeenCalledWith(guidePath);
128
- expect(normalizePathSpy).toHaveBeenCalledWith(apiPath);
129
- expect(result.detailDataSources).toContain("Guide content");
130
- expect(result.detailDataSources).toContain("API content");
131
- });
132
-
133
- test("should handle relative path conversion", async () => {
134
- // Create test files
135
- const absPath = path.join(testDir, "abs-file.md");
136
- const relPath = path.join(testDir, "rel-file.md");
137
- await writeFile(absPath, "Absolute content");
138
- await writeFile(relPath, "Relative content");
139
-
140
- normalizePathSpy.mockImplementation((p) => p);
141
- toRelativePathSpy.mockImplementation((p) => p?.replace(/^\/+/, "").replace(/^\.\//, ""));
142
-
143
- const input = {
144
- sourceIds: [absPath, relPath],
145
- };
146
-
147
- const result = transformDetailDatasources(input);
148
-
149
- expect(toRelativePathSpy).toHaveBeenCalledWith(absPath);
150
- expect(toRelativePathSpy).toHaveBeenCalledWith(relPath);
151
- expect(result.detailDataSources).toContain("Absolute content");
152
- expect(result.detailDataSources).toContain("Relative content");
153
- });
154
-
155
- // MISSING DATA TESTS
156
- test("should filter out sourceIds for files that don't exist", async () => {
157
- // Create only some test files
158
- const guidePath = path.join(testDir, "guide.md");
159
- const apiPath = path.join(testDir, "api.md");
160
- const missingPath = path.join(testDir, "missing.md");
161
- await writeFile(guidePath, "Guide content");
162
- await writeFile(apiPath, "API content");
163
- // missingPath intentionally not created
164
-
165
- normalizePathSpy.mockImplementation((p) => p);
166
-
167
- const input = {
168
- sourceIds: [guidePath, missingPath, apiPath],
169
- };
170
-
171
- const result = transformDetailDatasources(input);
172
-
173
- expect(result.detailDataSources).toContain("Guide content");
174
- expect(result.detailDataSources).toContain("API content");
175
- expect(result.detailDataSources).not.toContain("missing");
176
- });
177
-
178
- test("should handle empty sourceIds array", () => {
179
- const input = {
180
- sourceIds: [],
181
- };
182
-
183
- const result = transformDetailDatasources(input);
184
-
185
- expect(result.detailDataSources).toBe("");
186
- });
187
-
188
- // NULL AND UNDEFINED HANDLING
189
- test("should handle null sourceIds", () => {
190
- const input = {
191
- sourceIds: null,
192
- };
193
-
194
- const result = transformDetailDatasources(input);
195
-
196
- expect(result.detailDataSources).toBe("");
197
- });
198
-
199
- test("should handle undefined sourceIds", () => {
200
- const input = {
201
- sourceIds: undefined,
202
- };
203
-
204
- const result = transformDetailDatasources(input);
205
-
206
- expect(result.detailDataSources).toBe("");
207
- });
208
-
209
- // CONTENT FORMATTING TESTS
210
- test("should format content with proper sourceId comments", async () => {
211
- const mainPath = path.join(testDir, "main.js");
212
- await writeFile(mainPath, "console.log('Hello World');\nprocess.exit(0);");
213
-
214
- normalizePathSpy.mockImplementation((p) => p);
215
-
216
- const input = {
217
- sourceIds: [mainPath],
218
- };
219
-
220
- const result = transformDetailDatasources(input);
221
-
222
- expect(result.detailDataSources).toContain("console.log('Hello World');\nprocess.exit(0);");
223
- expect(result.detailDataSources).toContain("// sourceId:");
224
- });
225
-
226
- test("should handle empty content", async () => {
227
- const emptyPath = path.join(testDir, "empty.md");
228
- await writeFile(emptyPath, "");
229
-
230
- normalizePathSpy.mockImplementation((p) => p);
231
-
232
- const input = {
233
- sourceIds: [emptyPath],
234
- };
235
-
236
- const result = transformDetailDatasources(input);
237
-
238
- // Empty file content still gets included with sourceId comment
239
- expect(result.detailDataSources).toContain("// sourceId:");
240
- expect(result.detailDataSources.trim()).not.toBe("");
241
- });
242
-
243
- test("should handle whitespace-only content", async () => {
244
- const whitespacePath = path.join(testDir, "whitespace.md");
245
- await writeFile(whitespacePath, " \n\t ");
246
-
247
- normalizePathSpy.mockImplementation((p) => p);
248
-
249
- const input = {
250
- sourceIds: [whitespacePath],
251
- };
252
-
253
- const result = transformDetailDatasources(input);
254
-
255
- // Whitespace content is truthy, so it should be included
256
- expect(result.detailDataSources).toContain(" \n\t ");
257
- });
258
-
259
- test("should handle content with special characters", async () => {
260
- const specialPath = path.join(testDir, "特殊字符.md");
261
- await writeFile(specialPath, "# 中文标题\n\n这是一个包含特殊字符的文档: @#$%^&*()");
262
-
263
- normalizePathSpy.mockImplementation((p) => p);
264
-
265
- const input = {
266
- sourceIds: [specialPath],
267
- };
268
-
269
- const result = transformDetailDatasources(input);
270
-
271
- expect(result.detailDataSources).toContain("中文标题");
272
- expect(result.detailDataSources).toContain("@#$%^&*()");
273
- });
274
-
275
- // DUPLICATE HANDLING TESTS
276
- test("should handle duplicate sourceIds in list", async () => {
277
- const guidePath = path.join(testDir, "guide.md");
278
- await writeFile(guidePath, "Guide content");
279
-
280
- normalizePathSpy.mockImplementation((p) => p);
281
-
282
- const input = {
283
- sourceIds: [guidePath, guidePath], // Duplicate paths
284
- };
285
-
286
- const result = transformDetailDatasources(input);
287
-
288
- // Both duplicates should be included
289
- const matches = result.detailDataSources.match(/Guide content/g);
290
- expect(matches?.length).toBe(2);
291
- });
292
-
293
- // RETURN VALUE STRUCTURE TESTS
294
- test("should always return object with detailDataSources property", async () => {
295
- const inputs = [{ sourceIds: [] }, { sourceIds: null }];
296
-
297
- for (const input of inputs) {
298
- const result = transformDetailDatasources(input);
299
- expect(result).toHaveProperty("detailDataSources");
300
- expect(typeof result.detailDataSources).toBe("string");
301
- }
302
- });
303
-
304
- // EDGE CASES
305
- test("should handle sourceId with null or undefined values", async () => {
306
- const validPath = path.join(testDir, "valid.md");
307
- await writeFile(validPath, "Valid content");
308
-
309
- normalizePathSpy.mockImplementation((p) => p || "");
310
- toRelativePathSpy.mockImplementation((p) => p || "");
311
-
312
- const input = {
313
- sourceIds: [null, undefined, validPath],
314
- };
315
-
316
- const result = transformDetailDatasources(input);
317
-
318
- expect(result.detailDataSources).toContain("Valid content");
319
- });
320
- });