@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.
- package/CHANGELOG.md +25 -0
- package/agents/clear/choose-contents.mjs +14 -1
- package/agents/clear/clear-media-description.mjs +129 -0
- package/agents/clear/index.yaml +3 -1
- package/agents/evaluate/code-snippet.mjs +28 -24
- package/agents/evaluate/document-structure.yaml +0 -4
- package/agents/evaluate/document.yaml +1 -5
- package/agents/generate/index.yaml +1 -0
- package/agents/init/index.mjs +10 -0
- package/agents/media/batch-generate-media-description.yaml +44 -0
- package/agents/media/generate-media-description.yaml +47 -0
- package/agents/media/load-media-description.mjs +238 -0
- package/agents/publish/index.yaml +4 -0
- package/agents/publish/publish-docs.mjs +77 -5
- package/agents/publish/translate-meta.mjs +103 -0
- package/agents/update/generate-document.yaml +30 -28
- package/agents/update/index.yaml +1 -0
- package/agents/update/update-document-detail.yaml +3 -1
- package/agents/utils/load-sources.mjs +103 -53
- package/agents/utils/update-branding.mjs +69 -0
- package/aigne.yaml +6 -0
- package/assets/report-template/report.html +34 -34
- package/package.json +17 -2
- package/prompts/common/document/role-and-personality.md +3 -1
- package/prompts/detail/d2-diagram/guide.md +7 -1
- package/prompts/detail/d2-diagram/user-prompt.md +3 -0
- package/prompts/detail/generate/system-prompt.md +6 -7
- package/prompts/detail/generate/user-prompt.md +12 -3
- package/prompts/detail/update/user-prompt.md +0 -2
- package/prompts/evaluate/document-structure.md +6 -7
- package/prompts/evaluate/document.md +16 -25
- package/prompts/media/media-description/system-prompt.md +35 -0
- package/prompts/media/media-description/user-prompt.md +8 -0
- package/prompts/structure/update/user-prompt.md +0 -4
- package/utils/constants/index.mjs +0 -107
- package/utils/file-utils.mjs +86 -0
- package/utils/markdown-checker.mjs +0 -20
- package/utils/request.mjs +7 -0
- package/utils/upload-files.mjs +231 -0
- package/utils/utils.mjs +11 -1
- package/.aigne/doc-smith/config.yaml +0 -77
- package/.aigne/doc-smith/history.yaml +0 -37
- package/.aigne/doc-smith/output/structure-plan.json +0 -162
- package/.aigne/doc-smith/preferences.yml +0 -97
- package/.aigne/doc-smith/upload-cache.yaml +0 -1893
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -28
- package/.github/workflows/ci.yml +0 -54
- package/.github/workflows/create-release-pr.yaml +0 -21
- package/.github/workflows/publish-docs.yml +0 -65
- package/.github/workflows/release.yml +0 -49
- package/.github/workflows/reviewer.yml +0 -54
- package/.release-please-manifest.json +0 -3
- package/RELEASE.md +0 -9
- package/assets/screenshots/doc-complete-setup.png +0 -0
- package/assets/screenshots/doc-generate-docs.png +0 -0
- package/assets/screenshots/doc-generate.png +0 -0
- package/assets/screenshots/doc-generated-successfully.png +0 -0
- package/assets/screenshots/doc-publish.png +0 -0
- package/assets/screenshots/doc-regenerate.png +0 -0
- package/assets/screenshots/doc-translate-langs.png +0 -0
- package/assets/screenshots/doc-translate.png +0 -0
- package/assets/screenshots/doc-update.png +0 -0
- package/biome.json +0 -73
- package/codecov.yml +0 -15
- package/docs/_sidebar.md +0 -15
- package/docs/configuration-initial-setup.ja.md +0 -179
- package/docs/configuration-initial-setup.md +0 -179
- package/docs/configuration-initial-setup.zh-TW.md +0 -179
- package/docs/configuration-initial-setup.zh.md +0 -179
- package/docs/configuration-managing-preferences.ja.md +0 -100
- package/docs/configuration-managing-preferences.md +0 -100
- package/docs/configuration-managing-preferences.zh-TW.md +0 -100
- package/docs/configuration-managing-preferences.zh.md +0 -100
- package/docs/configuration.ja.md +0 -96
- package/docs/configuration.md +0 -96
- package/docs/configuration.zh-TW.md +0 -96
- package/docs/configuration.zh.md +0 -96
- package/docs/getting-started.ja.md +0 -88
- package/docs/getting-started.md +0 -88
- package/docs/getting-started.zh-TW.md +0 -88
- package/docs/getting-started.zh.md +0 -88
- package/docs/guides-cleaning-up.ja.md +0 -51
- package/docs/guides-cleaning-up.md +0 -51
- package/docs/guides-cleaning-up.zh-TW.md +0 -51
- package/docs/guides-cleaning-up.zh.md +0 -51
- package/docs/guides-evaluating-documents.ja.md +0 -66
- package/docs/guides-evaluating-documents.md +0 -66
- package/docs/guides-evaluating-documents.zh-TW.md +0 -66
- package/docs/guides-evaluating-documents.zh.md +0 -66
- package/docs/guides-generating-documentation.ja.md +0 -151
- package/docs/guides-generating-documentation.md +0 -151
- package/docs/guides-generating-documentation.zh-TW.md +0 -151
- package/docs/guides-generating-documentation.zh.md +0 -151
- package/docs/guides-interactive-chat.ja.md +0 -85
- package/docs/guides-interactive-chat.md +0 -85
- package/docs/guides-interactive-chat.zh-TW.md +0 -85
- package/docs/guides-interactive-chat.zh.md +0 -85
- package/docs/guides-managing-history.ja.md +0 -48
- package/docs/guides-managing-history.md +0 -48
- package/docs/guides-managing-history.zh-TW.md +0 -48
- package/docs/guides-managing-history.zh.md +0 -48
- package/docs/guides-publishing-your-docs.ja.md +0 -78
- package/docs/guides-publishing-your-docs.md +0 -78
- package/docs/guides-publishing-your-docs.zh-TW.md +0 -78
- package/docs/guides-publishing-your-docs.zh.md +0 -78
- package/docs/guides-translating-documentation.ja.md +0 -95
- package/docs/guides-translating-documentation.md +0 -95
- package/docs/guides-translating-documentation.zh-TW.md +0 -95
- package/docs/guides-translating-documentation.zh.md +0 -95
- package/docs/guides-updating-documentation.ja.md +0 -77
- package/docs/guides-updating-documentation.md +0 -77
- package/docs/guides-updating-documentation.zh-TW.md +0 -77
- package/docs/guides-updating-documentation.zh.md +0 -77
- package/docs/guides.ja.md +0 -32
- package/docs/guides.md +0 -32
- package/docs/guides.zh-TW.md +0 -32
- package/docs/guides.zh.md +0 -32
- package/docs/overview.ja.md +0 -61
- package/docs/overview.md +0 -61
- package/docs/overview.zh-TW.md +0 -61
- package/docs/overview.zh.md +0 -61
- package/docs/release-notes.ja.md +0 -255
- package/docs/release-notes.md +0 -255
- package/docs/release-notes.zh-TW.md +0 -255
- package/docs/release-notes.zh.md +0 -255
- package/media.md +0 -19
- package/prompts/common/afs/afs-tools-usage.md +0 -5
- package/prompts/common/afs/use-afs-instruction.md +0 -1
- package/release-please-config.json +0 -14
- package/tests/agents/chat/chat.test.mjs +0 -46
- package/tests/agents/clear/choose-contents.test.mjs +0 -284
- package/tests/agents/clear/clear-auth-tokens.test.mjs +0 -268
- package/tests/agents/clear/clear-document-config.test.mjs +0 -167
- package/tests/agents/clear/clear-document-structure.test.mjs +0 -380
- package/tests/agents/clear/clear-generated-docs.test.mjs +0 -222
- package/tests/agents/evaluate/code-snippet.test.mjs +0 -163
- package/tests/agents/evaluate/fixtures/api-services.md +0 -87
- package/tests/agents/evaluate/fixtures/js-sdk.md +0 -94
- package/tests/agents/evaluate/generate-report.test.mjs +0 -312
- package/tests/agents/generate/check-document-structure.test.mjs +0 -45
- package/tests/agents/generate/check-need-generate-structure.test.mjs +0 -279
- package/tests/agents/generate/document-structure-tools/add-document.test.mjs +0 -449
- package/tests/agents/generate/document-structure-tools/delete-document.test.mjs +0 -410
- package/tests/agents/generate/document-structure-tools/generate-sub-structure.test.mjs +0 -277
- package/tests/agents/generate/document-structure-tools/move-document.test.mjs +0 -476
- package/tests/agents/generate/document-structure-tools/update-document.test.mjs +0 -548
- package/tests/agents/generate/generate-structure.test.mjs +0 -45
- package/tests/agents/generate/user-review-document-structure.test.mjs +0 -319
- package/tests/agents/history/view.test.mjs +0 -97
- package/tests/agents/init/init.test.mjs +0 -1657
- package/tests/agents/prefs/prefs.test.mjs +0 -431
- package/tests/agents/publish/publish-docs.test.mjs +0 -787
- package/tests/agents/translate/choose-language.test.mjs +0 -311
- package/tests/agents/translate/translate-document.test.mjs +0 -51
- package/tests/agents/update/check-document.test.mjs +0 -463
- package/tests/agents/update/check-update-is-single.test.mjs +0 -300
- package/tests/agents/update/document-tools/update-document-content.test.mjs +0 -329
- package/tests/agents/update/generate-document.test.mjs +0 -51
- package/tests/agents/update/save-and-translate-document.test.mjs +0 -369
- package/tests/agents/update/user-review-document.test.mjs +0 -582
- package/tests/agents/utils/action-success.test.mjs +0 -54
- package/tests/agents/utils/check-detail-result.test.mjs +0 -743
- package/tests/agents/utils/check-feedback-refiner.test.mjs +0 -478
- package/tests/agents/utils/choose-docs.test.mjs +0 -406
- package/tests/agents/utils/exit.test.mjs +0 -70
- package/tests/agents/utils/feedback-refiner.test.mjs +0 -51
- package/tests/agents/utils/find-item-by-path.test.mjs +0 -517
- package/tests/agents/utils/find-user-preferences-by-path.test.mjs +0 -382
- package/tests/agents/utils/format-document-structure.test.mjs +0 -364
- package/tests/agents/utils/fs.test.mjs +0 -267
- package/tests/agents/utils/load-sources.test.mjs +0 -1470
- package/tests/agents/utils/save-docs.test.mjs +0 -109
- package/tests/agents/utils/save-output.test.mjs +0 -315
- package/tests/agents/utils/save-single-doc.test.mjs +0 -364
- package/tests/agents/utils/transform-detail-datasources.test.mjs +0 -320
- package/tests/utils/auth-utils.test.mjs +0 -596
- package/tests/utils/blocklet.test.mjs +0 -336
- package/tests/utils/conflict-detector.test.mjs +0 -355
- package/tests/utils/constants.test.mjs +0 -295
- package/tests/utils/d2-utils.test.mjs +0 -437
- package/tests/utils/deploy.test.mjs +0 -399
- package/tests/utils/docs-finder-utils.test.mjs +0 -650
- package/tests/utils/file-utils.test.mjs +0 -521
- package/tests/utils/history-utils.test.mjs +0 -206
- package/tests/utils/kroki-utils.test.mjs +0 -646
- package/tests/utils/linter/fixtures/css/keyword-error.css +0 -1
- package/tests/utils/linter/fixtures/css/missing-semicolon.css +0 -1
- package/tests/utils/linter/fixtures/css/syntax-error.css +0 -1
- package/tests/utils/linter/fixtures/css/undeclare-variable.css +0 -1
- package/tests/utils/linter/fixtures/css/unused-variable.css +0 -2
- package/tests/utils/linter/fixtures/css/valid-code.css +0 -1
- package/tests/utils/linter/fixtures/dockerfile/keyword-error.dockerfile +0 -1
- package/tests/utils/linter/fixtures/dockerfile/missing-semicolon.dockerfile +0 -2
- package/tests/utils/linter/fixtures/dockerfile/syntax-error.dockerfile +0 -2
- package/tests/utils/linter/fixtures/dockerfile/undeclare-variable.dockerfile +0 -1
- package/tests/utils/linter/fixtures/dockerfile/unused-variable.dockerfile +0 -1
- package/tests/utils/linter/fixtures/dockerfile/valid-code.dockerfile +0 -2
- package/tests/utils/linter/fixtures/go/keyword-error.go +0 -5
- package/tests/utils/linter/fixtures/go/missing-semicolon.go +0 -5
- package/tests/utils/linter/fixtures/go/syntax-error.go +0 -6
- package/tests/utils/linter/fixtures/go/undeclare-variable.go +0 -5
- package/tests/utils/linter/fixtures/go/unused-variable.go +0 -5
- package/tests/utils/linter/fixtures/go/valid-code.go +0 -7
- package/tests/utils/linter/fixtures/js/keyword-error.js +0 -3
- package/tests/utils/linter/fixtures/js/missing-semicolon.js +0 -6
- package/tests/utils/linter/fixtures/js/syntax-error.js +0 -4
- package/tests/utils/linter/fixtures/js/undeclare-variable.js +0 -3
- package/tests/utils/linter/fixtures/js/unused-variable.js +0 -7
- package/tests/utils/linter/fixtures/js/valid-code.js +0 -15
- package/tests/utils/linter/fixtures/json/keyword-error.json +0 -1
- package/tests/utils/linter/fixtures/json/missing-semicolon.json +0 -1
- package/tests/utils/linter/fixtures/json/syntax-error.json +0 -1
- package/tests/utils/linter/fixtures/json/undeclare-variable.json +0 -1
- package/tests/utils/linter/fixtures/json/unused-variable.json +0 -1
- package/tests/utils/linter/fixtures/json/valid-code.json +0 -1
- package/tests/utils/linter/fixtures/jsx/keyword-error.jsx +0 -5
- package/tests/utils/linter/fixtures/jsx/missing-semicolon.jsx +0 -5
- package/tests/utils/linter/fixtures/jsx/syntax-error.jsx +0 -5
- package/tests/utils/linter/fixtures/jsx/undeclare-variable.jsx +0 -5
- package/tests/utils/linter/fixtures/jsx/unused-variable.jsx +0 -4
- package/tests/utils/linter/fixtures/jsx/valid-code.jsx +0 -5
- package/tests/utils/linter/fixtures/python/keyword-error.py +0 -3
- package/tests/utils/linter/fixtures/python/missing-semicolon.py +0 -2
- package/tests/utils/linter/fixtures/python/syntax-error.py +0 -3
- package/tests/utils/linter/fixtures/python/undeclare-variable.py +0 -3
- package/tests/utils/linter/fixtures/python/unused-variable.py +0 -6
- package/tests/utils/linter/fixtures/python/valid-code.py +0 -12
- package/tests/utils/linter/fixtures/ruby/keyword-error.rb +0 -2
- package/tests/utils/linter/fixtures/ruby/missing-semicolon.rb +0 -1
- package/tests/utils/linter/fixtures/ruby/syntax-error.rb +0 -2
- package/tests/utils/linter/fixtures/ruby/undeclare-variable.rb +0 -1
- package/tests/utils/linter/fixtures/ruby/unused-variable.rb +0 -2
- package/tests/utils/linter/fixtures/ruby/valid-code.rb +0 -1
- package/tests/utils/linter/fixtures/sass/keyword-error.sass +0 -2
- package/tests/utils/linter/fixtures/sass/missing-semicolon.sass +0 -3
- package/tests/utils/linter/fixtures/sass/syntax-error.sass +0 -3
- package/tests/utils/linter/fixtures/sass/undeclare-variable.sass +0 -2
- package/tests/utils/linter/fixtures/sass/unused-variable.sass +0 -4
- package/tests/utils/linter/fixtures/sass/valid-code.sass +0 -2
- package/tests/utils/linter/fixtures/scss/keyword-error.scss +0 -1
- package/tests/utils/linter/fixtures/scss/missing-semicolon.scss +0 -1
- package/tests/utils/linter/fixtures/scss/syntax-error.scss +0 -1
- package/tests/utils/linter/fixtures/scss/undeclare-variable.scss +0 -1
- package/tests/utils/linter/fixtures/scss/unused-variable.scss +0 -2
- package/tests/utils/linter/fixtures/scss/valid-code.scss +0 -1
- package/tests/utils/linter/fixtures/shell/keyword-error.sh +0 -5
- package/tests/utils/linter/fixtures/shell/missing-semicolon.sh +0 -3
- package/tests/utils/linter/fixtures/shell/syntax-error.sh +0 -4
- package/tests/utils/linter/fixtures/shell/undeclare-variable.sh +0 -3
- package/tests/utils/linter/fixtures/shell/unused-variable.sh +0 -4
- package/tests/utils/linter/fixtures/shell/valid-code.sh +0 -3
- package/tests/utils/linter/fixtures/ts/keyword-error.ts +0 -1
- package/tests/utils/linter/fixtures/ts/missing-semicolon.ts +0 -1
- package/tests/utils/linter/fixtures/ts/syntax-error.ts +0 -1
- package/tests/utils/linter/fixtures/ts/undeclare-variable.ts +0 -1
- package/tests/utils/linter/fixtures/ts/unused-variable.ts +0 -3
- package/tests/utils/linter/fixtures/ts/valid-code.ts +0 -3
- package/tests/utils/linter/fixtures/tsx/keyword-error.tsx +0 -5
- package/tests/utils/linter/fixtures/tsx/missing-semicolon.tsx +0 -5
- package/tests/utils/linter/fixtures/tsx/syntax-error.tsx +0 -5
- package/tests/utils/linter/fixtures/tsx/undeclare-variable.tsx +0 -6
- package/tests/utils/linter/fixtures/tsx/unused-variable.tsx +0 -6
- package/tests/utils/linter/fixtures/tsx/valid-code.tsx +0 -5
- package/tests/utils/linter/fixtures/vue/keyword-error.vue +0 -6
- package/tests/utils/linter/fixtures/vue/missing-semicolon.vue +0 -6
- package/tests/utils/linter/fixtures/vue/syntax-error.vue +0 -6
- package/tests/utils/linter/fixtures/vue/undeclare-variable.vue +0 -6
- package/tests/utils/linter/fixtures/vue/unused-variable.vue +0 -7
- package/tests/utils/linter/fixtures/vue/valid-code.vue +0 -6
- package/tests/utils/linter/fixtures/yaml/keyword-error.yml +0 -1
- package/tests/utils/linter/fixtures/yaml/missing-semicolon.yml +0 -2
- package/tests/utils/linter/fixtures/yaml/syntax-error.yml +0 -1
- package/tests/utils/linter/fixtures/yaml/undeclare-variable.yml +0 -1
- package/tests/utils/linter/fixtures/yaml/unused-variable.yml +0 -2
- package/tests/utils/linter/fixtures/yaml/valid-code.yml +0 -3
- package/tests/utils/linter/index.test.mjs +0 -440
- package/tests/utils/linter/scan-results.mjs +0 -42
- package/tests/utils/load-config.test.mjs +0 -141
- package/tests/utils/markdown/index.test.mjs +0 -478
- package/tests/utils/mermaid-validator.test.mjs +0 -541
- package/tests/utils/mock-chat-model.mjs +0 -12
- package/tests/utils/preferences-utils.test.mjs +0 -465
- package/tests/utils/save-value-to-config.test.mjs +0 -483
- package/tests/utils/utils.test.mjs +0 -941
|
@@ -1,364 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test";
|
|
2
|
-
import saveSingleDoc from "../../../agents/utils/save-single-doc.mjs";
|
|
3
|
-
import * as mermaidWorkerPool from "../../../utils/mermaid-worker-pool.mjs";
|
|
4
|
-
import * as utils from "../../../utils/utils.mjs";
|
|
5
|
-
|
|
6
|
-
describe("saveSingleDoc utility", () => {
|
|
7
|
-
let consoleWarnSpy;
|
|
8
|
-
let shutdownMermaidWorkerPoolSpy;
|
|
9
|
-
let saveDocWithTranslationsSpy;
|
|
10
|
-
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
shutdownMermaidWorkerPoolSpy = spyOn(
|
|
13
|
-
mermaidWorkerPool,
|
|
14
|
-
"shutdownMermaidWorkerPool",
|
|
15
|
-
).mockResolvedValue();
|
|
16
|
-
saveDocWithTranslationsSpy = spyOn(utils, "saveDocWithTranslations").mockResolvedValue({
|
|
17
|
-
success: true,
|
|
18
|
-
});
|
|
19
|
-
consoleWarnSpy = spyOn(console, "warn").mockImplementation(() => {});
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
afterEach(() => {
|
|
23
|
-
// Restore all spies
|
|
24
|
-
shutdownMermaidWorkerPoolSpy?.mockRestore();
|
|
25
|
-
saveDocWithTranslationsSpy?.mockRestore();
|
|
26
|
-
consoleWarnSpy?.mockRestore();
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
// BASIC FUNCTIONALITY TESTS
|
|
30
|
-
test("should save document without showing message", async () => {
|
|
31
|
-
const options = {
|
|
32
|
-
path: "/docs/guide.md",
|
|
33
|
-
content: "# User Guide\n\nThis is a guide.",
|
|
34
|
-
docsDir: "/project/docs",
|
|
35
|
-
translates: [],
|
|
36
|
-
labels: {},
|
|
37
|
-
locale: "en",
|
|
38
|
-
isTranslate: false,
|
|
39
|
-
isShowMessage: false,
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const result = await saveSingleDoc(options);
|
|
43
|
-
|
|
44
|
-
expect(saveDocWithTranslationsSpy).toHaveBeenCalledWith({
|
|
45
|
-
path: "/docs/guide.md",
|
|
46
|
-
content: "# User Guide\n\nThis is a guide.",
|
|
47
|
-
docsDir: "/project/docs",
|
|
48
|
-
translates: [],
|
|
49
|
-
labels: {},
|
|
50
|
-
locale: "en",
|
|
51
|
-
isTranslate: false,
|
|
52
|
-
});
|
|
53
|
-
expect(shutdownMermaidWorkerPoolSpy).not.toHaveBeenCalled();
|
|
54
|
-
expect(result).toEqual({});
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
test("should save document with success message for regular update", async () => {
|
|
58
|
-
const options = {
|
|
59
|
-
path: "/docs/api.md",
|
|
60
|
-
content: "# API Reference",
|
|
61
|
-
docsDir: "/project/docs",
|
|
62
|
-
translates: ["zh", "ja"],
|
|
63
|
-
labels: { api: "API" },
|
|
64
|
-
locale: "en",
|
|
65
|
-
isTranslate: false,
|
|
66
|
-
isShowMessage: true,
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
const result = await saveSingleDoc(options);
|
|
70
|
-
|
|
71
|
-
expect(saveDocWithTranslationsSpy).toHaveBeenCalledWith({
|
|
72
|
-
path: "/docs/api.md",
|
|
73
|
-
content: "# API Reference",
|
|
74
|
-
docsDir: "/project/docs",
|
|
75
|
-
translates: ["zh", "ja"],
|
|
76
|
-
labels: { api: "API" },
|
|
77
|
-
locale: "en",
|
|
78
|
-
isTranslate: false,
|
|
79
|
-
});
|
|
80
|
-
expect(shutdownMermaidWorkerPoolSpy).toHaveBeenCalled();
|
|
81
|
-
expect(result).toEqual({
|
|
82
|
-
message: "✅ Document updated successfully",
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
test("should save document with success message for translation", async () => {
|
|
87
|
-
const options = {
|
|
88
|
-
path: "/docs/zh/guide.md",
|
|
89
|
-
content: "# 用户指南\n\n这是一个指南。",
|
|
90
|
-
docsDir: "/project/docs",
|
|
91
|
-
translates: ["zh", "ja"],
|
|
92
|
-
labels: { guide: "指南" },
|
|
93
|
-
locale: "zh",
|
|
94
|
-
isTranslate: true,
|
|
95
|
-
isShowMessage: true,
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
const result = await saveSingleDoc(options);
|
|
99
|
-
|
|
100
|
-
expect(saveDocWithTranslationsSpy).toHaveBeenCalledWith({
|
|
101
|
-
path: "/docs/zh/guide.md",
|
|
102
|
-
content: "# 用户指南\n\n这是一个指南。",
|
|
103
|
-
docsDir: "/project/docs",
|
|
104
|
-
translates: ["zh", "ja"],
|
|
105
|
-
labels: { guide: "指南" },
|
|
106
|
-
locale: "zh",
|
|
107
|
-
isTranslate: true,
|
|
108
|
-
});
|
|
109
|
-
expect(shutdownMermaidWorkerPoolSpy).toHaveBeenCalled();
|
|
110
|
-
expect(result).toEqual({
|
|
111
|
-
message: "✅ Translation completed successfully",
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
// DEFAULT VALUES TESTS
|
|
116
|
-
test("should use default values for optional parameters", async () => {
|
|
117
|
-
const options = {
|
|
118
|
-
path: "/docs/minimal.md",
|
|
119
|
-
content: "# Minimal",
|
|
120
|
-
docsDir: "/docs",
|
|
121
|
-
translates: [],
|
|
122
|
-
labels: {},
|
|
123
|
-
locale: "en",
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
const result = await saveSingleDoc(options);
|
|
127
|
-
|
|
128
|
-
expect(saveDocWithTranslationsSpy).toHaveBeenCalledWith({
|
|
129
|
-
path: "/docs/minimal.md",
|
|
130
|
-
content: "# Minimal",
|
|
131
|
-
docsDir: "/docs",
|
|
132
|
-
translates: [],
|
|
133
|
-
labels: {},
|
|
134
|
-
locale: "en",
|
|
135
|
-
isTranslate: false, // Default value
|
|
136
|
-
});
|
|
137
|
-
expect(shutdownMermaidWorkerPoolSpy).not.toHaveBeenCalled();
|
|
138
|
-
expect(result).toEqual({});
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
test("should handle explicit false values", async () => {
|
|
142
|
-
const options = {
|
|
143
|
-
path: "/docs/explicit.md",
|
|
144
|
-
content: "# Explicit",
|
|
145
|
-
docsDir: "/docs",
|
|
146
|
-
translates: [],
|
|
147
|
-
labels: {},
|
|
148
|
-
locale: "en",
|
|
149
|
-
isTranslate: false,
|
|
150
|
-
isShowMessage: false,
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
const result = await saveSingleDoc(options);
|
|
154
|
-
|
|
155
|
-
expect(saveDocWithTranslationsSpy).toHaveBeenCalledWith(
|
|
156
|
-
expect.objectContaining({
|
|
157
|
-
isTranslate: false,
|
|
158
|
-
}),
|
|
159
|
-
);
|
|
160
|
-
expect(result).toEqual({});
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
// MERMAID WORKER POOL SHUTDOWN TESTS
|
|
164
|
-
test("should handle mermaid worker pool shutdown error gracefully", async () => {
|
|
165
|
-
const shutdownError = new Error("Worker pool shutdown failed");
|
|
166
|
-
shutdownMermaidWorkerPoolSpy.mockRejectedValue(shutdownError);
|
|
167
|
-
|
|
168
|
-
const options = {
|
|
169
|
-
path: "/docs/with-error.md",
|
|
170
|
-
content: "# Document with shutdown error",
|
|
171
|
-
docsDir: "/docs",
|
|
172
|
-
translates: [],
|
|
173
|
-
labels: {},
|
|
174
|
-
locale: "en",
|
|
175
|
-
isTranslate: false,
|
|
176
|
-
isShowMessage: true,
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
const result = await saveSingleDoc(options);
|
|
180
|
-
|
|
181
|
-
expect(shutdownMermaidWorkerPoolSpy).toHaveBeenCalled();
|
|
182
|
-
expect(consoleWarnSpy).toHaveBeenCalledWith(
|
|
183
|
-
"Failed to shutdown mermaid worker pool:",
|
|
184
|
-
"Worker pool shutdown failed",
|
|
185
|
-
);
|
|
186
|
-
expect(result).toEqual({
|
|
187
|
-
message: "✅ Document updated successfully",
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
test("should handle mermaid worker pool shutdown error for translation", async () => {
|
|
192
|
-
const shutdownError = new Error("Pool cleanup failed");
|
|
193
|
-
shutdownMermaidWorkerPoolSpy.mockRejectedValue(shutdownError);
|
|
194
|
-
|
|
195
|
-
const options = {
|
|
196
|
-
path: "/docs/zh/with-error.md",
|
|
197
|
-
content: "# 带错误的文档",
|
|
198
|
-
docsDir: "/docs",
|
|
199
|
-
translates: ["zh"],
|
|
200
|
-
labels: {},
|
|
201
|
-
locale: "zh",
|
|
202
|
-
isTranslate: true,
|
|
203
|
-
isShowMessage: true,
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
const result = await saveSingleDoc(options);
|
|
207
|
-
|
|
208
|
-
expect(consoleWarnSpy).toHaveBeenCalledWith(
|
|
209
|
-
"Failed to shutdown mermaid worker pool:",
|
|
210
|
-
"Pool cleanup failed",
|
|
211
|
-
);
|
|
212
|
-
expect(result).toEqual({
|
|
213
|
-
message: "✅ Translation completed successfully",
|
|
214
|
-
});
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
// COMPREHENSIVE PARAMETER TESTS
|
|
218
|
-
test("should pass all parameters correctly to saveDocWithTranslations", async () => {
|
|
219
|
-
const complexOptions = {
|
|
220
|
-
path: "/docs/complex/nested/file.md",
|
|
221
|
-
content: "# Complex Document\n\nWith multiple sections.",
|
|
222
|
-
docsDir: "/project/documentation",
|
|
223
|
-
translates: ["zh-CN", "ja-JP", "ko-KR"],
|
|
224
|
-
labels: {
|
|
225
|
-
title: "标题",
|
|
226
|
-
section: "部分",
|
|
227
|
-
example: "例子",
|
|
228
|
-
},
|
|
229
|
-
locale: "zh-CN",
|
|
230
|
-
isTranslate: true,
|
|
231
|
-
isShowMessage: false,
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
await saveSingleDoc(complexOptions);
|
|
235
|
-
|
|
236
|
-
expect(saveDocWithTranslationsSpy).toHaveBeenCalledWith({
|
|
237
|
-
path: "/docs/complex/nested/file.md",
|
|
238
|
-
content: "# Complex Document\n\nWith multiple sections.",
|
|
239
|
-
docsDir: "/project/documentation",
|
|
240
|
-
translates: ["zh-CN", "ja-JP", "ko-KR"],
|
|
241
|
-
labels: {
|
|
242
|
-
title: "标题",
|
|
243
|
-
section: "部分",
|
|
244
|
-
example: "例子",
|
|
245
|
-
},
|
|
246
|
-
locale: "zh-CN",
|
|
247
|
-
isTranslate: true,
|
|
248
|
-
});
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
// EDGE CASES
|
|
252
|
-
test("should handle empty content", async () => {
|
|
253
|
-
const options = {
|
|
254
|
-
path: "/docs/empty.md",
|
|
255
|
-
content: "",
|
|
256
|
-
docsDir: "/docs",
|
|
257
|
-
translates: [],
|
|
258
|
-
labels: {},
|
|
259
|
-
locale: "en",
|
|
260
|
-
isShowMessage: true,
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
const result = await saveSingleDoc(options);
|
|
264
|
-
|
|
265
|
-
expect(saveDocWithTranslationsSpy).toHaveBeenCalledWith(
|
|
266
|
-
expect.objectContaining({
|
|
267
|
-
content: "",
|
|
268
|
-
}),
|
|
269
|
-
);
|
|
270
|
-
expect(result).toEqual({
|
|
271
|
-
message: "✅ Document updated successfully",
|
|
272
|
-
});
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
test("should handle empty translations array", async () => {
|
|
276
|
-
const options = {
|
|
277
|
-
path: "/docs/no-translations.md",
|
|
278
|
-
content: "# No Translations",
|
|
279
|
-
docsDir: "/docs",
|
|
280
|
-
translates: [],
|
|
281
|
-
labels: {},
|
|
282
|
-
locale: "en",
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
await saveSingleDoc(options);
|
|
286
|
-
|
|
287
|
-
expect(saveDocWithTranslationsSpy).toHaveBeenCalledWith(
|
|
288
|
-
expect.objectContaining({
|
|
289
|
-
translates: [],
|
|
290
|
-
}),
|
|
291
|
-
);
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
test("should handle empty labels object", async () => {
|
|
295
|
-
const options = {
|
|
296
|
-
path: "/docs/no-labels.md",
|
|
297
|
-
content: "# No Labels",
|
|
298
|
-
docsDir: "/docs",
|
|
299
|
-
translates: ["zh"],
|
|
300
|
-
labels: {},
|
|
301
|
-
locale: "en",
|
|
302
|
-
};
|
|
303
|
-
|
|
304
|
-
await saveSingleDoc(options);
|
|
305
|
-
|
|
306
|
-
expect(saveDocWithTranslationsSpy).toHaveBeenCalledWith(
|
|
307
|
-
expect.objectContaining({
|
|
308
|
-
labels: {},
|
|
309
|
-
}),
|
|
310
|
-
);
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
// SPECIAL CHARACTERS AND PATHS
|
|
314
|
-
test("should handle paths with special characters", async () => {
|
|
315
|
-
const options = {
|
|
316
|
-
path: "/docs/特殊字符/file with spaces.md",
|
|
317
|
-
content: "# Special Characters 特殊字符",
|
|
318
|
-
docsDir: "/project/docs",
|
|
319
|
-
translates: ["zh-CN"],
|
|
320
|
-
labels: { special: "特殊" },
|
|
321
|
-
locale: "zh-CN",
|
|
322
|
-
isTranslate: true,
|
|
323
|
-
};
|
|
324
|
-
|
|
325
|
-
await saveSingleDoc(options);
|
|
326
|
-
|
|
327
|
-
expect(saveDocWithTranslationsSpy).toHaveBeenCalledWith(
|
|
328
|
-
expect.objectContaining({
|
|
329
|
-
path: "/docs/特殊字符/file with spaces.md",
|
|
330
|
-
content: "# Special Characters 特殊字符",
|
|
331
|
-
labels: { special: "特殊" },
|
|
332
|
-
locale: "zh-CN",
|
|
333
|
-
}),
|
|
334
|
-
);
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
// RETURN VALUE CONSISTENCY
|
|
338
|
-
test("should always return object structure", async () => {
|
|
339
|
-
const withoutMessage = await saveSingleDoc({
|
|
340
|
-
path: "/docs/test1.md",
|
|
341
|
-
content: "Test",
|
|
342
|
-
docsDir: "/docs",
|
|
343
|
-
translates: [],
|
|
344
|
-
labels: {},
|
|
345
|
-
locale: "en",
|
|
346
|
-
isShowMessage: false,
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
const withMessage = await saveSingleDoc({
|
|
350
|
-
path: "/docs/test2.md",
|
|
351
|
-
content: "Test",
|
|
352
|
-
docsDir: "/docs",
|
|
353
|
-
translates: [],
|
|
354
|
-
labels: {},
|
|
355
|
-
locale: "en",
|
|
356
|
-
isShowMessage: true,
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
expect(typeof withoutMessage).toBe("object");
|
|
360
|
-
expect(typeof withMessage).toBe("object");
|
|
361
|
-
expect(withoutMessage).toEqual({});
|
|
362
|
-
expect(withMessage).toHaveProperty("message");
|
|
363
|
-
});
|
|
364
|
-
});
|
|
@@ -1,320 +0,0 @@
|
|
|
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";
|
|
5
|
-
import transformDetailDatasources from "../../../agents/utils/transform-detail-datasources.mjs";
|
|
6
|
-
import * as utils from "../../../utils/utils.mjs";
|
|
7
|
-
|
|
8
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
-
|
|
10
|
-
describe("transformDetailDatasources utility", () => {
|
|
11
|
-
let normalizePathSpy;
|
|
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 });
|
|
20
|
-
|
|
21
|
-
// Spy on utility functions
|
|
22
|
-
normalizePathSpy = spyOn(utils, "normalizePath").mockImplementation((path) =>
|
|
23
|
-
path?.replace(/\\/g, "/").replace(/^\.\//, ""),
|
|
24
|
-
);
|
|
25
|
-
toRelativePathSpy = spyOn(utils, "toRelativePath").mockImplementation((path) =>
|
|
26
|
-
path?.startsWith("/") ? path.substring(1) : path,
|
|
27
|
-
);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
afterEach(async () => {
|
|
31
|
-
// Restore all spies
|
|
32
|
-
normalizePathSpy?.mockRestore();
|
|
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
|
-
}
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
// BASIC FUNCTIONALITY TESTS
|
|
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
|
-
|
|
54
|
-
const input = {
|
|
55
|
-
sourceIds: [guidePath, apiPath],
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const result = transformDetailDatasources(input);
|
|
59
|
-
|
|
60
|
-
expect(normalizePathSpy).toHaveBeenCalledWith(guidePath);
|
|
61
|
-
expect(normalizePathSpy).toHaveBeenCalledWith(apiPath);
|
|
62
|
-
expect(toRelativePathSpy).toHaveBeenCalledWith(guidePath);
|
|
63
|
-
expect(toRelativePathSpy).toHaveBeenCalledWith(apiPath);
|
|
64
|
-
|
|
65
|
-
expect(result.detailDataSources).toContain("# User Guide\n\nThis is a guide.");
|
|
66
|
-
expect(result.detailDataSources).toContain("# API Reference\n\nAPI documentation.");
|
|
67
|
-
});
|
|
68
|
-
|
|
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
|
-
|
|
76
|
-
const input = {
|
|
77
|
-
sourceIds: [readmePath],
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const result = transformDetailDatasources(input);
|
|
81
|
-
|
|
82
|
-
expect(result.detailDataSources).toContain("# README\n\nProject documentation.");
|
|
83
|
-
});
|
|
84
|
-
|
|
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
|
-
|
|
96
|
-
const input = {
|
|
97
|
-
sourceIds: [cPath, aPath, bPath],
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const result = transformDetailDatasources(input);
|
|
101
|
-
|
|
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);
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
// PATH NORMALIZATION TESTS
|
|
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, "/"));
|
|
120
|
-
|
|
121
|
-
const input = {
|
|
122
|
-
sourceIds: [guidePath, apiPath],
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
const result = transformDetailDatasources(input);
|
|
126
|
-
|
|
127
|
-
expect(normalizePathSpy).toHaveBeenCalledWith(guidePath);
|
|
128
|
-
expect(normalizePathSpy).toHaveBeenCalledWith(apiPath);
|
|
129
|
-
expect(result.detailDataSources).toContain("Guide content");
|
|
130
|
-
expect(result.detailDataSources).toContain("API content");
|
|
131
|
-
});
|
|
132
|
-
|
|
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(/^\.\//, ""));
|
|
142
|
-
|
|
143
|
-
const input = {
|
|
144
|
-
sourceIds: [absPath, relPath],
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
const result = transformDetailDatasources(input);
|
|
148
|
-
|
|
149
|
-
expect(toRelativePathSpy).toHaveBeenCalledWith(absPath);
|
|
150
|
-
expect(toRelativePathSpy).toHaveBeenCalledWith(relPath);
|
|
151
|
-
expect(result.detailDataSources).toContain("Absolute content");
|
|
152
|
-
expect(result.detailDataSources).toContain("Relative content");
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
// MISSING DATA TESTS
|
|
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
|
-
|
|
167
|
-
const input = {
|
|
168
|
-
sourceIds: [guidePath, missingPath, apiPath],
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
const result = transformDetailDatasources(input);
|
|
172
|
-
|
|
173
|
-
expect(result.detailDataSources).toContain("Guide content");
|
|
174
|
-
expect(result.detailDataSources).toContain("API content");
|
|
175
|
-
expect(result.detailDataSources).not.toContain("missing");
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
test("should handle empty sourceIds array", () => {
|
|
179
|
-
const input = {
|
|
180
|
-
sourceIds: [],
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
const result = transformDetailDatasources(input);
|
|
184
|
-
|
|
185
|
-
expect(result.detailDataSources).toBe("");
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
// NULL AND UNDEFINED HANDLING
|
|
189
|
-
test("should handle null sourceIds", () => {
|
|
190
|
-
const input = {
|
|
191
|
-
sourceIds: null,
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
const result = transformDetailDatasources(input);
|
|
195
|
-
|
|
196
|
-
expect(result.detailDataSources).toBe("");
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
test("should handle undefined sourceIds", () => {
|
|
200
|
-
const input = {
|
|
201
|
-
sourceIds: undefined,
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
const result = transformDetailDatasources(input);
|
|
205
|
-
|
|
206
|
-
expect(result.detailDataSources).toBe("");
|
|
207
|
-
});
|
|
208
|
-
|
|
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);");
|
|
213
|
-
|
|
214
|
-
normalizePathSpy.mockImplementation((p) => p);
|
|
215
|
-
|
|
216
|
-
const input = {
|
|
217
|
-
sourceIds: [mainPath],
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
const result = transformDetailDatasources(input);
|
|
221
|
-
|
|
222
|
-
expect(result.detailDataSources).toContain("console.log('Hello World');\nprocess.exit(0);");
|
|
223
|
-
expect(result.detailDataSources).toContain("// sourceId:");
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
test("should handle empty content", async () => {
|
|
227
|
-
const emptyPath = path.join(testDir, "empty.md");
|
|
228
|
-
await writeFile(emptyPath, "");
|
|
229
|
-
|
|
230
|
-
normalizePathSpy.mockImplementation((p) => p);
|
|
231
|
-
|
|
232
|
-
const input = {
|
|
233
|
-
sourceIds: [emptyPath],
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
const result = transformDetailDatasources(input);
|
|
237
|
-
|
|
238
|
-
// Empty file content still gets included with sourceId comment
|
|
239
|
-
expect(result.detailDataSources).toContain("// sourceId:");
|
|
240
|
-
expect(result.detailDataSources.trim()).not.toBe("");
|
|
241
|
-
});
|
|
242
|
-
|
|
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
|
-
|
|
249
|
-
const input = {
|
|
250
|
-
sourceIds: [whitespacePath],
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
const result = transformDetailDatasources(input);
|
|
254
|
-
|
|
255
|
-
// Whitespace content is truthy, so it should be included
|
|
256
|
-
expect(result.detailDataSources).toContain(" \n\t ");
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
test("should handle content with special characters", async () => {
|
|
260
|
-
const specialPath = path.join(testDir, "特殊字符.md");
|
|
261
|
-
await writeFile(specialPath, "# 中文标题\n\n这是一个包含特殊字符的文档: @#$%^&*()");
|
|
262
|
-
|
|
263
|
-
normalizePathSpy.mockImplementation((p) => p);
|
|
264
|
-
|
|
265
|
-
const input = {
|
|
266
|
-
sourceIds: [specialPath],
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
const result = transformDetailDatasources(input);
|
|
270
|
-
|
|
271
|
-
expect(result.detailDataSources).toContain("中文标题");
|
|
272
|
-
expect(result.detailDataSources).toContain("@#$%^&*()");
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
// DUPLICATE HANDLING TESTS
|
|
276
|
-
test("should handle duplicate sourceIds in list", async () => {
|
|
277
|
-
const guidePath = path.join(testDir, "guide.md");
|
|
278
|
-
await writeFile(guidePath, "Guide content");
|
|
279
|
-
|
|
280
|
-
normalizePathSpy.mockImplementation((p) => p);
|
|
281
|
-
|
|
282
|
-
const input = {
|
|
283
|
-
sourceIds: [guidePath, guidePath], // Duplicate paths
|
|
284
|
-
};
|
|
285
|
-
|
|
286
|
-
const result = transformDetailDatasources(input);
|
|
287
|
-
|
|
288
|
-
// Both duplicates should be included
|
|
289
|
-
const matches = result.detailDataSources.match(/Guide content/g);
|
|
290
|
-
expect(matches?.length).toBe(2);
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
// RETURN VALUE STRUCTURE TESTS
|
|
294
|
-
test("should always return object with detailDataSources property", async () => {
|
|
295
|
-
const inputs = [{ sourceIds: [] }, { sourceIds: null }];
|
|
296
|
-
|
|
297
|
-
for (const input of inputs) {
|
|
298
|
-
const result = transformDetailDatasources(input);
|
|
299
|
-
expect(result).toHaveProperty("detailDataSources");
|
|
300
|
-
expect(typeof result.detailDataSources).toBe("string");
|
|
301
|
-
}
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
// EDGE CASES
|
|
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");
|
|
308
|
-
|
|
309
|
-
normalizePathSpy.mockImplementation((p) => p || "");
|
|
310
|
-
toRelativePathSpy.mockImplementation((p) => p || "");
|
|
311
|
-
|
|
312
|
-
const input = {
|
|
313
|
-
sourceIds: [null, undefined, validPath],
|
|
314
|
-
};
|
|
315
|
-
|
|
316
|
-
const result = transformDetailDatasources(input);
|
|
317
|
-
|
|
318
|
-
expect(result.detailDataSources).toContain("Valid content");
|
|
319
|
-
});
|
|
320
|
-
});
|