@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,369 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from "bun:test";
2
- import saveAndTranslateDocument from "../../../agents/update/save-and-translate-document.mjs";
3
- import * as historyUtils from "../../../utils/history-utils.mjs";
4
-
5
- describe("save-and-translate-document", () => {
6
- let mockOptions;
7
- let consoleErrorSpy;
8
- let recordUpdateSpy;
9
-
10
- beforeEach(() => {
11
- // Reset all mocks
12
- mock.restore();
13
-
14
- mockOptions = {
15
- prompts: {
16
- select: mock(async () => "no"),
17
- },
18
- context: {
19
- agents: {
20
- saveSingleDoc: { mockSaveAgent: true },
21
- translateMultilingual: { mockTranslateAgent: true },
22
- },
23
- invoke: mock(async () => ({ mockResult: true })),
24
- },
25
- };
26
-
27
- consoleErrorSpy = spyOn(console, "error").mockImplementation(() => {});
28
- recordUpdateSpy = spyOn(historyUtils, "recordUpdate").mockImplementation(() => {});
29
-
30
- // Clear context mock call history
31
- mockOptions.prompts.select.mockClear();
32
- mockOptions.context.invoke.mockClear();
33
- });
34
-
35
- afterEach(() => {
36
- consoleErrorSpy?.mockRestore();
37
- recordUpdateSpy?.mockRestore();
38
- });
39
-
40
- // INPUT VALIDATION TESTS
41
- test("should handle empty or invalid selectedDocs", async () => {
42
- const testCases = [
43
- { selectedDocs: [], description: "empty array" },
44
- { selectedDocs: null, description: "null" },
45
- { selectedDocs: undefined, description: "undefined" },
46
- { selectedDocs: "not-array", description: "non-array" },
47
- ];
48
-
49
- for (const testCase of testCases) {
50
- const input = {
51
- selectedDocs: testCase.selectedDocs,
52
- docsDir: "./docs",
53
- translateLanguages: ["en", "zh"],
54
- locale: "en",
55
- };
56
-
57
- const result = await saveAndTranslateDocument(input, mockOptions);
58
-
59
- expect(result).toEqual({});
60
- expect(mockOptions.context.invoke).not.toHaveBeenCalled();
61
- expect(mockOptions.prompts.select).not.toHaveBeenCalled();
62
- }
63
- });
64
-
65
- // SCENARIO 1: NO TRANSLATION CONFIGURATION
66
- test("should skip translation when no translation languages configured", async () => {
67
- const testCases = [
68
- { translateLanguages: null, description: "null" },
69
- { translateLanguages: undefined, description: "undefined" },
70
- { translateLanguages: [], description: "empty array" },
71
- { translateLanguages: ["en"], description: "only current locale" },
72
- ];
73
-
74
- for (const testCase of testCases) {
75
- const input = {
76
- selectedDocs: [
77
- {
78
- path: "/docs/test.md",
79
- content: "# Test Document",
80
- translates: {},
81
- labels: {},
82
- feedback: "Good content",
83
- },
84
- ],
85
- docsDir: "./docs",
86
- translateLanguages: testCase.translateLanguages,
87
- locale: "en",
88
- };
89
-
90
- const result = await saveAndTranslateDocument(input, mockOptions);
91
-
92
- expect(result).toEqual({});
93
- expect(mockOptions.prompts.select).not.toHaveBeenCalled();
94
- expect(mockOptions.context.invoke).toHaveBeenCalledTimes(1);
95
- expect(recordUpdateSpy).toHaveBeenCalledWith({
96
- operation: "document_update",
97
- feedback: "Good content",
98
- documentPath: "/docs/test.md",
99
- });
100
-
101
- // Reset mocks for next iteration
102
- mockOptions.prompts.select.mockClear();
103
- mockOptions.context.invoke.mockClear();
104
- recordUpdateSpy.mockClear();
105
- }
106
- });
107
-
108
- // SCENARIO 2: USER CHOOSES NOT TO TRANSLATE
109
- test("should save documents and skip translation when user chooses no", async () => {
110
- const input = {
111
- selectedDocs: [
112
- {
113
- path: "/docs/test1.md",
114
- content: "# Test Document 1",
115
- translates: {},
116
- labels: {},
117
- feedback: "Update needed",
118
- },
119
- {
120
- path: "/docs/test2.md",
121
- content: "# Test Document 2",
122
- translates: {},
123
- labels: {},
124
- feedback: "Second feedback",
125
- },
126
- {
127
- path: "/docs/test3.md",
128
- content: "# Test Document 3",
129
- translates: {},
130
- labels: {},
131
- feedback: " ", // Whitespace only
132
- },
133
- ],
134
- docsDir: "./docs",
135
- translateLanguages: ["en", "zh", "ja"],
136
- locale: "en",
137
- };
138
-
139
- mockOptions.prompts.select.mockResolvedValue("no");
140
-
141
- const result = await saveAndTranslateDocument(input, mockOptions);
142
-
143
- expect(result).toEqual({});
144
- expect(mockOptions.prompts.select).toHaveBeenCalledWith({
145
- message: "Document update completed. Would you like to translate these documents now?",
146
- choices: [
147
- {
148
- name: "Review documents first, translate later",
149
- value: "no",
150
- },
151
- {
152
- name: "Translate now",
153
- value: "yes",
154
- },
155
- ],
156
- });
157
- expect(mockOptions.context.invoke).toHaveBeenCalledTimes(3); // Only saveDocument calls
158
- expect(recordUpdateSpy).toHaveBeenCalledTimes(2); // Only documents with non-empty feedback
159
- expect(recordUpdateSpy).toHaveBeenCalledWith({
160
- operation: "document_update",
161
- feedback: "Update needed",
162
- documentPath: "/docs/test1.md",
163
- });
164
- expect(recordUpdateSpy).toHaveBeenCalledWith({
165
- operation: "document_update",
166
- feedback: "Second feedback",
167
- documentPath: "/docs/test2.md",
168
- });
169
- });
170
-
171
- // SCENARIO 3: USER CHOOSES TO TRANSLATE
172
- test("should save and translate documents when user chooses yes", async () => {
173
- const input = {
174
- selectedDocs: [
175
- {
176
- path: "/docs/test1.md",
177
- content: "# Test Document 1",
178
- translates: {},
179
- labels: {},
180
- feedback: "Translation needed",
181
- title: "Test Document 1",
182
- },
183
- {
184
- path: "/docs/test2.md",
185
- content: "# Test Document 2",
186
- translates: {},
187
- labels: {},
188
- title: "Test Document 2",
189
- },
190
- ],
191
- docsDir: "./docs",
192
- translateLanguages: ["en", "zh"],
193
- locale: "en",
194
- };
195
-
196
- mockOptions.prompts.select.mockResolvedValue("yes");
197
- mockOptions.context.invoke
198
- .mockResolvedValueOnce({ mockSaveResult: true }) // saveDocument 1
199
- .mockResolvedValueOnce({ mockSaveResult: true }) // saveDocument 2
200
- .mockResolvedValueOnce({ translates: { zh: "# 测试文档 1" } }) // translateMultilingual 1
201
- .mockResolvedValueOnce({ translates: { zh: "# 测试文档 2" } }) // translateMultilingual 2
202
- .mockResolvedValueOnce({ mockSaveResult: true }) // saveDocument with translation 1
203
- .mockResolvedValueOnce({ mockSaveResult: true }); // saveDocument with translation 2
204
-
205
- const result = await saveAndTranslateDocument(input, mockOptions);
206
-
207
- expect(result).toEqual({});
208
- expect(mockOptions.prompts.select).toHaveBeenCalledWith({
209
- message: "Document update completed. Would you like to translate these documents now?",
210
- choices: [
211
- {
212
- name: "Review documents first, translate later",
213
- value: "no",
214
- },
215
- {
216
- name: "Translate now",
217
- value: "yes",
218
- },
219
- ],
220
- });
221
- expect(mockOptions.context.invoke).toHaveBeenCalledTimes(6);
222
-
223
- // Verify feedback is cleared before translation
224
- expect(input.selectedDocs[0].feedback).toBe("");
225
- expect(input.selectedDocs[1].feedback).toBe("");
226
-
227
- expect(recordUpdateSpy).toHaveBeenCalledWith({
228
- operation: "document_update",
229
- feedback: "Translation needed",
230
- documentPath: "/docs/test1.md",
231
- });
232
- });
233
-
234
- // ERROR HANDLING TESTS
235
- test("should handle errors gracefully", async () => {
236
- // Test saveDocument error
237
- const saveErrorInput = {
238
- selectedDocs: [
239
- {
240
- path: "/docs/test1.md",
241
- content: "# Test Document 1",
242
- translates: {},
243
- labels: {},
244
- feedback: "Error test",
245
- },
246
- ],
247
- docsDir: "./docs",
248
- translateLanguages: ["en", "zh"],
249
- locale: "en",
250
- };
251
-
252
- mockOptions.prompts.select.mockResolvedValue("no");
253
- mockOptions.context.invoke.mockRejectedValue(new Error("Save failed"));
254
-
255
- const saveErrorResult = await saveAndTranslateDocument(saveErrorInput, mockOptions);
256
-
257
- expect(saveErrorResult).toEqual({});
258
- expect(consoleErrorSpy).toHaveBeenCalledWith(
259
- "❌ Failed to save document /docs/test1.md:",
260
- "Save failed",
261
- );
262
- expect(recordUpdateSpy).not.toHaveBeenCalled(); // Should not record if save failed
263
-
264
- // Reset mocks
265
- mockOptions.prompts.select.mockClear();
266
- mockOptions.context.invoke.mockClear();
267
- consoleErrorSpy.mockClear();
268
- recordUpdateSpy.mockClear();
269
-
270
- // Test translateMultilingual error
271
- const translateErrorInput = {
272
- selectedDocs: [
273
- {
274
- path: "/docs/test2.md",
275
- content: "# Test Document 2",
276
- translates: {},
277
- labels: {},
278
- title: "Test Document 2",
279
- },
280
- ],
281
- docsDir: "./docs",
282
- translateLanguages: ["en", "zh"],
283
- locale: "en",
284
- };
285
-
286
- mockOptions.prompts.select.mockResolvedValue("yes");
287
- mockOptions.context.invoke
288
- .mockResolvedValueOnce({ mockSaveResult: true }) // saveDocument succeeds
289
- .mockRejectedValueOnce(new Error("Translation failed")); // translateMultilingual fails
290
-
291
- const translateErrorResult = await saveAndTranslateDocument(translateErrorInput, mockOptions);
292
-
293
- expect(translateErrorResult).toEqual({});
294
- expect(consoleErrorSpy).toHaveBeenCalledWith(
295
- "❌ Failed to translate document /docs/test2.md:",
296
- "Translation failed",
297
- );
298
- expect(mockOptions.context.invoke).toHaveBeenCalledTimes(2);
299
- });
300
-
301
- // EDGE CASES AND INTEGRATION
302
- test("should handle edge cases and complex scenarios", async () => {
303
- // Test edge cases with different document properties
304
- const edgeCaseInput = {
305
- selectedDocs: [
306
- {
307
- path: "/docs/test1.md",
308
- content: "# Test Document 1",
309
- translates: null, // null translates
310
- labels: {},
311
- feedback: "", // empty feedback
312
- },
313
- {
314
- path: "/docs/test2.md",
315
- content: "# Test Document 2",
316
- translates: undefined, // undefined translates
317
- labels: {},
318
- feedback: " ", // whitespace feedback
319
- },
320
- {
321
- path: "/docs/test3.md",
322
- content: "# Test Document 3",
323
- translates: {},
324
- labels: {},
325
- // no title
326
- },
327
- ],
328
- docsDir: "./docs",
329
- translateLanguages: ["en", "zh"],
330
- locale: "en",
331
- };
332
-
333
- mockOptions.prompts.select.mockResolvedValue("no");
334
-
335
- const edgeCaseResult = await saveAndTranslateDocument(edgeCaseInput, mockOptions);
336
-
337
- expect(edgeCaseResult).toEqual({});
338
- expect(mockOptions.context.invoke).toHaveBeenCalledTimes(3);
339
- expect(recordUpdateSpy).not.toHaveBeenCalled(); // No valid feedback
340
-
341
- // Reset mocks
342
- mockOptions.prompts.select.mockClear();
343
- mockOptions.context.invoke.mockClear();
344
- recordUpdateSpy.mockClear();
345
-
346
- // Test batch processing with multiple documents
347
- const batchInput = {
348
- selectedDocs: Array.from({ length: 5 }, (_, i) => ({
349
- path: `/docs/batch${i + 1}.md`,
350
- content: `# Batch Document ${i + 1}`,
351
- translates: {},
352
- labels: {},
353
- title: `Batch Document ${i + 1}`,
354
- })),
355
- docsDir: "./docs",
356
- translateLanguages: ["en", "zh"],
357
- locale: "en",
358
- };
359
-
360
- mockOptions.prompts.select.mockResolvedValue("yes");
361
- mockOptions.context.invoke.mockResolvedValue({ mockResult: true });
362
-
363
- const batchResult = await saveAndTranslateDocument(batchInput, mockOptions);
364
-
365
- expect(batchResult).toEqual({});
366
- // 5 documents * 3 calls each (save, translate, save) = 15 calls
367
- expect(mockOptions.context.invoke).toHaveBeenCalledTimes(15);
368
- });
369
- });