@aigne/doc-smith 0.8.12-beta.8 → 0.8.12-beta.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (264) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/agents/publish/index.yaml +4 -0
  3. package/agents/publish/publish-docs.mjs +77 -5
  4. package/agents/publish/translate-meta.mjs +103 -0
  5. package/agents/update/generate-document.yaml +30 -28
  6. package/agents/update/update-document-detail.yaml +3 -1
  7. package/agents/utils/update-branding.mjs +69 -0
  8. package/package.json +16 -2
  9. package/prompts/common/document/role-and-personality.md +3 -1
  10. package/prompts/detail/d2-diagram/guide.md +7 -1
  11. package/prompts/detail/d2-diagram/user-prompt.md +3 -0
  12. package/prompts/detail/generate/system-prompt.md +6 -7
  13. package/prompts/detail/generate/user-prompt.md +12 -3
  14. package/prompts/detail/update/user-prompt.md +0 -2
  15. package/prompts/structure/update/user-prompt.md +0 -4
  16. package/utils/file-utils.mjs +69 -24
  17. package/utils/markdown-checker.mjs +0 -20
  18. package/utils/request.mjs +7 -0
  19. package/utils/upload-files.mjs +231 -0
  20. package/utils/utils.mjs +11 -1
  21. package/.aigne/doc-smith/config.yaml +0 -77
  22. package/.aigne/doc-smith/history.yaml +0 -37
  23. package/.aigne/doc-smith/media-description.yaml +0 -91
  24. package/.aigne/doc-smith/output/structure-plan.json +0 -162
  25. package/.aigne/doc-smith/preferences.yml +0 -97
  26. package/.aigne/doc-smith/upload-cache.yaml +0 -1830
  27. package/.github/PULL_REQUEST_TEMPLATE.md +0 -28
  28. package/.github/workflows/ci.yml +0 -54
  29. package/.github/workflows/create-release-pr.yaml +0 -21
  30. package/.github/workflows/publish-docs.yml +0 -65
  31. package/.github/workflows/release.yml +0 -49
  32. package/.github/workflows/reviewer.yml +0 -54
  33. package/.release-please-manifest.json +0 -3
  34. package/RELEASE.md +0 -9
  35. package/assets/screenshots/doc-complete-setup.png +0 -0
  36. package/assets/screenshots/doc-generate-docs.png +0 -0
  37. package/assets/screenshots/doc-generate.png +0 -0
  38. package/assets/screenshots/doc-generated-successfully.png +0 -0
  39. package/assets/screenshots/doc-publish.png +0 -0
  40. package/assets/screenshots/doc-regenerate.png +0 -0
  41. package/assets/screenshots/doc-translate-langs.png +0 -0
  42. package/assets/screenshots/doc-translate.png +0 -0
  43. package/assets/screenshots/doc-update.png +0 -0
  44. package/biome.json +0 -73
  45. package/codecov.yml +0 -15
  46. package/docs/_sidebar.md +0 -15
  47. package/docs/configuration-initial-setup.ja.md +0 -179
  48. package/docs/configuration-initial-setup.md +0 -198
  49. package/docs/configuration-initial-setup.zh-TW.md +0 -179
  50. package/docs/configuration-initial-setup.zh.md +0 -179
  51. package/docs/configuration-managing-preferences.ja.md +0 -100
  52. package/docs/configuration-managing-preferences.md +0 -100
  53. package/docs/configuration-managing-preferences.zh-TW.md +0 -100
  54. package/docs/configuration-managing-preferences.zh.md +0 -100
  55. package/docs/configuration.ja.md +0 -69
  56. package/docs/configuration.md +0 -69
  57. package/docs/configuration.zh-TW.md +0 -69
  58. package/docs/configuration.zh.md +0 -69
  59. package/docs/getting-started.ja.md +0 -107
  60. package/docs/getting-started.md +0 -107
  61. package/docs/getting-started.zh-TW.md +0 -107
  62. package/docs/getting-started.zh.md +0 -107
  63. package/docs/guides-cleaning-up.ja.md +0 -51
  64. package/docs/guides-cleaning-up.md +0 -52
  65. package/docs/guides-cleaning-up.zh-TW.md +0 -51
  66. package/docs/guides-cleaning-up.zh.md +0 -51
  67. package/docs/guides-evaluating-documents.ja.md +0 -66
  68. package/docs/guides-evaluating-documents.md +0 -107
  69. package/docs/guides-evaluating-documents.zh-TW.md +0 -66
  70. package/docs/guides-evaluating-documents.zh.md +0 -66
  71. package/docs/guides-generating-documentation.ja.md +0 -151
  72. package/docs/guides-generating-documentation.md +0 -89
  73. package/docs/guides-generating-documentation.zh-TW.md +0 -151
  74. package/docs/guides-generating-documentation.zh.md +0 -151
  75. package/docs/guides-interactive-chat.ja.md +0 -85
  76. package/docs/guides-interactive-chat.md +0 -93
  77. package/docs/guides-interactive-chat.zh-TW.md +0 -85
  78. package/docs/guides-interactive-chat.zh.md +0 -85
  79. package/docs/guides-managing-history.ja.md +0 -48
  80. package/docs/guides-managing-history.md +0 -53
  81. package/docs/guides-managing-history.zh-TW.md +0 -48
  82. package/docs/guides-managing-history.zh.md +0 -48
  83. package/docs/guides-publishing-your-docs.ja.md +0 -78
  84. package/docs/guides-publishing-your-docs.md +0 -83
  85. package/docs/guides-publishing-your-docs.zh-TW.md +0 -78
  86. package/docs/guides-publishing-your-docs.zh.md +0 -78
  87. package/docs/guides-translating-documentation.ja.md +0 -95
  88. package/docs/guides-translating-documentation.md +0 -100
  89. package/docs/guides-translating-documentation.zh-TW.md +0 -95
  90. package/docs/guides-translating-documentation.zh.md +0 -95
  91. package/docs/guides-updating-documentation.ja.md +0 -77
  92. package/docs/guides-updating-documentation.md +0 -79
  93. package/docs/guides-updating-documentation.zh-TW.md +0 -77
  94. package/docs/guides-updating-documentation.zh.md +0 -77
  95. package/docs/guides.ja.md +0 -32
  96. package/docs/guides.md +0 -32
  97. package/docs/guides.zh-TW.md +0 -32
  98. package/docs/guides.zh.md +0 -32
  99. package/docs/overview.ja.md +0 -61
  100. package/docs/overview.md +0 -61
  101. package/docs/overview.zh-TW.md +0 -61
  102. package/docs/overview.zh.md +0 -61
  103. package/docs/release-notes.ja.md +0 -255
  104. package/docs/release-notes.md +0 -288
  105. package/docs/release-notes.zh-TW.md +0 -255
  106. package/docs/release-notes.zh.md +0 -255
  107. package/prompts/common/afs/afs-tools-usage.md +0 -5
  108. package/prompts/common/afs/use-afs-instruction.md +0 -1
  109. package/release-please-config.json +0 -14
  110. package/tests/agents/chat/chat.test.mjs +0 -46
  111. package/tests/agents/clear/choose-contents.test.mjs +0 -284
  112. package/tests/agents/clear/clear-auth-tokens.test.mjs +0 -268
  113. package/tests/agents/clear/clear-document-config.test.mjs +0 -167
  114. package/tests/agents/clear/clear-document-structure.test.mjs +0 -380
  115. package/tests/agents/clear/clear-generated-docs.test.mjs +0 -222
  116. package/tests/agents/evaluate/code-snippet.test.mjs +0 -163
  117. package/tests/agents/evaluate/fixtures/api-services.md +0 -87
  118. package/tests/agents/evaluate/fixtures/js-sdk.md +0 -94
  119. package/tests/agents/evaluate/generate-report.test.mjs +0 -312
  120. package/tests/agents/generate/check-document-structure.test.mjs +0 -45
  121. package/tests/agents/generate/check-need-generate-structure.test.mjs +0 -279
  122. package/tests/agents/generate/document-structure-tools/add-document.test.mjs +0 -449
  123. package/tests/agents/generate/document-structure-tools/delete-document.test.mjs +0 -410
  124. package/tests/agents/generate/document-structure-tools/generate-sub-structure.test.mjs +0 -277
  125. package/tests/agents/generate/document-structure-tools/move-document.test.mjs +0 -476
  126. package/tests/agents/generate/document-structure-tools/update-document.test.mjs +0 -548
  127. package/tests/agents/generate/generate-structure.test.mjs +0 -45
  128. package/tests/agents/generate/user-review-document-structure.test.mjs +0 -319
  129. package/tests/agents/history/view.test.mjs +0 -97
  130. package/tests/agents/init/init.test.mjs +0 -1657
  131. package/tests/agents/prefs/prefs.test.mjs +0 -431
  132. package/tests/agents/publish/publish-docs.test.mjs +0 -787
  133. package/tests/agents/translate/choose-language.test.mjs +0 -311
  134. package/tests/agents/translate/translate-document.test.mjs +0 -51
  135. package/tests/agents/update/check-document.test.mjs +0 -463
  136. package/tests/agents/update/check-update-is-single.test.mjs +0 -300
  137. package/tests/agents/update/document-tools/update-document-content.test.mjs +0 -329
  138. package/tests/agents/update/generate-document.test.mjs +0 -51
  139. package/tests/agents/update/save-and-translate-document.test.mjs +0 -369
  140. package/tests/agents/update/user-review-document.test.mjs +0 -582
  141. package/tests/agents/utils/action-success.test.mjs +0 -54
  142. package/tests/agents/utils/check-detail-result.test.mjs +0 -743
  143. package/tests/agents/utils/check-feedback-refiner.test.mjs +0 -478
  144. package/tests/agents/utils/choose-docs.test.mjs +0 -406
  145. package/tests/agents/utils/exit.test.mjs +0 -70
  146. package/tests/agents/utils/feedback-refiner.test.mjs +0 -51
  147. package/tests/agents/utils/find-item-by-path.test.mjs +0 -517
  148. package/tests/agents/utils/find-user-preferences-by-path.test.mjs +0 -382
  149. package/tests/agents/utils/format-document-structure.test.mjs +0 -364
  150. package/tests/agents/utils/fs.test.mjs +0 -267
  151. package/tests/agents/utils/load-sources.test.mjs +0 -1470
  152. package/tests/agents/utils/save-docs.test.mjs +0 -109
  153. package/tests/agents/utils/save-output.test.mjs +0 -315
  154. package/tests/agents/utils/save-single-doc.test.mjs +0 -364
  155. package/tests/agents/utils/transform-detail-datasources.test.mjs +0 -320
  156. package/tests/utils/auth-utils.test.mjs +0 -596
  157. package/tests/utils/blocklet.test.mjs +0 -336
  158. package/tests/utils/conflict-detector.test.mjs +0 -355
  159. package/tests/utils/constants.test.mjs +0 -295
  160. package/tests/utils/d2-utils.test.mjs +0 -437
  161. package/tests/utils/deploy.test.mjs +0 -399
  162. package/tests/utils/docs-finder-utils.test.mjs +0 -650
  163. package/tests/utils/file-utils.test.mjs +0 -521
  164. package/tests/utils/history-utils.test.mjs +0 -206
  165. package/tests/utils/kroki-utils.test.mjs +0 -646
  166. package/tests/utils/linter/fixtures/css/keyword-error.css +0 -1
  167. package/tests/utils/linter/fixtures/css/missing-semicolon.css +0 -1
  168. package/tests/utils/linter/fixtures/css/syntax-error.css +0 -1
  169. package/tests/utils/linter/fixtures/css/undeclare-variable.css +0 -1
  170. package/tests/utils/linter/fixtures/css/unused-variable.css +0 -2
  171. package/tests/utils/linter/fixtures/css/valid-code.css +0 -1
  172. package/tests/utils/linter/fixtures/dockerfile/keyword-error.dockerfile +0 -1
  173. package/tests/utils/linter/fixtures/dockerfile/missing-semicolon.dockerfile +0 -2
  174. package/tests/utils/linter/fixtures/dockerfile/syntax-error.dockerfile +0 -2
  175. package/tests/utils/linter/fixtures/dockerfile/undeclare-variable.dockerfile +0 -1
  176. package/tests/utils/linter/fixtures/dockerfile/unused-variable.dockerfile +0 -1
  177. package/tests/utils/linter/fixtures/dockerfile/valid-code.dockerfile +0 -2
  178. package/tests/utils/linter/fixtures/go/keyword-error.go +0 -5
  179. package/tests/utils/linter/fixtures/go/missing-semicolon.go +0 -5
  180. package/tests/utils/linter/fixtures/go/syntax-error.go +0 -6
  181. package/tests/utils/linter/fixtures/go/undeclare-variable.go +0 -5
  182. package/tests/utils/linter/fixtures/go/unused-variable.go +0 -5
  183. package/tests/utils/linter/fixtures/go/valid-code.go +0 -7
  184. package/tests/utils/linter/fixtures/js/keyword-error.js +0 -3
  185. package/tests/utils/linter/fixtures/js/missing-semicolon.js +0 -6
  186. package/tests/utils/linter/fixtures/js/syntax-error.js +0 -4
  187. package/tests/utils/linter/fixtures/js/undeclare-variable.js +0 -3
  188. package/tests/utils/linter/fixtures/js/unused-variable.js +0 -7
  189. package/tests/utils/linter/fixtures/js/valid-code.js +0 -15
  190. package/tests/utils/linter/fixtures/json/keyword-error.json +0 -1
  191. package/tests/utils/linter/fixtures/json/missing-semicolon.json +0 -1
  192. package/tests/utils/linter/fixtures/json/syntax-error.json +0 -1
  193. package/tests/utils/linter/fixtures/json/undeclare-variable.json +0 -1
  194. package/tests/utils/linter/fixtures/json/unused-variable.json +0 -1
  195. package/tests/utils/linter/fixtures/json/valid-code.json +0 -1
  196. package/tests/utils/linter/fixtures/jsx/keyword-error.jsx +0 -5
  197. package/tests/utils/linter/fixtures/jsx/missing-semicolon.jsx +0 -5
  198. package/tests/utils/linter/fixtures/jsx/syntax-error.jsx +0 -5
  199. package/tests/utils/linter/fixtures/jsx/undeclare-variable.jsx +0 -5
  200. package/tests/utils/linter/fixtures/jsx/unused-variable.jsx +0 -4
  201. package/tests/utils/linter/fixtures/jsx/valid-code.jsx +0 -5
  202. package/tests/utils/linter/fixtures/python/keyword-error.py +0 -3
  203. package/tests/utils/linter/fixtures/python/missing-semicolon.py +0 -2
  204. package/tests/utils/linter/fixtures/python/syntax-error.py +0 -3
  205. package/tests/utils/linter/fixtures/python/undeclare-variable.py +0 -3
  206. package/tests/utils/linter/fixtures/python/unused-variable.py +0 -6
  207. package/tests/utils/linter/fixtures/python/valid-code.py +0 -12
  208. package/tests/utils/linter/fixtures/ruby/keyword-error.rb +0 -2
  209. package/tests/utils/linter/fixtures/ruby/missing-semicolon.rb +0 -1
  210. package/tests/utils/linter/fixtures/ruby/syntax-error.rb +0 -2
  211. package/tests/utils/linter/fixtures/ruby/undeclare-variable.rb +0 -1
  212. package/tests/utils/linter/fixtures/ruby/unused-variable.rb +0 -2
  213. package/tests/utils/linter/fixtures/ruby/valid-code.rb +0 -1
  214. package/tests/utils/linter/fixtures/sass/keyword-error.sass +0 -2
  215. package/tests/utils/linter/fixtures/sass/missing-semicolon.sass +0 -3
  216. package/tests/utils/linter/fixtures/sass/syntax-error.sass +0 -3
  217. package/tests/utils/linter/fixtures/sass/undeclare-variable.sass +0 -2
  218. package/tests/utils/linter/fixtures/sass/unused-variable.sass +0 -4
  219. package/tests/utils/linter/fixtures/sass/valid-code.sass +0 -2
  220. package/tests/utils/linter/fixtures/scss/keyword-error.scss +0 -1
  221. package/tests/utils/linter/fixtures/scss/missing-semicolon.scss +0 -1
  222. package/tests/utils/linter/fixtures/scss/syntax-error.scss +0 -1
  223. package/tests/utils/linter/fixtures/scss/undeclare-variable.scss +0 -1
  224. package/tests/utils/linter/fixtures/scss/unused-variable.scss +0 -2
  225. package/tests/utils/linter/fixtures/scss/valid-code.scss +0 -1
  226. package/tests/utils/linter/fixtures/shell/keyword-error.sh +0 -5
  227. package/tests/utils/linter/fixtures/shell/missing-semicolon.sh +0 -3
  228. package/tests/utils/linter/fixtures/shell/syntax-error.sh +0 -4
  229. package/tests/utils/linter/fixtures/shell/undeclare-variable.sh +0 -3
  230. package/tests/utils/linter/fixtures/shell/unused-variable.sh +0 -4
  231. package/tests/utils/linter/fixtures/shell/valid-code.sh +0 -3
  232. package/tests/utils/linter/fixtures/ts/keyword-error.ts +0 -1
  233. package/tests/utils/linter/fixtures/ts/missing-semicolon.ts +0 -1
  234. package/tests/utils/linter/fixtures/ts/syntax-error.ts +0 -1
  235. package/tests/utils/linter/fixtures/ts/undeclare-variable.ts +0 -1
  236. package/tests/utils/linter/fixtures/ts/unused-variable.ts +0 -3
  237. package/tests/utils/linter/fixtures/ts/valid-code.ts +0 -3
  238. package/tests/utils/linter/fixtures/tsx/keyword-error.tsx +0 -5
  239. package/tests/utils/linter/fixtures/tsx/missing-semicolon.tsx +0 -5
  240. package/tests/utils/linter/fixtures/tsx/syntax-error.tsx +0 -5
  241. package/tests/utils/linter/fixtures/tsx/undeclare-variable.tsx +0 -6
  242. package/tests/utils/linter/fixtures/tsx/unused-variable.tsx +0 -6
  243. package/tests/utils/linter/fixtures/tsx/valid-code.tsx +0 -5
  244. package/tests/utils/linter/fixtures/vue/keyword-error.vue +0 -6
  245. package/tests/utils/linter/fixtures/vue/missing-semicolon.vue +0 -6
  246. package/tests/utils/linter/fixtures/vue/syntax-error.vue +0 -6
  247. package/tests/utils/linter/fixtures/vue/undeclare-variable.vue +0 -6
  248. package/tests/utils/linter/fixtures/vue/unused-variable.vue +0 -7
  249. package/tests/utils/linter/fixtures/vue/valid-code.vue +0 -6
  250. package/tests/utils/linter/fixtures/yaml/keyword-error.yml +0 -1
  251. package/tests/utils/linter/fixtures/yaml/missing-semicolon.yml +0 -2
  252. package/tests/utils/linter/fixtures/yaml/syntax-error.yml +0 -1
  253. package/tests/utils/linter/fixtures/yaml/undeclare-variable.yml +0 -1
  254. package/tests/utils/linter/fixtures/yaml/unused-variable.yml +0 -2
  255. package/tests/utils/linter/fixtures/yaml/valid-code.yml +0 -3
  256. package/tests/utils/linter/index.test.mjs +0 -440
  257. package/tests/utils/linter/scan-results.mjs +0 -42
  258. package/tests/utils/load-config.test.mjs +0 -141
  259. package/tests/utils/markdown/index.test.mjs +0 -478
  260. package/tests/utils/mermaid-validator.test.mjs +0 -541
  261. package/tests/utils/mock-chat-model.mjs +0 -12
  262. package/tests/utils/preferences-utils.test.mjs +0 -465
  263. package/tests/utils/save-value-to-config.test.mjs +0 -483
  264. package/tests/utils/utils.test.mjs +0 -941
@@ -1,364 +0,0 @@
1
- import { describe, expect, test } from "bun:test";
2
- import { stringify } from "yaml";
3
- import formatDocumentStructure from "../../../agents/utils/format-document-structure.mjs";
4
-
5
- describe("format-document-structure", () => {
6
- // EDGE CASE TESTS
7
- test("should handle when both documentStructure and originalDocumentStructure are null", async () => {
8
- const result = await formatDocumentStructure({
9
- documentStructure: null,
10
- originalDocumentStructure: null,
11
- });
12
-
13
- expect(result).toEqual({
14
- documentStructureYaml: "",
15
- documentStructure: [],
16
- });
17
- });
18
-
19
- test("should handle when both documentStructure and originalDocumentStructure are undefined", async () => {
20
- const result = await formatDocumentStructure({
21
- documentStructure: undefined,
22
- originalDocumentStructure: undefined,
23
- });
24
-
25
- expect(result).toEqual({
26
- documentStructureYaml: "",
27
- documentStructure: [],
28
- });
29
- });
30
-
31
- test("should handle when both parameters are missing", async () => {
32
- const result = await formatDocumentStructure({});
33
-
34
- expect(result).toEqual({
35
- documentStructureYaml: "",
36
- documentStructure: [],
37
- });
38
- });
39
-
40
- test("should use originalDocumentStructure when documentStructure is null", async () => {
41
- const originalDocumentStructure = [
42
- {
43
- title: "Original Document",
44
- path: "/original",
45
- parentId: null,
46
- description: "From original structure",
47
- extraField: "should be filtered out",
48
- },
49
- ];
50
-
51
- const result = await formatDocumentStructure({
52
- documentStructure: null,
53
- originalDocumentStructure,
54
- });
55
-
56
- const expectedData = [
57
- {
58
- title: "Original Document",
59
- path: "/original",
60
- parentId: null,
61
- description: "From original structure",
62
- },
63
- ];
64
- const expectedYaml = stringify(expectedData, {
65
- indent: 2,
66
- lineWidth: 120,
67
- minContentWidth: 20,
68
- });
69
-
70
- expect(result.documentStructureYaml).toBe(expectedYaml);
71
- expect(result.documentStructure).toBe(null);
72
- });
73
-
74
- test("should use originalDocumentStructure when documentStructure is undefined", async () => {
75
- const originalDocumentStructure = [
76
- {
77
- title: "Fallback Document",
78
- path: "/fallback",
79
- parentId: "parent-id",
80
- description: "Fallback to original",
81
- },
82
- ];
83
-
84
- const result = await formatDocumentStructure({
85
- originalDocumentStructure,
86
- });
87
-
88
- const expectedData = [
89
- {
90
- title: "Fallback Document",
91
- path: "/fallback",
92
- parentId: "parent-id",
93
- description: "Fallback to original",
94
- },
95
- ];
96
- const expectedYaml = stringify(expectedData, {
97
- indent: 2,
98
- lineWidth: 120,
99
- minContentWidth: 20,
100
- });
101
-
102
- expect(result.documentStructureYaml).toBe(expectedYaml);
103
- expect(result.documentStructure).toBe(undefined);
104
- });
105
-
106
- // BASIC FUNCTIONALITY TESTS
107
- test("should format empty documentation structure", async () => {
108
- const result = await formatDocumentStructure({
109
- documentStructure: [],
110
- });
111
-
112
- const expectedYaml = stringify([], {
113
- indent: 2,
114
- lineWidth: 120,
115
- minContentWidth: 20,
116
- });
117
-
118
- expect(result).toEqual({
119
- documentStructureYaml: expectedYaml,
120
- documentStructure: [],
121
- });
122
- });
123
-
124
- test("should format single item documentation structure", async () => {
125
- const documentStructure = [
126
- {
127
- title: "Getting Started",
128
- path: "/getting-started",
129
- parentId: null,
130
- description: "Introduction to the platform",
131
- extraField: "should be ignored",
132
- },
133
- ];
134
-
135
- const result = await formatDocumentStructure({ documentStructure });
136
-
137
- const expectedData = [
138
- {
139
- title: "Getting Started",
140
- path: "/getting-started",
141
- parentId: null,
142
- description: "Introduction to the platform",
143
- },
144
- ];
145
- const expectedYaml = stringify(expectedData, {
146
- indent: 2,
147
- lineWidth: 120,
148
- minContentWidth: 20,
149
- });
150
-
151
- expect(result.documentStructure).toEqual(documentStructure);
152
- expect(result.documentStructureYaml).toBe(expectedYaml);
153
- });
154
-
155
- test("should format multiple items documentation structure", async () => {
156
- const documentStructure = [
157
- {
158
- title: "API Reference",
159
- path: "/api",
160
- parentId: null,
161
- description: "Complete API documentation",
162
- },
163
- {
164
- title: "Authentication",
165
- path: "/api/auth",
166
- parentId: "/api",
167
- description: "Authentication endpoints",
168
- },
169
- {
170
- title: "Users",
171
- path: "/api/users",
172
- parentId: "/api",
173
- description: "User management endpoints",
174
- },
175
- ];
176
-
177
- const result = await formatDocumentStructure({ documentStructure });
178
-
179
- const expectedData = [
180
- {
181
- title: "API Reference",
182
- path: "/api",
183
- parentId: null,
184
- description: "Complete API documentation",
185
- },
186
- {
187
- title: "Authentication",
188
- path: "/api/auth",
189
- parentId: "/api",
190
- description: "Authentication endpoints",
191
- },
192
- {
193
- title: "Users",
194
- path: "/api/users",
195
- parentId: "/api",
196
- description: "User management endpoints",
197
- },
198
- ];
199
- const expectedYaml = stringify(expectedData, {
200
- indent: 2,
201
- lineWidth: 120,
202
- minContentWidth: 20,
203
- });
204
-
205
- expect(result.documentStructure).toEqual(documentStructure);
206
- expect(result.documentStructureYaml).toBe(expectedYaml);
207
- });
208
-
209
- // FIELD EXTRACTION TESTS
210
- test("should extract only required fields", async () => {
211
- const documentStructure = [
212
- {
213
- title: "Test Document",
214
- path: "/test",
215
- parentId: "parent-123",
216
- description: "Test description",
217
- // Extra fields that should be filtered out
218
- id: "doc-123",
219
- content: "Document content",
220
- metadata: { tags: ["test"] },
221
- lastModified: "2024-01-01",
222
- author: "John Doe",
223
- },
224
- ];
225
-
226
- const result = await formatDocumentStructure({ documentStructure });
227
-
228
- const expectedData = [
229
- {
230
- title: "Test Document",
231
- path: "/test",
232
- parentId: "parent-123",
233
- description: "Test description",
234
- },
235
- ];
236
- const expectedYaml = stringify(expectedData, {
237
- indent: 2,
238
- lineWidth: 120,
239
- minContentWidth: 20,
240
- });
241
-
242
- expect(result.documentStructureYaml).toBe(expectedYaml);
243
- // Verify extra fields are not in the YAML output
244
- expect(result.documentStructureYaml).not.toContain("doc-123");
245
- expect(result.documentStructureYaml).not.toContain("Document content");
246
- expect(result.documentStructureYaml).not.toContain("John Doe");
247
- });
248
-
249
- test("should handle items with missing optional fields", async () => {
250
- const documentStructure = [
251
- {
252
- title: "Required Title",
253
- path: "/required-path",
254
- // parentId and description are missing
255
- },
256
- ];
257
-
258
- const result = await formatDocumentStructure({ documentStructure });
259
-
260
- const expectedData = [
261
- {
262
- title: "Required Title",
263
- path: "/required-path",
264
- parentId: undefined,
265
- description: undefined,
266
- },
267
- ];
268
- const expectedYaml = stringify(expectedData, {
269
- indent: 2,
270
- lineWidth: 120,
271
- minContentWidth: 20,
272
- });
273
-
274
- expect(result.documentStructureYaml).toBe(expectedYaml);
275
- });
276
-
277
- test("should preserve null and undefined values", async () => {
278
- const documentStructure = [
279
- {
280
- title: "Test Item",
281
- path: "/test",
282
- parentId: null,
283
- description: undefined,
284
- },
285
- ];
286
-
287
- const result = await formatDocumentStructure({ documentStructure });
288
-
289
- const expectedData = [
290
- {
291
- title: "Test Item",
292
- path: "/test",
293
- parentId: null,
294
- description: undefined,
295
- },
296
- ];
297
- const expectedYaml = stringify(expectedData, {
298
- indent: 2,
299
- lineWidth: 120,
300
- minContentWidth: 20,
301
- });
302
-
303
- expect(result.documentStructureYaml).toBe(expectedYaml);
304
- });
305
-
306
- test("should handle items with special characters", async () => {
307
- const documentStructure = [
308
- {
309
- title: "Special Characters: @#$%^&*()",
310
- path: "/special-chars-test",
311
- parentId: null,
312
- description: 'Testing with 中文, émojis 🚀, and "quotes"',
313
- },
314
- ];
315
-
316
- const result = await formatDocumentStructure({ documentStructure });
317
-
318
- // Since YAML is mocked, just verify the function runs without error
319
- // and returns a structure with the expected properties
320
- expect(result.documentStructureYaml).toBeDefined();
321
- expect(result.documentStructure).toEqual(documentStructure);
322
- });
323
-
324
- test("should return both yaml string and original documentation structure", async () => {
325
- const documentStructure = [
326
- {
327
- title: "Return Test",
328
- path: "/return-test",
329
- parentId: null,
330
- description: "Testing return values",
331
- },
332
- ];
333
-
334
- const result = await formatDocumentStructure({ documentStructure });
335
-
336
- expect(result).toHaveProperty("documentStructureYaml");
337
- expect(result).toHaveProperty("documentStructure");
338
- expect(typeof result.documentStructureYaml).toBe("string");
339
- expect(result.documentStructure).toBe(documentStructure); // Should be the same reference
340
- });
341
-
342
- test("should preserve original documentation structure unchanged", async () => {
343
- const originalDocumentStructure = [
344
- {
345
- title: "Original",
346
- path: "/original",
347
- parentId: null,
348
- description: "Original description",
349
- extraField: "should remain",
350
- },
351
- ];
352
-
353
- const result = await formatDocumentStructure({
354
- documentStructure: originalDocumentStructure,
355
- });
356
-
357
- // Original should be unchanged
358
- expect(originalDocumentStructure[0]).toHaveProperty("extraField");
359
- expect(originalDocumentStructure[0].extraField).toBe("should remain");
360
-
361
- // Return value should reference the same object
362
- expect(result.documentStructure).toBe(originalDocumentStructure);
363
- });
364
- });
@@ -1,267 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test";
2
- import * as fsPromises from "node:fs/promises";
3
- import * as path from "node:path";
4
- import fs from "../../../agents/utils/fs.mjs";
5
-
6
- describe("fs utility", () => {
7
- let readFileSpy;
8
- let writeFileSpy;
9
- let mkdirSpy;
10
- let rmSpy;
11
- let readdirSpy;
12
- let joinSpy;
13
- let dirnameSpy;
14
-
15
- beforeEach(() => {
16
- // Spy on fs/promises methods
17
- readFileSpy = spyOn(fsPromises, "readFile").mockResolvedValue("mocked file content");
18
- writeFileSpy = spyOn(fsPromises, "writeFile").mockResolvedValue();
19
- mkdirSpy = spyOn(fsPromises, "mkdir").mockResolvedValue();
20
- rmSpy = spyOn(fsPromises, "rm").mockResolvedValue();
21
- readdirSpy = spyOn(fsPromises, "readdir").mockResolvedValue([
22
- { name: "file1.txt", parentPath: "/test/root", isDirectory: () => false },
23
- { name: "subdir", parentPath: "/test/root", isDirectory: () => true },
24
- ]);
25
-
26
- // Spy on path methods
27
- joinSpy = spyOn(path, "join").mockImplementation((...paths) => paths.join("/"));
28
- dirnameSpy = spyOn(path, "dirname").mockImplementation(
29
- (path) => path.split("/").slice(0, -1).join("/") || "/",
30
- );
31
- });
32
-
33
- afterEach(() => {
34
- // Restore all spies
35
- readFileSpy?.mockRestore();
36
- writeFileSpy?.mockRestore();
37
- mkdirSpy?.mockRestore();
38
- rmSpy?.mockRestore();
39
- readdirSpy?.mockRestore();
40
- joinSpy?.mockRestore();
41
- dirnameSpy?.mockRestore();
42
- });
43
-
44
- // ERROR HANDLING TESTS
45
- test("should throw error when rootDir is not specified", async () => {
46
- await expect(
47
- fs({
48
- action: "read_file",
49
- path: "test.txt",
50
- }),
51
- ).rejects.toThrow("Root directory is not specified");
52
- });
53
-
54
- test("should throw error when rootDir is empty string", async () => {
55
- await expect(
56
- fs({
57
- rootDir: "",
58
- action: "read_file",
59
- path: "test.txt",
60
- }),
61
- ).rejects.toThrow("Root directory is not specified");
62
- });
63
-
64
- // READ_FILE ACTION TESTS
65
- test("should read file successfully", async () => {
66
- readFileSpy.mockResolvedValue("test file content");
67
-
68
- const result = await fs({
69
- rootDir: "/test/root",
70
- action: "read_file",
71
- path: "test.txt",
72
- });
73
-
74
- expect(joinSpy).toHaveBeenCalledWith("/test/root", "test.txt");
75
- expect(readFileSpy).toHaveBeenCalledWith("/test/root/test.txt", "utf-8");
76
- expect(result).toEqual({
77
- status: "ok",
78
- path: "/test/root/test.txt",
79
- content: "test file content",
80
- });
81
- });
82
-
83
- test("should handle read file with nested path", async () => {
84
- await fs({
85
- rootDir: "/project",
86
- action: "read_file",
87
- path: "src/components/Button.tsx",
88
- });
89
-
90
- expect(joinSpy).toHaveBeenCalledWith("/project", "src/components/Button.tsx");
91
- expect(readFileSpy).toHaveBeenCalledWith("/project/src/components/Button.tsx", "utf-8");
92
- });
93
-
94
- // WRITE_FILE ACTION TESTS
95
- test("should write file successfully", async () => {
96
- const result = await fs({
97
- rootDir: "/test/root",
98
- action: "write_file",
99
- path: "output.txt",
100
- content: "Hello, world!",
101
- });
102
-
103
- expect(dirnameSpy).toHaveBeenCalledWith("/test/root/output.txt");
104
- expect(mkdirSpy).toHaveBeenCalledWith("/test/root", { recursive: true });
105
- expect(writeFileSpy).toHaveBeenCalledWith("/test/root/output.txt", "Hello, world!");
106
- expect(result).toEqual({
107
- status: "ok",
108
- path: "/test/root/output.txt",
109
- content: "Hello, world!",
110
- });
111
- });
112
-
113
- test("should write file with empty content when content is not provided", async () => {
114
- const result = await fs({
115
- rootDir: "/test/root",
116
- action: "write_file",
117
- path: "empty.txt",
118
- });
119
-
120
- expect(writeFileSpy).toHaveBeenCalledWith("/test/root/empty.txt", "");
121
- expect(result.content).toBeUndefined(); // The function returns the original content parameter
122
- });
123
-
124
- test("should create directories recursively when writing file", async () => {
125
- dirnameSpy.mockReturnValue("/test/root/deep/nested");
126
-
127
- await fs({
128
- rootDir: "/test/root",
129
- action: "write_file",
130
- path: "deep/nested/file.txt",
131
- content: "nested content",
132
- });
133
-
134
- expect(mkdirSpy).toHaveBeenCalledWith("/test/root/deep/nested", {
135
- recursive: true,
136
- });
137
- });
138
-
139
- // DELETE_FILE ACTION TESTS
140
- test("should delete file successfully", async () => {
141
- const result = await fs({
142
- rootDir: "/test/root",
143
- action: "delete_file",
144
- path: "to-delete.txt",
145
- });
146
-
147
- expect(joinSpy).toHaveBeenCalledWith("/test/root", "to-delete.txt");
148
- expect(rmSpy).toHaveBeenCalledWith("/test/root/to-delete.txt", {
149
- recursive: true,
150
- force: true,
151
- });
152
- expect(result).toEqual({
153
- status: "ok",
154
- path: "/test/root/to-delete.txt",
155
- });
156
- });
157
-
158
- test("should delete directory recursively", async () => {
159
- await fs({
160
- rootDir: "/project",
161
- action: "delete_file",
162
- path: "build",
163
- });
164
-
165
- expect(rmSpy).toHaveBeenCalledWith("/project/build", {
166
- recursive: true,
167
- force: true,
168
- });
169
- });
170
-
171
- // LIST_DIRECTORY ACTION TESTS
172
- test("should list directory entries successfully", async () => {
173
- const result = await fs({
174
- rootDir: "/test/root",
175
- action: "list_directory",
176
- path: "src",
177
- });
178
-
179
- expect(joinSpy).toHaveBeenCalledWith("/test/root", "src");
180
- expect(readdirSpy).toHaveBeenCalledWith("/test/root/src", { withFileTypes: true });
181
- expect(result).toEqual({
182
- status: "ok",
183
- entries: [
184
- { path: "/test/root/file1.txt", isDirectory: false },
185
- { path: "/test/root/subdir", isDirectory: true },
186
- ],
187
- });
188
- });
189
-
190
- test("should handle empty directory listing", async () => {
191
- readdirSpy.mockResolvedValue([]);
192
-
193
- const result = await fs({
194
- rootDir: "/test/root",
195
- action: "list_directory",
196
- path: "empty-dir",
197
- });
198
-
199
- expect(result.entries).toEqual([]);
200
- });
201
-
202
- // PATH HANDLING TESTS
203
- test("should handle root directory with trailing slash", async () => {
204
- await fs({
205
- rootDir: "/test/root/",
206
- action: "read_file",
207
- path: "file.txt",
208
- });
209
-
210
- expect(joinSpy).toHaveBeenCalledWith("/test/root/", "file.txt");
211
- });
212
-
213
- test("should handle path with leading slash", async () => {
214
- await fs({
215
- rootDir: "/test/root",
216
- action: "read_file",
217
- path: "/absolute/path.txt",
218
- });
219
-
220
- expect(joinSpy).toHaveBeenCalledWith("/test/root", "/absolute/path.txt");
221
- });
222
-
223
- test("should handle complex nested paths", async () => {
224
- await fs({
225
- rootDir: "/project",
226
- action: "write_file",
227
- path: "src/components/ui/Button/index.tsx",
228
- content: "export default Button;",
229
- });
230
-
231
- expect(joinSpy).toHaveBeenCalledWith("/project", "src/components/ui/Button/index.tsx");
232
- });
233
-
234
- // UNDEFINED ACTION TEST
235
- test("should return undefined for unknown action", async () => {
236
- const result = await fs({
237
- rootDir: "/test/root",
238
- action: "unknown_action",
239
- path: "test.txt",
240
- });
241
-
242
- expect(result).toBeUndefined();
243
- });
244
-
245
- // EDGE CASES
246
- test("should handle special characters in paths", async () => {
247
- await fs({
248
- rootDir: "/test/root",
249
- action: "read_file",
250
- path: "文件名 with spaces & symbols!.txt",
251
- });
252
-
253
- expect(joinSpy).toHaveBeenCalledWith("/test/root", "文件名 with spaces & symbols!.txt");
254
- });
255
-
256
- test("should handle null content for write_file", async () => {
257
- const result = await fs({
258
- rootDir: "/test/root",
259
- action: "write_file",
260
- path: "null-content.txt",
261
- content: null,
262
- });
263
-
264
- expect(writeFileSpy).toHaveBeenCalledWith("/test/root/null-content.txt", "");
265
- expect(result.content).toBe(null);
266
- });
267
- });