@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,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
- });