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

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