@aigne/doc-smith 0.8.12-beta.3 → 0.8.12-beta.4

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 (169) hide show
  1. package/.aigne/doc-smith/config.yaml +9 -6
  2. package/.aigne/doc-smith/output/structure-plan.json +123 -109
  3. package/.aigne/doc-smith/upload-cache.yaml +48 -0
  4. package/.github/workflows/publish-docs.yml +4 -7
  5. package/.release-please-manifest.json +1 -1
  6. package/CHANGELOG.md +13 -0
  7. package/agents/clear/choose-contents.mjs +22 -5
  8. package/agents/clear/clear-auth-tokens.mjs +2 -4
  9. package/agents/clear/clear-deployment-config.mjs +49 -0
  10. package/agents/clear/clear-document-config.mjs +2 -5
  11. package/agents/clear/clear-document-structure.mjs +2 -6
  12. package/agents/clear/clear-generated-docs.mjs +0 -1
  13. package/agents/generate/check-need-generate-structure.mjs +15 -60
  14. package/agents/generate/document-structure-tools/generate-sub-structure.mjs +131 -0
  15. package/agents/generate/generate-structure-without-tools.yaml +65 -0
  16. package/agents/generate/generate-structure.yaml +7 -1
  17. package/agents/generate/index.yaml +0 -3
  18. package/agents/generate/update-document-structure.yaml +3 -0
  19. package/agents/generate/user-review-document-structure.mjs +7 -5
  20. package/agents/init/index.mjs +15 -15
  21. package/agents/publish/publish-docs.mjs +130 -111
  22. package/agents/translate/index.yaml +1 -1
  23. package/agents/update/batch-generate-document.yaml +1 -1
  24. package/agents/update/batch-update-document.yaml +1 -1
  25. package/agents/update/check-document.mjs +3 -19
  26. package/agents/update/user-review-document.mjs +4 -3
  27. package/agents/utils/load-sources.mjs +54 -151
  28. package/agents/utils/transform-detail-datasources.mjs +14 -18
  29. package/aigne.yaml +2 -0
  30. package/biome.json +1 -1
  31. package/docs/_sidebar.md +13 -15
  32. package/docs/configuration-initial-setup.ja.md +179 -0
  33. package/docs/configuration-initial-setup.md +179 -0
  34. package/docs/configuration-initial-setup.zh-TW.md +179 -0
  35. package/docs/configuration-initial-setup.zh.md +179 -0
  36. package/docs/configuration-managing-preferences.ja.md +100 -0
  37. package/docs/configuration-managing-preferences.md +100 -0
  38. package/docs/configuration-managing-preferences.zh-TW.md +100 -0
  39. package/docs/configuration-managing-preferences.zh.md +100 -0
  40. package/docs/configuration.ja.md +68 -184
  41. package/docs/configuration.md +62 -178
  42. package/docs/configuration.zh-TW.md +70 -186
  43. package/docs/configuration.zh.md +67 -183
  44. package/docs/getting-started.ja.md +46 -78
  45. package/docs/getting-started.md +46 -78
  46. package/docs/getting-started.zh-TW.md +47 -79
  47. package/docs/getting-started.zh.md +47 -79
  48. package/docs/guides-cleaning-up.ja.md +50 -0
  49. package/docs/guides-cleaning-up.md +50 -0
  50. package/docs/guides-cleaning-up.zh-TW.md +50 -0
  51. package/docs/guides-cleaning-up.zh.md +50 -0
  52. package/docs/guides-evaluating-documents.ja.md +66 -0
  53. package/docs/guides-evaluating-documents.md +66 -0
  54. package/docs/guides-evaluating-documents.zh-TW.md +66 -0
  55. package/docs/guides-evaluating-documents.zh.md +66 -0
  56. package/docs/guides-generating-documentation.ja.md +149 -0
  57. package/docs/guides-generating-documentation.md +149 -0
  58. package/docs/guides-generating-documentation.zh-TW.md +149 -0
  59. package/docs/guides-generating-documentation.zh.md +149 -0
  60. package/docs/guides-interactive-chat.ja.md +85 -0
  61. package/docs/guides-interactive-chat.md +85 -0
  62. package/docs/guides-interactive-chat.zh-TW.md +85 -0
  63. package/docs/guides-interactive-chat.zh.md +85 -0
  64. package/docs/guides-managing-history.ja.md +51 -0
  65. package/docs/guides-managing-history.md +51 -0
  66. package/docs/guides-managing-history.zh-TW.md +51 -0
  67. package/docs/guides-managing-history.zh.md +51 -0
  68. package/docs/guides-publishing-your-docs.ja.md +78 -0
  69. package/docs/guides-publishing-your-docs.md +78 -0
  70. package/docs/guides-publishing-your-docs.zh-TW.md +78 -0
  71. package/docs/guides-publishing-your-docs.zh.md +78 -0
  72. package/docs/guides-translating-documentation.ja.md +95 -0
  73. package/docs/guides-translating-documentation.md +95 -0
  74. package/docs/guides-translating-documentation.zh-TW.md +95 -0
  75. package/docs/guides-translating-documentation.zh.md +95 -0
  76. package/docs/guides-updating-documentation.ja.md +77 -0
  77. package/docs/guides-updating-documentation.md +77 -0
  78. package/docs/guides-updating-documentation.zh-TW.md +77 -0
  79. package/docs/guides-updating-documentation.zh.md +77 -0
  80. package/docs/guides.ja.md +32 -0
  81. package/docs/guides.md +32 -0
  82. package/docs/guides.zh-TW.md +32 -0
  83. package/docs/guides.zh.md +32 -0
  84. package/docs/overview.ja.md +39 -60
  85. package/docs/overview.md +39 -60
  86. package/docs/overview.zh-TW.md +39 -60
  87. package/docs/overview.zh.md +39 -60
  88. package/docs/release-notes.ja.md +255 -0
  89. package/docs/release-notes.md +255 -0
  90. package/docs/release-notes.zh-TW.md +255 -0
  91. package/docs/release-notes.zh.md +255 -0
  92. package/package.json +4 -2
  93. package/prompts/common/document/content-rules-core.md +1 -0
  94. package/prompts/common/document-structure/document-structure-rules.md +8 -9
  95. package/prompts/common/document-structure/output-constraints.md +1 -1
  96. package/prompts/structure/document-rules.md +8 -2
  97. package/prompts/structure/generate/system-prompt.md +27 -2
  98. package/prompts/structure/generate/user-prompt.md +18 -0
  99. package/prompts/structure/update/system-prompt.md +12 -0
  100. package/prompts/structure/update/user-prompt.md +3 -0
  101. package/tests/agents/clear/choose-contents.test.mjs +8 -4
  102. package/tests/agents/generate/check-need-generate-structure.test.mjs +53 -63
  103. package/tests/agents/generate/document-structure-tools/generate-sub-structure.test.mjs +277 -0
  104. package/tests/agents/init/init.test.mjs +18 -18
  105. package/tests/agents/publish/publish-docs.test.mjs +79 -0
  106. package/tests/agents/update/check-document.test.mjs +7 -67
  107. package/tests/agents/utils/load-sources.test.mjs +90 -90
  108. package/tests/agents/utils/transform-detail-datasources.test.mjs +153 -196
  109. package/tests/utils/file-utils.test.mjs +309 -1
  110. package/utils/auth-utils.mjs +9 -3
  111. package/utils/constants/index.mjs +3 -1
  112. package/utils/file-utils.mjs +315 -0
  113. package/utils/utils.mjs +89 -50
  114. package/docs/advanced-how-it-works.ja.md +0 -101
  115. package/docs/advanced-how-it-works.md +0 -101
  116. package/docs/advanced-how-it-works.zh-TW.md +0 -101
  117. package/docs/advanced-how-it-works.zh.md +0 -101
  118. package/docs/advanced-quality-assurance.ja.md +0 -92
  119. package/docs/advanced-quality-assurance.md +0 -92
  120. package/docs/advanced-quality-assurance.zh-TW.md +0 -92
  121. package/docs/advanced-quality-assurance.zh.md +0 -92
  122. package/docs/advanced.ja.md +0 -20
  123. package/docs/advanced.md +0 -20
  124. package/docs/advanced.zh-TW.md +0 -20
  125. package/docs/advanced.zh.md +0 -20
  126. package/docs/changelog.ja.md +0 -486
  127. package/docs/changelog.md +0 -486
  128. package/docs/changelog.zh-TW.md +0 -486
  129. package/docs/changelog.zh.md +0 -486
  130. package/docs/cli-reference.ja.md +0 -311
  131. package/docs/cli-reference.md +0 -311
  132. package/docs/cli-reference.zh-TW.md +0 -311
  133. package/docs/cli-reference.zh.md +0 -311
  134. package/docs/configuration-interactive-setup.ja.md +0 -138
  135. package/docs/configuration-interactive-setup.md +0 -138
  136. package/docs/configuration-interactive-setup.zh-TW.md +0 -138
  137. package/docs/configuration-interactive-setup.zh.md +0 -138
  138. package/docs/configuration-language-support.ja.md +0 -64
  139. package/docs/configuration-language-support.md +0 -64
  140. package/docs/configuration-language-support.zh-TW.md +0 -64
  141. package/docs/configuration-language-support.zh.md +0 -64
  142. package/docs/configuration-llm-setup.ja.md +0 -56
  143. package/docs/configuration-llm-setup.md +0 -56
  144. package/docs/configuration-llm-setup.zh-TW.md +0 -56
  145. package/docs/configuration-llm-setup.zh.md +0 -56
  146. package/docs/configuration-preferences.ja.md +0 -144
  147. package/docs/configuration-preferences.md +0 -144
  148. package/docs/configuration-preferences.zh-TW.md +0 -144
  149. package/docs/configuration-preferences.zh.md +0 -144
  150. package/docs/features-generate-documentation.ja.md +0 -95
  151. package/docs/features-generate-documentation.md +0 -95
  152. package/docs/features-generate-documentation.zh-TW.md +0 -95
  153. package/docs/features-generate-documentation.zh.md +0 -95
  154. package/docs/features-publish-your-docs.ja.md +0 -130
  155. package/docs/features-publish-your-docs.md +0 -130
  156. package/docs/features-publish-your-docs.zh-TW.md +0 -130
  157. package/docs/features-publish-your-docs.zh.md +0 -130
  158. package/docs/features-translate-documentation.ja.md +0 -90
  159. package/docs/features-translate-documentation.md +0 -90
  160. package/docs/features-translate-documentation.zh-TW.md +0 -90
  161. package/docs/features-translate-documentation.zh.md +0 -90
  162. package/docs/features-update-and-refine.ja.md +0 -142
  163. package/docs/features-update-and-refine.md +0 -142
  164. package/docs/features-update-and-refine.zh-TW.md +0 -143
  165. package/docs/features-update-and-refine.zh.md +0 -142
  166. package/docs/features.ja.md +0 -62
  167. package/docs/features.md +0 -62
  168. package/docs/features.zh-TW.md +0 -62
  169. package/docs/features.zh.md +0 -62
@@ -1,12 +1,23 @@
1
1
  import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test";
2
+ import { mkdir, rm, writeFile } from "node:fs/promises";
3
+ import path, { dirname } from "node:path";
4
+ import { fileURLToPath } from "node:url";
2
5
  import transformDetailDatasources from "../../../agents/utils/transform-detail-datasources.mjs";
3
6
  import * as utils from "../../../utils/utils.mjs";
4
7
 
8
+ const __dirname = dirname(fileURLToPath(import.meta.url));
9
+
5
10
  describe("transformDetailDatasources utility", () => {
6
11
  let normalizePathSpy;
7
12
  let toRelativePathSpy;
13
+ let testDir;
14
+
15
+ beforeEach(async () => {
16
+ // Create test directory
17
+ const uniqueId = `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
18
+ testDir = path.join(__dirname, `test-transform-${uniqueId}`);
19
+ await mkdir(testDir, { recursive: true });
8
20
 
9
- beforeEach(() => {
10
21
  // Spy on utility functions
11
22
  normalizePathSpy = spyOn(utils, "normalizePath").mockImplementation((path) =>
12
23
  path?.replace(/\\/g, "/").replace(/^\.\//, ""),
@@ -16,117 +27,145 @@ describe("transformDetailDatasources utility", () => {
16
27
  );
17
28
  });
18
29
 
19
- afterEach(() => {
30
+ afterEach(async () => {
20
31
  // Restore all spies
21
32
  normalizePathSpy?.mockRestore();
22
33
  toRelativePathSpy?.mockRestore();
34
+
35
+ // Clean up test directory
36
+ try {
37
+ await rm(testDir, { recursive: true, force: true });
38
+ } catch {
39
+ console.warn(`Warning: Could not clean up test directory: ${testDir}`);
40
+ }
23
41
  });
24
42
 
25
43
  // BASIC FUNCTIONALITY TESTS
26
- test("should transform simple datasources correctly", () => {
44
+ test("should transform simple datasources correctly", async () => {
45
+ // Create test files
46
+ const guidePath = path.join(testDir, "guide.md");
47
+ const apiPath = path.join(testDir, "api.md");
48
+ await writeFile(guidePath, "# User Guide\n\nThis is a guide.");
49
+ await writeFile(apiPath, "# API Reference\n\nAPI documentation.");
50
+
51
+ // Mock normalizePath to return the actual file path
52
+ normalizePathSpy.mockImplementation((p) => p);
53
+
27
54
  const input = {
28
- sourceIds: ["/docs/guide.md", "/docs/api.md"],
29
- datasourcesList: [
30
- { sourceId: "/docs/guide.md", content: "# User Guide\n\nThis is a guide." },
31
- { sourceId: "/docs/api.md", content: "# API Reference\n\nAPI documentation." },
32
- ],
55
+ sourceIds: [guidePath, apiPath],
33
56
  };
34
57
 
35
58
  const result = transformDetailDatasources(input);
36
59
 
37
- expect(normalizePathSpy).toHaveBeenCalledWith("/docs/guide.md");
38
- expect(normalizePathSpy).toHaveBeenCalledWith("/docs/api.md");
39
- expect(toRelativePathSpy).toHaveBeenCalledWith("/docs/guide.md");
40
- expect(toRelativePathSpy).toHaveBeenCalledWith("/docs/api.md");
60
+ expect(normalizePathSpy).toHaveBeenCalledWith(guidePath);
61
+ expect(normalizePathSpy).toHaveBeenCalledWith(apiPath);
62
+ expect(toRelativePathSpy).toHaveBeenCalledWith(guidePath);
63
+ expect(toRelativePathSpy).toHaveBeenCalledWith(apiPath);
41
64
 
42
- expect(result).toEqual({
43
- detailDataSources:
44
- "// sourceId: docs/guide.md\n# User Guide\n\nThis is a guide.\n" +
45
- "// sourceId: docs/api.md\n# API Reference\n\nAPI documentation.\n",
46
- });
65
+ expect(result.detailDataSources).toContain("# User Guide\n\nThis is a guide.");
66
+ expect(result.detailDataSources).toContain("# API Reference\n\nAPI documentation.");
47
67
  });
48
68
 
49
- test("should handle single datasource", () => {
69
+ test("should handle single datasource", async () => {
70
+ // Create test file
71
+ const readmePath = path.join(testDir, "readme.md");
72
+ await writeFile(readmePath, "# README\n\nProject documentation.");
73
+
74
+ normalizePathSpy.mockImplementation((p) => p);
75
+
50
76
  const input = {
51
- sourceIds: ["/docs/readme.md"],
52
- datasourcesList: [
53
- { sourceId: "/docs/readme.md", content: "# README\n\nProject documentation." },
54
- ],
77
+ sourceIds: [readmePath],
55
78
  };
56
79
 
57
80
  const result = transformDetailDatasources(input);
58
81
 
59
- expect(result.detailDataSources).toBe(
60
- "// sourceId: docs/readme.md\n# README\n\nProject documentation.\n",
61
- );
82
+ expect(result.detailDataSources).toContain("# README\n\nProject documentation.");
62
83
  });
63
84
 
64
- test("should maintain order of sourceIds", () => {
85
+ test("should maintain order of sourceIds", async () => {
86
+ // Create test files
87
+ const cPath = path.join(testDir, "c.md");
88
+ const aPath = path.join(testDir, "a.md");
89
+ const bPath = path.join(testDir, "b.md");
90
+ await writeFile(cPath, "Content C");
91
+ await writeFile(aPath, "Content A");
92
+ await writeFile(bPath, "Content B");
93
+
94
+ normalizePathSpy.mockImplementation((p) => p);
95
+
65
96
  const input = {
66
- sourceIds: ["/docs/c.md", "/docs/a.md", "/docs/b.md"],
67
- datasourcesList: [
68
- { sourceId: "/docs/a.md", content: "Content A" },
69
- { sourceId: "/docs/b.md", content: "Content B" },
70
- { sourceId: "/docs/c.md", content: "Content C" },
71
- ],
97
+ sourceIds: [cPath, aPath, bPath],
72
98
  };
73
99
 
74
100
  const result = transformDetailDatasources(input);
75
101
 
76
- expect(result.detailDataSources).toBe(
77
- "// sourceId: docs/c.md\nContent C\n" +
78
- "// sourceId: docs/a.md\nContent A\n" +
79
- "// sourceId: docs/b.md\nContent B\n",
80
- );
102
+ // Check order by finding indices
103
+ const indexC = result.detailDataSources.indexOf("Content C");
104
+ const indexA = result.detailDataSources.indexOf("Content A");
105
+ const indexB = result.detailDataSources.indexOf("Content B");
106
+
107
+ expect(indexC).toBeLessThan(indexA);
108
+ expect(indexA).toBeLessThan(indexB);
81
109
  });
82
110
 
83
111
  // PATH NORMALIZATION TESTS
84
- test("should normalize paths correctly", () => {
85
- normalizePathSpy.mockImplementation((path) => path?.replace(/\\/g, "/"));
112
+ test("should normalize paths correctly", async () => {
113
+ // Create test files
114
+ const guidePath = path.join(testDir, "guide.md");
115
+ const apiPath = path.join(testDir, "api.md");
116
+ await writeFile(guidePath, "Guide content");
117
+ await writeFile(apiPath, "API content");
118
+
119
+ normalizePathSpy.mockImplementation((p) => p?.replace(/\\/g, "/"));
86
120
 
87
121
  const input = {
88
- sourceIds: ["docs\\guide.md", "/docs/api.md"],
89
- datasourcesList: [
90
- { sourceId: "docs\\guide.md", content: "Guide content" },
91
- { sourceId: "/docs/api.md", content: "API content" },
92
- ],
122
+ sourceIds: [guidePath, apiPath],
93
123
  };
94
124
 
95
125
  const result = transformDetailDatasources(input);
96
126
 
97
- expect(normalizePathSpy).toHaveBeenCalledWith("docs\\guide.md");
98
- expect(normalizePathSpy).toHaveBeenCalledWith("/docs/api.md");
127
+ expect(normalizePathSpy).toHaveBeenCalledWith(guidePath);
128
+ expect(normalizePathSpy).toHaveBeenCalledWith(apiPath);
99
129
  expect(result.detailDataSources).toContain("Guide content");
100
130
  expect(result.detailDataSources).toContain("API content");
101
131
  });
102
132
 
103
- test("should handle relative path conversion", () => {
104
- toRelativePathSpy.mockImplementation((path) => path?.replace(/^\/+/, "").replace(/^\.\//, ""));
133
+ test("should handle relative path conversion", async () => {
134
+ // Create test files
135
+ const absPath = path.join(testDir, "abs-file.md");
136
+ const relPath = path.join(testDir, "rel-file.md");
137
+ await writeFile(absPath, "Absolute content");
138
+ await writeFile(relPath, "Relative content");
139
+
140
+ normalizePathSpy.mockImplementation((p) => p);
141
+ toRelativePathSpy.mockImplementation((p) => p?.replace(/^\/+/, "").replace(/^\.\//, ""));
105
142
 
106
143
  const input = {
107
- sourceIds: ["/abs/path/file.md", "./rel/path/file.md"],
108
- datasourcesList: [
109
- { sourceId: "/abs/path/file.md", content: "Absolute content" },
110
- { sourceId: "./rel/path/file.md", content: "Relative content" },
111
- ],
144
+ sourceIds: [absPath, relPath],
112
145
  };
113
146
 
114
147
  const result = transformDetailDatasources(input);
115
148
 
116
- expect(toRelativePathSpy).toHaveBeenCalledWith("/abs/path/file.md");
117
- expect(toRelativePathSpy).toHaveBeenCalledWith("./rel/path/file.md");
118
- expect(result.detailDataSources).toContain("abs/path/file.md");
119
- expect(result.detailDataSources).toContain("rel/path/file.md");
149
+ expect(toRelativePathSpy).toHaveBeenCalledWith(absPath);
150
+ expect(toRelativePathSpy).toHaveBeenCalledWith(relPath);
151
+ expect(result.detailDataSources).toContain("Absolute content");
152
+ expect(result.detailDataSources).toContain("Relative content");
120
153
  });
121
154
 
122
155
  // MISSING DATA TESTS
123
- test("should filter out sourceIds not found in datasourcesList", () => {
156
+ test("should filter out sourceIds for files that don't exist", async () => {
157
+ // Create only some test files
158
+ const guidePath = path.join(testDir, "guide.md");
159
+ const apiPath = path.join(testDir, "api.md");
160
+ const missingPath = path.join(testDir, "missing.md");
161
+ await writeFile(guidePath, "Guide content");
162
+ await writeFile(apiPath, "API content");
163
+ // missingPath intentionally not created
164
+
165
+ normalizePathSpy.mockImplementation((p) => p);
166
+
124
167
  const input = {
125
- sourceIds: ["/docs/guide.md", "/docs/missing.md", "/docs/api.md"],
126
- datasourcesList: [
127
- { sourceId: "/docs/guide.md", content: "Guide content" },
128
- { sourceId: "/docs/api.md", content: "API content" },
129
- ],
168
+ sourceIds: [guidePath, missingPath, apiPath],
130
169
  };
131
170
 
132
171
  const result = transformDetailDatasources(input);
@@ -134,27 +173,11 @@ describe("transformDetailDatasources utility", () => {
134
173
  expect(result.detailDataSources).toContain("Guide content");
135
174
  expect(result.detailDataSources).toContain("API content");
136
175
  expect(result.detailDataSources).not.toContain("missing");
137
- expect(result.detailDataSources.split("// sourceId:")).toHaveLength(3); // Empty first element + 2 sources
138
176
  });
139
177
 
140
178
  test("should handle empty sourceIds array", () => {
141
179
  const input = {
142
180
  sourceIds: [],
143
- datasourcesList: [
144
- { sourceId: "/docs/guide.md", content: "Guide content" },
145
- { sourceId: "/docs/api.md", content: "API content" },
146
- ],
147
- };
148
-
149
- const result = transformDetailDatasources(input);
150
-
151
- expect(result.detailDataSources).toBe("");
152
- });
153
-
154
- test("should handle empty datasourcesList array", () => {
155
- const input = {
156
- sourceIds: ["/docs/guide.md", "/docs/api.md"],
157
- datasourcesList: [],
158
181
  };
159
182
 
160
183
  const result = transformDetailDatasources(input);
@@ -166,7 +189,6 @@ describe("transformDetailDatasources utility", () => {
166
189
  test("should handle null sourceIds", () => {
167
190
  const input = {
168
191
  sourceIds: null,
169
- datasourcesList: [{ sourceId: "/docs/guide.md", content: "Guide content" }],
170
192
  };
171
193
 
172
194
  const result = transformDetailDatasources(input);
@@ -177,7 +199,6 @@ describe("transformDetailDatasources utility", () => {
177
199
  test("should handle undefined sourceIds", () => {
178
200
  const input = {
179
201
  sourceIds: undefined,
180
- datasourcesList: [{ sourceId: "/docs/guide.md", content: "Guide content" }],
181
202
  };
182
203
 
183
204
  const result = transformDetailDatasources(input);
@@ -185,179 +206,115 @@ describe("transformDetailDatasources utility", () => {
185
206
  expect(result.detailDataSources).toBe("");
186
207
  });
187
208
 
188
- test("should handle null datasourcesList", () => {
189
- const input = {
190
- sourceIds: ["/docs/guide.md"],
191
- datasourcesList: null,
192
- };
193
-
194
- const result = transformDetailDatasources(input);
209
+ // CONTENT FORMATTING TESTS
210
+ test("should format content with proper sourceId comments", async () => {
211
+ const mainPath = path.join(testDir, "main.js");
212
+ await writeFile(mainPath, "console.log('Hello World');\nprocess.exit(0);");
195
213
 
196
- expect(result.detailDataSources).toBe("");
197
- });
214
+ normalizePathSpy.mockImplementation((p) => p);
198
215
 
199
- test("should handle undefined datasourcesList", () => {
200
216
  const input = {
201
- sourceIds: ["/docs/guide.md"],
202
- datasourcesList: undefined,
217
+ sourceIds: [mainPath],
203
218
  };
204
219
 
205
220
  const result = transformDetailDatasources(input);
206
221
 
207
- expect(result.detailDataSources).toBe("");
222
+ expect(result.detailDataSources).toContain("console.log('Hello World');\nprocess.exit(0);");
223
+ expect(result.detailDataSources).toContain("// sourceId:");
208
224
  });
209
225
 
210
- // CONTENT FORMATTING TESTS
211
- test("should format content with proper sourceId comments", () => {
212
- const input = {
213
- sourceIds: ["/project/src/main.js"],
214
- datasourcesList: [
215
- {
216
- sourceId: "/project/src/main.js",
217
- content: "console.log('Hello World');\nprocess.exit(0);",
218
- },
219
- ],
220
- };
221
-
222
- const result = transformDetailDatasources(input);
226
+ test("should handle empty content", async () => {
227
+ const emptyPath = path.join(testDir, "empty.md");
228
+ await writeFile(emptyPath, "");
223
229
 
224
- expect(result.detailDataSources).toBe(
225
- "// sourceId: project/src/main.js\nconsole.log('Hello World');\nprocess.exit(0);\n",
226
- );
227
- });
230
+ normalizePathSpy.mockImplementation((p) => p);
228
231
 
229
- test("should handle empty content", () => {
230
232
  const input = {
231
- sourceIds: ["/docs/empty.md"],
232
- datasourcesList: [{ sourceId: "/docs/empty.md", content: "" }],
233
+ sourceIds: [emptyPath],
233
234
  };
234
235
 
235
236
  const result = transformDetailDatasources(input);
236
237
 
237
- // Empty content is falsy, so it gets filtered out
238
- expect(result.detailDataSources).toBe("");
238
+ // Empty file content still gets included with sourceId comment
239
+ expect(result.detailDataSources).toContain("// sourceId:");
240
+ expect(result.detailDataSources.trim()).not.toBe("");
239
241
  });
240
242
 
241
- test("should handle whitespace-only content", () => {
243
+ test("should handle whitespace-only content", async () => {
244
+ const whitespacePath = path.join(testDir, "whitespace.md");
245
+ await writeFile(whitespacePath, " \n\t ");
246
+
247
+ normalizePathSpy.mockImplementation((p) => p);
248
+
242
249
  const input = {
243
- sourceIds: ["/docs/whitespace.md"],
244
- datasourcesList: [{ sourceId: "/docs/whitespace.md", content: " \n\t " }],
250
+ sourceIds: [whitespacePath],
245
251
  };
246
252
 
247
253
  const result = transformDetailDatasources(input);
248
254
 
249
255
  // Whitespace content is truthy, so it should be included
250
- expect(result.detailDataSources).toBe("// sourceId: docs/whitespace.md\n \n\t \n");
256
+ expect(result.detailDataSources).toContain(" \n\t ");
251
257
  });
252
258
 
253
- test("should handle content with special characters", () => {
254
- const input = {
255
- sourceIds: ["/docs/特殊字符.md"],
256
- datasourcesList: [
257
- {
258
- sourceId: "/docs/特殊字符.md",
259
- content: "# 中文标题\n\n这是一个包含特殊字符的文档: @#$%^&*()",
260
- },
261
- ],
262
- };
263
-
264
- const result = transformDetailDatasources(input);
259
+ test("should handle content with special characters", async () => {
260
+ const specialPath = path.join(testDir, "特殊字符.md");
261
+ await writeFile(specialPath, "# 中文标题\n\n这是一个包含特殊字符的文档: @#$%^&*()");
265
262
 
266
- expect(result.detailDataSources).toContain("特殊字符.md");
267
- expect(result.detailDataSources).toContain("中文标题");
268
- expect(result.detailDataSources).toContain("@#$%^&*()");
269
- });
263
+ normalizePathSpy.mockImplementation((p) => p);
270
264
 
271
- // LARGE DATA TESTS
272
- test("should handle multiple large datasources", () => {
273
- const largeContent = "A".repeat(1000);
274
265
  const input = {
275
- sourceIds: Array.from({ length: 50 }, (_, i) => `/docs/file-${i}.md`),
276
- datasourcesList: Array.from({ length: 50 }, (_, i) => ({
277
- sourceId: `/docs/file-${i}.md`,
278
- content: `${largeContent}-${i}`,
279
- })),
266
+ sourceIds: [specialPath],
280
267
  };
281
268
 
282
269
  const result = transformDetailDatasources(input);
283
270
 
284
- expect(result.detailDataSources.split("// sourceId:")).toHaveLength(51); // 50 files + empty first
285
- expect(result.detailDataSources).toContain("file-0.md");
286
- expect(result.detailDataSources).toContain("file-49.md");
287
- expect(result.detailDataSources.length).toBeGreaterThan(50000); // Should be quite large
271
+ expect(result.detailDataSources).toContain("中文标题");
272
+ expect(result.detailDataSources).toContain("@#$%^&*()");
288
273
  });
289
274
 
290
275
  // DUPLICATE HANDLING TESTS
291
- test("should handle duplicate sourceIds in list", () => {
292
- const input = {
293
- sourceIds: ["/docs/guide.md", "/docs/guide.md"],
294
- datasourcesList: [{ sourceId: "/docs/guide.md", content: "Guide content" }],
295
- };
296
-
297
- const result = transformDetailDatasources(input);
276
+ test("should handle duplicate sourceIds in list", async () => {
277
+ const guidePath = path.join(testDir, "guide.md");
278
+ await writeFile(guidePath, "Guide content");
298
279
 
299
- expect(result.detailDataSources).toBe(
300
- "// sourceId: docs/guide.md\nGuide content\n" + "// sourceId: docs/guide.md\nGuide content\n",
301
- );
302
- });
280
+ normalizePathSpy.mockImplementation((p) => p);
303
281
 
304
- test("should handle duplicate entries in datasourcesList", () => {
305
282
  const input = {
306
- sourceIds: ["/docs/guide.md"],
307
- datasourcesList: [
308
- { sourceId: "/docs/guide.md", content: "First content" },
309
- { sourceId: "/docs/guide.md", content: "Second content" },
310
- ],
283
+ sourceIds: [guidePath, guidePath], // Duplicate paths
311
284
  };
312
285
 
313
286
  const result = transformDetailDatasources(input);
314
287
 
315
- // Should use the last entry due to Object.fromEntries behavior
316
- expect(result.detailDataSources).toBe("// sourceId: docs/guide.md\nSecond content\n");
288
+ // Both duplicates should be included
289
+ const matches = result.detailDataSources.match(/Guide content/g);
290
+ expect(matches?.length).toBe(2);
317
291
  });
318
292
 
319
293
  // RETURN VALUE STRUCTURE TESTS
320
- test("should always return object with detailDataSources property", () => {
321
- const inputs = [
322
- { sourceIds: [], datasourcesList: [] },
323
- { sourceIds: null, datasourcesList: null },
324
- { sourceIds: ["/test"], datasourcesList: [{ sourceId: "/test", content: "test" }] },
325
- ];
326
-
327
- inputs.forEach((input) => {
294
+ test("should always return object with detailDataSources property", async () => {
295
+ const inputs = [{ sourceIds: [] }, { sourceIds: null }];
296
+
297
+ for (const input of inputs) {
328
298
  const result = transformDetailDatasources(input);
329
299
  expect(result).toHaveProperty("detailDataSources");
330
300
  expect(typeof result.detailDataSources).toBe("string");
331
- });
301
+ }
332
302
  });
333
303
 
334
304
  // EDGE CASES
335
- test("should handle sourceId with null or undefined values", () => {
336
- normalizePathSpy.mockImplementation((path) => path || "");
337
- toRelativePathSpy.mockImplementation((path) => path || "");
338
-
339
- const input = {
340
- sourceIds: [null, undefined, "/docs/valid.md"],
341
- datasourcesList: [{ sourceId: "/docs/valid.md", content: "Valid content" }],
342
- };
343
-
344
- const result = transformDetailDatasources(input);
305
+ test("should handle sourceId with null or undefined values", async () => {
306
+ const validPath = path.join(testDir, "valid.md");
307
+ await writeFile(validPath, "Valid content");
345
308
 
346
- // The toRelativePath spy is returning the original path, let's adjust expectation
347
- expect(result.detailDataSources).toBe("// sourceId: /docs/valid.md\nValid content\n");
348
- });
309
+ normalizePathSpy.mockImplementation((p) => p || "");
310
+ toRelativePathSpy.mockImplementation((p) => p || "");
349
311
 
350
- test("should handle datasource with null sourceId", () => {
351
312
  const input = {
352
- sourceIds: ["/docs/guide.md"],
353
- datasourcesList: [
354
- { sourceId: null, content: "Null sourceId content" },
355
- { sourceId: "/docs/guide.md", content: "Valid content" },
356
- ],
313
+ sourceIds: [null, undefined, validPath],
357
314
  };
358
315
 
359
316
  const result = transformDetailDatasources(input);
360
317
 
361
- expect(result.detailDataSources).toBe("// sourceId: docs/guide.md\nValid content\n");
318
+ expect(result.detailDataSources).toContain("Valid content");
362
319
  });
363
320
  });