@aigne/doc-smith 0.8.12-beta.8 → 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 +13 -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/update-document-detail.yaml +3 -1
- package/agents/utils/update-branding.mjs +69 -0
- package/package.json +16 -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/structure/update/user-prompt.md +0 -4
- package/utils/file-utils.mjs +69 -24
- 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/media-description.yaml +0 -91
- 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 -1830
- 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 -198
- 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 -69
- package/docs/configuration.md +0 -69
- package/docs/configuration.zh-TW.md +0 -69
- package/docs/configuration.zh.md +0 -69
- package/docs/getting-started.ja.md +0 -107
- package/docs/getting-started.md +0 -107
- package/docs/getting-started.zh-TW.md +0 -107
- package/docs/getting-started.zh.md +0 -107
- package/docs/guides-cleaning-up.ja.md +0 -51
- package/docs/guides-cleaning-up.md +0 -52
- 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 -107
- 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 -89
- 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 -93
- 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 -53
- 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 -83
- 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 -100
- 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 -79
- 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 -288
- package/docs/release-notes.zh-TW.md +0 -255
- package/docs/release-notes.zh.md +0 -255
- 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,1657 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from "bun:test";
|
|
2
|
-
import { promises as fs } from "node:fs";
|
|
3
|
-
import { tmpdir } from "node:os";
|
|
4
|
-
import { join } from "node:path";
|
|
5
|
-
import { parse as parseYAML } from "yaml";
|
|
6
|
-
import init, { generateYAML } from "../../../agents/init/index.mjs";
|
|
7
|
-
|
|
8
|
-
describe("generateYAML", () => {
|
|
9
|
-
// Helper function to parse YAML and verify it's valid
|
|
10
|
-
function parseAndValidateYAML(yamlString) {
|
|
11
|
-
let config;
|
|
12
|
-
expect(() => {
|
|
13
|
-
config = parseYAML(yamlString);
|
|
14
|
-
}).not.toThrow(); // YAML should be parseable
|
|
15
|
-
expect(config).toBeDefined();
|
|
16
|
-
return config;
|
|
17
|
-
}
|
|
18
|
-
describe("Complete valid user scenarios", () => {
|
|
19
|
-
test("should handle typical developer-focused configuration", () => {
|
|
20
|
-
const input = {
|
|
21
|
-
// Question 1: Document Purpose (checkbox, at least 1)
|
|
22
|
-
documentPurpose: ["getStarted", "findAnswers"],
|
|
23
|
-
|
|
24
|
-
// Question 2: Target Audience (checkbox, at least 1)
|
|
25
|
-
targetAudienceTypes: ["developers"],
|
|
26
|
-
|
|
27
|
-
// Question 3: Reader Knowledge Level (select, single choice)
|
|
28
|
-
readerKnowledgeLevel: "domainFamiliar",
|
|
29
|
-
|
|
30
|
-
// Question 4: Documentation Depth (select, single choice)
|
|
31
|
-
documentationDepth: "balancedCoverage",
|
|
32
|
-
|
|
33
|
-
// Question 5: Primary Language (select, single choice)
|
|
34
|
-
locale: "en",
|
|
35
|
-
|
|
36
|
-
// Question 6: Translation Languages (checkbox, optional)
|
|
37
|
-
translateLanguages: ["zh", "ja"],
|
|
38
|
-
|
|
39
|
-
// Question 7: Documentation Directory (input, with default)
|
|
40
|
-
docsDir: ".aigne/doc-smith/docs",
|
|
41
|
-
|
|
42
|
-
// Question 8: Source Paths (multiple inputs, with default)
|
|
43
|
-
sourcesPath: ["./src", "./lib"],
|
|
44
|
-
|
|
45
|
-
// Project Info (from getProjectInfo)
|
|
46
|
-
projectName: "My Awesome Project",
|
|
47
|
-
projectDesc: "A comprehensive library for developers",
|
|
48
|
-
projectLogo: "assets/logo.png",
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const result = generateYAML(input);
|
|
52
|
-
|
|
53
|
-
// Parse and validate YAML structure
|
|
54
|
-
const config = parseAndValidateYAML(result);
|
|
55
|
-
|
|
56
|
-
// Verify project information
|
|
57
|
-
expect(config.projectName).toBe("My Awesome Project");
|
|
58
|
-
expect(config.projectDesc).toBe("A comprehensive library for developers");
|
|
59
|
-
expect(config.projectLogo).toBe("assets/logo.png");
|
|
60
|
-
|
|
61
|
-
// Verify document purpose array
|
|
62
|
-
expect(Array.isArray(config.documentPurpose)).toBe(true);
|
|
63
|
-
expect(config.documentPurpose).toEqual(["getStarted", "findAnswers"]);
|
|
64
|
-
|
|
65
|
-
// Verify target audience array
|
|
66
|
-
expect(Array.isArray(config.targetAudienceTypes)).toBe(true);
|
|
67
|
-
expect(config.targetAudienceTypes).toEqual(["developers"]);
|
|
68
|
-
|
|
69
|
-
// Verify single value fields
|
|
70
|
-
expect(config.readerKnowledgeLevel).toBe("domainFamiliar");
|
|
71
|
-
expect(config.documentationDepth).toBe("balancedCoverage");
|
|
72
|
-
expect(config.locale).toBe("en");
|
|
73
|
-
|
|
74
|
-
// Verify translation languages array
|
|
75
|
-
expect(Array.isArray(config.translateLanguages)).toBe(true);
|
|
76
|
-
expect(config.translateLanguages).toEqual(["zh", "ja"]);
|
|
77
|
-
|
|
78
|
-
// Verify paths
|
|
79
|
-
expect(config.docsDir).toBe(".aigne/doc-smith/docs");
|
|
80
|
-
expect(Array.isArray(config.sourcesPath)).toBe(true);
|
|
81
|
-
expect(config.sourcesPath).toEqual(["./src", "./lib"]);
|
|
82
|
-
|
|
83
|
-
// Verify comments are present (using string matching for comments)
|
|
84
|
-
expect(result).toContain("# Project information for documentation publishing");
|
|
85
|
-
expect(result).toContain("# Documentation Configuration");
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
test("should handle end-user focused minimal configuration", () => {
|
|
89
|
-
const input = {
|
|
90
|
-
documentPurpose: ["getStarted"],
|
|
91
|
-
targetAudienceTypes: ["endUsers"],
|
|
92
|
-
readerKnowledgeLevel: "completeBeginners",
|
|
93
|
-
documentationDepth: "essentialOnly",
|
|
94
|
-
locale: "en",
|
|
95
|
-
translateLanguages: [],
|
|
96
|
-
docsDir: "./docs",
|
|
97
|
-
sourcesPath: ["./"],
|
|
98
|
-
projectName: "User-Friendly App",
|
|
99
|
-
projectDesc: "Simple app for everyone",
|
|
100
|
-
projectLogo: "",
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
const result = generateYAML(input);
|
|
104
|
-
|
|
105
|
-
// Parse and validate YAML structure
|
|
106
|
-
const config = parseAndValidateYAML(result);
|
|
107
|
-
|
|
108
|
-
// Verify configuration values
|
|
109
|
-
expect(config.documentPurpose).toEqual(["getStarted"]);
|
|
110
|
-
expect(config.targetAudienceTypes).toEqual(["endUsers"]);
|
|
111
|
-
expect(config.readerKnowledgeLevel).toBe("completeBeginners");
|
|
112
|
-
expect(config.documentationDepth).toBe("essentialOnly");
|
|
113
|
-
expect(config.locale).toBe("en");
|
|
114
|
-
expect(config.translateLanguages).toEqual(undefined);
|
|
115
|
-
expect(config.docsDir).toBe("./docs");
|
|
116
|
-
expect(config.sourcesPath).toEqual(["./"]);
|
|
117
|
-
expect(config.projectName).toBe("User-Friendly App");
|
|
118
|
-
expect(config.projectDesc).toBe("Simple app for everyone");
|
|
119
|
-
expect(config.projectLogo).toBe("");
|
|
120
|
-
|
|
121
|
-
// Verify comments for empty translateLanguages (string matching for comments)
|
|
122
|
-
expect(result).toContain("# translateLanguages: # List of languages to translate");
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
test("should handle mixed purpose with priority selection", () => {
|
|
126
|
-
// Simulates user selecting mixedPurpose first, then choosing top 2 priorities
|
|
127
|
-
const input = {
|
|
128
|
-
documentPurpose: ["completeTasks", "findAnswers"], // The 2 priorities selected after mixedPurpose
|
|
129
|
-
targetAudienceTypes: ["developers", "devops"],
|
|
130
|
-
readerKnowledgeLevel: "experiencedUsers",
|
|
131
|
-
documentationDepth: "comprehensive",
|
|
132
|
-
locale: "zh-CN",
|
|
133
|
-
translateLanguages: ["en"],
|
|
134
|
-
docsDir: "./documentation",
|
|
135
|
-
sourcesPath: ["./src/**/*.js", "./lib/**/*.ts"],
|
|
136
|
-
projectName: "Enterprise Solution",
|
|
137
|
-
projectDesc: "Advanced enterprise-grade solution",
|
|
138
|
-
projectLogo: "brand/logo.svg",
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
const result = generateYAML(input);
|
|
142
|
-
|
|
143
|
-
expect(result).toContain("- completeTasks");
|
|
144
|
-
expect(result).toContain("- findAnswers");
|
|
145
|
-
expect(result).toContain("- developers");
|
|
146
|
-
expect(result).toContain("- devops");
|
|
147
|
-
expect(result).toContain("locale: zh-CN");
|
|
148
|
-
expect(result).toContain("- en");
|
|
149
|
-
});
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
describe("Document Purpose combinations", () => {
|
|
153
|
-
test("should handle single purpose selection", () => {
|
|
154
|
-
const validPurposes = [
|
|
155
|
-
"getStarted",
|
|
156
|
-
"completeTasks",
|
|
157
|
-
"findAnswers",
|
|
158
|
-
"understandSystem",
|
|
159
|
-
"solveProblems",
|
|
160
|
-
];
|
|
161
|
-
|
|
162
|
-
validPurposes.forEach((purpose) => {
|
|
163
|
-
const input = {
|
|
164
|
-
documentPurpose: [purpose],
|
|
165
|
-
targetAudienceTypes: ["developers"],
|
|
166
|
-
locale: "en",
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
const result = generateYAML(input);
|
|
170
|
-
const config = parseAndValidateYAML(result);
|
|
171
|
-
|
|
172
|
-
expect(config.documentPurpose).toEqual([purpose]);
|
|
173
|
-
});
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
test("should handle multiple purpose combinations", () => {
|
|
177
|
-
const combinations = [
|
|
178
|
-
["getStarted", "completeTasks"],
|
|
179
|
-
["findAnswers", "solveProblems"],
|
|
180
|
-
["understandSystem", "completeTasks", "findAnswers"],
|
|
181
|
-
];
|
|
182
|
-
|
|
183
|
-
combinations.forEach((purposes) => {
|
|
184
|
-
const input = {
|
|
185
|
-
documentPurpose: purposes,
|
|
186
|
-
targetAudienceTypes: ["developers"],
|
|
187
|
-
locale: "en",
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
const result = generateYAML(input);
|
|
191
|
-
const config = parseAndValidateYAML(result);
|
|
192
|
-
|
|
193
|
-
expect(config.documentPurpose).toEqual(purposes);
|
|
194
|
-
});
|
|
195
|
-
});
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
describe("Target Audience combinations", () => {
|
|
199
|
-
test("should handle all valid audience types", () => {
|
|
200
|
-
const validAudiences = [
|
|
201
|
-
"endUsers",
|
|
202
|
-
"developers",
|
|
203
|
-
"devops",
|
|
204
|
-
"decisionMakers",
|
|
205
|
-
"supportTeams",
|
|
206
|
-
"mixedTechnical",
|
|
207
|
-
];
|
|
208
|
-
|
|
209
|
-
validAudiences.forEach((audience) => {
|
|
210
|
-
const input = {
|
|
211
|
-
documentPurpose: ["getStarted"],
|
|
212
|
-
targetAudienceTypes: [audience],
|
|
213
|
-
locale: "en",
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
const result = generateYAML(input);
|
|
217
|
-
expect(result).toContain(`- ${audience}`);
|
|
218
|
-
});
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
test("should handle mixed audience selections", () => {
|
|
222
|
-
const input = {
|
|
223
|
-
documentPurpose: ["completeTasks"],
|
|
224
|
-
targetAudienceTypes: ["developers", "devops", "supportTeams"],
|
|
225
|
-
locale: "en",
|
|
226
|
-
};
|
|
227
|
-
|
|
228
|
-
const result = generateYAML(input);
|
|
229
|
-
expect(result).toContain("- developers");
|
|
230
|
-
expect(result).toContain("- devops");
|
|
231
|
-
expect(result).toContain("- supportTeams");
|
|
232
|
-
});
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
describe("Knowledge Level scenarios", () => {
|
|
236
|
-
test("should handle all valid knowledge levels", () => {
|
|
237
|
-
const validLevels = [
|
|
238
|
-
"completeBeginners",
|
|
239
|
-
"domainFamiliar",
|
|
240
|
-
"hasBasicKnowledge",
|
|
241
|
-
"experiencedUsers",
|
|
242
|
-
"emergencyTroubleshooting",
|
|
243
|
-
"exploringEvaluating",
|
|
244
|
-
];
|
|
245
|
-
|
|
246
|
-
validLevels.forEach((level) => {
|
|
247
|
-
const input = {
|
|
248
|
-
documentPurpose: ["getStarted"],
|
|
249
|
-
targetAudienceTypes: ["developers"],
|
|
250
|
-
readerKnowledgeLevel: level,
|
|
251
|
-
locale: "en",
|
|
252
|
-
docsDir: "./docs", // Provide required field to avoid YAML generation bug
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
const result = generateYAML(input);
|
|
256
|
-
const config = parseAndValidateYAML(result);
|
|
257
|
-
|
|
258
|
-
expect(config.readerKnowledgeLevel).toBe(level);
|
|
259
|
-
});
|
|
260
|
-
});
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
describe("Documentation Depth scenarios", () => {
|
|
264
|
-
test("should handle all valid depth levels", () => {
|
|
265
|
-
const validDepths = ["essentialOnly", "balancedCoverage", "comprehensive", "aiDecide"];
|
|
266
|
-
|
|
267
|
-
validDepths.forEach((depth) => {
|
|
268
|
-
const input = {
|
|
269
|
-
documentPurpose: ["getStarted"],
|
|
270
|
-
targetAudienceTypes: ["developers"],
|
|
271
|
-
documentationDepth: depth,
|
|
272
|
-
locale: "en",
|
|
273
|
-
};
|
|
274
|
-
|
|
275
|
-
const result = generateYAML(input);
|
|
276
|
-
expect(result).toContain(`documentationDepth: ${depth}`);
|
|
277
|
-
});
|
|
278
|
-
});
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
describe("Locale and translation scenarios", () => {
|
|
282
|
-
test("should handle all supported locales", () => {
|
|
283
|
-
const supportedLocales = [
|
|
284
|
-
"en",
|
|
285
|
-
"zh",
|
|
286
|
-
"ja",
|
|
287
|
-
"ko",
|
|
288
|
-
"es",
|
|
289
|
-
"fr",
|
|
290
|
-
"de",
|
|
291
|
-
"it",
|
|
292
|
-
"pt",
|
|
293
|
-
"ru",
|
|
294
|
-
"ar",
|
|
295
|
-
"hi",
|
|
296
|
-
"th",
|
|
297
|
-
"vi",
|
|
298
|
-
"id",
|
|
299
|
-
"ms",
|
|
300
|
-
"tl",
|
|
301
|
-
"tr",
|
|
302
|
-
"pl",
|
|
303
|
-
"nl",
|
|
304
|
-
"sv",
|
|
305
|
-
"da",
|
|
306
|
-
"no",
|
|
307
|
-
"fi",
|
|
308
|
-
"hu",
|
|
309
|
-
"cs",
|
|
310
|
-
"sk",
|
|
311
|
-
"ro",
|
|
312
|
-
"bg",
|
|
313
|
-
"hr",
|
|
314
|
-
"sl",
|
|
315
|
-
"et",
|
|
316
|
-
"lv",
|
|
317
|
-
"lt",
|
|
318
|
-
"mt",
|
|
319
|
-
"el",
|
|
320
|
-
"he",
|
|
321
|
-
"fa",
|
|
322
|
-
"ur",
|
|
323
|
-
"bn",
|
|
324
|
-
"ta",
|
|
325
|
-
"te",
|
|
326
|
-
"kn",
|
|
327
|
-
"ml",
|
|
328
|
-
"gu",
|
|
329
|
-
"pa",
|
|
330
|
-
"or",
|
|
331
|
-
"as",
|
|
332
|
-
"ne",
|
|
333
|
-
"si",
|
|
334
|
-
];
|
|
335
|
-
|
|
336
|
-
// Test a subset to keep test reasonable
|
|
337
|
-
const testLocales = supportedLocales.slice(0, 10);
|
|
338
|
-
|
|
339
|
-
testLocales.forEach((locale) => {
|
|
340
|
-
const input = {
|
|
341
|
-
documentPurpose: ["getStarted"],
|
|
342
|
-
targetAudienceTypes: ["developers"],
|
|
343
|
-
locale: locale,
|
|
344
|
-
};
|
|
345
|
-
|
|
346
|
-
const result = generateYAML(input);
|
|
347
|
-
const config = parseAndValidateYAML(result);
|
|
348
|
-
|
|
349
|
-
expect(config.locale).toBe(locale);
|
|
350
|
-
});
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
test("should handle complex locale formats", () => {
|
|
354
|
-
const complexLocales = ["zh-CN", "zh-TW", "en-US", "en-GB", "pt-BR", "es-ES", "fr-CA"];
|
|
355
|
-
|
|
356
|
-
complexLocales.forEach((locale) => {
|
|
357
|
-
const input = {
|
|
358
|
-
documentPurpose: ["getStarted"],
|
|
359
|
-
targetAudienceTypes: ["developers"],
|
|
360
|
-
locale: locale,
|
|
361
|
-
};
|
|
362
|
-
|
|
363
|
-
const result = generateYAML(input);
|
|
364
|
-
expect(result).toContain(`locale: ${locale}`);
|
|
365
|
-
});
|
|
366
|
-
});
|
|
367
|
-
|
|
368
|
-
test("should handle translation language combinations", () => {
|
|
369
|
-
const input = {
|
|
370
|
-
documentPurpose: ["getStarted"],
|
|
371
|
-
targetAudienceTypes: ["developers"],
|
|
372
|
-
locale: "en",
|
|
373
|
-
translateLanguages: ["zh", "ja", "ko", "es", "fr"],
|
|
374
|
-
};
|
|
375
|
-
|
|
376
|
-
const result = generateYAML(input);
|
|
377
|
-
expect(result).toContain("translateLanguages:");
|
|
378
|
-
expect(result).toContain("- zh");
|
|
379
|
-
expect(result).toContain("- ja");
|
|
380
|
-
expect(result).toContain("- ko");
|
|
381
|
-
expect(result).toContain("- es");
|
|
382
|
-
expect(result).toContain("- fr");
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
test("should handle empty translation languages", () => {
|
|
386
|
-
const input = {
|
|
387
|
-
documentPurpose: ["getStarted"],
|
|
388
|
-
targetAudienceTypes: ["developers"],
|
|
389
|
-
locale: "en",
|
|
390
|
-
translateLanguages: [],
|
|
391
|
-
};
|
|
392
|
-
|
|
393
|
-
const result = generateYAML(input);
|
|
394
|
-
expect(result).toContain("# translateLanguages: # List of languages to translate");
|
|
395
|
-
expect(result).toContain("# - zh # Example: Chinese translation");
|
|
396
|
-
expect(result).toContain("# - en # Example: English translation");
|
|
397
|
-
});
|
|
398
|
-
});
|
|
399
|
-
|
|
400
|
-
describe("Project info from GitHub/Git scenarios - Strict YAML validation", () => {
|
|
401
|
-
test("should handle typical GitHub project names with various formats", () => {
|
|
402
|
-
const githubProjectNames = [
|
|
403
|
-
// Common GitHub naming patterns
|
|
404
|
-
"awesome-project",
|
|
405
|
-
"my_awesome_project",
|
|
406
|
-
"AwesomeProject",
|
|
407
|
-
"project-v2.0.1",
|
|
408
|
-
"project_name_2024",
|
|
409
|
-
"some-org.awesome-project",
|
|
410
|
-
"project.config.js",
|
|
411
|
-
"@scoped/package-name",
|
|
412
|
-
"react-native-component",
|
|
413
|
-
"vue3-typescript-starter",
|
|
414
|
-
"nestjs-api-boilerplate",
|
|
415
|
-
"k8s-deployment-tools",
|
|
416
|
-
];
|
|
417
|
-
|
|
418
|
-
githubProjectNames.forEach((projectName) => {
|
|
419
|
-
const input = {
|
|
420
|
-
documentPurpose: ["getStarted"],
|
|
421
|
-
targetAudienceTypes: ["developers"],
|
|
422
|
-
locale: "en",
|
|
423
|
-
docsDir: "./docs",
|
|
424
|
-
projectName,
|
|
425
|
-
projectDesc: `Description for ${projectName}`,
|
|
426
|
-
projectLogo: "assets/logo.png",
|
|
427
|
-
};
|
|
428
|
-
|
|
429
|
-
const result = generateYAML(input);
|
|
430
|
-
const config = parseAndValidateYAML(result);
|
|
431
|
-
|
|
432
|
-
expect(config.projectName).toBe(projectName);
|
|
433
|
-
expect(config.projectDesc).toBe(`Description for ${projectName}`);
|
|
434
|
-
});
|
|
435
|
-
});
|
|
436
|
-
|
|
437
|
-
test("should handle project names with special characters and symbols", () => {
|
|
438
|
-
const specialCharacterNames = [
|
|
439
|
-
// YAML potentially problematic characters
|
|
440
|
-
"project: with colon",
|
|
441
|
-
'project "with quotes"',
|
|
442
|
-
"project 'with single quotes'",
|
|
443
|
-
"project [with brackets]",
|
|
444
|
-
"project {with braces}",
|
|
445
|
-
"project | with pipe",
|
|
446
|
-
"project > with gt",
|
|
447
|
-
"project < with lt",
|
|
448
|
-
"project & with ampersand",
|
|
449
|
-
"project % with percent",
|
|
450
|
-
"project # with hash",
|
|
451
|
-
"project @ with at",
|
|
452
|
-
"project ! with exclamation",
|
|
453
|
-
"project ? with question",
|
|
454
|
-
"project * with asterisk",
|
|
455
|
-
"project ~ with tilde",
|
|
456
|
-
"project ` with backtick",
|
|
457
|
-
"project \\ with backslash",
|
|
458
|
-
"project / with slash",
|
|
459
|
-
];
|
|
460
|
-
|
|
461
|
-
specialCharacterNames.forEach((projectName) => {
|
|
462
|
-
const input = {
|
|
463
|
-
documentPurpose: ["getStarted"],
|
|
464
|
-
targetAudienceTypes: ["developers"],
|
|
465
|
-
locale: "en",
|
|
466
|
-
docsDir: "./docs",
|
|
467
|
-
projectName,
|
|
468
|
-
projectDesc: "Project with special characters",
|
|
469
|
-
projectLogo: "logo.png",
|
|
470
|
-
};
|
|
471
|
-
|
|
472
|
-
const result = generateYAML(input);
|
|
473
|
-
const config = parseAndValidateYAML(result);
|
|
474
|
-
|
|
475
|
-
// YAML should be valid and preserve the exact project name
|
|
476
|
-
expect(config.projectName).toBe(projectName);
|
|
477
|
-
});
|
|
478
|
-
});
|
|
479
|
-
|
|
480
|
-
test("should handle project descriptions with complex formatting", () => {
|
|
481
|
-
const complexDescriptions = [
|
|
482
|
-
// Multi-line with various formatting
|
|
483
|
-
"Line 1: Overview\nLine 2: Features\n\nLine 4: Usage",
|
|
484
|
-
"Description with\ttabs\tand\nnewlines",
|
|
485
|
-
"Description with 'single quotes' and \"double quotes\"",
|
|
486
|
-
"Description with [links](http://example.com) and *emphasis*",
|
|
487
|
-
"Description with #hashtags and @mentions",
|
|
488
|
-
'JSON-like content: {"key": "value", "array": [1, 2, 3]}',
|
|
489
|
-
"YAML-like content:\n key: value\n list:\n - item1\n - item2",
|
|
490
|
-
"Code snippets: `npm install` and ```javascript\nconsole.log('hello');\n```",
|
|
491
|
-
"URLs: https://github.com/user/repo and http://example.com:8080/path?query=value",
|
|
492
|
-
"Email: user@example.com and file paths: /usr/local/bin/app",
|
|
493
|
-
];
|
|
494
|
-
|
|
495
|
-
complexDescriptions.forEach((projectDesc) => {
|
|
496
|
-
const input = {
|
|
497
|
-
documentPurpose: ["getStarted"],
|
|
498
|
-
targetAudienceTypes: ["developers"],
|
|
499
|
-
locale: "en",
|
|
500
|
-
docsDir: "./docs",
|
|
501
|
-
projectName: "Test Project",
|
|
502
|
-
projectDesc,
|
|
503
|
-
projectLogo: "logo.png",
|
|
504
|
-
};
|
|
505
|
-
|
|
506
|
-
const result = generateYAML(input);
|
|
507
|
-
const config = parseAndValidateYAML(result);
|
|
508
|
-
|
|
509
|
-
// YAML should be valid and preserve the exact description
|
|
510
|
-
expect(config.projectDesc).toBe(projectDesc);
|
|
511
|
-
});
|
|
512
|
-
});
|
|
513
|
-
|
|
514
|
-
test("should handle international and emoji-rich project info", () => {
|
|
515
|
-
const internationalCases = [
|
|
516
|
-
{
|
|
517
|
-
projectName: "项目名称-中文",
|
|
518
|
-
projectDesc: "这是一个中文项目描述,包含中文标点符号:,。!?",
|
|
519
|
-
locale: "zh-CN",
|
|
520
|
-
},
|
|
521
|
-
{
|
|
522
|
-
projectName: "プロジェクト名前-日本語",
|
|
523
|
-
projectDesc: "これは日本語のプロジェクト説明です。ひらがな、カタカナ、漢字を含みます。",
|
|
524
|
-
locale: "ja",
|
|
525
|
-
},
|
|
526
|
-
{
|
|
527
|
-
projectName: "proyecto-español",
|
|
528
|
-
projectDesc: "Descripción del proyecto con acentos: ñáéíóúü y signos ¡¿",
|
|
529
|
-
locale: "es",
|
|
530
|
-
},
|
|
531
|
-
{
|
|
532
|
-
projectName: "проект-русский",
|
|
533
|
-
projectDesc: "Описание проекта на русском языке с кириллицей",
|
|
534
|
-
locale: "ru",
|
|
535
|
-
},
|
|
536
|
-
{
|
|
537
|
-
projectName: "مشروع-عربي",
|
|
538
|
-
projectDesc: "وصف المشروع باللغة العربية من اليمين إلى اليسار",
|
|
539
|
-
locale: "ar",
|
|
540
|
-
},
|
|
541
|
-
{
|
|
542
|
-
projectName: "🚀 Awesome Project 🎉",
|
|
543
|
-
projectDesc: "Project with emojis: 📱💻🔥⚡🌟✨🎯🚀💡🔧⭐🎨🎪🎭",
|
|
544
|
-
locale: "en",
|
|
545
|
-
},
|
|
546
|
-
{
|
|
547
|
-
projectName: "Mixed語言Project混合नाम",
|
|
548
|
-
projectDesc: "Multi-language混合description with हिंदी, 中文, English, and العربية",
|
|
549
|
-
locale: "en",
|
|
550
|
-
},
|
|
551
|
-
];
|
|
552
|
-
|
|
553
|
-
internationalCases.forEach(({ projectName, projectDesc, locale }) => {
|
|
554
|
-
const input = {
|
|
555
|
-
documentPurpose: ["getStarted"],
|
|
556
|
-
targetAudienceTypes: ["developers"],
|
|
557
|
-
locale,
|
|
558
|
-
docsDir: "./docs",
|
|
559
|
-
projectName,
|
|
560
|
-
projectDesc,
|
|
561
|
-
projectLogo: "assets/logo.svg",
|
|
562
|
-
};
|
|
563
|
-
|
|
564
|
-
const result = generateYAML(input);
|
|
565
|
-
const config = parseAndValidateYAML(result);
|
|
566
|
-
|
|
567
|
-
expect(config.projectName).toBe(projectName);
|
|
568
|
-
expect(config.projectDesc).toBe(projectDesc);
|
|
569
|
-
expect(config.locale).toBe(locale);
|
|
570
|
-
});
|
|
571
|
-
});
|
|
572
|
-
|
|
573
|
-
test("should handle project logos with various path formats", () => {
|
|
574
|
-
const logoPaths = [
|
|
575
|
-
// Different path formats that might come from GitHub
|
|
576
|
-
"logo.png",
|
|
577
|
-
"assets/logo.svg",
|
|
578
|
-
"docs/images/logo-128x128.png",
|
|
579
|
-
"public/icons/favicon.ico",
|
|
580
|
-
".github/logo.jpg",
|
|
581
|
-
"static/brand/logo_dark.png",
|
|
582
|
-
"src/assets/images/logo@2x.png",
|
|
583
|
-
"media/logos/company-logo.webp",
|
|
584
|
-
"https://raw.githubusercontent.com/user/repo/main/logo.png",
|
|
585
|
-
"https://github.com/user/repo/blob/main/assets/logo.svg?raw=true",
|
|
586
|
-
// Paths with special characters
|
|
587
|
-
"assets/logo with spaces.png",
|
|
588
|
-
"logos/logo-企业.svg",
|
|
589
|
-
"images/логотип.png",
|
|
590
|
-
"assets/logo_v2.0-beta.png",
|
|
591
|
-
"brand/logo[dark].png",
|
|
592
|
-
"icons/logo{small}.ico",
|
|
593
|
-
];
|
|
594
|
-
|
|
595
|
-
logoPaths.forEach((projectLogo) => {
|
|
596
|
-
const input = {
|
|
597
|
-
documentPurpose: ["getStarted"],
|
|
598
|
-
targetAudienceTypes: ["developers"],
|
|
599
|
-
locale: "en",
|
|
600
|
-
docsDir: "./docs",
|
|
601
|
-
projectName: "Test Project",
|
|
602
|
-
projectDesc: "Project with various logo paths",
|
|
603
|
-
projectLogo,
|
|
604
|
-
};
|
|
605
|
-
|
|
606
|
-
const result = generateYAML(input);
|
|
607
|
-
const config = parseAndValidateYAML(result);
|
|
608
|
-
|
|
609
|
-
expect(config.projectLogo).toBe(projectLogo);
|
|
610
|
-
});
|
|
611
|
-
});
|
|
612
|
-
|
|
613
|
-
test("should handle edge cases from GitHub repository parsing", () => {
|
|
614
|
-
const edgeCases = [
|
|
615
|
-
{
|
|
616
|
-
name: "Empty values",
|
|
617
|
-
projectName: "",
|
|
618
|
-
projectDesc: "",
|
|
619
|
-
projectLogo: "",
|
|
620
|
-
},
|
|
621
|
-
{
|
|
622
|
-
name: "Very long values",
|
|
623
|
-
projectName: "a".repeat(200),
|
|
624
|
-
projectDesc:
|
|
625
|
-
"This is a very long description that might come from a detailed README file. ".repeat(
|
|
626
|
-
50,
|
|
627
|
-
),
|
|
628
|
-
projectLogo:
|
|
629
|
-
"assets/very/deep/path/to/a/logo/file/that/might/exist/in/some/repository/structure/logo.png",
|
|
630
|
-
},
|
|
631
|
-
{
|
|
632
|
-
name: "YAML reserved words",
|
|
633
|
-
projectName: "true",
|
|
634
|
-
projectDesc: "false",
|
|
635
|
-
projectLogo: "null",
|
|
636
|
-
},
|
|
637
|
-
{
|
|
638
|
-
name: "Numeric strings",
|
|
639
|
-
projectName: "123",
|
|
640
|
-
projectDesc: "456.789",
|
|
641
|
-
projectLogo: "0x123.png",
|
|
642
|
-
},
|
|
643
|
-
{
|
|
644
|
-
name: "Boolean-like strings",
|
|
645
|
-
projectName: "yes",
|
|
646
|
-
projectDesc: "no",
|
|
647
|
-
projectLogo: "on.svg",
|
|
648
|
-
},
|
|
649
|
-
];
|
|
650
|
-
|
|
651
|
-
edgeCases.forEach(({ projectName, projectDesc, projectLogo }) => {
|
|
652
|
-
const input = {
|
|
653
|
-
documentPurpose: ["getStarted"],
|
|
654
|
-
targetAudienceTypes: ["developers"],
|
|
655
|
-
locale: "en",
|
|
656
|
-
docsDir: "./docs",
|
|
657
|
-
projectName,
|
|
658
|
-
projectDesc,
|
|
659
|
-
projectLogo,
|
|
660
|
-
};
|
|
661
|
-
|
|
662
|
-
const result = generateYAML(input);
|
|
663
|
-
const config = parseAndValidateYAML(result);
|
|
664
|
-
|
|
665
|
-
// All values should be preserved exactly as input
|
|
666
|
-
expect(config.projectName).toBe(projectName);
|
|
667
|
-
expect(config.projectDesc).toBe(projectDesc);
|
|
668
|
-
expect(config.projectLogo).toBe(projectLogo);
|
|
669
|
-
});
|
|
670
|
-
});
|
|
671
|
-
|
|
672
|
-
test("should handle GitHub-specific metadata patterns", () => {
|
|
673
|
-
const githubPatterns = [
|
|
674
|
-
{
|
|
675
|
-
projectName: "facebook/react",
|
|
676
|
-
projectDesc:
|
|
677
|
-
"A declarative, efficient, and flexible JavaScript library for building user interfaces.",
|
|
678
|
-
projectLogo:
|
|
679
|
-
"https://github.com/facebook/react/blob/main/fixtures/attribute-behavior/src/logo.svg",
|
|
680
|
-
},
|
|
681
|
-
{
|
|
682
|
-
projectName: "microsoft/vscode",
|
|
683
|
-
projectDesc:
|
|
684
|
-
"Visual Studio Code - The editor you love. Built for developers, by developers.",
|
|
685
|
-
projectLogo: "resources/linux/code.png",
|
|
686
|
-
},
|
|
687
|
-
{
|
|
688
|
-
projectName: "vercel/next.js",
|
|
689
|
-
projectDesc: "The React Framework – created and maintained by @vercel.",
|
|
690
|
-
projectLogo: "docs/assets/next-logo.svg",
|
|
691
|
-
},
|
|
692
|
-
{
|
|
693
|
-
projectName: "nodejs/node",
|
|
694
|
-
projectDesc: "Node.js JavaScript runtime ✨🐢🚀✨",
|
|
695
|
-
projectLogo: "src/res/node.ico",
|
|
696
|
-
},
|
|
697
|
-
];
|
|
698
|
-
|
|
699
|
-
githubPatterns.forEach(({ projectName, projectDesc, projectLogo }) => {
|
|
700
|
-
const input = {
|
|
701
|
-
documentPurpose: ["getStarted"],
|
|
702
|
-
targetAudienceTypes: ["developers"],
|
|
703
|
-
locale: "en",
|
|
704
|
-
docsDir: "./docs",
|
|
705
|
-
projectName,
|
|
706
|
-
projectDesc,
|
|
707
|
-
projectLogo,
|
|
708
|
-
};
|
|
709
|
-
|
|
710
|
-
const result = generateYAML(input);
|
|
711
|
-
const config = parseAndValidateYAML(result);
|
|
712
|
-
|
|
713
|
-
expect(config.projectName).toBe(projectName);
|
|
714
|
-
expect(config.projectDesc).toBe(projectDesc);
|
|
715
|
-
expect(config.projectLogo).toBe(projectLogo);
|
|
716
|
-
});
|
|
717
|
-
});
|
|
718
|
-
|
|
719
|
-
test("should handle malformed or unusual project info", () => {
|
|
720
|
-
const malformedCases = [
|
|
721
|
-
{
|
|
722
|
-
name: "HTML-like content",
|
|
723
|
-
projectName: "<script>alert('xss')</script>",
|
|
724
|
-
projectDesc: "<h1>Title</h1><p>Description with <a href='#'>links</a></p>",
|
|
725
|
-
projectLogo: "<img src='logo.png' alt='Logo'/>",
|
|
726
|
-
},
|
|
727
|
-
{
|
|
728
|
-
name: "Markdown content",
|
|
729
|
-
projectName: "# My Project",
|
|
730
|
-
projectDesc:
|
|
731
|
-
"## Description\n\n- Feature 1\n- Feature 2\n\n```js\nconsole.log('hello');\n```",
|
|
732
|
-
projectLogo: "",
|
|
733
|
-
},
|
|
734
|
-
{
|
|
735
|
-
name: "Control characters",
|
|
736
|
-
projectName: "Project\x00Name",
|
|
737
|
-
projectDesc: "Description\x01with\x02control\x03characters",
|
|
738
|
-
projectLogo: "logo\x04.png",
|
|
739
|
-
},
|
|
740
|
-
];
|
|
741
|
-
|
|
742
|
-
malformedCases.forEach(({ projectName, projectDesc, projectLogo }) => {
|
|
743
|
-
const input = {
|
|
744
|
-
documentPurpose: ["getStarted"],
|
|
745
|
-
targetAudienceTypes: ["developers"],
|
|
746
|
-
locale: "en",
|
|
747
|
-
docsDir: "./docs",
|
|
748
|
-
projectName,
|
|
749
|
-
projectDesc,
|
|
750
|
-
projectLogo,
|
|
751
|
-
};
|
|
752
|
-
|
|
753
|
-
const result = generateYAML(input);
|
|
754
|
-
const config = parseAndValidateYAML(result);
|
|
755
|
-
|
|
756
|
-
// Even malformed content should be handled safely
|
|
757
|
-
expect(config.projectName).toBe(projectName);
|
|
758
|
-
expect(config.projectDesc).toBe(projectDesc);
|
|
759
|
-
expect(config.projectLogo).toBe(projectLogo);
|
|
760
|
-
});
|
|
761
|
-
});
|
|
762
|
-
});
|
|
763
|
-
|
|
764
|
-
describe("User input path scenarios", () => {
|
|
765
|
-
test("should handle documentation directory variations", () => {
|
|
766
|
-
const docDirVariations = [
|
|
767
|
-
"./docs",
|
|
768
|
-
".aigne/doc-smith/docs",
|
|
769
|
-
"/absolute/path/to/docs",
|
|
770
|
-
"~/user/docs",
|
|
771
|
-
"../relative/docs",
|
|
772
|
-
"docs with spaces",
|
|
773
|
-
"文档目录",
|
|
774
|
-
];
|
|
775
|
-
|
|
776
|
-
docDirVariations.forEach((docsDir) => {
|
|
777
|
-
const input = {
|
|
778
|
-
documentPurpose: ["getStarted"],
|
|
779
|
-
targetAudienceTypes: ["developers"],
|
|
780
|
-
locale: "en",
|
|
781
|
-
docsDir: docsDir,
|
|
782
|
-
};
|
|
783
|
-
|
|
784
|
-
const result = generateYAML(input);
|
|
785
|
-
expect(result).toContain("docsDir:");
|
|
786
|
-
expect(result).toBeDefined();
|
|
787
|
-
});
|
|
788
|
-
});
|
|
789
|
-
|
|
790
|
-
test("should handle various source path patterns", () => {
|
|
791
|
-
const input = {
|
|
792
|
-
documentPurpose: ["getStarted"],
|
|
793
|
-
targetAudienceTypes: ["developers"],
|
|
794
|
-
locale: "en",
|
|
795
|
-
sourcesPath: [
|
|
796
|
-
"./src",
|
|
797
|
-
"./lib",
|
|
798
|
-
"packages/*/src",
|
|
799
|
-
"apps/**/*.ts",
|
|
800
|
-
"!**/*.test.js",
|
|
801
|
-
"src with spaces",
|
|
802
|
-
"源代码/模块",
|
|
803
|
-
],
|
|
804
|
-
};
|
|
805
|
-
|
|
806
|
-
const result = generateYAML(input);
|
|
807
|
-
expect(result).toContain("sourcesPath:");
|
|
808
|
-
expect(result).toContain("- ./src");
|
|
809
|
-
expect(result).toContain("- ./lib");
|
|
810
|
-
expect(result).toContain("- packages/*/src");
|
|
811
|
-
expect(result).toBeDefined();
|
|
812
|
-
});
|
|
813
|
-
|
|
814
|
-
test("should handle single source path", () => {
|
|
815
|
-
const input = {
|
|
816
|
-
documentPurpose: ["getStarted"],
|
|
817
|
-
targetAudienceTypes: ["developers"],
|
|
818
|
-
locale: "en",
|
|
819
|
-
sourcesPath: ["./"],
|
|
820
|
-
};
|
|
821
|
-
|
|
822
|
-
const result = generateYAML(input);
|
|
823
|
-
expect(result).toContain("sourcesPath:");
|
|
824
|
-
expect(result).toContain("- ./");
|
|
825
|
-
});
|
|
826
|
-
|
|
827
|
-
test("should handle complex glob patterns from user input", () => {
|
|
828
|
-
const input = {
|
|
829
|
-
documentPurpose: ["findAnswers"],
|
|
830
|
-
targetAudienceTypes: ["developers"],
|
|
831
|
-
locale: "en",
|
|
832
|
-
sourcesPath: [
|
|
833
|
-
"**/*.{js,ts,jsx,tsx}",
|
|
834
|
-
"src/**/*.{vue,svelte}",
|
|
835
|
-
"!**/node_modules/**",
|
|
836
|
-
"{packages,apps}/**/*.py",
|
|
837
|
-
"docs/**/*.md",
|
|
838
|
-
],
|
|
839
|
-
};
|
|
840
|
-
|
|
841
|
-
const result = generateYAML(input);
|
|
842
|
-
expect(result).toContain("sourcesPath:");
|
|
843
|
-
expect(result).toBeDefined();
|
|
844
|
-
expect(typeof result).toBe("string");
|
|
845
|
-
});
|
|
846
|
-
});
|
|
847
|
-
|
|
848
|
-
describe("Edge cases that should not occur from init() but may happen", () => {
|
|
849
|
-
test("should handle undefined required fields - exposes bug", () => {
|
|
850
|
-
// This could happen if init() has bugs or incomplete validation
|
|
851
|
-
const input = {
|
|
852
|
-
documentPurpose: ["getStarted"],
|
|
853
|
-
targetAudienceTypes: ["developers"],
|
|
854
|
-
locale: undefined, // Should not happen from init()
|
|
855
|
-
docsDir: undefined, // Should not happen from init()
|
|
856
|
-
};
|
|
857
|
-
|
|
858
|
-
const result = generateYAML(input);
|
|
859
|
-
|
|
860
|
-
// This test will FAIL because the function generates invalid YAML
|
|
861
|
-
// The YAML should be parseable and contain proper default values
|
|
862
|
-
const config = parseAndValidateYAML(result);
|
|
863
|
-
|
|
864
|
-
// These expectations will FAIL because function generates invalid "{}" values
|
|
865
|
-
expect(config.locale).toBe("en"); // Should default to "en"
|
|
866
|
-
expect(config.docsDir).toBe("./aigne/doc-smith/docs"); // Should default to "./docs"
|
|
867
|
-
|
|
868
|
-
// Verify other fields work correctly
|
|
869
|
-
expect(config.documentPurpose).toEqual(["getStarted"]);
|
|
870
|
-
expect(config.targetAudienceTypes).toEqual(["developers"]);
|
|
871
|
-
});
|
|
872
|
-
|
|
873
|
-
test("should handle empty arrays from validation failures", () => {
|
|
874
|
-
// This could happen if validation fails but doesn't stop execution
|
|
875
|
-
const input = {
|
|
876
|
-
documentPurpose: [], // Should not happen due to validation
|
|
877
|
-
targetAudienceTypes: [], // Should not happen due to validation
|
|
878
|
-
locale: "en",
|
|
879
|
-
docsDir: "./docs",
|
|
880
|
-
};
|
|
881
|
-
|
|
882
|
-
const result = generateYAML(input);
|
|
883
|
-
expect(result).toContain("documentPurpose: []");
|
|
884
|
-
expect(result).toContain("targetAudienceTypes: []");
|
|
885
|
-
});
|
|
886
|
-
});
|
|
887
|
-
|
|
888
|
-
describe("YAML output structure validation", () => {
|
|
889
|
-
test("should maintain consistent structure across different inputs", () => {
|
|
890
|
-
const inputs = [
|
|
891
|
-
{
|
|
892
|
-
documentPurpose: ["getStarted"],
|
|
893
|
-
targetAudienceTypes: ["endUsers"],
|
|
894
|
-
locale: "en",
|
|
895
|
-
},
|
|
896
|
-
{
|
|
897
|
-
documentPurpose: ["findAnswers", "completeTasks"],
|
|
898
|
-
targetAudienceTypes: ["developers", "devops"],
|
|
899
|
-
locale: "zh-CN",
|
|
900
|
-
translateLanguages: ["en", "ja"],
|
|
901
|
-
},
|
|
902
|
-
];
|
|
903
|
-
|
|
904
|
-
inputs.forEach((input) => {
|
|
905
|
-
const result = generateYAML(input);
|
|
906
|
-
|
|
907
|
-
// Should always include these sections
|
|
908
|
-
expect(result).toContain("# Project information for documentation publishing");
|
|
909
|
-
expect(result).toContain("# Documentation Configuration");
|
|
910
|
-
expect(result).toContain("projectName:");
|
|
911
|
-
expect(result).toContain("documentPurpose:");
|
|
912
|
-
expect(result).toContain("targetAudienceTypes:");
|
|
913
|
-
expect(result).toContain("locale:");
|
|
914
|
-
expect(result).toContain("sourcesPath:");
|
|
915
|
-
});
|
|
916
|
-
});
|
|
917
|
-
|
|
918
|
-
test("should include all necessary comments and examples", () => {
|
|
919
|
-
const input = {
|
|
920
|
-
documentPurpose: ["getStarted"],
|
|
921
|
-
targetAudienceTypes: ["developers"],
|
|
922
|
-
locale: "en",
|
|
923
|
-
translateLanguages: [],
|
|
924
|
-
};
|
|
925
|
-
|
|
926
|
-
const result = generateYAML(input);
|
|
927
|
-
|
|
928
|
-
expect(result).toContain("# Purpose: What's the main outcome");
|
|
929
|
-
expect(result).toContain("# Available options (uncomment and modify as needed):");
|
|
930
|
-
expect(result).toContain("# Target Audience: Who will be reading this most often?");
|
|
931
|
-
expect(result).toContain("# Reader Knowledge Level:");
|
|
932
|
-
expect(result).toContain("# Documentation Depth:");
|
|
933
|
-
expect(result).toContain("# Custom Rules:");
|
|
934
|
-
expect(result).toContain("# Glossary:");
|
|
935
|
-
});
|
|
936
|
-
});
|
|
937
|
-
});
|
|
938
|
-
|
|
939
|
-
describe("init", () => {
|
|
940
|
-
// Helper function to create mock prompts
|
|
941
|
-
function createMockPrompts(responses) {
|
|
942
|
-
return {
|
|
943
|
-
checkbox: (options) => {
|
|
944
|
-
const key = options.message.match(/\[(\d+)\/\d+\]/)?.[1] || "default";
|
|
945
|
-
const response = responses[`checkbox_${key}`] || responses["checkbox"] || [];
|
|
946
|
-
return Promise.resolve(response);
|
|
947
|
-
},
|
|
948
|
-
select: (options) => {
|
|
949
|
-
const key = options.message.match(/\[(\d+)\/\d+\]/)?.[1] || "default";
|
|
950
|
-
const response = responses[`select_${key}`] || responses["select"] || "";
|
|
951
|
-
return Promise.resolve(response);
|
|
952
|
-
},
|
|
953
|
-
input: (options) => {
|
|
954
|
-
const key = options.message.match(/\[(\d+)\/\d+\]/)?.[1] || "default";
|
|
955
|
-
const response = responses[`input_${key}`] || responses["input"] || options.default || "";
|
|
956
|
-
return Promise.resolve(response);
|
|
957
|
-
},
|
|
958
|
-
search: () => {
|
|
959
|
-
const response = responses["search"] || "";
|
|
960
|
-
return Promise.resolve(response);
|
|
961
|
-
},
|
|
962
|
-
};
|
|
963
|
-
}
|
|
964
|
-
|
|
965
|
-
// Helper function to create temporary directory
|
|
966
|
-
async function createTempDir() {
|
|
967
|
-
const tempDir = join(tmpdir(), `aigne-test-${Date.now()}`);
|
|
968
|
-
await fs.mkdir(tempDir, { recursive: true });
|
|
969
|
-
return tempDir;
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
// Helper function to cleanup temp directory
|
|
973
|
-
async function cleanupTempDir(tempDir) {
|
|
974
|
-
try {
|
|
975
|
-
await fs.rm(tempDir, { recursive: true, force: true });
|
|
976
|
-
} catch {
|
|
977
|
-
// Ignore cleanup errors since they don't affect test results
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
|
|
981
|
-
describe("Complete init workflow", () => {
|
|
982
|
-
test("should complete full init workflow with typical developer responses", async () => {
|
|
983
|
-
const tempDir = await createTempDir();
|
|
984
|
-
|
|
985
|
-
try {
|
|
986
|
-
const mockResponses = {
|
|
987
|
-
checkbox_1: ["getStarted", "findAnswers"], // Document purpose
|
|
988
|
-
checkbox_2: ["developers"], // Target audience
|
|
989
|
-
select_3: "domainFamiliar", // Reader knowledge level
|
|
990
|
-
select_4: "balancedCoverage", // Documentation depth
|
|
991
|
-
select_5: "en", // Primary language
|
|
992
|
-
checkbox_6: ["zh", "ja"], // Translation languages
|
|
993
|
-
input_7: join(tempDir, "docs"), // Documentation directory
|
|
994
|
-
search: "", // Source paths (empty to finish)
|
|
995
|
-
input_9: "Custom rules for documentation", // Custom rules (last step)
|
|
996
|
-
};
|
|
997
|
-
|
|
998
|
-
const mockPrompts = createMockPrompts(mockResponses);
|
|
999
|
-
const options = { prompts: mockPrompts };
|
|
1000
|
-
|
|
1001
|
-
const result = await init(
|
|
1002
|
-
{
|
|
1003
|
-
outputPath: tempDir,
|
|
1004
|
-
fileName: "config.yaml",
|
|
1005
|
-
skipIfExists: false,
|
|
1006
|
-
},
|
|
1007
|
-
options,
|
|
1008
|
-
);
|
|
1009
|
-
|
|
1010
|
-
// Check that function completed successfully
|
|
1011
|
-
expect(result).toBeDefined();
|
|
1012
|
-
|
|
1013
|
-
// Check that config file was created
|
|
1014
|
-
const configPath = join(tempDir, "config.yaml");
|
|
1015
|
-
const configExists = await fs
|
|
1016
|
-
.access(configPath)
|
|
1017
|
-
.then(() => true)
|
|
1018
|
-
.catch(() => false);
|
|
1019
|
-
expect(configExists).toBe(true);
|
|
1020
|
-
|
|
1021
|
-
// Verify the generated config content
|
|
1022
|
-
const configContent = await fs.readFile(configPath, "utf8");
|
|
1023
|
-
const config = parseYAML(configContent);
|
|
1024
|
-
|
|
1025
|
-
expect(config.documentPurpose).toEqual(["getStarted", "findAnswers"]);
|
|
1026
|
-
expect(config.targetAudienceTypes).toEqual(["developers"]);
|
|
1027
|
-
expect(config.rules).toBe("Custom rules for documentation");
|
|
1028
|
-
expect(config.readerKnowledgeLevel).toBe("domainFamiliar");
|
|
1029
|
-
expect(config.documentationDepth).toBe("balancedCoverage");
|
|
1030
|
-
expect(config.locale).toBe("en");
|
|
1031
|
-
expect(config.translateLanguages).toEqual(["zh", "ja"]);
|
|
1032
|
-
expect(config.docsDir).toBe(join(tempDir, "docs"));
|
|
1033
|
-
expect(config.sourcesPath).toEqual(["./"]); // Default when no paths provided
|
|
1034
|
-
} finally {
|
|
1035
|
-
await cleanupTempDir(tempDir);
|
|
1036
|
-
}
|
|
1037
|
-
});
|
|
1038
|
-
|
|
1039
|
-
test("should handle mixed purpose workflow with priority selection", async () => {
|
|
1040
|
-
const tempDir = await createTempDir();
|
|
1041
|
-
|
|
1042
|
-
try {
|
|
1043
|
-
const mockResponses = {
|
|
1044
|
-
checkbox_1: ["mixedPurpose"], // Document purpose - triggers follow-up
|
|
1045
|
-
checkbox: ["completeTasks", "findAnswers"], // Top priorities after mixedPurpose
|
|
1046
|
-
checkbox_2: ["developers", "devops"], // Target audience
|
|
1047
|
-
select_3: "experiencedUsers", // Reader knowledge level
|
|
1048
|
-
select_4: "comprehensive", // Documentation depth
|
|
1049
|
-
select_5: "zh-CN", // Primary language
|
|
1050
|
-
checkbox_6: ["en"], // Translation languages
|
|
1051
|
-
input_7: join(tempDir, "documentation"), // Documentation directory
|
|
1052
|
-
search: "", // Source paths (empty to finish)
|
|
1053
|
-
input_9: "Custom rules for documentation", // Custom rules (last step)
|
|
1054
|
-
};
|
|
1055
|
-
|
|
1056
|
-
const mockPrompts = createMockPrompts(mockResponses);
|
|
1057
|
-
const options = { prompts: mockPrompts };
|
|
1058
|
-
|
|
1059
|
-
const result = await init(
|
|
1060
|
-
{
|
|
1061
|
-
outputPath: tempDir,
|
|
1062
|
-
fileName: "test-config.yaml",
|
|
1063
|
-
skipIfExists: false,
|
|
1064
|
-
},
|
|
1065
|
-
options,
|
|
1066
|
-
);
|
|
1067
|
-
|
|
1068
|
-
expect(result).toBeDefined();
|
|
1069
|
-
|
|
1070
|
-
// Verify the generated config
|
|
1071
|
-
const configPath = join(tempDir, "test-config.yaml");
|
|
1072
|
-
const configContent = await fs.readFile(configPath, "utf8");
|
|
1073
|
-
const config = parseYAML(configContent);
|
|
1074
|
-
|
|
1075
|
-
expect(config.documentPurpose).toEqual(["completeTasks", "findAnswers"]);
|
|
1076
|
-
expect(config.targetAudienceTypes).toEqual(["developers", "devops"]);
|
|
1077
|
-
expect(config.rules).toBe("Custom rules for documentation");
|
|
1078
|
-
expect(config.readerKnowledgeLevel).toBe("experiencedUsers");
|
|
1079
|
-
expect(config.documentationDepth).toBe("comprehensive");
|
|
1080
|
-
expect(config.locale).toBe("zh-CN");
|
|
1081
|
-
expect(config.translateLanguages).toEqual(["en"]);
|
|
1082
|
-
} finally {
|
|
1083
|
-
await cleanupTempDir(tempDir);
|
|
1084
|
-
}
|
|
1085
|
-
});
|
|
1086
|
-
|
|
1087
|
-
test("should handle end-user focused minimal configuration", async () => {
|
|
1088
|
-
const tempDir = await createTempDir();
|
|
1089
|
-
|
|
1090
|
-
try {
|
|
1091
|
-
const mockResponses = {
|
|
1092
|
-
checkbox_1: ["getStarted"], // Document purpose
|
|
1093
|
-
checkbox_2: ["endUsers"], // Target audience
|
|
1094
|
-
select_3: "completeBeginners", // Reader knowledge level
|
|
1095
|
-
select_4: "essentialOnly", // Documentation depth
|
|
1096
|
-
select_5: "en", // Primary language
|
|
1097
|
-
checkbox_6: [], // No translation languages
|
|
1098
|
-
input_7: join(tempDir, "simple-docs"), // Documentation directory
|
|
1099
|
-
search: "", // Source paths (empty to finish)
|
|
1100
|
-
input_9: "Custom rules for documentation", // Custom rules (last step)
|
|
1101
|
-
};
|
|
1102
|
-
|
|
1103
|
-
const mockPrompts = createMockPrompts(mockResponses);
|
|
1104
|
-
const options = { prompts: mockPrompts };
|
|
1105
|
-
|
|
1106
|
-
const result = await init(
|
|
1107
|
-
{
|
|
1108
|
-
outputPath: tempDir,
|
|
1109
|
-
fileName: "simple-config.yaml",
|
|
1110
|
-
skipIfExists: false,
|
|
1111
|
-
},
|
|
1112
|
-
options,
|
|
1113
|
-
);
|
|
1114
|
-
|
|
1115
|
-
expect(result).toBeDefined();
|
|
1116
|
-
|
|
1117
|
-
const configPath = join(tempDir, "simple-config.yaml");
|
|
1118
|
-
const configContent = await fs.readFile(configPath, "utf8");
|
|
1119
|
-
const config = parseYAML(configContent);
|
|
1120
|
-
|
|
1121
|
-
expect(config.documentPurpose).toEqual(["getStarted"]);
|
|
1122
|
-
expect(config.targetAudienceTypes).toEqual(["endUsers"]);
|
|
1123
|
-
expect(config.rules).toBe("Custom rules for documentation");
|
|
1124
|
-
expect(config.readerKnowledgeLevel).toBe("completeBeginners");
|
|
1125
|
-
expect(config.documentationDepth).toBe("essentialOnly");
|
|
1126
|
-
expect(config.locale).toBe("en");
|
|
1127
|
-
expect(config.translateLanguages).toBeUndefined();
|
|
1128
|
-
} finally {
|
|
1129
|
-
await cleanupTempDir(tempDir);
|
|
1130
|
-
}
|
|
1131
|
-
});
|
|
1132
|
-
});
|
|
1133
|
-
|
|
1134
|
-
describe("Source paths handling", () => {
|
|
1135
|
-
test("should handle multiple source paths input when search returns valid paths", async () => {
|
|
1136
|
-
const tempDir = await createTempDir();
|
|
1137
|
-
|
|
1138
|
-
try {
|
|
1139
|
-
let searchCallCount = 0;
|
|
1140
|
-
const sourcePaths = ["./src", "./lib", "./packages", ""];
|
|
1141
|
-
|
|
1142
|
-
const mockPrompts = {
|
|
1143
|
-
checkbox: () => Promise.resolve(["getStarted"]),
|
|
1144
|
-
select: () => Promise.resolve("en"),
|
|
1145
|
-
input: () => Promise.resolve(join(tempDir, "docs")),
|
|
1146
|
-
search: () => {
|
|
1147
|
-
const response = sourcePaths[searchCallCount];
|
|
1148
|
-
searchCallCount++;
|
|
1149
|
-
return Promise.resolve(response);
|
|
1150
|
-
},
|
|
1151
|
-
};
|
|
1152
|
-
|
|
1153
|
-
const options = { prompts: mockPrompts };
|
|
1154
|
-
|
|
1155
|
-
// First let's create the directories that will be searched for
|
|
1156
|
-
await fs.mkdir(join(process.cwd(), "src"), { recursive: true }).catch(() => {
|
|
1157
|
-
// Ignore if directory already exists
|
|
1158
|
-
});
|
|
1159
|
-
await fs.mkdir(join(process.cwd(), "lib"), { recursive: true }).catch(() => {
|
|
1160
|
-
// Ignore if directory already exists
|
|
1161
|
-
});
|
|
1162
|
-
await fs.mkdir(join(process.cwd(), "packages"), { recursive: true }).catch(() => {
|
|
1163
|
-
// Ignore if directory already exists
|
|
1164
|
-
});
|
|
1165
|
-
|
|
1166
|
-
try {
|
|
1167
|
-
const result = await init(
|
|
1168
|
-
{ outputPath: tempDir, fileName: "config.yaml", skipIfExists: false },
|
|
1169
|
-
options,
|
|
1170
|
-
);
|
|
1171
|
-
|
|
1172
|
-
expect(result).toBeDefined();
|
|
1173
|
-
|
|
1174
|
-
const configPath = join(tempDir, "config.yaml");
|
|
1175
|
-
const configContent = await fs.readFile(configPath, "utf8");
|
|
1176
|
-
const config = parseYAML(configContent);
|
|
1177
|
-
|
|
1178
|
-
// Should contain the paths that were added before empty string
|
|
1179
|
-
expect(config.sourcesPath.length).toBeGreaterThan(0);
|
|
1180
|
-
} finally {
|
|
1181
|
-
// Clean up test directories
|
|
1182
|
-
await fs.rm(join(process.cwd(), "src"), { recursive: true, force: true }).catch(() => {
|
|
1183
|
-
// Ignore cleanup errors since directories may not exist
|
|
1184
|
-
});
|
|
1185
|
-
await fs.rm(join(process.cwd(), "lib"), { recursive: true, force: true }).catch(() => {
|
|
1186
|
-
// Ignore cleanup errors since directories may not exist
|
|
1187
|
-
});
|
|
1188
|
-
await fs
|
|
1189
|
-
.rm(join(process.cwd(), "packages"), { recursive: true, force: true })
|
|
1190
|
-
.catch(() => {
|
|
1191
|
-
// Ignore cleanup errors since directories may not exist
|
|
1192
|
-
});
|
|
1193
|
-
}
|
|
1194
|
-
} finally {
|
|
1195
|
-
await cleanupTempDir(tempDir);
|
|
1196
|
-
}
|
|
1197
|
-
});
|
|
1198
|
-
|
|
1199
|
-
test("should use default source path when no paths provided", async () => {
|
|
1200
|
-
const tempDir = await createTempDir();
|
|
1201
|
-
|
|
1202
|
-
try {
|
|
1203
|
-
const mockPrompts = {
|
|
1204
|
-
checkbox: () => Promise.resolve(["getStarted"]),
|
|
1205
|
-
select: () => Promise.resolve("en"),
|
|
1206
|
-
input: () => Promise.resolve(join(tempDir, "docs")),
|
|
1207
|
-
search: () => Promise.resolve(""), // Immediately finish without adding paths
|
|
1208
|
-
};
|
|
1209
|
-
|
|
1210
|
-
const options = { prompts: mockPrompts };
|
|
1211
|
-
|
|
1212
|
-
const result = await init(
|
|
1213
|
-
{ outputPath: tempDir, fileName: "config.yaml", skipIfExists: false },
|
|
1214
|
-
options,
|
|
1215
|
-
);
|
|
1216
|
-
|
|
1217
|
-
expect(result).toBeDefined();
|
|
1218
|
-
|
|
1219
|
-
const configPath = join(tempDir, "config.yaml");
|
|
1220
|
-
const configContent = await fs.readFile(configPath, "utf8");
|
|
1221
|
-
const config = parseYAML(configContent);
|
|
1222
|
-
|
|
1223
|
-
expect(config.sourcesPath).toEqual(["./"]); // Default value
|
|
1224
|
-
} finally {
|
|
1225
|
-
await cleanupTempDir(tempDir);
|
|
1226
|
-
}
|
|
1227
|
-
});
|
|
1228
|
-
});
|
|
1229
|
-
|
|
1230
|
-
describe("Skip existing configuration", () => {
|
|
1231
|
-
test("should skip if config exists and skipIfExists is true", async () => {
|
|
1232
|
-
const tempDir = await createTempDir();
|
|
1233
|
-
|
|
1234
|
-
try {
|
|
1235
|
-
// Create existing config file
|
|
1236
|
-
const configPath = join(tempDir, "config.yaml");
|
|
1237
|
-
const existingConfig = 'projectName: "Existing Project"\nlocale: "zh"';
|
|
1238
|
-
await fs.writeFile(configPath, existingConfig, "utf8");
|
|
1239
|
-
|
|
1240
|
-
const mockPrompts = {
|
|
1241
|
-
checkbox: () => Promise.resolve(["getStarted"]),
|
|
1242
|
-
select: () => Promise.resolve("en"),
|
|
1243
|
-
input: () => Promise.resolve("docs"),
|
|
1244
|
-
search: () => Promise.resolve(""),
|
|
1245
|
-
};
|
|
1246
|
-
|
|
1247
|
-
const options = { prompts: mockPrompts };
|
|
1248
|
-
|
|
1249
|
-
const result = await init(
|
|
1250
|
-
{ outputPath: tempDir, fileName: "config.yaml", skipIfExists: true },
|
|
1251
|
-
options,
|
|
1252
|
-
);
|
|
1253
|
-
|
|
1254
|
-
expect(result).toBeDefined();
|
|
1255
|
-
|
|
1256
|
-
// Config should remain unchanged
|
|
1257
|
-
const configContent = await fs.readFile(configPath, "utf8");
|
|
1258
|
-
expect(configContent).toBe(existingConfig);
|
|
1259
|
-
} finally {
|
|
1260
|
-
await cleanupTempDir(tempDir);
|
|
1261
|
-
}
|
|
1262
|
-
});
|
|
1263
|
-
|
|
1264
|
-
test("should not skip if config file is empty even when skipIfExists is true", async () => {
|
|
1265
|
-
const tempDir = await createTempDir();
|
|
1266
|
-
|
|
1267
|
-
try {
|
|
1268
|
-
// Create empty config file
|
|
1269
|
-
const configPath = join(tempDir, "config.yaml");
|
|
1270
|
-
await fs.writeFile(configPath, "", "utf8");
|
|
1271
|
-
|
|
1272
|
-
const mockPrompts = {
|
|
1273
|
-
checkbox: () => Promise.resolve(["getStarted"]),
|
|
1274
|
-
select: () => Promise.resolve("en"),
|
|
1275
|
-
input: () => Promise.resolve(join(tempDir, "docs")),
|
|
1276
|
-
search: () => Promise.resolve(""),
|
|
1277
|
-
};
|
|
1278
|
-
|
|
1279
|
-
const options = { prompts: mockPrompts };
|
|
1280
|
-
|
|
1281
|
-
const result = await init(
|
|
1282
|
-
{ outputPath: tempDir, fileName: "config.yaml", skipIfExists: true },
|
|
1283
|
-
options,
|
|
1284
|
-
);
|
|
1285
|
-
|
|
1286
|
-
expect(result).toBeDefined();
|
|
1287
|
-
|
|
1288
|
-
// Config should be generated since original was empty
|
|
1289
|
-
const configContent = await fs.readFile(configPath, "utf8");
|
|
1290
|
-
expect(configContent).toContain("projectName:");
|
|
1291
|
-
expect(configContent).toContain("locale: en");
|
|
1292
|
-
} finally {
|
|
1293
|
-
await cleanupTempDir(tempDir);
|
|
1294
|
-
}
|
|
1295
|
-
});
|
|
1296
|
-
});
|
|
1297
|
-
|
|
1298
|
-
describe("Validation error handling", () => {
|
|
1299
|
-
test("should handle empty document purpose validation", async () => {
|
|
1300
|
-
const tempDir = await createTempDir();
|
|
1301
|
-
|
|
1302
|
-
try {
|
|
1303
|
-
// Mock prompts that will trigger validation errors by calling validate function
|
|
1304
|
-
let validateCalled = false;
|
|
1305
|
-
const mockPrompts = {
|
|
1306
|
-
checkbox: (options) => {
|
|
1307
|
-
if (options.message.includes("[1/9]") && options.validate) {
|
|
1308
|
-
// Test the validation function directly
|
|
1309
|
-
const validationResult = options.validate([]);
|
|
1310
|
-
expect(validationResult).toBe(
|
|
1311
|
-
"Please choose at least one goal for your documentation.",
|
|
1312
|
-
);
|
|
1313
|
-
validateCalled = true;
|
|
1314
|
-
// Return valid result after testing validation
|
|
1315
|
-
return Promise.resolve(["getStarted"]);
|
|
1316
|
-
}
|
|
1317
|
-
return Promise.resolve(["getStarted"]);
|
|
1318
|
-
},
|
|
1319
|
-
select: () => Promise.resolve("en"),
|
|
1320
|
-
input: () => Promise.resolve(join(tempDir, "docs")),
|
|
1321
|
-
search: () => Promise.resolve(""),
|
|
1322
|
-
};
|
|
1323
|
-
|
|
1324
|
-
const options = { prompts: mockPrompts };
|
|
1325
|
-
|
|
1326
|
-
const result = await init(
|
|
1327
|
-
{ outputPath: tempDir, fileName: "config.yaml", skipIfExists: false },
|
|
1328
|
-
options,
|
|
1329
|
-
);
|
|
1330
|
-
|
|
1331
|
-
expect(result).toBeDefined();
|
|
1332
|
-
expect(validateCalled).toBe(true);
|
|
1333
|
-
} finally {
|
|
1334
|
-
await cleanupTempDir(tempDir);
|
|
1335
|
-
}
|
|
1336
|
-
});
|
|
1337
|
-
|
|
1338
|
-
test("should handle empty target audience validation", async () => {
|
|
1339
|
-
const tempDir = await createTempDir();
|
|
1340
|
-
|
|
1341
|
-
try {
|
|
1342
|
-
let audienceValidateCalled = false;
|
|
1343
|
-
const mockPrompts = {
|
|
1344
|
-
checkbox: (options) => {
|
|
1345
|
-
if (options.message.includes("[1/9]")) {
|
|
1346
|
-
return Promise.resolve(["getStarted"]); // Valid document purpose
|
|
1347
|
-
}
|
|
1348
|
-
if (options.message.includes("[2/9]") && options.validate) {
|
|
1349
|
-
// Test the validation function for target audience
|
|
1350
|
-
const validationResult = options.validate([]);
|
|
1351
|
-
expect(validationResult).toBe("Please choose at least one audience.");
|
|
1352
|
-
audienceValidateCalled = true;
|
|
1353
|
-
return Promise.resolve(["developers"]); // Valid result after testing
|
|
1354
|
-
}
|
|
1355
|
-
return Promise.resolve(["developers"]);
|
|
1356
|
-
},
|
|
1357
|
-
select: () => Promise.resolve("en"),
|
|
1358
|
-
input: () => Promise.resolve(join(tempDir, "docs")),
|
|
1359
|
-
search: () => Promise.resolve(""),
|
|
1360
|
-
};
|
|
1361
|
-
|
|
1362
|
-
const options = { prompts: mockPrompts };
|
|
1363
|
-
|
|
1364
|
-
const result = await init(
|
|
1365
|
-
{ outputPath: tempDir, fileName: "config.yaml", skipIfExists: false },
|
|
1366
|
-
options,
|
|
1367
|
-
);
|
|
1368
|
-
|
|
1369
|
-
expect(result).toBeDefined();
|
|
1370
|
-
expect(audienceValidateCalled).toBe(true);
|
|
1371
|
-
} finally {
|
|
1372
|
-
await cleanupTempDir(tempDir);
|
|
1373
|
-
}
|
|
1374
|
-
});
|
|
1375
|
-
|
|
1376
|
-
test("should handle mixed purpose priority validation errors", async () => {
|
|
1377
|
-
const tempDir = await createTempDir();
|
|
1378
|
-
|
|
1379
|
-
try {
|
|
1380
|
-
let priorityValidateCalled = false;
|
|
1381
|
-
const mockPrompts = {
|
|
1382
|
-
checkbox: (options) => {
|
|
1383
|
-
if (options.message.includes("[1/9]")) {
|
|
1384
|
-
return Promise.resolve(["mixedPurpose"]); // Trigger follow-up question
|
|
1385
|
-
}
|
|
1386
|
-
// This is the follow-up priority selection
|
|
1387
|
-
if (options.message.includes("Which is most important?") && options.validate) {
|
|
1388
|
-
// Test validation for empty selection
|
|
1389
|
-
let validationResult = options.validate([]);
|
|
1390
|
-
expect(validationResult).toBe("Please choose at least one priority.");
|
|
1391
|
-
|
|
1392
|
-
// Test validation for too many selections
|
|
1393
|
-
validationResult = options.validate(["getStarted", "completeTasks", "findAnswers"]);
|
|
1394
|
-
expect(validationResult).toBe("Please choose maximum 2 priorities.");
|
|
1395
|
-
|
|
1396
|
-
// Test validation for valid selection
|
|
1397
|
-
validationResult = options.validate(["getStarted", "completeTasks"]);
|
|
1398
|
-
expect(validationResult).toBe(true);
|
|
1399
|
-
|
|
1400
|
-
priorityValidateCalled = true;
|
|
1401
|
-
return Promise.resolve(["getStarted", "completeTasks"]); // Valid selection
|
|
1402
|
-
}
|
|
1403
|
-
return Promise.resolve(["getStarted", "completeTasks"]);
|
|
1404
|
-
},
|
|
1405
|
-
select: () => Promise.resolve("en"),
|
|
1406
|
-
input: () => Promise.resolve(join(tempDir, "docs")),
|
|
1407
|
-
search: () => Promise.resolve(""),
|
|
1408
|
-
};
|
|
1409
|
-
|
|
1410
|
-
const options = { prompts: mockPrompts };
|
|
1411
|
-
|
|
1412
|
-
const result = await init(
|
|
1413
|
-
{ outputPath: tempDir, fileName: "config.yaml", skipIfExists: false },
|
|
1414
|
-
options,
|
|
1415
|
-
);
|
|
1416
|
-
|
|
1417
|
-
expect(result).toBeDefined();
|
|
1418
|
-
expect(priorityValidateCalled).toBe(true);
|
|
1419
|
-
} finally {
|
|
1420
|
-
await cleanupTempDir(tempDir);
|
|
1421
|
-
}
|
|
1422
|
-
});
|
|
1423
|
-
|
|
1424
|
-
test("should handle file write errors", async () => {
|
|
1425
|
-
const invalidPath = "/invalid/path/that/does/not/exist";
|
|
1426
|
-
|
|
1427
|
-
const mockPrompts = {
|
|
1428
|
-
checkbox: () => Promise.resolve(["getStarted"]),
|
|
1429
|
-
select: () => Promise.resolve("en"),
|
|
1430
|
-
input: () => Promise.resolve("docs"),
|
|
1431
|
-
search: () => Promise.resolve(""),
|
|
1432
|
-
};
|
|
1433
|
-
|
|
1434
|
-
const options = { prompts: mockPrompts };
|
|
1435
|
-
|
|
1436
|
-
const result = await init(
|
|
1437
|
-
{ outputPath: invalidPath, fileName: "config.yaml", skipIfExists: false },
|
|
1438
|
-
options,
|
|
1439
|
-
);
|
|
1440
|
-
|
|
1441
|
-
expect(result).toHaveProperty("inputGeneratorStatus", false);
|
|
1442
|
-
expect(result).toHaveProperty("inputGeneratorError");
|
|
1443
|
-
expect(typeof result.inputGeneratorError).toBe("string");
|
|
1444
|
-
});
|
|
1445
|
-
});
|
|
1446
|
-
|
|
1447
|
-
describe("checkOnly parameter", () => {
|
|
1448
|
-
test("should exit silently when checkOnly is true and config exists", async () => {
|
|
1449
|
-
const tempDir = await createTempDir();
|
|
1450
|
-
|
|
1451
|
-
try {
|
|
1452
|
-
// Create existing config file
|
|
1453
|
-
const configPath = join(tempDir, "config.yaml");
|
|
1454
|
-
const existingConfig = `projectName: "Test Project"
|
|
1455
|
-
locale: "en"
|
|
1456
|
-
documentPurpose:
|
|
1457
|
-
- getStarted
|
|
1458
|
-
targetAudienceTypes:
|
|
1459
|
-
- developers`;
|
|
1460
|
-
await fs.writeFile(configPath, existingConfig, "utf8");
|
|
1461
|
-
|
|
1462
|
-
// The function should continue normally when config exists
|
|
1463
|
-
// No mocking needed as it doesn't log or exit in this case
|
|
1464
|
-
const result = await init(
|
|
1465
|
-
{
|
|
1466
|
-
outputPath: tempDir,
|
|
1467
|
-
fileName: "config.yaml",
|
|
1468
|
-
checkOnly: true,
|
|
1469
|
-
},
|
|
1470
|
-
{ prompts: {} }, // Options not needed for checkOnly
|
|
1471
|
-
);
|
|
1472
|
-
|
|
1473
|
-
// Should return loaded config
|
|
1474
|
-
expect(result).toBeDefined();
|
|
1475
|
-
expect(result.projectName).toBe("Test Project");
|
|
1476
|
-
expect(result.locale).toBe("en");
|
|
1477
|
-
} finally {
|
|
1478
|
-
await cleanupTempDir(tempDir);
|
|
1479
|
-
}
|
|
1480
|
-
});
|
|
1481
|
-
|
|
1482
|
-
test("should show reminder and exit when checkOnly is true and config doesn't exist", async () => {
|
|
1483
|
-
const tempDir = await createTempDir();
|
|
1484
|
-
|
|
1485
|
-
try {
|
|
1486
|
-
// Mock console.log and process.exit
|
|
1487
|
-
const originalLog = console.log;
|
|
1488
|
-
const originalExit = process.exit;
|
|
1489
|
-
const logMessages = [];
|
|
1490
|
-
let exitCalled = false;
|
|
1491
|
-
let exitCode = null;
|
|
1492
|
-
|
|
1493
|
-
console.log = (...args) => logMessages.push(args.join(" "));
|
|
1494
|
-
process.exit = (code) => {
|
|
1495
|
-
exitCalled = true;
|
|
1496
|
-
exitCode = code;
|
|
1497
|
-
throw new Error("process.exit called"); // Prevent actual exit
|
|
1498
|
-
};
|
|
1499
|
-
|
|
1500
|
-
try {
|
|
1501
|
-
await expect(
|
|
1502
|
-
init(
|
|
1503
|
-
{
|
|
1504
|
-
outputPath: tempDir,
|
|
1505
|
-
fileName: "config.yaml",
|
|
1506
|
-
checkOnly: true,
|
|
1507
|
-
},
|
|
1508
|
-
{ prompts: {} },
|
|
1509
|
-
),
|
|
1510
|
-
).rejects.toThrow("process.exit called");
|
|
1511
|
-
|
|
1512
|
-
// Should log reminder messages
|
|
1513
|
-
expect(logMessages.some((msg) => msg.includes("No configuration found"))).toBe(true);
|
|
1514
|
-
expect(logMessages.some((msg) => msg.includes("aigne doc init"))).toBe(true);
|
|
1515
|
-
|
|
1516
|
-
// Should call process.exit(0)
|
|
1517
|
-
expect(exitCalled).toBe(true);
|
|
1518
|
-
expect(exitCode).toBe(0);
|
|
1519
|
-
} finally {
|
|
1520
|
-
console.log = originalLog;
|
|
1521
|
-
process.exit = originalExit;
|
|
1522
|
-
}
|
|
1523
|
-
} finally {
|
|
1524
|
-
await cleanupTempDir(tempDir);
|
|
1525
|
-
}
|
|
1526
|
-
});
|
|
1527
|
-
|
|
1528
|
-
test("should not interfere with normal workflow when checkOnly is false", async () => {
|
|
1529
|
-
const tempDir = await createTempDir();
|
|
1530
|
-
|
|
1531
|
-
try {
|
|
1532
|
-
const mockPrompts = createMockPrompts({
|
|
1533
|
-
checkbox_1: ["getStarted"],
|
|
1534
|
-
checkbox_2: ["developers"],
|
|
1535
|
-
select_3: "domainFamiliar",
|
|
1536
|
-
select_4: "balancedCoverage",
|
|
1537
|
-
select_5: "en",
|
|
1538
|
-
checkbox_6: [],
|
|
1539
|
-
input_7: join(tempDir, "docs"),
|
|
1540
|
-
search: "",
|
|
1541
|
-
});
|
|
1542
|
-
|
|
1543
|
-
const options = { prompts: mockPrompts };
|
|
1544
|
-
|
|
1545
|
-
const result = await init(
|
|
1546
|
-
{
|
|
1547
|
-
outputPath: tempDir,
|
|
1548
|
-
fileName: "config.yaml",
|
|
1549
|
-
checkOnly: false, // Explicit false
|
|
1550
|
-
},
|
|
1551
|
-
options,
|
|
1552
|
-
);
|
|
1553
|
-
|
|
1554
|
-
expect(result).toBeDefined();
|
|
1555
|
-
|
|
1556
|
-
// Check that config file was created normally
|
|
1557
|
-
const configPath = join(tempDir, "config.yaml");
|
|
1558
|
-
const configExists = await fs
|
|
1559
|
-
.access(configPath)
|
|
1560
|
-
.then(() => true)
|
|
1561
|
-
.catch(() => false);
|
|
1562
|
-
expect(configExists).toBe(true);
|
|
1563
|
-
} finally {
|
|
1564
|
-
await cleanupTempDir(tempDir);
|
|
1565
|
-
}
|
|
1566
|
-
});
|
|
1567
|
-
});
|
|
1568
|
-
|
|
1569
|
-
describe("Advanced source path scenarios", () => {
|
|
1570
|
-
test("should handle source path validation and duplicate detection", async () => {
|
|
1571
|
-
const tempDir = await createTempDir();
|
|
1572
|
-
|
|
1573
|
-
try {
|
|
1574
|
-
let searchCallCount = 0;
|
|
1575
|
-
const responses = [
|
|
1576
|
-
"invalid/path/that/does/not/exist", // Should trigger validation error
|
|
1577
|
-
"invalid/path/that/does/not/exist", // Duplicate path
|
|
1578
|
-
join(tempDir, "valid-path"), // Valid path after creating it
|
|
1579
|
-
join(tempDir, "valid-path"), // Duplicate of valid path
|
|
1580
|
-
"**/*.glob", // Glob pattern (should be accepted)
|
|
1581
|
-
"**/*.glob", // Duplicate glob pattern
|
|
1582
|
-
"", // End input
|
|
1583
|
-
];
|
|
1584
|
-
|
|
1585
|
-
// Create a valid directory for testing
|
|
1586
|
-
await fs.mkdir(join(tempDir, "valid-path"), { recursive: true });
|
|
1587
|
-
|
|
1588
|
-
const mockPrompts = {
|
|
1589
|
-
checkbox: () => Promise.resolve(["getStarted"]),
|
|
1590
|
-
select: () => Promise.resolve("en"),
|
|
1591
|
-
input: () => Promise.resolve(join(tempDir, "docs")),
|
|
1592
|
-
search: () => {
|
|
1593
|
-
const response = responses[searchCallCount];
|
|
1594
|
-
searchCallCount++;
|
|
1595
|
-
return Promise.resolve(response);
|
|
1596
|
-
},
|
|
1597
|
-
};
|
|
1598
|
-
|
|
1599
|
-
const options = { prompts: mockPrompts };
|
|
1600
|
-
|
|
1601
|
-
const result = await init(
|
|
1602
|
-
{ outputPath: tempDir, fileName: "config.yaml", skipIfExists: false },
|
|
1603
|
-
options,
|
|
1604
|
-
);
|
|
1605
|
-
|
|
1606
|
-
expect(result).toBeDefined();
|
|
1607
|
-
|
|
1608
|
-
const configPath = join(tempDir, "config.yaml");
|
|
1609
|
-
const configContent = await fs.readFile(configPath, "utf8");
|
|
1610
|
-
const config = parseYAML(configContent);
|
|
1611
|
-
|
|
1612
|
-
// Should contain the valid paths that were successfully added
|
|
1613
|
-
expect(config.sourcesPath.length).toBeGreaterThan(0);
|
|
1614
|
-
} finally {
|
|
1615
|
-
await cleanupTempDir(tempDir);
|
|
1616
|
-
}
|
|
1617
|
-
});
|
|
1618
|
-
|
|
1619
|
-
test("should handle search source function callback", async () => {
|
|
1620
|
-
const tempDir = await createTempDir();
|
|
1621
|
-
|
|
1622
|
-
try {
|
|
1623
|
-
const mockPrompts = {
|
|
1624
|
-
checkbox: () => Promise.resolve(["getStarted"]),
|
|
1625
|
-
select: () => Promise.resolve("en"),
|
|
1626
|
-
input: () => Promise.resolve(join(tempDir, "docs")),
|
|
1627
|
-
search: (options) => {
|
|
1628
|
-
// Test the source callback function
|
|
1629
|
-
if (options?.source) {
|
|
1630
|
-
// Call the source function with different inputs to test the logic
|
|
1631
|
-
const sourceResults1 = options.source("");
|
|
1632
|
-
const sourceResults2 = options.source("src");
|
|
1633
|
-
const sourceResults3 = options.source("**/*.js");
|
|
1634
|
-
|
|
1635
|
-
// Verify these are promises
|
|
1636
|
-
expect(sourceResults1).toBeInstanceOf(Promise);
|
|
1637
|
-
expect(sourceResults2).toBeInstanceOf(Promise);
|
|
1638
|
-
expect(sourceResults3).toBeInstanceOf(Promise);
|
|
1639
|
-
}
|
|
1640
|
-
return Promise.resolve(""); // End input
|
|
1641
|
-
},
|
|
1642
|
-
};
|
|
1643
|
-
|
|
1644
|
-
const options = { prompts: mockPrompts };
|
|
1645
|
-
|
|
1646
|
-
const result = await init(
|
|
1647
|
-
{ outputPath: tempDir, fileName: "config.yaml", skipIfExists: false },
|
|
1648
|
-
options,
|
|
1649
|
-
);
|
|
1650
|
-
|
|
1651
|
-
expect(result).toBeDefined();
|
|
1652
|
-
} finally {
|
|
1653
|
-
await cleanupTempDir(tempDir);
|
|
1654
|
-
}
|
|
1655
|
-
});
|
|
1656
|
-
});
|
|
1657
|
-
});
|