@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,336 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test";
2
- import {
3
- ComponentNotFoundError,
4
- getComponentMountPoint,
5
- InvalidBlockletError,
6
- } from "../../utils/blocklet.mjs";
7
-
8
- describe("blocklet", () => {
9
- let mockFetch;
10
- beforeEach(() => {
11
- // Mock global fetch
12
- mockFetch = spyOn(global, "fetch").mockResolvedValue({
13
- ok: true,
14
- json: () => Promise.resolve({ name: "test-repo", description: "Test repo" }),
15
- statusText: "OK",
16
- });
17
- });
18
-
19
- afterEach(() => {
20
- mockFetch?.mockRestore();
21
- });
22
-
23
- // ERROR CLASSES TESTS
24
- describe("InvalidBlockletError", () => {
25
- test("should create error with correct properties", () => {
26
- const url = "https://example.com";
27
- const status = 404;
28
- const statusText = "Not Found";
29
-
30
- const error = new InvalidBlockletError(url, status, statusText);
31
-
32
- expect(error).toBeInstanceOf(Error);
33
- expect(error.name).toBe("InvalidBlockletError");
34
- expect(error.message).toBe(
35
- 'Invalid application URL: "https://example.com". Unable to fetch configuration.',
36
- );
37
- expect(error.url).toBe(url);
38
- expect(error.status).toBe(status);
39
- expect(error.statusText).toBe(statusText);
40
- });
41
-
42
- test("should handle null status and statusText", () => {
43
- const url = "https://example.com";
44
-
45
- const error = new InvalidBlockletError(url, null, "Network error");
46
-
47
- expect(error.url).toBe(url);
48
- expect(error.status).toBeNull();
49
- expect(error.statusText).toBe("Network error");
50
- });
51
-
52
- test("should be instanceof Error", () => {
53
- const error = new InvalidBlockletError("https://example.com");
54
- expect(error instanceof Error).toBe(true);
55
- expect(error instanceof InvalidBlockletError).toBe(true);
56
- });
57
- });
58
-
59
- describe("ComponentNotFoundError", () => {
60
- test("should create error with correct properties", () => {
61
- const did = "z8ia28nJVd6UMcS4dcJf5NLhv3rLmrFCK";
62
- const appUrl = "https://example.com";
63
-
64
- const error = new ComponentNotFoundError(did, appUrl);
65
-
66
- expect(error).toBeInstanceOf(Error);
67
- expect(error.name).toBe("ComponentNotFoundError");
68
- expect(error.message).toBe(
69
- 'Your website "https://example.com" missing required component to host your docs.',
70
- );
71
- expect(error.did).toBe(did);
72
- expect(error.appUrl).toBe(appUrl);
73
- });
74
-
75
- test("should be instanceof Error", () => {
76
- const error = new ComponentNotFoundError("test-did", "https://example.com");
77
- expect(error instanceof Error).toBe(true);
78
- expect(error instanceof ComponentNotFoundError).toBe(true);
79
- });
80
- });
81
-
82
- // GETCOMPONENTMOUNTPOINT FUNCTION TESTS
83
- describe("getComponentMountPoint", () => {
84
- const testAppUrl = "https://example.com";
85
- const testDid = "z8ia28nJVd6UMcS4dcJf5NLhv3rLmrFCK";
86
- const expectedUrl = "https://example.com/__blocklet__.js?type=json";
87
-
88
- test("should return mount point for existing component", async () => {
89
- const mockConfig = {
90
- componentMountPoints: [
91
- { did: "other-did", mountPoint: "/other" },
92
- { did: testDid, mountPoint: "/api/discuss" },
93
- { did: "another-did", mountPoint: "/another" },
94
- ],
95
- };
96
-
97
- mockFetch.mockResolvedValue({
98
- ok: true,
99
- json: () => Promise.resolve(mockConfig),
100
- });
101
-
102
- const result = await getComponentMountPoint(testAppUrl, testDid);
103
-
104
- expect(result).toBe("/api/discuss");
105
- expect(mockFetch).toHaveBeenCalledWith(expectedUrl, {
106
- method: "GET",
107
- headers: { Accept: "application/json" },
108
- });
109
- });
110
-
111
- // NETWORK ERROR TESTS
112
- test("should throw InvalidBlockletError when fetch fails", async () => {
113
- mockFetch.mockRejectedValue(new Error("Network timeout"));
114
-
115
- await expect(getComponentMountPoint(testAppUrl, testDid)).rejects.toThrow(
116
- InvalidBlockletError,
117
- );
118
-
119
- try {
120
- await getComponentMountPoint(testAppUrl, testDid);
121
- } catch (error) {
122
- expect(error.url).toBe(testAppUrl);
123
- expect(error.status).toBeNull();
124
- expect(error.statusText).toBe("Network timeout");
125
- }
126
- });
127
-
128
- test("should throw InvalidBlockletError when response is not ok", async () => {
129
- mockFetch.mockResolvedValue({
130
- ok: false,
131
- status: 404,
132
- statusText: "Not Found",
133
- });
134
-
135
- await expect(getComponentMountPoint(testAppUrl, testDid)).rejects.toThrow(
136
- InvalidBlockletError,
137
- );
138
-
139
- try {
140
- await getComponentMountPoint(testAppUrl, testDid);
141
- } catch (error) {
142
- expect(error.url).toBe(testAppUrl);
143
- expect(error.status).toBe(404);
144
- expect(error.statusText).toBe("Not Found");
145
- }
146
- });
147
-
148
- test("should throw InvalidBlockletError when JSON parsing fails", async () => {
149
- mockFetch.mockResolvedValue({
150
- ok: true,
151
- json: () => Promise.reject(new Error("Invalid JSON")),
152
- });
153
-
154
- await expect(getComponentMountPoint(testAppUrl, testDid)).rejects.toThrow(
155
- InvalidBlockletError,
156
- );
157
-
158
- try {
159
- await getComponentMountPoint(testAppUrl, testDid);
160
- } catch (error) {
161
- expect(error.url).toBe(testAppUrl);
162
- expect(error.status).toBeNull();
163
- expect(error.statusText).toBe("Invalid JSON response");
164
- }
165
- });
166
-
167
- // COMPONENT NOT FOUND TESTS
168
- test("should throw ComponentNotFoundError when component is not found", async () => {
169
- const mockConfig = {
170
- componentMountPoints: [
171
- { did: "other-did", mountPoint: "/other" },
172
- { did: "another-did", mountPoint: "/another" },
173
- ],
174
- };
175
-
176
- mockFetch.mockResolvedValue({
177
- ok: true,
178
- json: () => Promise.resolve(mockConfig),
179
- });
180
-
181
- await expect(getComponentMountPoint(testAppUrl, testDid)).rejects.toThrow(
182
- ComponentNotFoundError,
183
- );
184
-
185
- try {
186
- await getComponentMountPoint(testAppUrl, testDid);
187
- } catch (error) {
188
- expect(error.did).toBe(testDid);
189
- expect(error.appUrl).toBe(testAppUrl);
190
- }
191
- });
192
-
193
- test("should throw ComponentNotFoundError when componentMountPoints is undefined", async () => {
194
- const mockConfig = {};
195
-
196
- mockFetch.mockResolvedValue({
197
- ok: true,
198
- json: () => Promise.resolve(mockConfig),
199
- });
200
-
201
- await expect(getComponentMountPoint(testAppUrl, testDid)).rejects.toThrow(
202
- ComponentNotFoundError,
203
- );
204
- });
205
-
206
- test("should throw ComponentNotFoundError when componentMountPoints is empty", async () => {
207
- const mockConfig = {
208
- componentMountPoints: [],
209
- };
210
-
211
- mockFetch.mockResolvedValue({
212
- ok: true,
213
- json: () => Promise.resolve(mockConfig),
214
- });
215
-
216
- await expect(getComponentMountPoint(testAppUrl, testDid)).rejects.toThrow(
217
- ComponentNotFoundError,
218
- );
219
- });
220
-
221
- // EDGE CASES
222
- test("should handle component at the beginning of array", async () => {
223
- const mockConfig = {
224
- componentMountPoints: [
225
- { did: testDid, mountPoint: "/first" },
226
- { did: "other-did", mountPoint: "/other" },
227
- ],
228
- };
229
-
230
- mockFetch.mockResolvedValue({
231
- ok: true,
232
- json: () => Promise.resolve(mockConfig),
233
- });
234
-
235
- const result = await getComponentMountPoint(testAppUrl, testDid);
236
- expect(result).toBe("/first");
237
- });
238
-
239
- test("should handle component at the end of array", async () => {
240
- const mockConfig = {
241
- componentMountPoints: [
242
- { did: "other-did", mountPoint: "/other" },
243
- { did: testDid, mountPoint: "/last" },
244
- ],
245
- };
246
-
247
- mockFetch.mockResolvedValue({
248
- ok: true,
249
- json: () => Promise.resolve(mockConfig),
250
- });
251
-
252
- const result = await getComponentMountPoint(testAppUrl, testDid);
253
- expect(result).toBe("/last");
254
- });
255
-
256
- test("should handle single component", async () => {
257
- const mockConfig = {
258
- componentMountPoints: [{ did: testDid, mountPoint: "/single" }],
259
- };
260
-
261
- mockFetch.mockResolvedValue({
262
- ok: true,
263
- json: () => Promise.resolve(mockConfig),
264
- });
265
-
266
- const result = await getComponentMountPoint(testAppUrl, testDid);
267
- expect(result).toBe("/single");
268
- });
269
-
270
- test("should handle complex mount points", async () => {
271
- const mockConfig = {
272
- componentMountPoints: [{ did: testDid, mountPoint: "/api/v1/discuss-kit/endpoint" }],
273
- };
274
-
275
- mockFetch.mockResolvedValue({
276
- ok: true,
277
- json: () => Promise.resolve(mockConfig),
278
- });
279
-
280
- const result = await getComponentMountPoint(testAppUrl, testDid);
281
- expect(result).toBe("/api/v1/discuss-kit/endpoint");
282
- });
283
-
284
- test("should handle empty mount point", async () => {
285
- const mockConfig = {
286
- componentMountPoints: [{ did: testDid, mountPoint: "" }],
287
- };
288
-
289
- mockFetch.mockResolvedValue({
290
- ok: true,
291
- json: () => Promise.resolve(mockConfig),
292
- });
293
-
294
- const result = await getComponentMountPoint(testAppUrl, testDid);
295
- expect(result).toBe("");
296
- });
297
-
298
- test("should handle null/undefined mount point", async () => {
299
- const mockConfig = {
300
- componentMountPoints: [{ did: testDid, mountPoint: null }],
301
- };
302
-
303
- mockFetch.mockResolvedValue({
304
- ok: true,
305
- json: () => Promise.resolve(mockConfig),
306
- });
307
-
308
- const result = await getComponentMountPoint(testAppUrl, testDid);
309
- expect(result).toBeNull();
310
- });
311
-
312
- // NETWORK TIMEOUT AND RETRY SCENARIOS
313
- test("should handle network errors with different error types", async () => {
314
- const errorTypes = [
315
- new TypeError("Failed to fetch"),
316
- new Error("Connection refused"),
317
- new Error("Timeout"),
318
- new ReferenceError("Network error"),
319
- ];
320
-
321
- for (const error of errorTypes) {
322
- mockFetch.mockRejectedValueOnce(error);
323
-
324
- try {
325
- await getComponentMountPoint(testAppUrl, testDid);
326
- expect(true).toBe(false); // Should not reach here
327
- } catch (caughtError) {
328
- expect(caughtError).toBeInstanceOf(InvalidBlockletError);
329
- expect(caughtError.url).toBe(testAppUrl);
330
- expect(caughtError.status).toBeNull();
331
- expect(caughtError.statusText).toBe(error.message);
332
- }
333
- }
334
- });
335
- });
336
- });
@@ -1,355 +0,0 @@
1
- import { describe, expect, test } from "bun:test";
2
- import {
3
- detectResolvableConflicts,
4
- generateConflictResolutionRules,
5
- getFilteredOptions,
6
- } from "../../utils/conflict-detector.mjs";
7
- import { processConfigFields } from "../../utils/utils.mjs";
8
-
9
- describe("conflict-detector", () => {
10
- describe("getFilteredOptions", () => {
11
- test("should filter experiencedUsers when documentPurpose is getStarted", () => {
12
- const allOptions = {
13
- completeBeginners: "Complete beginners",
14
- domainFamiliar: "Domain familiar",
15
- experiencedUsers: "Experienced users",
16
- emergencyTroubleshooting: "Emergency troubleshooting",
17
- };
18
-
19
- const currentSelections = {
20
- documentPurpose: ["getStarted"],
21
- };
22
-
23
- const result = getFilteredOptions("readerKnowledgeLevel", currentSelections, allOptions);
24
-
25
- expect(result.filteredOptions).not.toHaveProperty("experiencedUsers");
26
- expect(result.appliedFilters).toHaveLength(1);
27
- expect(result.appliedFilters[0].removedOption).toBe("experiencedUsers");
28
- });
29
-
30
- test("should filter completeBeginners when documentPurpose is findAnswers", () => {
31
- const allOptions = {
32
- completeBeginners: "Complete beginners",
33
- domainFamiliar: "Domain familiar",
34
- experiencedUsers: "Experienced users",
35
- };
36
-
37
- const currentSelections = {
38
- documentPurpose: ["findAnswers"],
39
- };
40
-
41
- const result = getFilteredOptions("readerKnowledgeLevel", currentSelections, allOptions);
42
-
43
- expect(result.filteredOptions).not.toHaveProperty("completeBeginners");
44
- expect(result.appliedFilters).toHaveLength(1);
45
- expect(result.appliedFilters[0].removedOption).toBe("completeBeginners");
46
- });
47
-
48
- test("should filter emergencyTroubleshooting when documentPurpose is understandSystem", () => {
49
- const allOptions = {
50
- completeBeginners: "Complete beginners",
51
- emergencyTroubleshooting: "Emergency troubleshooting",
52
- };
53
-
54
- const currentSelections = {
55
- documentPurpose: ["understandSystem"],
56
- };
57
-
58
- const result = getFilteredOptions("readerKnowledgeLevel", currentSelections, allOptions);
59
-
60
- expect(result.filteredOptions).not.toHaveProperty("emergencyTroubleshooting");
61
- expect(result.appliedFilters).toHaveLength(1);
62
- });
63
-
64
- test("should filter experiencedUsers when targetAudienceTypes includes endUsers", () => {
65
- const allOptions = {
66
- completeBeginners: "Complete beginners",
67
- experiencedUsers: "Experienced users",
68
- };
69
-
70
- const currentSelections = {
71
- targetAudienceTypes: ["endUsers"],
72
- };
73
-
74
- const result = getFilteredOptions("readerKnowledgeLevel", currentSelections, allOptions);
75
-
76
- expect(result.filteredOptions).not.toHaveProperty("experiencedUsers");
77
- expect(result.appliedFilters).toHaveLength(1);
78
- });
79
-
80
- test("should return original options when no conflicts", () => {
81
- const allOptions = {
82
- option1: "Option 1",
83
- option2: "Option 2",
84
- };
85
-
86
- const currentSelections = {};
87
-
88
- const result = getFilteredOptions("unknownType", currentSelections, allOptions);
89
-
90
- expect(result.filteredOptions).toEqual(allOptions);
91
- expect(result.appliedFilters).toHaveLength(0);
92
- });
93
-
94
- test("should handle object selections with value property", () => {
95
- const allOptions = {
96
- experiencedUsers: "Experienced users",
97
- domainFamiliar: "Domain familiar",
98
- };
99
-
100
- const currentSelections = {
101
- documentPurpose: [{ value: "getStarted", label: "Get Started" }],
102
- };
103
-
104
- const result = getFilteredOptions("readerKnowledgeLevel", currentSelections, allOptions);
105
-
106
- expect(result.filteredOptions).not.toHaveProperty("experiencedUsers");
107
- expect(result.appliedFilters).toHaveLength(1);
108
- });
109
-
110
- test("should handle multiple conditions in cross-conflict rules", () => {
111
- const allOptions = {
112
- emergencyTroubleshooting: "Emergency troubleshooting",
113
- domainFamiliar: "Domain familiar",
114
- };
115
-
116
- const currentSelections = {
117
- targetAudienceTypes: ["decisionMakers"],
118
- };
119
-
120
- const result = getFilteredOptions("readerKnowledgeLevel", currentSelections, allOptions);
121
-
122
- expect(result.filteredOptions).not.toHaveProperty("emergencyTroubleshooting");
123
- expect(result.appliedFilters).toHaveLength(1);
124
- });
125
- });
126
-
127
- describe("detectResolvableConflicts", () => {
128
- test("should detect document purpose conflicts", () => {
129
- const config = {
130
- documentPurpose: ["getStarted", "findAnswers"],
131
- targetAudienceTypes: ["developers"],
132
- };
133
-
134
- const conflicts = detectResolvableConflicts(config);
135
-
136
- expect(conflicts).toHaveLength(1);
137
- expect(conflicts[0]).toMatchObject({
138
- type: "documentPurpose",
139
- items: ["getStarted", "findAnswers"],
140
- strategy: "layered_structure",
141
- description: "Quick start and API reference conflict, resolved through layered structure",
142
- });
143
- });
144
-
145
- test("should detect target audience conflicts", () => {
146
- const config = {
147
- documentPurpose: ["completeTasks"],
148
- targetAudienceTypes: ["endUsers", "developers"],
149
- };
150
-
151
- const conflicts = detectResolvableConflicts(config);
152
-
153
- expect(conflicts).toHaveLength(1);
154
- expect(conflicts[0]).toMatchObject({
155
- type: "targetAudienceTypes",
156
- items: ["endUsers", "developers"],
157
- strategy: "separate_user_paths",
158
- description: "End users and developers conflict, resolved through separate user paths",
159
- });
160
- });
161
-
162
- test("should detect multiple conflicts", () => {
163
- const config = {
164
- documentPurpose: ["getStarted", "findAnswers", "understandSystem"],
165
- targetAudienceTypes: ["endUsers", "developers"],
166
- };
167
-
168
- const conflicts = detectResolvableConflicts(config);
169
-
170
- expect(conflicts).toHaveLength(3);
171
-
172
- // Check for getStarted vs findAnswers conflict
173
- expect(
174
- conflicts.some(
175
- (c) =>
176
- c.type === "documentPurpose" &&
177
- c.items.includes("getStarted") &&
178
- c.items.includes("findAnswers"),
179
- ),
180
- ).toBe(true);
181
-
182
- // Check for getStarted vs understandSystem conflict
183
- expect(
184
- conflicts.some(
185
- (c) =>
186
- c.type === "documentPurpose" &&
187
- c.items.includes("getStarted") &&
188
- c.items.includes("understandSystem"),
189
- ),
190
- ).toBe(true);
191
-
192
- // Check for endUsers vs developers conflict
193
- expect(
194
- conflicts.some(
195
- (c) =>
196
- c.type === "targetAudienceTypes" &&
197
- c.items.includes("endUsers") &&
198
- c.items.includes("developers"),
199
- ),
200
- ).toBe(true);
201
- });
202
-
203
- test("should not detect conflicts with single selections", () => {
204
- const config = {
205
- documentPurpose: ["getStarted"],
206
- targetAudienceTypes: ["developers"],
207
- };
208
-
209
- const conflicts = detectResolvableConflicts(config);
210
-
211
- expect(conflicts).toHaveLength(0);
212
- });
213
-
214
- test("should not detect conflicts with non-conflicting combinations", () => {
215
- const config = {
216
- documentPurpose: ["completeTasks", "solveProblems"],
217
- targetAudienceTypes: ["developers", "devops"],
218
- };
219
-
220
- const conflicts = detectResolvableConflicts(config);
221
-
222
- expect(conflicts).toHaveLength(0);
223
- });
224
-
225
- test("should handle object arrays with value property", () => {
226
- const config = {
227
- documentPurpose: [
228
- { value: "getStarted", label: "Get Started" },
229
- { value: "findAnswers", label: "Find Answers" },
230
- ],
231
- };
232
-
233
- const conflicts = detectResolvableConflicts(config);
234
-
235
- expect(conflicts).toHaveLength(1);
236
- expect(conflicts[0].items).toEqual(["getStarted", "findAnswers"]);
237
- });
238
- });
239
-
240
- describe("generateConflictResolutionRules", () => {
241
- test("should generate resolution rules for conflicts", () => {
242
- const conflicts = [
243
- {
244
- type: "documentPurpose",
245
- items: ["getStarted", "findAnswers"],
246
- strategy: "layered_structure",
247
- description: "Quick start and API reference conflict, resolved through layered structure",
248
- },
249
- {
250
- type: "targetAudienceTypes",
251
- items: ["endUsers", "developers"],
252
- strategy: "separate_user_paths",
253
- description: "End users and developers conflict, resolved through separate user paths",
254
- },
255
- ];
256
-
257
- const rules = generateConflictResolutionRules(conflicts);
258
-
259
- expect(rules).toContain("=== Conflict Resolution Guidelines ===");
260
- expect(rules).toContain('Detected "getStarted" and "findAnswers" purpose conflict');
261
- expect(rules).toContain('Detected "endUsers" and "developers" audience conflict');
262
- expect(rules).toContain('Quick start section: Uses "get started" style');
263
- expect(rules).toContain('User guide path: Uses "end users" style');
264
- expect(rules).toContain("Conflict Resolution Principles:");
265
- expect(rules).toContain(
266
- "1. Meet diverse needs through intelligent structural design, not simple concatenation",
267
- );
268
- });
269
-
270
- test("should return empty string for no conflicts", () => {
271
- const conflicts = [];
272
- const rules = generateConflictResolutionRules(conflicts);
273
- expect(rules).toBe("");
274
- });
275
-
276
- test("should handle unknown strategies gracefully", () => {
277
- const conflicts = [
278
- {
279
- type: "documentPurpose",
280
- items: ["unknown1", "unknown2"],
281
- strategy: "unknown_strategy",
282
- description: "Unknown conflict",
283
- },
284
- ];
285
-
286
- const rules = generateConflictResolutionRules(conflicts);
287
-
288
- expect(rules).toContain("=== Conflict Resolution Guidelines ===");
289
- expect(rules).toContain("Conflict Resolution Principles:");
290
- // Should not contain any strategy-specific text since strategy is unknown
291
- expect(rules).not.toContain('Detected "unknown1" and "unknown2"');
292
- });
293
- });
294
-
295
- describe("processConfigFields integration", () => {
296
- test("should integrate conflict resolution into config processing", () => {
297
- const config = {
298
- documentPurpose: ["getStarted", "findAnswers"],
299
- targetAudienceTypes: ["endUsers", "developers"],
300
- readerKnowledgeLevel: "completeBeginners",
301
- documentationDepth: "balancedCoverage",
302
- };
303
-
304
- const result = processConfigFields(config);
305
-
306
- // Should detect conflicts
307
- expect(result.detectedConflicts).toBeDefined();
308
- expect(result.detectedConflicts).toHaveLength(2);
309
-
310
- // Should include conflict resolution rules in final rules
311
- expect(result.rules).toContain("=== Conflict Resolution Guidelines ===");
312
- expect(result.rules).toContain("Create layered documentation structure");
313
- expect(result.rules).toContain("Create separate user paths");
314
-
315
- // Should also include regular configuration content with enhanced format
316
- expect(result.rules).toContain("Document Purpose - Get started quickly:");
317
- expect(result.rules).toContain("Target Audience - End users (non-technical):");
318
- expect(result.rules).toContain("Target Audience - Developers integrating your product/API:");
319
- expect(result.rules).toContain("Reader Knowledge Level:");
320
- });
321
-
322
- test("should work without conflicts", () => {
323
- const config = {
324
- documentPurpose: ["completeTasks"],
325
- targetAudienceTypes: ["developers"],
326
- readerKnowledgeLevel: "domainFamiliar",
327
- };
328
-
329
- const result = processConfigFields(config);
330
-
331
- // Should not detect conflicts
332
- expect(result.detectedConflicts).toBeUndefined();
333
-
334
- // Should not include conflict resolution rules
335
- expect(result.rules).not.toContain("=== Conflict Resolution Guidelines ===");
336
-
337
- // Should still include regular configuration content with enhanced format
338
- expect(result.rules).toContain("Document Purpose - Complete specific tasks:");
339
- expect(result.rules).toContain("Target Audience - Developers integrating your product/API:");
340
- });
341
-
342
- test("should preserve target audience field processing", () => {
343
- const config = {
344
- targetAudienceTypes: ["developers", "devops"],
345
- targetAudience: "Existing audience description",
346
- };
347
-
348
- const result = processConfigFields(config);
349
-
350
- expect(result.targetAudience).toContain("Existing audience description");
351
- expect(result.targetAudience).toContain("Developers integrating your product/API");
352
- expect(result.targetAudience).toContain("DevOps / SRE / Infrastructure teams");
353
- });
354
- });
355
- });