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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (284) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/agents/clear/choose-contents.mjs +14 -1
  3. package/agents/clear/clear-media-description.mjs +129 -0
  4. package/agents/clear/index.yaml +3 -1
  5. package/agents/evaluate/code-snippet.mjs +28 -24
  6. package/agents/evaluate/document-structure.yaml +0 -4
  7. package/agents/evaluate/document.yaml +1 -5
  8. package/agents/generate/index.yaml +1 -0
  9. package/agents/init/index.mjs +10 -0
  10. package/agents/media/batch-generate-media-description.yaml +44 -0
  11. package/agents/media/generate-media-description.yaml +47 -0
  12. package/agents/media/load-media-description.mjs +238 -0
  13. package/agents/publish/index.yaml +4 -0
  14. package/agents/publish/publish-docs.mjs +77 -5
  15. package/agents/publish/translate-meta.mjs +103 -0
  16. package/agents/update/generate-document.yaml +30 -28
  17. package/agents/update/index.yaml +1 -0
  18. package/agents/update/update-document-detail.yaml +3 -1
  19. package/agents/utils/load-sources.mjs +103 -53
  20. package/agents/utils/update-branding.mjs +69 -0
  21. package/aigne.yaml +6 -0
  22. package/assets/report-template/report.html +34 -34
  23. package/package.json +17 -2
  24. package/prompts/common/document/role-and-personality.md +3 -1
  25. package/prompts/detail/d2-diagram/guide.md +7 -1
  26. package/prompts/detail/d2-diagram/user-prompt.md +3 -0
  27. package/prompts/detail/generate/system-prompt.md +6 -7
  28. package/prompts/detail/generate/user-prompt.md +12 -3
  29. package/prompts/detail/update/user-prompt.md +0 -2
  30. package/prompts/evaluate/document-structure.md +6 -7
  31. package/prompts/evaluate/document.md +16 -25
  32. package/prompts/media/media-description/system-prompt.md +35 -0
  33. package/prompts/media/media-description/user-prompt.md +8 -0
  34. package/prompts/structure/update/user-prompt.md +0 -4
  35. package/utils/constants/index.mjs +0 -107
  36. package/utils/file-utils.mjs +86 -0
  37. package/utils/markdown-checker.mjs +0 -20
  38. package/utils/request.mjs +7 -0
  39. package/utils/upload-files.mjs +231 -0
  40. package/utils/utils.mjs +11 -1
  41. package/.aigne/doc-smith/config.yaml +0 -77
  42. package/.aigne/doc-smith/history.yaml +0 -37
  43. package/.aigne/doc-smith/output/structure-plan.json +0 -162
  44. package/.aigne/doc-smith/preferences.yml +0 -97
  45. package/.aigne/doc-smith/upload-cache.yaml +0 -1893
  46. package/.github/PULL_REQUEST_TEMPLATE.md +0 -28
  47. package/.github/workflows/ci.yml +0 -54
  48. package/.github/workflows/create-release-pr.yaml +0 -21
  49. package/.github/workflows/publish-docs.yml +0 -65
  50. package/.github/workflows/release.yml +0 -49
  51. package/.github/workflows/reviewer.yml +0 -54
  52. package/.release-please-manifest.json +0 -3
  53. package/RELEASE.md +0 -9
  54. package/assets/screenshots/doc-complete-setup.png +0 -0
  55. package/assets/screenshots/doc-generate-docs.png +0 -0
  56. package/assets/screenshots/doc-generate.png +0 -0
  57. package/assets/screenshots/doc-generated-successfully.png +0 -0
  58. package/assets/screenshots/doc-publish.png +0 -0
  59. package/assets/screenshots/doc-regenerate.png +0 -0
  60. package/assets/screenshots/doc-translate-langs.png +0 -0
  61. package/assets/screenshots/doc-translate.png +0 -0
  62. package/assets/screenshots/doc-update.png +0 -0
  63. package/biome.json +0 -73
  64. package/codecov.yml +0 -15
  65. package/docs/_sidebar.md +0 -15
  66. package/docs/configuration-initial-setup.ja.md +0 -179
  67. package/docs/configuration-initial-setup.md +0 -179
  68. package/docs/configuration-initial-setup.zh-TW.md +0 -179
  69. package/docs/configuration-initial-setup.zh.md +0 -179
  70. package/docs/configuration-managing-preferences.ja.md +0 -100
  71. package/docs/configuration-managing-preferences.md +0 -100
  72. package/docs/configuration-managing-preferences.zh-TW.md +0 -100
  73. package/docs/configuration-managing-preferences.zh.md +0 -100
  74. package/docs/configuration.ja.md +0 -96
  75. package/docs/configuration.md +0 -96
  76. package/docs/configuration.zh-TW.md +0 -96
  77. package/docs/configuration.zh.md +0 -96
  78. package/docs/getting-started.ja.md +0 -88
  79. package/docs/getting-started.md +0 -88
  80. package/docs/getting-started.zh-TW.md +0 -88
  81. package/docs/getting-started.zh.md +0 -88
  82. package/docs/guides-cleaning-up.ja.md +0 -51
  83. package/docs/guides-cleaning-up.md +0 -51
  84. package/docs/guides-cleaning-up.zh-TW.md +0 -51
  85. package/docs/guides-cleaning-up.zh.md +0 -51
  86. package/docs/guides-evaluating-documents.ja.md +0 -66
  87. package/docs/guides-evaluating-documents.md +0 -66
  88. package/docs/guides-evaluating-documents.zh-TW.md +0 -66
  89. package/docs/guides-evaluating-documents.zh.md +0 -66
  90. package/docs/guides-generating-documentation.ja.md +0 -151
  91. package/docs/guides-generating-documentation.md +0 -151
  92. package/docs/guides-generating-documentation.zh-TW.md +0 -151
  93. package/docs/guides-generating-documentation.zh.md +0 -151
  94. package/docs/guides-interactive-chat.ja.md +0 -85
  95. package/docs/guides-interactive-chat.md +0 -85
  96. package/docs/guides-interactive-chat.zh-TW.md +0 -85
  97. package/docs/guides-interactive-chat.zh.md +0 -85
  98. package/docs/guides-managing-history.ja.md +0 -48
  99. package/docs/guides-managing-history.md +0 -48
  100. package/docs/guides-managing-history.zh-TW.md +0 -48
  101. package/docs/guides-managing-history.zh.md +0 -48
  102. package/docs/guides-publishing-your-docs.ja.md +0 -78
  103. package/docs/guides-publishing-your-docs.md +0 -78
  104. package/docs/guides-publishing-your-docs.zh-TW.md +0 -78
  105. package/docs/guides-publishing-your-docs.zh.md +0 -78
  106. package/docs/guides-translating-documentation.ja.md +0 -95
  107. package/docs/guides-translating-documentation.md +0 -95
  108. package/docs/guides-translating-documentation.zh-TW.md +0 -95
  109. package/docs/guides-translating-documentation.zh.md +0 -95
  110. package/docs/guides-updating-documentation.ja.md +0 -77
  111. package/docs/guides-updating-documentation.md +0 -77
  112. package/docs/guides-updating-documentation.zh-TW.md +0 -77
  113. package/docs/guides-updating-documentation.zh.md +0 -77
  114. package/docs/guides.ja.md +0 -32
  115. package/docs/guides.md +0 -32
  116. package/docs/guides.zh-TW.md +0 -32
  117. package/docs/guides.zh.md +0 -32
  118. package/docs/overview.ja.md +0 -61
  119. package/docs/overview.md +0 -61
  120. package/docs/overview.zh-TW.md +0 -61
  121. package/docs/overview.zh.md +0 -61
  122. package/docs/release-notes.ja.md +0 -255
  123. package/docs/release-notes.md +0 -255
  124. package/docs/release-notes.zh-TW.md +0 -255
  125. package/docs/release-notes.zh.md +0 -255
  126. package/media.md +0 -19
  127. package/prompts/common/afs/afs-tools-usage.md +0 -5
  128. package/prompts/common/afs/use-afs-instruction.md +0 -1
  129. package/release-please-config.json +0 -14
  130. package/tests/agents/chat/chat.test.mjs +0 -46
  131. package/tests/agents/clear/choose-contents.test.mjs +0 -284
  132. package/tests/agents/clear/clear-auth-tokens.test.mjs +0 -268
  133. package/tests/agents/clear/clear-document-config.test.mjs +0 -167
  134. package/tests/agents/clear/clear-document-structure.test.mjs +0 -380
  135. package/tests/agents/clear/clear-generated-docs.test.mjs +0 -222
  136. package/tests/agents/evaluate/code-snippet.test.mjs +0 -163
  137. package/tests/agents/evaluate/fixtures/api-services.md +0 -87
  138. package/tests/agents/evaluate/fixtures/js-sdk.md +0 -94
  139. package/tests/agents/evaluate/generate-report.test.mjs +0 -312
  140. package/tests/agents/generate/check-document-structure.test.mjs +0 -45
  141. package/tests/agents/generate/check-need-generate-structure.test.mjs +0 -279
  142. package/tests/agents/generate/document-structure-tools/add-document.test.mjs +0 -449
  143. package/tests/agents/generate/document-structure-tools/delete-document.test.mjs +0 -410
  144. package/tests/agents/generate/document-structure-tools/generate-sub-structure.test.mjs +0 -277
  145. package/tests/agents/generate/document-structure-tools/move-document.test.mjs +0 -476
  146. package/tests/agents/generate/document-structure-tools/update-document.test.mjs +0 -548
  147. package/tests/agents/generate/generate-structure.test.mjs +0 -45
  148. package/tests/agents/generate/user-review-document-structure.test.mjs +0 -319
  149. package/tests/agents/history/view.test.mjs +0 -97
  150. package/tests/agents/init/init.test.mjs +0 -1657
  151. package/tests/agents/prefs/prefs.test.mjs +0 -431
  152. package/tests/agents/publish/publish-docs.test.mjs +0 -787
  153. package/tests/agents/translate/choose-language.test.mjs +0 -311
  154. package/tests/agents/translate/translate-document.test.mjs +0 -51
  155. package/tests/agents/update/check-document.test.mjs +0 -463
  156. package/tests/agents/update/check-update-is-single.test.mjs +0 -300
  157. package/tests/agents/update/document-tools/update-document-content.test.mjs +0 -329
  158. package/tests/agents/update/generate-document.test.mjs +0 -51
  159. package/tests/agents/update/save-and-translate-document.test.mjs +0 -369
  160. package/tests/agents/update/user-review-document.test.mjs +0 -582
  161. package/tests/agents/utils/action-success.test.mjs +0 -54
  162. package/tests/agents/utils/check-detail-result.test.mjs +0 -743
  163. package/tests/agents/utils/check-feedback-refiner.test.mjs +0 -478
  164. package/tests/agents/utils/choose-docs.test.mjs +0 -406
  165. package/tests/agents/utils/exit.test.mjs +0 -70
  166. package/tests/agents/utils/feedback-refiner.test.mjs +0 -51
  167. package/tests/agents/utils/find-item-by-path.test.mjs +0 -517
  168. package/tests/agents/utils/find-user-preferences-by-path.test.mjs +0 -382
  169. package/tests/agents/utils/format-document-structure.test.mjs +0 -364
  170. package/tests/agents/utils/fs.test.mjs +0 -267
  171. package/tests/agents/utils/load-sources.test.mjs +0 -1470
  172. package/tests/agents/utils/save-docs.test.mjs +0 -109
  173. package/tests/agents/utils/save-output.test.mjs +0 -315
  174. package/tests/agents/utils/save-single-doc.test.mjs +0 -364
  175. package/tests/agents/utils/transform-detail-datasources.test.mjs +0 -320
  176. package/tests/utils/auth-utils.test.mjs +0 -596
  177. package/tests/utils/blocklet.test.mjs +0 -336
  178. package/tests/utils/conflict-detector.test.mjs +0 -355
  179. package/tests/utils/constants.test.mjs +0 -295
  180. package/tests/utils/d2-utils.test.mjs +0 -437
  181. package/tests/utils/deploy.test.mjs +0 -399
  182. package/tests/utils/docs-finder-utils.test.mjs +0 -650
  183. package/tests/utils/file-utils.test.mjs +0 -521
  184. package/tests/utils/history-utils.test.mjs +0 -206
  185. package/tests/utils/kroki-utils.test.mjs +0 -646
  186. package/tests/utils/linter/fixtures/css/keyword-error.css +0 -1
  187. package/tests/utils/linter/fixtures/css/missing-semicolon.css +0 -1
  188. package/tests/utils/linter/fixtures/css/syntax-error.css +0 -1
  189. package/tests/utils/linter/fixtures/css/undeclare-variable.css +0 -1
  190. package/tests/utils/linter/fixtures/css/unused-variable.css +0 -2
  191. package/tests/utils/linter/fixtures/css/valid-code.css +0 -1
  192. package/tests/utils/linter/fixtures/dockerfile/keyword-error.dockerfile +0 -1
  193. package/tests/utils/linter/fixtures/dockerfile/missing-semicolon.dockerfile +0 -2
  194. package/tests/utils/linter/fixtures/dockerfile/syntax-error.dockerfile +0 -2
  195. package/tests/utils/linter/fixtures/dockerfile/undeclare-variable.dockerfile +0 -1
  196. package/tests/utils/linter/fixtures/dockerfile/unused-variable.dockerfile +0 -1
  197. package/tests/utils/linter/fixtures/dockerfile/valid-code.dockerfile +0 -2
  198. package/tests/utils/linter/fixtures/go/keyword-error.go +0 -5
  199. package/tests/utils/linter/fixtures/go/missing-semicolon.go +0 -5
  200. package/tests/utils/linter/fixtures/go/syntax-error.go +0 -6
  201. package/tests/utils/linter/fixtures/go/undeclare-variable.go +0 -5
  202. package/tests/utils/linter/fixtures/go/unused-variable.go +0 -5
  203. package/tests/utils/linter/fixtures/go/valid-code.go +0 -7
  204. package/tests/utils/linter/fixtures/js/keyword-error.js +0 -3
  205. package/tests/utils/linter/fixtures/js/missing-semicolon.js +0 -6
  206. package/tests/utils/linter/fixtures/js/syntax-error.js +0 -4
  207. package/tests/utils/linter/fixtures/js/undeclare-variable.js +0 -3
  208. package/tests/utils/linter/fixtures/js/unused-variable.js +0 -7
  209. package/tests/utils/linter/fixtures/js/valid-code.js +0 -15
  210. package/tests/utils/linter/fixtures/json/keyword-error.json +0 -1
  211. package/tests/utils/linter/fixtures/json/missing-semicolon.json +0 -1
  212. package/tests/utils/linter/fixtures/json/syntax-error.json +0 -1
  213. package/tests/utils/linter/fixtures/json/undeclare-variable.json +0 -1
  214. package/tests/utils/linter/fixtures/json/unused-variable.json +0 -1
  215. package/tests/utils/linter/fixtures/json/valid-code.json +0 -1
  216. package/tests/utils/linter/fixtures/jsx/keyword-error.jsx +0 -5
  217. package/tests/utils/linter/fixtures/jsx/missing-semicolon.jsx +0 -5
  218. package/tests/utils/linter/fixtures/jsx/syntax-error.jsx +0 -5
  219. package/tests/utils/linter/fixtures/jsx/undeclare-variable.jsx +0 -5
  220. package/tests/utils/linter/fixtures/jsx/unused-variable.jsx +0 -4
  221. package/tests/utils/linter/fixtures/jsx/valid-code.jsx +0 -5
  222. package/tests/utils/linter/fixtures/python/keyword-error.py +0 -3
  223. package/tests/utils/linter/fixtures/python/missing-semicolon.py +0 -2
  224. package/tests/utils/linter/fixtures/python/syntax-error.py +0 -3
  225. package/tests/utils/linter/fixtures/python/undeclare-variable.py +0 -3
  226. package/tests/utils/linter/fixtures/python/unused-variable.py +0 -6
  227. package/tests/utils/linter/fixtures/python/valid-code.py +0 -12
  228. package/tests/utils/linter/fixtures/ruby/keyword-error.rb +0 -2
  229. package/tests/utils/linter/fixtures/ruby/missing-semicolon.rb +0 -1
  230. package/tests/utils/linter/fixtures/ruby/syntax-error.rb +0 -2
  231. package/tests/utils/linter/fixtures/ruby/undeclare-variable.rb +0 -1
  232. package/tests/utils/linter/fixtures/ruby/unused-variable.rb +0 -2
  233. package/tests/utils/linter/fixtures/ruby/valid-code.rb +0 -1
  234. package/tests/utils/linter/fixtures/sass/keyword-error.sass +0 -2
  235. package/tests/utils/linter/fixtures/sass/missing-semicolon.sass +0 -3
  236. package/tests/utils/linter/fixtures/sass/syntax-error.sass +0 -3
  237. package/tests/utils/linter/fixtures/sass/undeclare-variable.sass +0 -2
  238. package/tests/utils/linter/fixtures/sass/unused-variable.sass +0 -4
  239. package/tests/utils/linter/fixtures/sass/valid-code.sass +0 -2
  240. package/tests/utils/linter/fixtures/scss/keyword-error.scss +0 -1
  241. package/tests/utils/linter/fixtures/scss/missing-semicolon.scss +0 -1
  242. package/tests/utils/linter/fixtures/scss/syntax-error.scss +0 -1
  243. package/tests/utils/linter/fixtures/scss/undeclare-variable.scss +0 -1
  244. package/tests/utils/linter/fixtures/scss/unused-variable.scss +0 -2
  245. package/tests/utils/linter/fixtures/scss/valid-code.scss +0 -1
  246. package/tests/utils/linter/fixtures/shell/keyword-error.sh +0 -5
  247. package/tests/utils/linter/fixtures/shell/missing-semicolon.sh +0 -3
  248. package/tests/utils/linter/fixtures/shell/syntax-error.sh +0 -4
  249. package/tests/utils/linter/fixtures/shell/undeclare-variable.sh +0 -3
  250. package/tests/utils/linter/fixtures/shell/unused-variable.sh +0 -4
  251. package/tests/utils/linter/fixtures/shell/valid-code.sh +0 -3
  252. package/tests/utils/linter/fixtures/ts/keyword-error.ts +0 -1
  253. package/tests/utils/linter/fixtures/ts/missing-semicolon.ts +0 -1
  254. package/tests/utils/linter/fixtures/ts/syntax-error.ts +0 -1
  255. package/tests/utils/linter/fixtures/ts/undeclare-variable.ts +0 -1
  256. package/tests/utils/linter/fixtures/ts/unused-variable.ts +0 -3
  257. package/tests/utils/linter/fixtures/ts/valid-code.ts +0 -3
  258. package/tests/utils/linter/fixtures/tsx/keyword-error.tsx +0 -5
  259. package/tests/utils/linter/fixtures/tsx/missing-semicolon.tsx +0 -5
  260. package/tests/utils/linter/fixtures/tsx/syntax-error.tsx +0 -5
  261. package/tests/utils/linter/fixtures/tsx/undeclare-variable.tsx +0 -6
  262. package/tests/utils/linter/fixtures/tsx/unused-variable.tsx +0 -6
  263. package/tests/utils/linter/fixtures/tsx/valid-code.tsx +0 -5
  264. package/tests/utils/linter/fixtures/vue/keyword-error.vue +0 -6
  265. package/tests/utils/linter/fixtures/vue/missing-semicolon.vue +0 -6
  266. package/tests/utils/linter/fixtures/vue/syntax-error.vue +0 -6
  267. package/tests/utils/linter/fixtures/vue/undeclare-variable.vue +0 -6
  268. package/tests/utils/linter/fixtures/vue/unused-variable.vue +0 -7
  269. package/tests/utils/linter/fixtures/vue/valid-code.vue +0 -6
  270. package/tests/utils/linter/fixtures/yaml/keyword-error.yml +0 -1
  271. package/tests/utils/linter/fixtures/yaml/missing-semicolon.yml +0 -2
  272. package/tests/utils/linter/fixtures/yaml/syntax-error.yml +0 -1
  273. package/tests/utils/linter/fixtures/yaml/undeclare-variable.yml +0 -1
  274. package/tests/utils/linter/fixtures/yaml/unused-variable.yml +0 -2
  275. package/tests/utils/linter/fixtures/yaml/valid-code.yml +0 -3
  276. package/tests/utils/linter/index.test.mjs +0 -440
  277. package/tests/utils/linter/scan-results.mjs +0 -42
  278. package/tests/utils/load-config.test.mjs +0 -141
  279. package/tests/utils/markdown/index.test.mjs +0 -478
  280. package/tests/utils/mermaid-validator.test.mjs +0 -541
  281. package/tests/utils/mock-chat-model.mjs +0 -12
  282. package/tests/utils/preferences-utils.test.mjs +0 -465
  283. package/tests/utils/save-value-to-config.test.mjs +0 -483
  284. package/tests/utils/utils.test.mjs +0 -941
@@ -1,476 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test";
2
- import moveDocument from "../../../../agents/generate/document-structure-tools/move-document.mjs";
3
-
4
- describe("move-document", () => {
5
- let consoleSpy;
6
- let baseDocumentStructure;
7
-
8
- beforeEach(() => {
9
- consoleSpy = spyOn(console, "log").mockImplementation(() => {});
10
- baseDocumentStructure = [
11
- {
12
- title: "Getting Started",
13
- description: "Introduction to the project",
14
- path: "/getting-started",
15
- parentId: null,
16
- sourceIds: ["intro.md"],
17
- },
18
- {
19
- title: "API Reference",
20
- description: "Complete API documentation",
21
- path: "/api",
22
- parentId: null,
23
- sourceIds: ["api.js"],
24
- },
25
- {
26
- title: "Authentication",
27
- description: "How to authenticate with the API",
28
- path: "/api/auth",
29
- parentId: "/api",
30
- sourceIds: ["auth.js", "security.md"],
31
- },
32
- {
33
- title: "Rate Limiting",
34
- description: "API rate limiting documentation",
35
- path: "/api/rate-limiting",
36
- parentId: "/api",
37
- sourceIds: ["rate-limit.js"],
38
- },
39
- {
40
- title: "OAuth",
41
- description: "OAuth authentication flow",
42
- path: "/api/auth/oauth",
43
- parentId: "/api/auth",
44
- sourceIds: ["oauth.js"],
45
- },
46
- {
47
- title: "Tutorials",
48
- description: "Step-by-step tutorials",
49
- path: "/tutorials",
50
- parentId: null,
51
- sourceIds: ["tutorials.md"],
52
- },
53
- ];
54
- });
55
-
56
- afterEach(() => {
57
- consoleSpy?.mockRestore();
58
- });
59
-
60
- // SUCCESSFUL MOVE TESTS
61
- test("should move document to different parent successfully", async () => {
62
- const result = await moveDocument({
63
- documentStructure: baseDocumentStructure,
64
- path: "/api/rate-limiting",
65
- newParentId: "/tutorials",
66
- });
67
-
68
- expect(result.documentStructure).toHaveLength(6);
69
- expect(result.updatedDocument).toEqual({
70
- title: "Rate Limiting",
71
- description: "API rate limiting documentation",
72
- path: "/api/rate-limiting",
73
- parentId: "/tutorials",
74
- sourceIds: ["rate-limit.js"],
75
- });
76
-
77
- expect(result.originalDocument).toEqual({
78
- title: "Rate Limiting",
79
- description: "API rate limiting documentation",
80
- path: "/api/rate-limiting",
81
- parentId: "/api",
82
- sourceIds: ["rate-limit.js"],
83
- });
84
-
85
- // Verify the document was actually updated in the structure
86
- const updatedDoc = result.documentStructure.find((doc) => doc.path === "/api/rate-limiting");
87
- expect(updatedDoc.parentId).toBe("/tutorials");
88
- expect(consoleSpy).not.toHaveBeenCalled();
89
- });
90
-
91
- test("should move document to top level (null parent)", async () => {
92
- const result = await moveDocument({
93
- documentStructure: baseDocumentStructure,
94
- path: "/api/auth",
95
- newParentId: null,
96
- });
97
-
98
- expect(result.updatedDocument.parentId).toBeNull();
99
- expect(result.originalDocument.parentId).toBe("/api");
100
-
101
- const updatedDoc = result.documentStructure.find((doc) => doc.path === "/api/auth");
102
- expect(updatedDoc.parentId).toBeNull();
103
- expect(consoleSpy).not.toHaveBeenCalled();
104
- });
105
-
106
- test("should handle undefined newParentId as null", async () => {
107
- const result = await moveDocument({
108
- documentStructure: baseDocumentStructure,
109
- path: "/api/auth",
110
- newParentId: undefined,
111
- });
112
-
113
- expect(result.updatedDocument.parentId).toBeNull();
114
- expect(consoleSpy).not.toHaveBeenCalled();
115
- });
116
-
117
- test("should handle empty string newParentId as null", async () => {
118
- const result = await moveDocument({
119
- documentStructure: baseDocumentStructure,
120
- path: "/api/rate-limiting",
121
- newParentId: "",
122
- });
123
-
124
- expect(result.updatedDocument.parentId).toBeNull();
125
- expect(consoleSpy).not.toHaveBeenCalled();
126
- });
127
-
128
- test("should handle string 'null' newParentId but keep it as string", async () => {
129
- const result = await moveDocument({
130
- documentStructure: baseDocumentStructure,
131
- path: "/api/auth/oauth",
132
- newParentId: "null",
133
- });
134
-
135
- expect(result.updatedDocument.parentId).toBe("null");
136
- expect(consoleSpy).not.toHaveBeenCalled();
137
- });
138
-
139
- test("should move deeply nested document", async () => {
140
- const result = await moveDocument({
141
- documentStructure: baseDocumentStructure,
142
- path: "/api/auth/oauth",
143
- newParentId: "/getting-started",
144
- });
145
-
146
- expect(result.updatedDocument.parentId).toBe("/getting-started");
147
- expect(result.originalDocument.parentId).toBe("/api/auth");
148
- expect(consoleSpy).not.toHaveBeenCalled();
149
- });
150
-
151
- // VALIDATION ERROR TESTS
152
- test("should return error when path is missing", async () => {
153
- const result = await moveDocument({
154
- documentStructure: baseDocumentStructure,
155
- newParentId: "/tutorials",
156
- });
157
-
158
- expect(result.documentStructure).toEqual(baseDocumentStructure);
159
- expect(result.originalDocument).toBeUndefined();
160
- expect(result.updatedDocument).toBeUndefined();
161
- expect(consoleSpy).toHaveBeenCalledWith("⚠️ Cannot move document: path: Required");
162
- });
163
-
164
- test("should return error when path is empty string", async () => {
165
- const result = await moveDocument({
166
- documentStructure: baseDocumentStructure,
167
- path: "",
168
- newParentId: "/tutorials",
169
- });
170
-
171
- expect(result.documentStructure).toEqual(baseDocumentStructure);
172
- expect(consoleSpy).toHaveBeenCalledWith("⚠️ Cannot move document: path: Path is required");
173
- });
174
-
175
- test("should return error when document does not exist", async () => {
176
- const result = await moveDocument({
177
- documentStructure: baseDocumentStructure,
178
- path: "/nonexistent-document",
179
- newParentId: "/tutorials",
180
- });
181
-
182
- expect(result.documentStructure).toEqual(baseDocumentStructure);
183
- expect(consoleSpy).toHaveBeenCalledWith(
184
- "⚠️ Cannot move document: Document '/nonexistent-document' does not exist. Please select an existing document to move.",
185
- );
186
- });
187
-
188
- test("should return error when new parent does not exist", async () => {
189
- const result = await moveDocument({
190
- documentStructure: baseDocumentStructure,
191
- path: "/api/rate-limiting",
192
- newParentId: "/nonexistent-parent",
193
- });
194
-
195
- expect(result.documentStructure).toEqual(baseDocumentStructure);
196
- expect(consoleSpy).toHaveBeenCalledWith(
197
- "⚠️ Cannot move document: Target parent document '/nonexistent-parent' does not exist. Please select an existing parent document.",
198
- );
199
- });
200
-
201
- // CIRCULAR DEPENDENCY TESTS
202
- test("should prevent moving document under its own child", async () => {
203
- const result = await moveDocument({
204
- documentStructure: baseDocumentStructure,
205
- path: "/api",
206
- newParentId: "/api/auth",
207
- });
208
-
209
- expect(result.documentStructure).toEqual(baseDocumentStructure);
210
- expect(consoleSpy).toHaveBeenCalledWith(
211
- "⚠️ Cannot move document: Moving '/api' under '/api/auth' would create an invalid hierarchy. Please select a parent that is not nested under the document being moved.",
212
- );
213
- });
214
-
215
- test("should prevent moving document under its grandchild", async () => {
216
- const result = await moveDocument({
217
- documentStructure: baseDocumentStructure,
218
- path: "/api",
219
- newParentId: "/api/auth/oauth",
220
- });
221
-
222
- expect(result.documentStructure).toEqual(baseDocumentStructure);
223
- expect(consoleSpy).toHaveBeenCalledWith(
224
- "⚠️ Cannot move document: Moving '/api' under '/api/auth/oauth' would create an invalid hierarchy. Please select a parent that is not nested under the document being moved.",
225
- );
226
- });
227
-
228
- test("should allow moving document to same parent (no change)", async () => {
229
- const result = await moveDocument({
230
- documentStructure: baseDocumentStructure,
231
- path: "/api/auth",
232
- newParentId: "/api/auth",
233
- });
234
-
235
- // The move-document logic doesn't prevent self-assignment, it just does the operation
236
- expect(result.updatedDocument.parentId).toBe("/api/auth");
237
- expect(result.originalDocument.parentId).toBe("/api");
238
- expect(consoleSpy).not.toHaveBeenCalled();
239
- });
240
-
241
- test("should allow moving to sibling or unrelated documents", async () => {
242
- // Move from /api/auth to /tutorials (siblings under different parents)
243
- const result = await moveDocument({
244
- documentStructure: baseDocumentStructure,
245
- path: "/api/auth",
246
- newParentId: "/tutorials",
247
- });
248
-
249
- expect(result.updatedDocument.parentId).toBe("/tutorials");
250
- expect(consoleSpy).not.toHaveBeenCalled();
251
- });
252
-
253
- test("should handle complex circular dependency scenarios", async () => {
254
- const complexStructure = [
255
- ...baseDocumentStructure,
256
- {
257
- title: "OAuth Scopes",
258
- description: "OAuth scope documentation",
259
- path: "/api/auth/oauth/scopes",
260
- parentId: "/api/auth/oauth",
261
- sourceIds: ["scopes.md"],
262
- },
263
- {
264
- title: "JWT Tokens",
265
- description: "JWT token handling",
266
- path: "/api/auth/oauth/jwt",
267
- parentId: "/api/auth/oauth",
268
- sourceIds: ["jwt.js"],
269
- },
270
- ];
271
-
272
- // Try to move /api under its great-grandchild
273
- const result = await moveDocument({
274
- documentStructure: complexStructure,
275
- path: "/api",
276
- newParentId: "/api/auth/oauth/scopes",
277
- });
278
-
279
- expect(result.documentStructure).toEqual(complexStructure);
280
- expect(consoleSpy).toHaveBeenCalledWith(
281
- "⚠️ Cannot move document: Moving '/api' under '/api/auth/oauth/scopes' would create an invalid hierarchy. Please select a parent that is not nested under the document being moved.",
282
- );
283
- });
284
-
285
- // EDGE CASES
286
- test("should handle moving to same parent (no-op)", async () => {
287
- const result = await moveDocument({
288
- documentStructure: baseDocumentStructure,
289
- path: "/api/auth",
290
- newParentId: "/api",
291
- });
292
-
293
- // Should still work, even though it's essentially a no-op
294
- expect(result.updatedDocument.parentId).toBe("/api");
295
- expect(result.originalDocument.parentId).toBe("/api");
296
- expect(consoleSpy).not.toHaveBeenCalled();
297
- });
298
-
299
- test("should handle moving top-level document to become child", async () => {
300
- const result = await moveDocument({
301
- documentStructure: baseDocumentStructure,
302
- path: "/getting-started",
303
- newParentId: "/tutorials",
304
- });
305
-
306
- expect(result.originalDocument.parentId).toBeNull();
307
- expect(result.updatedDocument.parentId).toBe("/tutorials");
308
- expect(consoleSpy).not.toHaveBeenCalled();
309
- });
310
-
311
- test("should preserve all other document properties", async () => {
312
- const result = await moveDocument({
313
- documentStructure: baseDocumentStructure,
314
- path: "/api/rate-limiting",
315
- newParentId: "/tutorials",
316
- });
317
-
318
- const originalDoc = baseDocumentStructure.find((doc) => doc.path === "/api/rate-limiting");
319
- const updatedDoc = result.updatedDocument;
320
-
321
- expect(updatedDoc.title).toBe(originalDoc.title);
322
- expect(updatedDoc.description).toBe(originalDoc.description);
323
- expect(updatedDoc.path).toBe(originalDoc.path);
324
- expect(updatedDoc.sourceIds).toEqual(originalDoc.sourceIds);
325
- // Only parentId should change
326
- expect(updatedDoc.parentId).not.toBe(originalDoc.parentId);
327
- });
328
-
329
- test("should handle empty documentation structure", async () => {
330
- const result = await moveDocument({
331
- documentStructure: [],
332
- path: "/any-path",
333
- newParentId: "/any-parent",
334
- });
335
-
336
- expect(result.documentStructure).toEqual([]);
337
- expect(consoleSpy).toHaveBeenCalledWith(
338
- "⚠️ Cannot move document: Document '/any-path' does not exist. Please select an existing document to move.",
339
- );
340
- });
341
-
342
- test("should handle single documentation structure", async () => {
343
- const singleDocStructure = [
344
- {
345
- title: "Only Document",
346
- description: "The only document",
347
- path: "/only",
348
- parentId: null,
349
- sourceIds: ["only.md"],
350
- },
351
- ];
352
-
353
- const result = await moveDocument({
354
- documentStructure: singleDocStructure,
355
- path: "/only",
356
- newParentId: "/nonexistent",
357
- });
358
-
359
- expect(result.documentStructure).toEqual(singleDocStructure);
360
- expect(consoleSpy).toHaveBeenCalledWith(
361
- "⚠️ Cannot move document: Target parent document '/nonexistent' does not exist. Please select an existing parent document.",
362
- );
363
- });
364
-
365
- // DATA INTEGRITY TESTS
366
- test("should not modify original documentation structure", async () => {
367
- const originalStructure = [...baseDocumentStructure];
368
-
369
- await moveDocument({
370
- documentStructure: baseDocumentStructure,
371
- path: "/api/rate-limiting",
372
- newParentId: "/tutorials",
373
- });
374
-
375
- expect(baseDocumentStructure).toEqual(originalStructure);
376
- });
377
-
378
- test("should update only the specified document", async () => {
379
- const result = await moveDocument({
380
- documentStructure: baseDocumentStructure,
381
- path: "/api/rate-limiting",
382
- newParentId: "/tutorials",
383
- });
384
-
385
- // Count how many documents have changed
386
- let changedCount = 0;
387
- for (let i = 0; i < baseDocumentStructure.length; i++) {
388
- if (
389
- JSON.stringify(baseDocumentStructure[i]) !== JSON.stringify(result.documentStructure[i])
390
- ) {
391
- changedCount++;
392
- }
393
- }
394
-
395
- expect(changedCount).toBe(1);
396
- });
397
-
398
- test("should preserve document order in array", async () => {
399
- const result = await moveDocument({
400
- documentStructure: baseDocumentStructure,
401
- path: "/api/auth",
402
- newParentId: "/tutorials",
403
- });
404
-
405
- // Verify all documents are in the same positions except the moved one
406
- for (let i = 0; i < baseDocumentStructure.length; i++) {
407
- if (baseDocumentStructure[i].path === "/api/auth") {
408
- // This is the moved document, check everything except parentId
409
- const original = baseDocumentStructure[i];
410
- const updated = result.documentStructure[i];
411
- expect(updated.title).toBe(original.title);
412
- expect(updated.description).toBe(original.description);
413
- expect(updated.path).toBe(original.path);
414
- expect(updated.sourceIds).toEqual(original.sourceIds);
415
- expect(updated.parentId).toBe("/tutorials");
416
- } else {
417
- // Other documents should be unchanged
418
- expect(result.documentStructure[i]).toEqual(baseDocumentStructure[i]);
419
- }
420
- }
421
- });
422
-
423
- // RETURN VALUE TESTS
424
- test("should return complete original and updated document information", async () => {
425
- const result = await moveDocument({
426
- documentStructure: baseDocumentStructure,
427
- path: "/api/rate-limiting",
428
- newParentId: "/tutorials",
429
- });
430
-
431
- expect(result.originalDocument).toEqual({
432
- title: "Rate Limiting",
433
- description: "API rate limiting documentation",
434
- path: "/api/rate-limiting",
435
- parentId: "/api",
436
- sourceIds: ["rate-limit.js"],
437
- });
438
-
439
- expect(result.updatedDocument).toEqual({
440
- title: "Rate Limiting",
441
- description: "API rate limiting documentation",
442
- path: "/api/rate-limiting",
443
- parentId: "/tutorials",
444
- sourceIds: ["rate-limit.js"],
445
- });
446
-
447
- // Verify both have all required properties
448
- ["title", "description", "path", "parentId", "sourceIds"].forEach((prop) => {
449
- expect(result.originalDocument).toHaveProperty(prop);
450
- expect(result.updatedDocument).toHaveProperty(prop);
451
- });
452
- });
453
-
454
- test("should handle special characters in paths", async () => {
455
- const specialStructure = [
456
- ...baseDocumentStructure,
457
- {
458
- title: "Special Document",
459
- description: "Document with special characters",
460
- path: "/api/special-chars_and.numbers123",
461
- parentId: "/api",
462
- sourceIds: ["special.md"],
463
- },
464
- ];
465
-
466
- const result = await moveDocument({
467
- documentStructure: specialStructure,
468
- path: "/api/special-chars_and.numbers123",
469
- newParentId: "/tutorials",
470
- });
471
-
472
- expect(result.updatedDocument.path).toBe("/api/special-chars_and.numbers123");
473
- expect(result.updatedDocument.parentId).toBe("/tutorials");
474
- expect(consoleSpy).not.toHaveBeenCalled();
475
- });
476
- });