@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,787 +0,0 @@
1
- import {
2
- afterAll,
3
- afterEach,
4
- beforeAll,
5
- beforeEach,
6
- describe,
7
- expect,
8
- mock,
9
- spyOn,
10
- test,
11
- } from "bun:test";
12
- import publishDocs from "../../../agents/publish/publish-docs.mjs";
13
-
14
- // Import internal utils for selective spying
15
- import * as authUtils from "../../../utils/auth-utils.mjs";
16
- import * as d2Utils from "../../../utils/d2-utils.mjs";
17
- import * as utils from "../../../utils/utils.mjs";
18
- import * as deployUtils from "../../../utils/deploy.mjs";
19
-
20
- // Mock all external dependencies
21
- const mockPublishDocs = {
22
- publishDocs: mock(() => Promise.resolve({ success: true, boardId: "new-board-id" })),
23
- };
24
-
25
- const mockBrokerClient = {
26
- checkCacheSession: mock(() => Promise.resolve({ sessionId: null, paymentLink: null })),
27
- };
28
-
29
- const mockBrokerClientConstructor = mock(() => mockBrokerClient);
30
-
31
- const mockChalk = {
32
- bold: mock((text) => text),
33
- cyan: mock((text) => text),
34
- blue: mock((text) => text),
35
- green: mock((text) => text),
36
- yellow: mock((text) => text),
37
- };
38
-
39
- const mockFsExtra = {
40
- rm: mock(() => Promise.resolve()),
41
- mkdir: mock(() => Promise.resolve()),
42
- cp: mock(() => Promise.resolve()),
43
- };
44
-
45
- const mockPath = {
46
- basename: mock(() => "test-project"),
47
- join: mock((...paths) => paths.join("/")),
48
- };
49
-
50
- describe("publish-docs", () => {
51
- let mockOptions;
52
- let originalEnv;
53
-
54
- // Spies for internal utils
55
- let getAccessTokenSpy;
56
- let getOfficialAccessTokenSpy;
57
- let beforePublishHookSpy;
58
- let ensureTmpDirSpy;
59
- let getGithubRepoUrlSpy;
60
- let loadConfigFromFileSpy;
61
- let saveValueToConfigSpy;
62
- let deploySpy;
63
-
64
- beforeAll(() => {
65
- // Apply mocks for external dependencies only
66
- mock.module("@aigne/publish-docs", () => mockPublishDocs);
67
- mock.module("@blocklet/payment-broker-client/node", () => ({
68
- BrokerClient: mockBrokerClientConstructor,
69
- }));
70
- mock.module("chalk", () => ({ default: mockChalk }));
71
- mock.module("fs-extra", () => ({ default: mockFsExtra }));
72
- mock.module("node:path", () => mockPath);
73
- });
74
-
75
- afterAll(() => {
76
- // Restore all mocks when this test file is complete
77
- mock.restore();
78
- });
79
-
80
- beforeEach(() => {
81
- // Save original environment
82
- originalEnv = { ...process.env };
83
-
84
- // Reset external mocks and clear call history
85
- mockPublishDocs.publishDocs.mockClear();
86
- mockPublishDocs.publishDocs.mockImplementation(() =>
87
- Promise.resolve({ success: true, boardId: "new-board-id" }),
88
- );
89
- mockFsExtra.rm.mockClear();
90
- mockFsExtra.rm.mockImplementation(() => Promise.resolve());
91
- mockFsExtra.mkdir.mockClear();
92
- mockFsExtra.mkdir.mockImplementation(() => Promise.resolve());
93
- mockFsExtra.cp.mockClear();
94
- mockFsExtra.cp.mockImplementation(() => Promise.resolve());
95
- mockPath.basename.mockClear();
96
- mockPath.basename.mockImplementation(() => "test-project");
97
- mockPath.join.mockClear();
98
- mockPath.join.mockImplementation((...paths) => paths.join("/"));
99
- mockChalk.bold.mockClear();
100
- mockChalk.bold.mockImplementation((text) => text);
101
- mockChalk.cyan.mockClear();
102
- mockChalk.cyan.mockImplementation((text) => text);
103
-
104
- // Reset BrokerClient mock
105
- mockBrokerClientConstructor.mockClear();
106
- mockBrokerClientConstructor.mockImplementation(() => mockBrokerClient);
107
- mockBrokerClient.checkCacheSession.mockClear();
108
- mockBrokerClient.checkCacheSession.mockImplementation(() =>
109
- Promise.resolve({ sessionId: null, paymentLink: null }),
110
- );
111
-
112
- // Set up spies for internal utils
113
- getAccessTokenSpy = spyOn(authUtils, "getAccessToken").mockResolvedValue("mock-token");
114
- getOfficialAccessTokenSpy = spyOn(authUtils, "getOfficialAccessToken").mockResolvedValue(
115
- "official-mock-token",
116
- );
117
- beforePublishHookSpy = spyOn(d2Utils, "beforePublishHook").mockResolvedValue();
118
- ensureTmpDirSpy = spyOn(d2Utils, "ensureTmpDir").mockResolvedValue();
119
- getGithubRepoUrlSpy = spyOn(utils, "getGithubRepoUrl").mockReturnValue(
120
- "https://github.com/user/repo",
121
- );
122
- loadConfigFromFileSpy = spyOn(utils, "loadConfigFromFile").mockResolvedValue({});
123
- saveValueToConfigSpy = spyOn(utils, "saveValueToConfig").mockResolvedValue();
124
- deploySpy = spyOn(deployUtils, "deploy").mockResolvedValue({
125
- appUrl: "https://deployed.example.com",
126
- token: "deploy-token",
127
- });
128
-
129
- mockOptions = {
130
- prompts: {
131
- select: mock(async () => "default"),
132
- input: mock(async () => "https://example.com"),
133
- },
134
- };
135
-
136
- // Clear prompts mock call history
137
- mockOptions.prompts.select.mockClear();
138
- mockOptions.prompts.input.mockClear();
139
-
140
- // Clear environment variable
141
- delete process.env.DOC_DISCUSS_KIT_URL;
142
- });
143
-
144
- afterEach(() => {
145
- // Restore original environment
146
- process.env = originalEnv;
147
-
148
- // Restore all spies
149
- getAccessTokenSpy?.mockRestore();
150
- getOfficialAccessTokenSpy?.mockRestore();
151
- beforePublishHookSpy?.mockRestore();
152
- ensureTmpDirSpy?.mockRestore();
153
- getGithubRepoUrlSpy?.mockRestore();
154
- loadConfigFromFileSpy?.mockRestore();
155
- saveValueToConfigSpy?.mockRestore();
156
- deploySpy?.mockRestore();
157
- });
158
-
159
- // BASIC FUNCTIONALITY TESTS
160
- test("should publish docs successfully with default settings", async () => {
161
- loadConfigFromFileSpy.mockResolvedValue({ appUrl: "https://docsmith.aigne.io" });
162
-
163
- const result = await publishDocs(
164
- {
165
- docsDir: "./docs",
166
- appUrl: "https://docsmith.aigne.io",
167
- boardId: "board-123",
168
- },
169
- mockOptions,
170
- );
171
-
172
- expect(ensureTmpDirSpy).toHaveBeenCalled();
173
- expect(mockFsExtra.cp).toHaveBeenCalled();
174
- expect(beforePublishHookSpy).toHaveBeenCalled();
175
- expect(getAccessTokenSpy).toHaveBeenCalledWith("https://docsmith.aigne.io", "");
176
- expect(mockPublishDocs.publishDocs).toHaveBeenCalled();
177
- expect(result.message).toBe("✅ Documentation published successfully!");
178
- });
179
-
180
- // ENVIRONMENT VARIABLE TESTS
181
- test("should use environment variable DOC_DISCUSS_KIT_URL when set", async () => {
182
- process.env.DOC_DISCUSS_KIT_URL = "https://env.example.com";
183
-
184
- await publishDocs(
185
- {
186
- docsDir: "./docs",
187
- appUrl: "https://docsmith.aigne.io",
188
- },
189
- mockOptions,
190
- );
191
-
192
- expect(getAccessTokenSpy).toHaveBeenCalledWith("https://env.example.com", "");
193
- expect(mockPublishDocs.publishDocs).toHaveBeenCalledWith(
194
- expect.objectContaining({
195
- appUrl: "https://env.example.com",
196
- }),
197
- );
198
- // Should not save appUrl when using environment variable
199
- expect(saveValueToConfigSpy).not.toHaveBeenCalledWith("appUrl", expect.anything());
200
- });
201
-
202
- // USER INTERACTION TESTS
203
- test("should prompt user to select platform when using default URL without config", async () => {
204
- loadConfigFromFileSpy.mockResolvedValue({});
205
- mockOptions.prompts.select.mockResolvedValue("default");
206
-
207
- await publishDocs(
208
- {
209
- docsDir: "./docs",
210
- appUrl: "https://docsmith.aigne.io",
211
- },
212
- mockOptions,
213
- );
214
-
215
- expect(mockOptions.prompts.select).toHaveBeenCalledWith(
216
- expect.objectContaining({
217
- message: expect.stringContaining("Select platform"),
218
- choices: expect.any(Array),
219
- }),
220
- );
221
- });
222
-
223
- test("should handle custom platform selection", async () => {
224
- loadConfigFromFileSpy.mockResolvedValue({});
225
- mockOptions.prompts.select.mockResolvedValue("custom");
226
- mockOptions.prompts.input.mockResolvedValue("https://custom.example.com");
227
-
228
- const consoleSpy = spyOn(console, "log").mockImplementation(() => {});
229
-
230
- await publishDocs(
231
- {
232
- docsDir: "./docs",
233
- appUrl: "https://docsmith.aigne.io",
234
- },
235
- mockOptions,
236
- );
237
-
238
- expect(consoleSpy).toHaveBeenCalled();
239
- expect(mockOptions.prompts.input).toHaveBeenCalledWith({
240
- message: "Please enter your website URL:",
241
- validate: expect.any(Function),
242
- });
243
- expect(getAccessTokenSpy).toHaveBeenCalledWith("https://custom.example.com", "");
244
- });
245
-
246
- test("should validate URL input and accept valid URLs", async () => {
247
- loadConfigFromFileSpy.mockResolvedValue({});
248
- mockOptions.prompts.select.mockResolvedValue("custom");
249
- mockOptions.prompts.input.mockResolvedValue("https://valid.example.com");
250
-
251
- await publishDocs(
252
- {
253
- docsDir: "./docs",
254
- appUrl: "https://docsmith.aigne.io",
255
- },
256
- mockOptions,
257
- );
258
-
259
- const validateFn = mockOptions.prompts.input.mock.calls[0][0].validate;
260
-
261
- expect(validateFn("https://valid.com")).toBe(true);
262
- expect(validateFn("valid.com")).toBe(true); // Should work without protocol
263
- expect(validateFn("")).toBe("Please enter a valid URL");
264
- });
265
-
266
- test("should add https protocol when not provided in URL", async () => {
267
- loadConfigFromFileSpy.mockResolvedValue({});
268
- mockOptions.prompts.select.mockResolvedValue("custom");
269
- mockOptions.prompts.input.mockResolvedValue("example.com");
270
-
271
- await publishDocs(
272
- {
273
- docsDir: "./docs",
274
- appUrl: "https://docsmith.aigne.io",
275
- },
276
- mockOptions,
277
- );
278
-
279
- expect(getAccessTokenSpy).toHaveBeenCalledWith("https://example.com", "");
280
- });
281
-
282
- // PROJECT INFO TESTS
283
- test("should use provided project info parameters", async () => {
284
- await publishDocs(
285
- {
286
- docsDir: "./docs",
287
- appUrl: "https://example.com",
288
- projectName: "Test Project",
289
- projectDesc: "Test Description",
290
- projectLogo: "logo.png",
291
- },
292
- mockOptions,
293
- );
294
-
295
- expect(mockPublishDocs.publishDocs).toHaveBeenCalledWith(
296
- expect.objectContaining({
297
- boardName: "Test Project",
298
- boardDesc: "Test Description",
299
- boardCover: "logo.png",
300
- }),
301
- );
302
- });
303
-
304
- test("should fallback to config values for project info", async () => {
305
- loadConfigFromFileSpy.mockResolvedValue({
306
- projectName: "Config Project",
307
- projectDesc: "Config Description",
308
- projectLogo: "config-logo.png",
309
- });
310
-
311
- await publishDocs(
312
- {
313
- docsDir: "./docs",
314
- appUrl: "https://example.com",
315
- },
316
- mockOptions,
317
- );
318
-
319
- expect(mockPublishDocs.publishDocs).toHaveBeenCalledWith(
320
- expect.objectContaining({
321
- boardName: "Config Project",
322
- boardDesc: "Config Description",
323
- boardCover: "config-logo.png",
324
- }),
325
- );
326
- });
327
-
328
- test("should use default project name from current directory", async () => {
329
- mockPath.basename.mockReturnValue("default-project");
330
-
331
- await publishDocs(
332
- {
333
- docsDir: "./docs",
334
- appUrl: "https://example.com",
335
- },
336
- mockOptions,
337
- );
338
-
339
- expect(mockPublishDocs.publishDocs).toHaveBeenCalledWith(
340
- expect.objectContaining({
341
- boardName: "default-project",
342
- boardDesc: "",
343
- boardCover: "",
344
- }),
345
- );
346
- });
347
-
348
- // BOARD META TESTS
349
- test("should construct board meta correctly", async () => {
350
- loadConfigFromFileSpy.mockResolvedValue({
351
- documentPurpose: ["API", "Tutorial"],
352
- locale: "en",
353
- translateLanguages: ["zh", "ja"],
354
- lastGitHead: "abc123",
355
- });
356
-
357
- await publishDocs(
358
- {
359
- docsDir: "./docs",
360
- appUrl: "https://example.com",
361
- },
362
- mockOptions,
363
- );
364
-
365
- expect(mockPublishDocs.publishDocs).toHaveBeenCalledWith(
366
- expect.objectContaining({
367
- boardMeta: {
368
- category: ["API", "Tutorial"],
369
- githubRepoUrl: "https://github.com/user/repo",
370
- commitSha: "abc123",
371
- languages: ["en", "zh", "ja"],
372
- },
373
- }),
374
- );
375
- });
376
-
377
- test("should handle duplicate languages in board meta", async () => {
378
- loadConfigFromFileSpy.mockResolvedValue({
379
- locale: "en",
380
- translateLanguages: ["en", "zh", "en"], // Duplicates
381
- });
382
-
383
- await publishDocs(
384
- {
385
- docsDir: "./docs",
386
- appUrl: "https://example.com",
387
- },
388
- mockOptions,
389
- );
390
-
391
- expect(mockPublishDocs.publishDocs).toHaveBeenCalledWith(
392
- expect.objectContaining({
393
- boardMeta: expect.objectContaining({
394
- languages: ["en", "zh"], // Duplicates removed
395
- }),
396
- }),
397
- );
398
- });
399
-
400
- // CONFIG SAVING TESTS
401
- test("should save appUrl when not using environment variable", async () => {
402
- await publishDocs(
403
- {
404
- docsDir: "./docs",
405
- appUrl: "https://custom.example.com",
406
- },
407
- mockOptions,
408
- );
409
-
410
- expect(saveValueToConfigSpy).toHaveBeenCalledWith("appUrl", "https://custom.example.com");
411
- });
412
-
413
- test("should save new boardId when auto-created", async () => {
414
- mockPublishDocs.publishDocs.mockResolvedValue({
415
- success: true,
416
- boardId: "auto-created-id",
417
- });
418
-
419
- await publishDocs(
420
- {
421
- docsDir: "./docs",
422
- appUrl: "https://example.com",
423
- boardId: "original-id",
424
- },
425
- mockOptions,
426
- );
427
-
428
- expect(saveValueToConfigSpy).toHaveBeenCalledWith("boardId", "auto-created-id");
429
- });
430
-
431
- test("should not save boardId when it hasn't changed", async () => {
432
- mockPublishDocs.publishDocs.mockResolvedValue({
433
- success: true,
434
- boardId: "same-id",
435
- });
436
-
437
- await publishDocs(
438
- {
439
- docsDir: "./docs",
440
- appUrl: "https://example.com",
441
- boardId: "same-id",
442
- },
443
- mockOptions,
444
- );
445
-
446
- expect(saveValueToConfigSpy).not.toHaveBeenCalledWith("boardId", expect.anything());
447
- });
448
-
449
- test("should handle checkCacheSession failure", async () => {
450
- loadConfigFromFileSpy.mockResolvedValue({});
451
- getOfficialAccessTokenSpy.mockResolvedValue("valid-token");
452
- mockBrokerClient.checkCacheSession.mockRejectedValue(new Error("Cache session failed"));
453
- mockOptions.prompts.select.mockResolvedValue("default");
454
-
455
- const result = await publishDocs(
456
- {
457
- docsDir: "./docs",
458
- appUrl: "https://docsmith.aigne.io",
459
- },
460
- mockOptions,
461
- );
462
-
463
- expect(result.message).toBe("❌ Failed to publish docs: Cache session failed");
464
- });
465
-
466
- test("should handle publish failure", async () => {
467
- mockPublishDocs.publishDocs.mockRejectedValue(new Error("Publish failed"));
468
-
469
- const result = await publishDocs(
470
- {
471
- docsDir: "./docs",
472
- appUrl: "https://example.com",
473
- },
474
- mockOptions,
475
- );
476
-
477
- expect(result.message).toBe("❌ Failed to publish docs: Publish failed");
478
- });
479
-
480
- test("should handle unsuccessful publish", async () => {
481
- mockPublishDocs.publishDocs.mockResolvedValue({
482
- success: false,
483
- boardId: "failed-id",
484
- });
485
-
486
- const result = await publishDocs(
487
- {
488
- docsDir: "./docs",
489
- appUrl: "https://example.com",
490
- },
491
- mockOptions,
492
- );
493
-
494
- expect(result).toEqual({});
495
- });
496
-
497
- test("should clean up temporary directory on success", async () => {
498
- await publishDocs(
499
- {
500
- docsDir: "./docs",
501
- appUrl: "https://example.com",
502
- },
503
- mockOptions,
504
- );
505
-
506
- expect(mockFsExtra.rm).toHaveBeenCalledWith(
507
- expect.stringContaining(".aigne/doc-smith/.tmp/docs"),
508
- expect.objectContaining({
509
- recursive: true,
510
- force: true,
511
- }),
512
- );
513
- });
514
-
515
- test("should clean up temporary directory on error", async () => {
516
- mockPublishDocs.publishDocs.mockRejectedValue(new Error("Test error"));
517
-
518
- await publishDocs(
519
- {
520
- docsDir: "./docs",
521
- appUrl: "https://example.com",
522
- },
523
- mockOptions,
524
- );
525
-
526
- expect(mockFsExtra.rm).toHaveBeenCalledWith(
527
- expect.stringContaining(".aigne/doc-smith/.tmp/docs"),
528
- expect.objectContaining({
529
- recursive: true,
530
- force: true,
531
- }),
532
- );
533
- });
534
-
535
- // FILESYSTEM OPERATION TESTS
536
- test("should set up temporary directory correctly", async () => {
537
- await publishDocs(
538
- {
539
- docsDir: "./docs",
540
- appUrl: "https://example.com",
541
- },
542
- mockOptions,
543
- );
544
-
545
- expect(ensureTmpDirSpy).toHaveBeenCalled();
546
- expect(mockFsExtra.rm).toHaveBeenCalledWith(
547
- expect.stringContaining(".aigne/doc-smith/.tmp/docs"),
548
- expect.objectContaining({ recursive: true, force: true }),
549
- );
550
- expect(mockFsExtra.mkdir).toHaveBeenCalledWith(
551
- expect.stringContaining(".aigne/doc-smith/.tmp/docs"),
552
- expect.objectContaining({ recursive: true }),
553
- );
554
- expect(mockFsExtra.cp).toHaveBeenCalledWith(
555
- "./docs",
556
- expect.stringContaining(".aigne/doc-smith/.tmp/docs"),
557
- expect.objectContaining({ recursive: true }),
558
- );
559
- });
560
-
561
- test("should call beforePublishHook with correct docsDir", async () => {
562
- await publishDocs(
563
- {
564
- docsDir: "./docs",
565
- appUrl: "https://example.com",
566
- },
567
- mockOptions,
568
- );
569
-
570
- expect(beforePublishHookSpy).toHaveBeenCalledWith({
571
- docsDir: expect.stringContaining(".aigne/doc-smith/.tmp/docs"),
572
- });
573
- });
574
-
575
- test("should set DOC_ROOT_DIR environment variable", async () => {
576
- await publishDocs(
577
- {
578
- docsDir: "./docs",
579
- appUrl: "https://example.com",
580
- },
581
- mockOptions,
582
- );
583
-
584
- expect(process.env.DOC_ROOT_DIR).toContain(".aigne/doc-smith/.tmp/docs");
585
- });
586
-
587
- // EDGE CASES
588
- test("should handle missing config file", async () => {
589
- loadConfigFromFileSpy.mockResolvedValue(null);
590
-
591
- const result = await publishDocs(
592
- {
593
- docsDir: "./docs",
594
- appUrl: "https://example.com",
595
- },
596
- mockOptions,
597
- );
598
-
599
- expect(result.message).toBe("✅ Documentation published successfully!");
600
- });
601
-
602
- test("should handle empty config", async () => {
603
- loadConfigFromFileSpy.mockResolvedValue({});
604
-
605
- await publishDocs(
606
- {
607
- docsDir: "./docs",
608
- appUrl: "https://example.com",
609
- },
610
- mockOptions,
611
- );
612
-
613
- expect(mockPublishDocs.publishDocs).toHaveBeenCalledWith(
614
- expect.objectContaining({
615
- boardMeta: {
616
- category: [],
617
- githubRepoUrl: "https://github.com/user/repo",
618
- commitSha: "",
619
- languages: [],
620
- },
621
- }),
622
- );
623
- });
624
-
625
- test("should skip platform selection when appUrl is in config", async () => {
626
- loadConfigFromFileSpy.mockResolvedValue({
627
- appUrl: "https://existing.com",
628
- });
629
-
630
- await publishDocs(
631
- {
632
- docsDir: "./docs",
633
- appUrl: "https://docsmith.aigne.io", // Default URL
634
- },
635
- mockOptions,
636
- );
637
-
638
- expect(mockOptions.prompts.select).not.toHaveBeenCalled();
639
- });
640
-
641
- // RESUME PREVIOUS WEBSITE SETUP TESTS
642
- test("should show resume option when checkoutId exists in config", async () => {
643
- loadConfigFromFileSpy.mockResolvedValue({
644
- checkoutId: "cached-checkout-123",
645
- });
646
- mockBrokerClient.checkCacheSession.mockResolvedValue({
647
- sessionId: "cached-checkout-123",
648
- paymentLink: "https://payment.example.com",
649
- });
650
- mockOptions.prompts.select.mockResolvedValue("default");
651
-
652
- await publishDocs(
653
- {
654
- docsDir: "./docs",
655
- appUrl: "https://docsmith.aigne.io",
656
- },
657
- mockOptions,
658
- );
659
-
660
- expect(mockOptions.prompts.select).toHaveBeenCalledWith(
661
- expect.objectContaining({
662
- message: "Select platform to publish your documents:",
663
- choices: expect.arrayContaining([
664
- expect.objectContaining({
665
- name: expect.stringContaining("Resume previous website setup"),
666
- value: "new-instance-continue",
667
- }),
668
- ]),
669
- }),
670
- );
671
-
672
- // Verify the exact text content
673
- const selectCall = mockOptions.prompts.select.mock.calls[0][0];
674
- const resumeChoice = selectCall.choices.find(
675
- (choice) => choice.value === "new-instance-continue",
676
- );
677
- expect(resumeChoice.name).toContain("Resume previous website setup");
678
- expect(resumeChoice.name).toContain("Already paid.");
679
- expect(resumeChoice.name).toContain(
680
- "Continue where you left off. Your payment has already been processed.",
681
- );
682
- });
683
-
684
- test("should not show resume option when no checkoutId in config", async () => {
685
- loadConfigFromFileSpy.mockResolvedValue({});
686
- mockOptions.prompts.select.mockResolvedValue("default");
687
-
688
- await publishDocs(
689
- {
690
- docsDir: "./docs",
691
- appUrl: "https://docsmith.aigne.io",
692
- },
693
- mockOptions,
694
- );
695
-
696
- expect(mockOptions.prompts.select).toHaveBeenCalledWith(
697
- expect.objectContaining({
698
- message: "Select platform to publish your documents:",
699
- choices: expect.not.arrayContaining([
700
- expect.objectContaining({
701
- value: "new-instance-continue",
702
- }),
703
- ]),
704
- }),
705
- );
706
- });
707
-
708
- test("should handle resume previous website setup selection", async () => {
709
- deploySpy.mockResolvedValue({
710
- appUrl: "https://resumed.example.com",
711
- token: "resume-token",
712
- });
713
-
714
- loadConfigFromFileSpy.mockResolvedValue({
715
- checkoutId: "cached-checkout-123",
716
- paymentUrl: "https://payment.example.com",
717
- });
718
- mockBrokerClient.checkCacheSession.mockResolvedValue({
719
- sessionId: "cached-checkout-123",
720
- paymentLink: "https://payment.example.com",
721
- });
722
- mockOptions.prompts.select.mockResolvedValue("new-instance-continue");
723
-
724
- const consoleSpy = spyOn(console, "log").mockImplementation(() => {});
725
-
726
- await publishDocs(
727
- {
728
- docsDir: "./docs",
729
- appUrl: "https://docsmith.aigne.io",
730
- },
731
- mockOptions,
732
- );
733
-
734
- expect(consoleSpy).toHaveBeenCalledWith("\nResuming your previous website setup...");
735
- expect(deploySpy).toHaveBeenCalledWith("cached-checkout-123", "https://payment.example.com");
736
- expect(getAccessTokenSpy).toHaveBeenCalledWith("https://resumed.example.com", "resume-token");
737
-
738
- consoleSpy.mockRestore();
739
- });
740
-
741
- test("should handle URL validation edge cases", async () => {
742
- loadConfigFromFileSpy.mockResolvedValue({});
743
- mockOptions.prompts.select.mockResolvedValue("custom");
744
-
745
- await publishDocs(
746
- {
747
- docsDir: "./docs",
748
- appUrl: "https://docsmith.aigne.io",
749
- },
750
- mockOptions,
751
- );
752
-
753
- const validateFn = mockOptions.prompts.input.mock.calls[0][0].validate;
754
-
755
- expect(validateFn("")).toBe("Please enter a valid URL");
756
- expect(validateFn(" ")).toBe("Please enter a valid URL");
757
- expect(validateFn("http://valid.com")).toBe(true);
758
- expect(validateFn("https://valid.com")).toBe(true);
759
- expect(validateFn("valid.com")).toBe(true);
760
- });
761
-
762
- test("should handle parameters priority correctly", async () => {
763
- // Parameters > Config > Defaults
764
- loadConfigFromFileSpy.mockResolvedValue({
765
- projectName: "Config Name",
766
- projectDesc: "Config Desc",
767
- });
768
-
769
- await publishDocs(
770
- {
771
- docsDir: "./docs",
772
- appUrl: "https://example.com",
773
- projectName: "Param Name", // Should override config
774
- // projectDesc not provided - should use config
775
- },
776
- mockOptions,
777
- );
778
-
779
- expect(mockPublishDocs.publishDocs).toHaveBeenCalledWith(
780
- expect.objectContaining({
781
- boardName: "Param Name", // From parameter
782
- boardDesc: "Config Desc", // From config
783
- boardCover: "", // Default (empty)
784
- }),
785
- );
786
- });
787
- });