@aigne/doc-smith 0.8.5 → 0.8.7
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.
- package/.aigne/doc-smith/output/structure-plan.json +1 -5
- package/CHANGELOG.md +25 -0
- package/README.md +3 -3
- package/agents/{chat.yaml → chat/index.yaml} +7 -7
- package/agents/generate/check-document-structure.yaml +30 -0
- package/agents/{check-structure-plan.mjs → generate/check-need-generate-structure.mjs} +21 -21
- package/agents/generate/generate-structure.yaml +58 -0
- package/agents/{docs-generator.yaml → generate/index.yaml} +15 -16
- package/agents/generate/refine-document-structure.yaml +12 -0
- package/agents/{input-generator.mjs → init/index.mjs} +34 -27
- package/agents/{manage-prefs.mjs → prefs/index.mjs} +16 -16
- package/agents/publish/index.yaml +17 -0
- package/agents/{publish-docs.mjs → publish/publish-docs.mjs} +15 -16
- package/agents/schema/{structure-plan-result.yaml → document-execution-structure.yaml} +3 -3
- package/agents/schema/document-structure.yaml +26 -0
- package/agents/{language-selector.mjs → translate/choose-language.mjs} +5 -5
- package/agents/{retranslate.yaml → translate/index.yaml} +17 -18
- package/agents/translate/translate-document.yaml +32 -0
- package/agents/{batch-translate.yaml → translate/translate-multilingual.yaml} +5 -5
- package/agents/update/batch-generate-document.yaml +19 -0
- package/agents/{check-detail.mjs → update/check-document.mjs} +16 -16
- package/agents/{detail-generator-and-translate.yaml → update/generate-and-translate-document.yaml} +23 -23
- package/agents/update/generate-document.yaml +50 -0
- package/agents/{detail-regenerator.yaml → update/index.yaml} +16 -17
- package/agents/{action-success.mjs → utils/action-success.mjs} +2 -2
- package/agents/{check-detail-result.mjs → utils/check-detail-result.mjs} +3 -3
- package/agents/{check-feedback-refiner.mjs → utils/check-feedback-refiner.mjs} +6 -6
- package/agents/{find-items-by-paths.mjs → utils/choose-docs.mjs} +25 -10
- package/agents/{docs-fs.yaml → utils/docs-fs-actor.yaml} +3 -1
- package/agents/utils/feedback-refiner.yaml +50 -0
- package/agents/{find-item-by-path.mjs → utils/find-item-by-path.mjs} +17 -7
- package/agents/{find-user-preferences-by-path.mjs → utils/find-user-preferences-by-path.mjs} +1 -1
- package/agents/utils/format-document-structure.mjs +25 -0
- package/agents/{load-sources.mjs → utils/load-sources.mjs} +41 -28
- package/agents/{save-docs.mjs → utils/save-docs.mjs} +16 -16
- package/agents/{save-single-doc.mjs → utils/save-single-doc.mjs} +2 -2
- package/agents/{transform-detail-datasources.mjs → utils/transform-detail-datasources.mjs} +1 -1
- package/aigne.yaml +35 -35
- package/docs/cli-reference.md +1 -1
- package/docs/features-generate-documentation.md +1 -1
- package/docs/features-update-and-refine.md +2 -2
- package/docs-mcp/analyze-docs-relevance.yaml +10 -10
- package/docs-mcp/docs-search.yaml +5 -3
- package/package.json +10 -8
- package/prompts/{document → detail/custom}/custom-code-block.md +6 -6
- package/prompts/detail/custom/custom-components.md +172 -0
- package/prompts/{document → detail}/d2-chart/rules.md +95 -1
- package/prompts/{document → detail}/detail-example.md +80 -61
- package/prompts/{document/detail-generator.md → detail/document-rules.md} +4 -8
- package/prompts/{content-detail-generator.md → detail/generate-document.md} +48 -25
- package/prompts/{check-structure-planning-result.md → structure/check-document-structure.md} +23 -17
- package/prompts/{document/structure-planning.md → structure/document-rules.md} +0 -2
- package/prompts/{structure-planning.md → structure/generate-structure.md} +51 -30
- package/prompts/{document → structure}/structure-example.md +2 -2
- package/prompts/{document → structure}/structure-getting-started.md +2 -2
- package/prompts/translate/glossary.md +6 -0
- package/prompts/{translator.md → translate/translate-document.md} +29 -10
- package/prompts/{feedback-refiner.md → utils/feedback-refiner.md} +8 -8
- package/tests/agents/chat/chat.test.mjs +46 -0
- package/tests/agents/generate/check-document-structure.test.mjs +51 -0
- package/tests/agents/generate/check-need-generate-structure.test.mjs +292 -0
- package/tests/agents/generate/generate-structure.test.mjs +51 -0
- package/tests/{input-generator.test.mjs → agents/init/init.test.mjs} +19 -17
- package/tests/agents/prefs/prefs.test.mjs +431 -0
- package/tests/agents/publish/publish-docs.test.mjs +642 -0
- package/tests/agents/translate/choose-language.test.mjs +311 -0
- package/tests/agents/translate/translate-document.test.mjs +51 -0
- package/tests/agents/update/check-document.test.mjs +523 -0
- package/tests/agents/update/generate-document.test.mjs +51 -0
- package/tests/agents/utils/action-success.test.mjs +54 -0
- package/tests/{check-detail-result.test.mjs → agents/utils/check-detail-result.test.mjs} +98 -98
- package/tests/agents/utils/check-feedback-refiner.test.mjs +478 -0
- package/tests/agents/utils/choose-docs.test.mjs +417 -0
- package/tests/agents/utils/exit.test.mjs +70 -0
- package/tests/agents/utils/feedback-refiner.test.mjs +51 -0
- package/tests/agents/utils/find-item-by-path.test.mjs +526 -0
- package/tests/agents/utils/find-user-preferences-by-path.test.mjs +382 -0
- package/tests/agents/utils/format-document-structure.test.mjs +264 -0
- package/tests/agents/utils/fs.test.mjs +267 -0
- package/tests/{load-sources.test.mjs → agents/utils/load-sources.test.mjs} +153 -25
- package/tests/{save-docs.test.mjs → agents/utils/save-docs.test.mjs} +11 -5
- package/tests/agents/utils/save-output.test.mjs +315 -0
- package/tests/agents/utils/save-single-doc.test.mjs +364 -0
- package/tests/agents/utils/transform-detail-datasources.test.mjs +363 -0
- package/tests/utils/auth-utils.test.mjs +358 -0
- package/tests/utils/blocklet.test.mjs +334 -0
- package/tests/{conflict-resolution.test.mjs → utils/conflict-detector.test.mjs} +3 -3
- package/tests/utils/constants.test.mjs +295 -0
- package/tests/utils/d2-utils.test.mjs +423 -0
- package/tests/utils/deploy.test.mjs +365 -0
- package/tests/utils/docs-finder-utils.test.mjs +625 -0
- package/tests/utils/file-utils.test.mjs +213 -0
- package/tests/{kroki-utils.test.mjs → utils/kroki-utils.test.mjs} +2 -2
- package/tests/utils/load-config.test.mjs +141 -0
- package/tests/{mermaid-validation.test.mjs → utils/mermaid-validator.test.mjs} +2 -2
- package/tests/utils/mock-chat-model.mjs +12 -0
- package/tests/{preferences-utils.test.mjs → utils/preferences-utils.test.mjs} +1 -1
- package/tests/{save-value-to-config.test.mjs → utils/save-value-to-config.test.mjs} +61 -4
- package/tests/utils/utils.test.mjs +939 -0
- package/utils/auth-utils.mjs +1 -1
- package/utils/conflict-detector.mjs +1 -1
- package/utils/constants.mjs +5 -3
- package/utils/d2-utils.mjs +194 -0
- package/utils/deploy.mjs +3 -3
- package/utils/docs-finder-utils.mjs +26 -26
- package/utils/icon-map.mjs +26 -0
- package/{agents → utils}/load-config.mjs +2 -18
- package/utils/markdown-checker.mjs +5 -5
- package/agents/batch-docs-detail-generator.yaml +0 -19
- package/agents/check-structure-planning-result.yaml +0 -30
- package/agents/content-detail-generator.yaml +0 -50
- package/agents/feedback-refiner.yaml +0 -52
- package/agents/format-structure-plan.mjs +0 -25
- package/agents/reflective-structure-planner.yaml +0 -12
- package/agents/schema/structure-plan.yaml +0 -26
- package/agents/structure-planning.yaml +0 -58
- package/agents/team-publish-docs.yaml +0 -18
- package/agents/translate.yaml +0 -31
- package/prompts/document/custom-components.md +0 -104
- package/tests/README.md +0 -93
- package/tests/utils.test.mjs +0 -2067
- /package/agents/{exit.mjs → utils/exit.mjs} +0 -0
- /package/agents/{fs.mjs → utils/fs.mjs} +0 -0
- /package/agents/{save-output.mjs → utils/save-output.mjs} +0 -0
- /package/prompts/{document → detail}/d2-chart/official-examples.md +0 -0
- /package/prompts/{document → detail}/jsx/rules.md +0 -0
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test";
|
|
2
|
+
import transformDetailDatasources from "../../../agents/utils/transform-detail-datasources.mjs";
|
|
3
|
+
import * as utils from "../../../utils/utils.mjs";
|
|
4
|
+
|
|
5
|
+
describe("transformDetailDatasources utility", () => {
|
|
6
|
+
let normalizePathSpy;
|
|
7
|
+
let toRelativePathSpy;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
// Spy on utility functions
|
|
11
|
+
normalizePathSpy = spyOn(utils, "normalizePath").mockImplementation((path) =>
|
|
12
|
+
path?.replace(/\\/g, "/").replace(/^\.\//, ""),
|
|
13
|
+
);
|
|
14
|
+
toRelativePathSpy = spyOn(utils, "toRelativePath").mockImplementation((path) =>
|
|
15
|
+
path?.startsWith("/") ? path.substring(1) : path,
|
|
16
|
+
);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
// Restore all spies
|
|
21
|
+
normalizePathSpy?.mockRestore();
|
|
22
|
+
toRelativePathSpy?.mockRestore();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// BASIC FUNCTIONALITY TESTS
|
|
26
|
+
test("should transform simple datasources correctly", () => {
|
|
27
|
+
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
|
+
],
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const result = transformDetailDatasources(input);
|
|
36
|
+
|
|
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");
|
|
41
|
+
|
|
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
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("should handle single datasource", () => {
|
|
50
|
+
const input = {
|
|
51
|
+
sourceIds: ["/docs/readme.md"],
|
|
52
|
+
datasourcesList: [
|
|
53
|
+
{ sourceId: "/docs/readme.md", content: "# README\n\nProject documentation." },
|
|
54
|
+
],
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const result = transformDetailDatasources(input);
|
|
58
|
+
|
|
59
|
+
expect(result.detailDataSources).toBe(
|
|
60
|
+
"// sourceId: docs/readme.md\n# README\n\nProject documentation.\n",
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("should maintain order of sourceIds", () => {
|
|
65
|
+
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
|
+
],
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const result = transformDetailDatasources(input);
|
|
75
|
+
|
|
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
|
+
);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// PATH NORMALIZATION TESTS
|
|
84
|
+
test("should normalize paths correctly", () => {
|
|
85
|
+
normalizePathSpy.mockImplementation((path) => path?.replace(/\\/g, "/"));
|
|
86
|
+
|
|
87
|
+
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
|
+
],
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const result = transformDetailDatasources(input);
|
|
96
|
+
|
|
97
|
+
expect(normalizePathSpy).toHaveBeenCalledWith("docs\\guide.md");
|
|
98
|
+
expect(normalizePathSpy).toHaveBeenCalledWith("/docs/api.md");
|
|
99
|
+
expect(result.detailDataSources).toContain("Guide content");
|
|
100
|
+
expect(result.detailDataSources).toContain("API content");
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("should handle relative path conversion", () => {
|
|
104
|
+
toRelativePathSpy.mockImplementation((path) => path?.replace(/^\/+/, "").replace(/^\.\//, ""));
|
|
105
|
+
|
|
106
|
+
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
|
+
],
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const result = transformDetailDatasources(input);
|
|
115
|
+
|
|
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");
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// MISSING DATA TESTS
|
|
123
|
+
test("should filter out sourceIds not found in datasourcesList", () => {
|
|
124
|
+
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
|
+
],
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const result = transformDetailDatasources(input);
|
|
133
|
+
|
|
134
|
+
expect(result.detailDataSources).toContain("Guide content");
|
|
135
|
+
expect(result.detailDataSources).toContain("API content");
|
|
136
|
+
expect(result.detailDataSources).not.toContain("missing");
|
|
137
|
+
expect(result.detailDataSources.split("// sourceId:")).toHaveLength(3); // Empty first element + 2 sources
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("should handle empty sourceIds array", () => {
|
|
141
|
+
const input = {
|
|
142
|
+
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
|
+
};
|
|
159
|
+
|
|
160
|
+
const result = transformDetailDatasources(input);
|
|
161
|
+
|
|
162
|
+
expect(result.detailDataSources).toBe("");
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// NULL AND UNDEFINED HANDLING
|
|
166
|
+
test("should handle null sourceIds", () => {
|
|
167
|
+
const input = {
|
|
168
|
+
sourceIds: null,
|
|
169
|
+
datasourcesList: [{ sourceId: "/docs/guide.md", content: "Guide content" }],
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const result = transformDetailDatasources(input);
|
|
173
|
+
|
|
174
|
+
expect(result.detailDataSources).toBe("");
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
test("should handle undefined sourceIds", () => {
|
|
178
|
+
const input = {
|
|
179
|
+
sourceIds: undefined,
|
|
180
|
+
datasourcesList: [{ sourceId: "/docs/guide.md", content: "Guide content" }],
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const result = transformDetailDatasources(input);
|
|
184
|
+
|
|
185
|
+
expect(result.detailDataSources).toBe("");
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test("should handle null datasourcesList", () => {
|
|
189
|
+
const input = {
|
|
190
|
+
sourceIds: ["/docs/guide.md"],
|
|
191
|
+
datasourcesList: null,
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const result = transformDetailDatasources(input);
|
|
195
|
+
|
|
196
|
+
expect(result.detailDataSources).toBe("");
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test("should handle undefined datasourcesList", () => {
|
|
200
|
+
const input = {
|
|
201
|
+
sourceIds: ["/docs/guide.md"],
|
|
202
|
+
datasourcesList: undefined,
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const result = transformDetailDatasources(input);
|
|
206
|
+
|
|
207
|
+
expect(result.detailDataSources).toBe("");
|
|
208
|
+
});
|
|
209
|
+
|
|
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);
|
|
223
|
+
|
|
224
|
+
expect(result.detailDataSources).toBe(
|
|
225
|
+
"// sourceId: project/src/main.js\nconsole.log('Hello World');\nprocess.exit(0);\n",
|
|
226
|
+
);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
test("should handle empty content", () => {
|
|
230
|
+
const input = {
|
|
231
|
+
sourceIds: ["/docs/empty.md"],
|
|
232
|
+
datasourcesList: [{ sourceId: "/docs/empty.md", content: "" }],
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
const result = transformDetailDatasources(input);
|
|
236
|
+
|
|
237
|
+
// Empty content is falsy, so it gets filtered out
|
|
238
|
+
expect(result.detailDataSources).toBe("");
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test("should handle whitespace-only content", () => {
|
|
242
|
+
const input = {
|
|
243
|
+
sourceIds: ["/docs/whitespace.md"],
|
|
244
|
+
datasourcesList: [{ sourceId: "/docs/whitespace.md", content: " \n\t " }],
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
const result = transformDetailDatasources(input);
|
|
248
|
+
|
|
249
|
+
// Whitespace content is truthy, so it should be included
|
|
250
|
+
expect(result.detailDataSources).toBe("// sourceId: docs/whitespace.md\n \n\t \n");
|
|
251
|
+
});
|
|
252
|
+
|
|
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);
|
|
265
|
+
|
|
266
|
+
expect(result.detailDataSources).toContain("特殊字符.md");
|
|
267
|
+
expect(result.detailDataSources).toContain("中文标题");
|
|
268
|
+
expect(result.detailDataSources).toContain("@#$%^&*()");
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// LARGE DATA TESTS
|
|
272
|
+
test("should handle multiple large datasources", () => {
|
|
273
|
+
const largeContent = "A".repeat(1000);
|
|
274
|
+
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
|
+
})),
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
const result = transformDetailDatasources(input);
|
|
283
|
+
|
|
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
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// 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);
|
|
298
|
+
|
|
299
|
+
expect(result.detailDataSources).toBe(
|
|
300
|
+
"// sourceId: docs/guide.md\nGuide content\n" + "// sourceId: docs/guide.md\nGuide content\n",
|
|
301
|
+
);
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
test("should handle duplicate entries in datasourcesList", () => {
|
|
305
|
+
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
|
+
],
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
const result = transformDetailDatasources(input);
|
|
314
|
+
|
|
315
|
+
// Should use the last entry due to Object.fromEntries behavior
|
|
316
|
+
expect(result.detailDataSources).toBe("// sourceId: docs/guide.md\nSecond content\n");
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
// 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) => {
|
|
328
|
+
const result = transformDetailDatasources(input);
|
|
329
|
+
expect(result).toHaveProperty("detailDataSources");
|
|
330
|
+
expect(typeof result.detailDataSources).toBe("string");
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
// 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);
|
|
345
|
+
|
|
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
|
+
});
|
|
349
|
+
|
|
350
|
+
test("should handle datasource with null sourceId", () => {
|
|
351
|
+
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
|
+
],
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
const result = transformDetailDatasources(input);
|
|
360
|
+
|
|
361
|
+
expect(result.detailDataSources).toBe("// sourceId: docs/guide.md\nValid content\n");
|
|
362
|
+
});
|
|
363
|
+
});
|