@aigne/doc-smith 0.8.12-beta.8 → 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 (264) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/agents/publish/index.yaml +4 -0
  3. package/agents/publish/publish-docs.mjs +77 -5
  4. package/agents/publish/translate-meta.mjs +103 -0
  5. package/agents/update/generate-document.yaml +30 -28
  6. package/agents/update/update-document-detail.yaml +3 -1
  7. package/agents/utils/update-branding.mjs +69 -0
  8. package/package.json +16 -2
  9. package/prompts/common/document/role-and-personality.md +3 -1
  10. package/prompts/detail/d2-diagram/guide.md +7 -1
  11. package/prompts/detail/d2-diagram/user-prompt.md +3 -0
  12. package/prompts/detail/generate/system-prompt.md +6 -7
  13. package/prompts/detail/generate/user-prompt.md +12 -3
  14. package/prompts/detail/update/user-prompt.md +0 -2
  15. package/prompts/structure/update/user-prompt.md +0 -4
  16. package/utils/file-utils.mjs +69 -24
  17. package/utils/markdown-checker.mjs +0 -20
  18. package/utils/request.mjs +7 -0
  19. package/utils/upload-files.mjs +231 -0
  20. package/utils/utils.mjs +11 -1
  21. package/.aigne/doc-smith/config.yaml +0 -77
  22. package/.aigne/doc-smith/history.yaml +0 -37
  23. package/.aigne/doc-smith/media-description.yaml +0 -91
  24. package/.aigne/doc-smith/output/structure-plan.json +0 -162
  25. package/.aigne/doc-smith/preferences.yml +0 -97
  26. package/.aigne/doc-smith/upload-cache.yaml +0 -1830
  27. package/.github/PULL_REQUEST_TEMPLATE.md +0 -28
  28. package/.github/workflows/ci.yml +0 -54
  29. package/.github/workflows/create-release-pr.yaml +0 -21
  30. package/.github/workflows/publish-docs.yml +0 -65
  31. package/.github/workflows/release.yml +0 -49
  32. package/.github/workflows/reviewer.yml +0 -54
  33. package/.release-please-manifest.json +0 -3
  34. package/RELEASE.md +0 -9
  35. package/assets/screenshots/doc-complete-setup.png +0 -0
  36. package/assets/screenshots/doc-generate-docs.png +0 -0
  37. package/assets/screenshots/doc-generate.png +0 -0
  38. package/assets/screenshots/doc-generated-successfully.png +0 -0
  39. package/assets/screenshots/doc-publish.png +0 -0
  40. package/assets/screenshots/doc-regenerate.png +0 -0
  41. package/assets/screenshots/doc-translate-langs.png +0 -0
  42. package/assets/screenshots/doc-translate.png +0 -0
  43. package/assets/screenshots/doc-update.png +0 -0
  44. package/biome.json +0 -73
  45. package/codecov.yml +0 -15
  46. package/docs/_sidebar.md +0 -15
  47. package/docs/configuration-initial-setup.ja.md +0 -179
  48. package/docs/configuration-initial-setup.md +0 -198
  49. package/docs/configuration-initial-setup.zh-TW.md +0 -179
  50. package/docs/configuration-initial-setup.zh.md +0 -179
  51. package/docs/configuration-managing-preferences.ja.md +0 -100
  52. package/docs/configuration-managing-preferences.md +0 -100
  53. package/docs/configuration-managing-preferences.zh-TW.md +0 -100
  54. package/docs/configuration-managing-preferences.zh.md +0 -100
  55. package/docs/configuration.ja.md +0 -69
  56. package/docs/configuration.md +0 -69
  57. package/docs/configuration.zh-TW.md +0 -69
  58. package/docs/configuration.zh.md +0 -69
  59. package/docs/getting-started.ja.md +0 -107
  60. package/docs/getting-started.md +0 -107
  61. package/docs/getting-started.zh-TW.md +0 -107
  62. package/docs/getting-started.zh.md +0 -107
  63. package/docs/guides-cleaning-up.ja.md +0 -51
  64. package/docs/guides-cleaning-up.md +0 -52
  65. package/docs/guides-cleaning-up.zh-TW.md +0 -51
  66. package/docs/guides-cleaning-up.zh.md +0 -51
  67. package/docs/guides-evaluating-documents.ja.md +0 -66
  68. package/docs/guides-evaluating-documents.md +0 -107
  69. package/docs/guides-evaluating-documents.zh-TW.md +0 -66
  70. package/docs/guides-evaluating-documents.zh.md +0 -66
  71. package/docs/guides-generating-documentation.ja.md +0 -151
  72. package/docs/guides-generating-documentation.md +0 -89
  73. package/docs/guides-generating-documentation.zh-TW.md +0 -151
  74. package/docs/guides-generating-documentation.zh.md +0 -151
  75. package/docs/guides-interactive-chat.ja.md +0 -85
  76. package/docs/guides-interactive-chat.md +0 -93
  77. package/docs/guides-interactive-chat.zh-TW.md +0 -85
  78. package/docs/guides-interactive-chat.zh.md +0 -85
  79. package/docs/guides-managing-history.ja.md +0 -48
  80. package/docs/guides-managing-history.md +0 -53
  81. package/docs/guides-managing-history.zh-TW.md +0 -48
  82. package/docs/guides-managing-history.zh.md +0 -48
  83. package/docs/guides-publishing-your-docs.ja.md +0 -78
  84. package/docs/guides-publishing-your-docs.md +0 -83
  85. package/docs/guides-publishing-your-docs.zh-TW.md +0 -78
  86. package/docs/guides-publishing-your-docs.zh.md +0 -78
  87. package/docs/guides-translating-documentation.ja.md +0 -95
  88. package/docs/guides-translating-documentation.md +0 -100
  89. package/docs/guides-translating-documentation.zh-TW.md +0 -95
  90. package/docs/guides-translating-documentation.zh.md +0 -95
  91. package/docs/guides-updating-documentation.ja.md +0 -77
  92. package/docs/guides-updating-documentation.md +0 -79
  93. package/docs/guides-updating-documentation.zh-TW.md +0 -77
  94. package/docs/guides-updating-documentation.zh.md +0 -77
  95. package/docs/guides.ja.md +0 -32
  96. package/docs/guides.md +0 -32
  97. package/docs/guides.zh-TW.md +0 -32
  98. package/docs/guides.zh.md +0 -32
  99. package/docs/overview.ja.md +0 -61
  100. package/docs/overview.md +0 -61
  101. package/docs/overview.zh-TW.md +0 -61
  102. package/docs/overview.zh.md +0 -61
  103. package/docs/release-notes.ja.md +0 -255
  104. package/docs/release-notes.md +0 -288
  105. package/docs/release-notes.zh-TW.md +0 -255
  106. package/docs/release-notes.zh.md +0 -255
  107. package/prompts/common/afs/afs-tools-usage.md +0 -5
  108. package/prompts/common/afs/use-afs-instruction.md +0 -1
  109. package/release-please-config.json +0 -14
  110. package/tests/agents/chat/chat.test.mjs +0 -46
  111. package/tests/agents/clear/choose-contents.test.mjs +0 -284
  112. package/tests/agents/clear/clear-auth-tokens.test.mjs +0 -268
  113. package/tests/agents/clear/clear-document-config.test.mjs +0 -167
  114. package/tests/agents/clear/clear-document-structure.test.mjs +0 -380
  115. package/tests/agents/clear/clear-generated-docs.test.mjs +0 -222
  116. package/tests/agents/evaluate/code-snippet.test.mjs +0 -163
  117. package/tests/agents/evaluate/fixtures/api-services.md +0 -87
  118. package/tests/agents/evaluate/fixtures/js-sdk.md +0 -94
  119. package/tests/agents/evaluate/generate-report.test.mjs +0 -312
  120. package/tests/agents/generate/check-document-structure.test.mjs +0 -45
  121. package/tests/agents/generate/check-need-generate-structure.test.mjs +0 -279
  122. package/tests/agents/generate/document-structure-tools/add-document.test.mjs +0 -449
  123. package/tests/agents/generate/document-structure-tools/delete-document.test.mjs +0 -410
  124. package/tests/agents/generate/document-structure-tools/generate-sub-structure.test.mjs +0 -277
  125. package/tests/agents/generate/document-structure-tools/move-document.test.mjs +0 -476
  126. package/tests/agents/generate/document-structure-tools/update-document.test.mjs +0 -548
  127. package/tests/agents/generate/generate-structure.test.mjs +0 -45
  128. package/tests/agents/generate/user-review-document-structure.test.mjs +0 -319
  129. package/tests/agents/history/view.test.mjs +0 -97
  130. package/tests/agents/init/init.test.mjs +0 -1657
  131. package/tests/agents/prefs/prefs.test.mjs +0 -431
  132. package/tests/agents/publish/publish-docs.test.mjs +0 -787
  133. package/tests/agents/translate/choose-language.test.mjs +0 -311
  134. package/tests/agents/translate/translate-document.test.mjs +0 -51
  135. package/tests/agents/update/check-document.test.mjs +0 -463
  136. package/tests/agents/update/check-update-is-single.test.mjs +0 -300
  137. package/tests/agents/update/document-tools/update-document-content.test.mjs +0 -329
  138. package/tests/agents/update/generate-document.test.mjs +0 -51
  139. package/tests/agents/update/save-and-translate-document.test.mjs +0 -369
  140. package/tests/agents/update/user-review-document.test.mjs +0 -582
  141. package/tests/agents/utils/action-success.test.mjs +0 -54
  142. package/tests/agents/utils/check-detail-result.test.mjs +0 -743
  143. package/tests/agents/utils/check-feedback-refiner.test.mjs +0 -478
  144. package/tests/agents/utils/choose-docs.test.mjs +0 -406
  145. package/tests/agents/utils/exit.test.mjs +0 -70
  146. package/tests/agents/utils/feedback-refiner.test.mjs +0 -51
  147. package/tests/agents/utils/find-item-by-path.test.mjs +0 -517
  148. package/tests/agents/utils/find-user-preferences-by-path.test.mjs +0 -382
  149. package/tests/agents/utils/format-document-structure.test.mjs +0 -364
  150. package/tests/agents/utils/fs.test.mjs +0 -267
  151. package/tests/agents/utils/load-sources.test.mjs +0 -1470
  152. package/tests/agents/utils/save-docs.test.mjs +0 -109
  153. package/tests/agents/utils/save-output.test.mjs +0 -315
  154. package/tests/agents/utils/save-single-doc.test.mjs +0 -364
  155. package/tests/agents/utils/transform-detail-datasources.test.mjs +0 -320
  156. package/tests/utils/auth-utils.test.mjs +0 -596
  157. package/tests/utils/blocklet.test.mjs +0 -336
  158. package/tests/utils/conflict-detector.test.mjs +0 -355
  159. package/tests/utils/constants.test.mjs +0 -295
  160. package/tests/utils/d2-utils.test.mjs +0 -437
  161. package/tests/utils/deploy.test.mjs +0 -399
  162. package/tests/utils/docs-finder-utils.test.mjs +0 -650
  163. package/tests/utils/file-utils.test.mjs +0 -521
  164. package/tests/utils/history-utils.test.mjs +0 -206
  165. package/tests/utils/kroki-utils.test.mjs +0 -646
  166. package/tests/utils/linter/fixtures/css/keyword-error.css +0 -1
  167. package/tests/utils/linter/fixtures/css/missing-semicolon.css +0 -1
  168. package/tests/utils/linter/fixtures/css/syntax-error.css +0 -1
  169. package/tests/utils/linter/fixtures/css/undeclare-variable.css +0 -1
  170. package/tests/utils/linter/fixtures/css/unused-variable.css +0 -2
  171. package/tests/utils/linter/fixtures/css/valid-code.css +0 -1
  172. package/tests/utils/linter/fixtures/dockerfile/keyword-error.dockerfile +0 -1
  173. package/tests/utils/linter/fixtures/dockerfile/missing-semicolon.dockerfile +0 -2
  174. package/tests/utils/linter/fixtures/dockerfile/syntax-error.dockerfile +0 -2
  175. package/tests/utils/linter/fixtures/dockerfile/undeclare-variable.dockerfile +0 -1
  176. package/tests/utils/linter/fixtures/dockerfile/unused-variable.dockerfile +0 -1
  177. package/tests/utils/linter/fixtures/dockerfile/valid-code.dockerfile +0 -2
  178. package/tests/utils/linter/fixtures/go/keyword-error.go +0 -5
  179. package/tests/utils/linter/fixtures/go/missing-semicolon.go +0 -5
  180. package/tests/utils/linter/fixtures/go/syntax-error.go +0 -6
  181. package/tests/utils/linter/fixtures/go/undeclare-variable.go +0 -5
  182. package/tests/utils/linter/fixtures/go/unused-variable.go +0 -5
  183. package/tests/utils/linter/fixtures/go/valid-code.go +0 -7
  184. package/tests/utils/linter/fixtures/js/keyword-error.js +0 -3
  185. package/tests/utils/linter/fixtures/js/missing-semicolon.js +0 -6
  186. package/tests/utils/linter/fixtures/js/syntax-error.js +0 -4
  187. package/tests/utils/linter/fixtures/js/undeclare-variable.js +0 -3
  188. package/tests/utils/linter/fixtures/js/unused-variable.js +0 -7
  189. package/tests/utils/linter/fixtures/js/valid-code.js +0 -15
  190. package/tests/utils/linter/fixtures/json/keyword-error.json +0 -1
  191. package/tests/utils/linter/fixtures/json/missing-semicolon.json +0 -1
  192. package/tests/utils/linter/fixtures/json/syntax-error.json +0 -1
  193. package/tests/utils/linter/fixtures/json/undeclare-variable.json +0 -1
  194. package/tests/utils/linter/fixtures/json/unused-variable.json +0 -1
  195. package/tests/utils/linter/fixtures/json/valid-code.json +0 -1
  196. package/tests/utils/linter/fixtures/jsx/keyword-error.jsx +0 -5
  197. package/tests/utils/linter/fixtures/jsx/missing-semicolon.jsx +0 -5
  198. package/tests/utils/linter/fixtures/jsx/syntax-error.jsx +0 -5
  199. package/tests/utils/linter/fixtures/jsx/undeclare-variable.jsx +0 -5
  200. package/tests/utils/linter/fixtures/jsx/unused-variable.jsx +0 -4
  201. package/tests/utils/linter/fixtures/jsx/valid-code.jsx +0 -5
  202. package/tests/utils/linter/fixtures/python/keyword-error.py +0 -3
  203. package/tests/utils/linter/fixtures/python/missing-semicolon.py +0 -2
  204. package/tests/utils/linter/fixtures/python/syntax-error.py +0 -3
  205. package/tests/utils/linter/fixtures/python/undeclare-variable.py +0 -3
  206. package/tests/utils/linter/fixtures/python/unused-variable.py +0 -6
  207. package/tests/utils/linter/fixtures/python/valid-code.py +0 -12
  208. package/tests/utils/linter/fixtures/ruby/keyword-error.rb +0 -2
  209. package/tests/utils/linter/fixtures/ruby/missing-semicolon.rb +0 -1
  210. package/tests/utils/linter/fixtures/ruby/syntax-error.rb +0 -2
  211. package/tests/utils/linter/fixtures/ruby/undeclare-variable.rb +0 -1
  212. package/tests/utils/linter/fixtures/ruby/unused-variable.rb +0 -2
  213. package/tests/utils/linter/fixtures/ruby/valid-code.rb +0 -1
  214. package/tests/utils/linter/fixtures/sass/keyword-error.sass +0 -2
  215. package/tests/utils/linter/fixtures/sass/missing-semicolon.sass +0 -3
  216. package/tests/utils/linter/fixtures/sass/syntax-error.sass +0 -3
  217. package/tests/utils/linter/fixtures/sass/undeclare-variable.sass +0 -2
  218. package/tests/utils/linter/fixtures/sass/unused-variable.sass +0 -4
  219. package/tests/utils/linter/fixtures/sass/valid-code.sass +0 -2
  220. package/tests/utils/linter/fixtures/scss/keyword-error.scss +0 -1
  221. package/tests/utils/linter/fixtures/scss/missing-semicolon.scss +0 -1
  222. package/tests/utils/linter/fixtures/scss/syntax-error.scss +0 -1
  223. package/tests/utils/linter/fixtures/scss/undeclare-variable.scss +0 -1
  224. package/tests/utils/linter/fixtures/scss/unused-variable.scss +0 -2
  225. package/tests/utils/linter/fixtures/scss/valid-code.scss +0 -1
  226. package/tests/utils/linter/fixtures/shell/keyword-error.sh +0 -5
  227. package/tests/utils/linter/fixtures/shell/missing-semicolon.sh +0 -3
  228. package/tests/utils/linter/fixtures/shell/syntax-error.sh +0 -4
  229. package/tests/utils/linter/fixtures/shell/undeclare-variable.sh +0 -3
  230. package/tests/utils/linter/fixtures/shell/unused-variable.sh +0 -4
  231. package/tests/utils/linter/fixtures/shell/valid-code.sh +0 -3
  232. package/tests/utils/linter/fixtures/ts/keyword-error.ts +0 -1
  233. package/tests/utils/linter/fixtures/ts/missing-semicolon.ts +0 -1
  234. package/tests/utils/linter/fixtures/ts/syntax-error.ts +0 -1
  235. package/tests/utils/linter/fixtures/ts/undeclare-variable.ts +0 -1
  236. package/tests/utils/linter/fixtures/ts/unused-variable.ts +0 -3
  237. package/tests/utils/linter/fixtures/ts/valid-code.ts +0 -3
  238. package/tests/utils/linter/fixtures/tsx/keyword-error.tsx +0 -5
  239. package/tests/utils/linter/fixtures/tsx/missing-semicolon.tsx +0 -5
  240. package/tests/utils/linter/fixtures/tsx/syntax-error.tsx +0 -5
  241. package/tests/utils/linter/fixtures/tsx/undeclare-variable.tsx +0 -6
  242. package/tests/utils/linter/fixtures/tsx/unused-variable.tsx +0 -6
  243. package/tests/utils/linter/fixtures/tsx/valid-code.tsx +0 -5
  244. package/tests/utils/linter/fixtures/vue/keyword-error.vue +0 -6
  245. package/tests/utils/linter/fixtures/vue/missing-semicolon.vue +0 -6
  246. package/tests/utils/linter/fixtures/vue/syntax-error.vue +0 -6
  247. package/tests/utils/linter/fixtures/vue/undeclare-variable.vue +0 -6
  248. package/tests/utils/linter/fixtures/vue/unused-variable.vue +0 -7
  249. package/tests/utils/linter/fixtures/vue/valid-code.vue +0 -6
  250. package/tests/utils/linter/fixtures/yaml/keyword-error.yml +0 -1
  251. package/tests/utils/linter/fixtures/yaml/missing-semicolon.yml +0 -2
  252. package/tests/utils/linter/fixtures/yaml/syntax-error.yml +0 -1
  253. package/tests/utils/linter/fixtures/yaml/undeclare-variable.yml +0 -1
  254. package/tests/utils/linter/fixtures/yaml/unused-variable.yml +0 -2
  255. package/tests/utils/linter/fixtures/yaml/valid-code.yml +0 -3
  256. package/tests/utils/linter/index.test.mjs +0 -440
  257. package/tests/utils/linter/scan-results.mjs +0 -42
  258. package/tests/utils/load-config.test.mjs +0 -141
  259. package/tests/utils/markdown/index.test.mjs +0 -478
  260. package/tests/utils/mermaid-validator.test.mjs +0 -541
  261. package/tests/utils/mock-chat-model.mjs +0 -12
  262. package/tests/utils/preferences-utils.test.mjs +0 -465
  263. package/tests/utils/save-value-to-config.test.mjs +0 -483
  264. 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
- });