@aigne/doc-smith 0.8.6 → 0.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.aigne/doc-smith/output/structure-plan.json +1 -5
- package/CHANGELOG.md +7 -0
- package/README.md +3 -3
- package/agents/{chat.yaml → chat/index.yaml} +7 -7
- package/agents/generate/check-document-structure.yaml +30 -0
- package/agents/{check-structure-plan.mjs → generate/check-need-generate-structure.mjs} +20 -20
- package/agents/{structure-planning.yaml → generate/generate-structure.yaml} +6 -6
- package/agents/{docs-generator.yaml → generate/index.yaml} +11 -12
- package/agents/generate/refine-document-structure.yaml +12 -0
- package/agents/{input-generator.mjs → init/index.mjs} +12 -5
- package/agents/{manage-prefs.mjs → prefs/index.mjs} +1 -1
- package/agents/{team-publish-docs.yaml → publish/index.yaml} +1 -2
- package/agents/{publish-docs.mjs → publish/publish-docs.mjs} +6 -5
- package/agents/schema/{structure-plan-result.yaml → document-execution-structure.yaml} +3 -3
- package/agents/schema/document-structure.yaml +26 -0
- package/agents/{language-selector.mjs → translate/choose-language.mjs} +5 -5
- package/agents/{retranslate.yaml → translate/index.yaml} +11 -12
- package/agents/{translate.yaml → translate/translate-document.yaml} +3 -2
- package/agents/{batch-translate.yaml → translate/translate-multilingual.yaml} +5 -5
- package/agents/update/batch-generate-document.yaml +19 -0
- package/agents/{check-detail.mjs → update/check-document.mjs} +16 -16
- package/agents/{detail-generator-and-translate.yaml → update/generate-and-translate-document.yaml} +23 -23
- package/agents/update/generate-document.yaml +50 -0
- package/agents/{detail-regenerator.yaml → update/index.yaml} +10 -11
- package/agents/{action-success.mjs → utils/action-success.mjs} +1 -1
- package/agents/{check-detail-result.mjs → utils/check-detail-result.mjs} +3 -3
- package/agents/{check-feedback-refiner.mjs → utils/check-feedback-refiner.mjs} +6 -6
- package/agents/{find-items-by-paths.mjs → utils/choose-docs.mjs} +24 -9
- package/agents/{docs-fs.yaml → utils/docs-fs-actor.yaml} +3 -1
- package/agents/{feedback-refiner.yaml → utils/feedback-refiner.yaml} +2 -4
- package/agents/{find-item-by-path.mjs → utils/find-item-by-path.mjs} +16 -6
- package/agents/{find-user-preferences-by-path.mjs → utils/find-user-preferences-by-path.mjs} +1 -1
- package/agents/utils/format-document-structure.mjs +25 -0
- package/agents/{load-sources.mjs → utils/load-sources.mjs} +41 -28
- package/agents/{save-docs.mjs → utils/save-docs.mjs} +16 -16
- package/agents/{save-single-doc.mjs → utils/save-single-doc.mjs} +2 -2
- package/agents/{transform-detail-datasources.mjs → utils/transform-detail-datasources.mjs} +1 -1
- package/aigne.yaml +35 -35
- package/docs-mcp/analyze-docs-relevance.yaml +10 -10
- package/docs-mcp/docs-search.yaml +5 -3
- package/package.json +10 -8
- package/prompts/{document → detail/custom}/custom-code-block.md +6 -6
- package/prompts/detail/custom/custom-components.md +172 -0
- package/prompts/{document → detail}/d2-chart/rules.md +95 -1
- package/prompts/{document → detail}/detail-example.md +80 -61
- package/prompts/{document/detail-generator.md → detail/document-rules.md} +4 -8
- package/prompts/{content-detail-generator.md → detail/generate-document.md} +48 -25
- package/prompts/{check-structure-planning-result.md → structure/check-document-structure.md} +23 -17
- package/prompts/{document/structure-planning.md → structure/document-rules.md} +0 -2
- package/prompts/{structure-planning.md → structure/generate-structure.md} +51 -30
- package/prompts/{document → structure}/structure-example.md +2 -2
- package/prompts/{document → structure}/structure-getting-started.md +2 -2
- package/prompts/translate/glossary.md +6 -0
- package/prompts/{translator.md → translate/translate-document.md} +29 -10
- package/prompts/{feedback-refiner.md → utils/feedback-refiner.md} +8 -8
- package/tests/agents/chat/chat.test.mjs +46 -0
- package/tests/agents/generate/check-document-structure.test.mjs +51 -0
- package/tests/agents/generate/check-need-generate-structure.test.mjs +292 -0
- package/tests/agents/generate/generate-structure.test.mjs +51 -0
- package/tests/{input-generator.test.mjs → agents/init/init.test.mjs} +13 -13
- package/tests/agents/prefs/prefs.test.mjs +431 -0
- package/tests/agents/publish/publish-docs.test.mjs +642 -0
- package/tests/agents/translate/choose-language.test.mjs +311 -0
- package/tests/agents/translate/translate-document.test.mjs +51 -0
- package/tests/agents/update/check-document.test.mjs +523 -0
- package/tests/agents/update/generate-document.test.mjs +51 -0
- package/tests/agents/utils/action-success.test.mjs +54 -0
- package/tests/{check-detail-result.test.mjs → agents/utils/check-detail-result.test.mjs} +98 -98
- package/tests/agents/utils/check-feedback-refiner.test.mjs +478 -0
- package/tests/agents/utils/choose-docs.test.mjs +417 -0
- package/tests/agents/utils/exit.test.mjs +70 -0
- package/tests/agents/utils/feedback-refiner.test.mjs +51 -0
- package/tests/agents/utils/find-item-by-path.test.mjs +526 -0
- package/tests/agents/utils/find-user-preferences-by-path.test.mjs +382 -0
- package/tests/agents/utils/format-document-structure.test.mjs +264 -0
- package/tests/agents/utils/fs.test.mjs +267 -0
- package/tests/{load-sources.test.mjs → agents/utils/load-sources.test.mjs} +153 -25
- package/tests/{save-docs.test.mjs → agents/utils/save-docs.test.mjs} +11 -5
- package/tests/agents/utils/save-output.test.mjs +315 -0
- package/tests/agents/utils/save-single-doc.test.mjs +364 -0
- package/tests/agents/utils/transform-detail-datasources.test.mjs +363 -0
- package/tests/utils/auth-utils.test.mjs +358 -0
- package/tests/utils/blocklet.test.mjs +334 -0
- package/tests/{conflict-resolution.test.mjs → utils/conflict-detector.test.mjs} +3 -3
- package/tests/utils/constants.test.mjs +295 -0
- package/tests/utils/d2-utils.test.mjs +423 -0
- package/tests/{deploy.test.mjs → utils/deploy.test.mjs} +25 -36
- package/tests/utils/docs-finder-utils.test.mjs +625 -0
- package/tests/utils/file-utils.test.mjs +213 -0
- package/tests/{kroki-utils.test.mjs → utils/kroki-utils.test.mjs} +2 -2
- package/tests/utils/load-config.test.mjs +141 -0
- package/tests/{mermaid-validation.test.mjs → utils/mermaid-validator.test.mjs} +2 -2
- package/tests/utils/mock-chat-model.mjs +12 -0
- package/tests/{preferences-utils.test.mjs → utils/preferences-utils.test.mjs} +1 -1
- package/tests/{save-value-to-config.test.mjs → utils/save-value-to-config.test.mjs} +61 -4
- package/tests/utils/utils.test.mjs +939 -0
- package/utils/conflict-detector.mjs +1 -1
- package/utils/constants.mjs +5 -3
- package/utils/d2-utils.mjs +194 -0
- package/utils/docs-finder-utils.mjs +26 -26
- package/utils/icon-map.mjs +26 -0
- package/{agents → utils}/load-config.mjs +2 -18
- package/utils/markdown-checker.mjs +5 -5
- package/agents/batch-docs-detail-generator.yaml +0 -19
- package/agents/check-structure-planning-result.yaml +0 -30
- package/agents/content-detail-generator.yaml +0 -50
- package/agents/format-structure-plan.mjs +0 -25
- package/agents/reflective-structure-planner.yaml +0 -12
- package/agents/schema/structure-plan.yaml +0 -26
- package/prompts/document/custom-components.md +0 -104
- package/tests/README.md +0 -93
- package/tests/utils.test.mjs +0 -2067
- /package/agents/{exit.mjs → utils/exit.mjs} +0 -0
- /package/agents/{fs.mjs → utils/fs.mjs} +0 -0
- /package/agents/{save-output.mjs → utils/save-output.mjs} +0 -0
- /package/prompts/{document → detail}/d2-chart/official-examples.md +0 -0
- /package/prompts/{document → detail}/jsx/rules.md +0 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { getFilesWithGlob, loadGitignore } from "../../utils/file-utils.mjs";
|
|
6
|
+
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
|
|
9
|
+
describe("file-utils", () => {
|
|
10
|
+
let testDir;
|
|
11
|
+
|
|
12
|
+
beforeEach(async () => {
|
|
13
|
+
// Create a temporary test directory
|
|
14
|
+
testDir = join(__dirname, "test-file-utils");
|
|
15
|
+
await mkdir(testDir, { recursive: true });
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
afterEach(async () => {
|
|
19
|
+
// Clean up test directory
|
|
20
|
+
try {
|
|
21
|
+
await rm(testDir, { recursive: true, force: true });
|
|
22
|
+
} catch {
|
|
23
|
+
// Ignore cleanup errors since they don't affect test results
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe("loadGitignore", () => {
|
|
28
|
+
test("should load gitignore patterns from current directory", async () => {
|
|
29
|
+
const gitignorePath = join(testDir, ".gitignore");
|
|
30
|
+
const gitignoreContent = `
|
|
31
|
+
node_modules/
|
|
32
|
+
dist/
|
|
33
|
+
*.log
|
|
34
|
+
.env
|
|
35
|
+
# Comment line
|
|
36
|
+
`.trim();
|
|
37
|
+
|
|
38
|
+
await writeFile(gitignorePath, gitignoreContent);
|
|
39
|
+
|
|
40
|
+
const patterns = await loadGitignore(testDir);
|
|
41
|
+
|
|
42
|
+
expect(patterns).toBeDefined();
|
|
43
|
+
expect(Array.isArray(patterns)).toBe(true);
|
|
44
|
+
expect(patterns.length).toBeGreaterThan(0);
|
|
45
|
+
|
|
46
|
+
// Should convert gitignore patterns to glob patterns
|
|
47
|
+
expect(patterns.some((p) => p.includes("node_modules"))).toBe(true);
|
|
48
|
+
expect(patterns.some((p) => p.includes("dist"))).toBe(true);
|
|
49
|
+
expect(patterns.some((p) => p.includes("*.log"))).toBe(true);
|
|
50
|
+
expect(patterns.some((p) => p.includes(".env"))).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("should load gitignore patterns from git repository", async () => {
|
|
54
|
+
const patterns = await loadGitignore(testDir);
|
|
55
|
+
// Since we're in a git repository, it should load patterns
|
|
56
|
+
expect(patterns).not.toBeNull();
|
|
57
|
+
expect(Array.isArray(patterns)).toBe(true);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("should handle empty gitignore file", async () => {
|
|
61
|
+
const gitignorePath = join(testDir, ".gitignore");
|
|
62
|
+
await writeFile(gitignorePath, "");
|
|
63
|
+
|
|
64
|
+
const patterns = await loadGitignore(testDir);
|
|
65
|
+
// Even with empty gitignore, parent git repo patterns are loaded
|
|
66
|
+
expect(patterns).not.toBeNull();
|
|
67
|
+
expect(Array.isArray(patterns)).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("should ignore comment lines and empty lines", async () => {
|
|
71
|
+
const gitignorePath = join(testDir, ".gitignore");
|
|
72
|
+
const gitignoreContent = `
|
|
73
|
+
# This is a comment
|
|
74
|
+
node_modules/
|
|
75
|
+
|
|
76
|
+
# Another comment
|
|
77
|
+
*.log
|
|
78
|
+
`.trim();
|
|
79
|
+
|
|
80
|
+
await writeFile(gitignorePath, gitignoreContent);
|
|
81
|
+
|
|
82
|
+
const patterns = await loadGitignore(testDir);
|
|
83
|
+
|
|
84
|
+
expect(patterns).toBeDefined();
|
|
85
|
+
// Should not contain empty strings or comments
|
|
86
|
+
expect(patterns.every((p) => p.trim().length > 0 && !p.startsWith("#"))).toBe(true);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("should handle various gitignore pattern formats", async () => {
|
|
90
|
+
const gitignorePath = join(testDir, ".gitignore");
|
|
91
|
+
const gitignoreContent = `
|
|
92
|
+
/absolute-path
|
|
93
|
+
relative-path
|
|
94
|
+
directory/
|
|
95
|
+
*.extension
|
|
96
|
+
**/*.js
|
|
97
|
+
temp*
|
|
98
|
+
`.trim();
|
|
99
|
+
|
|
100
|
+
await writeFile(gitignorePath, gitignoreContent);
|
|
101
|
+
|
|
102
|
+
const patterns = await loadGitignore(testDir);
|
|
103
|
+
|
|
104
|
+
expect(patterns).toBeDefined();
|
|
105
|
+
expect(patterns.length).toBeGreaterThan(0);
|
|
106
|
+
|
|
107
|
+
// Should handle different pattern types
|
|
108
|
+
expect(patterns.some((p) => p.includes("absolute-path"))).toBe(true);
|
|
109
|
+
expect(patterns.some((p) => p.includes("relative-path"))).toBe(true);
|
|
110
|
+
expect(patterns.some((p) => p.includes("directory"))).toBe(true);
|
|
111
|
+
expect(patterns.some((p) => p.includes("*.extension"))).toBe(true);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe("getFilesWithGlob", () => {
|
|
116
|
+
beforeEach(async () => {
|
|
117
|
+
// Create test file structure
|
|
118
|
+
await mkdir(join(testDir, "src"), { recursive: true });
|
|
119
|
+
await mkdir(join(testDir, "lib"), { recursive: true });
|
|
120
|
+
await mkdir(join(testDir, "node_modules"), { recursive: true });
|
|
121
|
+
|
|
122
|
+
await writeFile(join(testDir, "src", "index.js"), "// main file");
|
|
123
|
+
await writeFile(join(testDir, "src", "utils.ts"), "// utils file");
|
|
124
|
+
await writeFile(join(testDir, "lib", "helper.js"), "// helper file");
|
|
125
|
+
await writeFile(join(testDir, "README.md"), "# readme");
|
|
126
|
+
await writeFile(join(testDir, "package.json"), "{}");
|
|
127
|
+
await writeFile(join(testDir, "node_modules", "dep.js"), "// dependency");
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("should find files with basic include patterns", async () => {
|
|
131
|
+
const files = await getFilesWithGlob(testDir, ["*.js"], [], []);
|
|
132
|
+
|
|
133
|
+
expect(files).toBeDefined();
|
|
134
|
+
expect(Array.isArray(files)).toBe(true);
|
|
135
|
+
expect(files.some((f) => f.includes("index.js"))).toBe(true);
|
|
136
|
+
expect(files.some((f) => f.includes("helper.js"))).toBe(true);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test("should exclude files based on exclude patterns", async () => {
|
|
140
|
+
const files = await getFilesWithGlob(testDir, ["**/*.js"], ["node_modules/**"], []);
|
|
141
|
+
|
|
142
|
+
expect(files).toBeDefined();
|
|
143
|
+
expect(files.some((f) => f.includes("index.js"))).toBe(true);
|
|
144
|
+
expect(files.some((f) => f.includes("helper.js"))).toBe(true);
|
|
145
|
+
expect(files.some((f) => f.includes("node_modules"))).toBe(false);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test("should handle multiple include patterns", async () => {
|
|
149
|
+
const files = await getFilesWithGlob(testDir, ["*.js", "*.ts"], [], []);
|
|
150
|
+
|
|
151
|
+
expect(files).toBeDefined();
|
|
152
|
+
expect(files.some((f) => f.includes("index.js"))).toBe(true);
|
|
153
|
+
expect(files.some((f) => f.includes("utils.ts"))).toBe(true);
|
|
154
|
+
expect(files.some((f) => f.includes("helper.js"))).toBe(true);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test("should handle gitignore patterns", async () => {
|
|
158
|
+
const gitignorePatterns = ["node_modules/**"];
|
|
159
|
+
const files = await getFilesWithGlob(testDir, ["**/*.js"], [], gitignorePatterns);
|
|
160
|
+
|
|
161
|
+
expect(files).toBeDefined();
|
|
162
|
+
expect(files.some((f) => f.includes("index.js"))).toBe(true);
|
|
163
|
+
expect(files.some((f) => f.includes("node_modules"))).toBe(false);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test("should return empty array for empty include patterns", async () => {
|
|
167
|
+
const files = await getFilesWithGlob(testDir, [], [], []);
|
|
168
|
+
|
|
169
|
+
expect(files).toBeDefined();
|
|
170
|
+
expect(Array.isArray(files)).toBe(true);
|
|
171
|
+
expect(files.length).toBe(0);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test("should return absolute paths", async () => {
|
|
175
|
+
const files = await getFilesWithGlob(testDir, ["*.js"], [], []);
|
|
176
|
+
|
|
177
|
+
expect(files).toBeDefined();
|
|
178
|
+
files.forEach((file) => {
|
|
179
|
+
expect(file.startsWith("/")).toBe(true);
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test("should handle nested directory patterns", async () => {
|
|
184
|
+
await mkdir(join(testDir, "src", "components"), { recursive: true });
|
|
185
|
+
await writeFile(join(testDir, "src", "components", "button.js"), "// button");
|
|
186
|
+
|
|
187
|
+
const files = await getFilesWithGlob(testDir, ["src/**/*.js"], [], []);
|
|
188
|
+
|
|
189
|
+
expect(files).toBeDefined();
|
|
190
|
+
expect(files.some((f) => f.includes("index.js"))).toBe(true);
|
|
191
|
+
expect(files.some((f) => f.includes("button.js"))).toBe(true);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test("should handle complex glob patterns", async () => {
|
|
195
|
+
const files = await getFilesWithGlob(testDir, ["**/*.{js,ts,md}"], ["node_modules/**"], []);
|
|
196
|
+
|
|
197
|
+
expect(files).toBeDefined();
|
|
198
|
+
expect(files.some((f) => f.includes("index.js"))).toBe(true);
|
|
199
|
+
expect(files.some((f) => f.includes("utils.ts"))).toBe(true);
|
|
200
|
+
expect(files.some((f) => f.includes("README.md"))).toBe(true);
|
|
201
|
+
expect(files.some((f) => f.includes("node_modules"))).toBe(false);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test("should handle non-existent directory gracefully", async () => {
|
|
205
|
+
const nonExistentDir = join(testDir, "non-existent");
|
|
206
|
+
const files = await getFilesWithGlob(nonExistentDir, ["*.js"], [], []);
|
|
207
|
+
|
|
208
|
+
expect(files).toBeDefined();
|
|
209
|
+
expect(Array.isArray(files)).toBe(true);
|
|
210
|
+
expect(files.length).toBe(0);
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
});
|
|
@@ -6,7 +6,7 @@ import path from "node:path";
|
|
|
6
6
|
|
|
7
7
|
import Debug from "debug";
|
|
8
8
|
|
|
9
|
-
import { TMP_ASSETS_DIR } from "
|
|
9
|
+
import { TMP_ASSETS_DIR } from "../../utils/constants.mjs";
|
|
10
10
|
import {
|
|
11
11
|
beforePublishHook,
|
|
12
12
|
checkD2Content,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
getChart,
|
|
15
15
|
getD2Svg,
|
|
16
16
|
saveD2Assets,
|
|
17
|
-
} from "
|
|
17
|
+
} from "../../utils/kroki-utils.mjs";
|
|
18
18
|
|
|
19
19
|
describe("kroki-utils", () => {
|
|
20
20
|
let tempDir;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import loadConfig from "../../utils/load-config.mjs";
|
|
6
|
+
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
|
|
9
|
+
describe("load-config", () => {
|
|
10
|
+
let testDir;
|
|
11
|
+
|
|
12
|
+
beforeEach(async () => {
|
|
13
|
+
// Create a temporary test directory
|
|
14
|
+
testDir = join(__dirname, "test-load-config");
|
|
15
|
+
await mkdir(testDir, { recursive: true });
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
afterEach(async () => {
|
|
19
|
+
// Clean up test directory
|
|
20
|
+
try {
|
|
21
|
+
await rm(testDir, { recursive: true, force: true });
|
|
22
|
+
} catch {
|
|
23
|
+
// Ignore cleanup errors since they don't affect test results
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("should load valid YAML config file", async () => {
|
|
28
|
+
const configPath = join(testDir, "config.yaml");
|
|
29
|
+
const configContent = `
|
|
30
|
+
projectName: "Test Project"
|
|
31
|
+
locale: "en"
|
|
32
|
+
docsDir: "./docs"
|
|
33
|
+
sourcesPath:
|
|
34
|
+
- "./src"
|
|
35
|
+
- "./lib"
|
|
36
|
+
`;
|
|
37
|
+
await writeFile(configPath, configContent);
|
|
38
|
+
|
|
39
|
+
const result = await loadConfig({ config: configPath });
|
|
40
|
+
|
|
41
|
+
expect(result).toBeDefined();
|
|
42
|
+
expect(result.projectName).toBe("Test Project");
|
|
43
|
+
expect(result.locale).toBe("en");
|
|
44
|
+
expect(result.docsDir).toBe("./docs");
|
|
45
|
+
expect(result.sourcesPath).toEqual(["./src", "./lib"]);
|
|
46
|
+
expect(result.lastGitHead).toBe("");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("should handle appUrl parameter", async () => {
|
|
50
|
+
const configPath = join(testDir, "config.yaml");
|
|
51
|
+
const configContent = `
|
|
52
|
+
projectName: "Test Project"
|
|
53
|
+
locale: "en"
|
|
54
|
+
`;
|
|
55
|
+
await writeFile(configPath, configContent);
|
|
56
|
+
|
|
57
|
+
const result = await loadConfig({
|
|
58
|
+
config: configPath,
|
|
59
|
+
appUrl: "example.com",
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
expect(result.appUrl).toBe("https://example.com");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("should preserve appUrl with existing protocol", async () => {
|
|
66
|
+
const configPath = join(testDir, "config.yaml");
|
|
67
|
+
const configContent = `
|
|
68
|
+
projectName: "Test Project"
|
|
69
|
+
locale: "en"
|
|
70
|
+
`;
|
|
71
|
+
await writeFile(configPath, configContent);
|
|
72
|
+
|
|
73
|
+
const result = await loadConfig({
|
|
74
|
+
config: configPath,
|
|
75
|
+
appUrl: "http://localhost:3000",
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
expect(result.appUrl).toBe("http://localhost:3000");
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("should handle absolute config path", async () => {
|
|
82
|
+
const configPath = join(testDir, "absolute-config.yaml");
|
|
83
|
+
const configContent = `
|
|
84
|
+
projectName: "Absolute Path Test"
|
|
85
|
+
locale: "zh"
|
|
86
|
+
`;
|
|
87
|
+
await writeFile(configPath, configContent);
|
|
88
|
+
|
|
89
|
+
const result = await loadConfig({ config: configPath });
|
|
90
|
+
|
|
91
|
+
expect(result.projectName).toBe("Absolute Path Test");
|
|
92
|
+
expect(result.locale).toBe("zh");
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("should throw error for non-existent config file", async () => {
|
|
96
|
+
const nonExistentPath = join(testDir, "non-existent.yaml");
|
|
97
|
+
|
|
98
|
+
await expect(loadConfig({ config: nonExistentPath })).rejects.toThrow(
|
|
99
|
+
`Config file not found: ${nonExistentPath}`,
|
|
100
|
+
);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("should throw error for invalid YAML syntax", async () => {
|
|
104
|
+
const configPath = join(testDir, "invalid.yaml");
|
|
105
|
+
const invalidContent = `
|
|
106
|
+
projectName: "Test
|
|
107
|
+
locale: en
|
|
108
|
+
invalid: yaml: syntax
|
|
109
|
+
`;
|
|
110
|
+
await writeFile(configPath, invalidContent);
|
|
111
|
+
|
|
112
|
+
await expect(loadConfig({ config: configPath })).rejects.toThrow(
|
|
113
|
+
"Failed to parse config file:",
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("should throw error for empty config file", async () => {
|
|
118
|
+
const configPath = join(testDir, "empty.yaml");
|
|
119
|
+
await writeFile(configPath, "");
|
|
120
|
+
|
|
121
|
+
// Empty YAML files result in null, which causes an error in the processing
|
|
122
|
+
await expect(loadConfig({ config: configPath })).rejects.toThrow(
|
|
123
|
+
"Failed to parse config file:",
|
|
124
|
+
);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("should handle config with lastGitHead", async () => {
|
|
128
|
+
const configPath = join(testDir, "config-with-git.yaml");
|
|
129
|
+
const configContent = `
|
|
130
|
+
projectName: "Git Project"
|
|
131
|
+
lastGitHead: "abc123def456"
|
|
132
|
+
locale: "en"
|
|
133
|
+
`;
|
|
134
|
+
await writeFile(configPath, configContent);
|
|
135
|
+
|
|
136
|
+
const result = await loadConfig({ config: configPath });
|
|
137
|
+
|
|
138
|
+
expect(result.lastGitHead).toBe("abc123def456");
|
|
139
|
+
expect(result.projectName).toBe("Git Project");
|
|
140
|
+
});
|
|
141
|
+
});
|
|
@@ -6,12 +6,12 @@ import {
|
|
|
6
6
|
shutdownValidation,
|
|
7
7
|
validateBasicMermaidSyntax,
|
|
8
8
|
validateMermaidSyntax,
|
|
9
|
-
} from "
|
|
9
|
+
} from "../../utils/mermaid-validator.mjs";
|
|
10
10
|
import {
|
|
11
11
|
getMermaidWorkerPool,
|
|
12
12
|
SimpleMermaidWorkerPool,
|
|
13
13
|
shutdownMermaidWorkerPool,
|
|
14
|
-
} from "
|
|
14
|
+
} from "../../utils/mermaid-worker-pool.mjs";
|
|
15
15
|
|
|
16
16
|
const __filename = fileURLToPath(import.meta.url);
|
|
17
17
|
const __dirname = dirname(__filename);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Mock ChatModel for testing
|
|
2
|
+
export class MockChatModel {
|
|
3
|
+
constructor(options = {}) {
|
|
4
|
+
this.options = options;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
process() {
|
|
8
|
+
throw new Error("Method not implemented in test mock");
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const loadModel = () => new MockChatModel();
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test";
|
|
2
|
+
import * as fs from "node:fs";
|
|
2
3
|
import { existsSync } from "node:fs";
|
|
4
|
+
import fsPromisesDefault, * as fsPromises from "node:fs/promises";
|
|
3
5
|
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
4
6
|
import { dirname, join } from "node:path";
|
|
5
7
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { saveValueToConfig } from "
|
|
8
|
+
import { saveValueToConfig } from "../../utils/utils.mjs";
|
|
7
9
|
|
|
8
10
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
11
|
const __dirname = dirname(__filename);
|
|
@@ -13,8 +15,14 @@ const TEST_DIR = join(__dirname, "temp-config-test");
|
|
|
13
15
|
const TEST_CONFIG_DIR = join(TEST_DIR, ".aigne", "doc-smith");
|
|
14
16
|
const TEST_CONFIG_PATH = join(TEST_CONFIG_DIR, "config.yaml");
|
|
15
17
|
|
|
18
|
+
// Store original working directory
|
|
19
|
+
let originalCwd;
|
|
20
|
+
|
|
16
21
|
// Setup and teardown helpers
|
|
17
22
|
async function setupTestDir() {
|
|
23
|
+
// Save original working directory
|
|
24
|
+
originalCwd = process.cwd();
|
|
25
|
+
|
|
18
26
|
if (existsSync(TEST_DIR)) {
|
|
19
27
|
await rm(TEST_DIR, { recursive: true, force: true });
|
|
20
28
|
}
|
|
@@ -26,7 +34,7 @@ async function setupTestDir() {
|
|
|
26
34
|
|
|
27
35
|
async function teardownTestDir() {
|
|
28
36
|
// Change back to original directory
|
|
29
|
-
process.chdir(
|
|
37
|
+
process.chdir(originalCwd);
|
|
30
38
|
|
|
31
39
|
if (existsSync(TEST_DIR)) {
|
|
32
40
|
await rm(TEST_DIR, { recursive: true, force: true });
|
|
@@ -46,13 +54,62 @@ async function createInitialConfig(content) {
|
|
|
46
54
|
}
|
|
47
55
|
|
|
48
56
|
// Test suite
|
|
49
|
-
describe("
|
|
57
|
+
describe("save-value-to-config", () => {
|
|
58
|
+
let restoreFunctions = [];
|
|
59
|
+
|
|
50
60
|
beforeEach(async () => {
|
|
51
61
|
await setupTestDir();
|
|
62
|
+
|
|
63
|
+
// Restore any existing mocks that might interfere with our file operations
|
|
64
|
+
// This is crucial when running alongside other test files like utils.test.mjs
|
|
65
|
+
restoreFunctions = [];
|
|
66
|
+
|
|
67
|
+
// Restore fs sync mocks if they exist
|
|
68
|
+
if (typeof fs.existsSync.mockRestore === "function") {
|
|
69
|
+
fs.existsSync.mockRestore();
|
|
70
|
+
restoreFunctions.push(() => spyOn(fs, "existsSync").mockReturnValue(true));
|
|
71
|
+
}
|
|
72
|
+
if (typeof fs.mkdirSync.mockRestore === "function") {
|
|
73
|
+
fs.mkdirSync.mockRestore();
|
|
74
|
+
restoreFunctions.push(() => spyOn(fs, "mkdirSync").mockImplementation(() => {}));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Restore fs async mocks if they exist
|
|
78
|
+
if (typeof fsPromises.writeFile.mockRestore === "function") {
|
|
79
|
+
fsPromises.writeFile.mockRestore();
|
|
80
|
+
restoreFunctions.push(() => spyOn(fsPromises, "writeFile").mockResolvedValue());
|
|
81
|
+
}
|
|
82
|
+
if (typeof fsPromises.mkdir.mockRestore === "function") {
|
|
83
|
+
fsPromises.mkdir.mockRestore();
|
|
84
|
+
restoreFunctions.push(() => spyOn(fsPromises, "mkdir").mockResolvedValue());
|
|
85
|
+
}
|
|
86
|
+
if (typeof fsPromises.readFile.mockRestore === "function") {
|
|
87
|
+
fsPromises.readFile.mockRestore();
|
|
88
|
+
restoreFunctions.push(() => spyOn(fsPromises, "readFile").mockResolvedValue("test content"));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Restore default import mocks if they exist
|
|
92
|
+
if (typeof fsPromisesDefault.writeFile.mockRestore === "function") {
|
|
93
|
+
fsPromisesDefault.writeFile.mockRestore();
|
|
94
|
+
restoreFunctions.push(() => spyOn(fsPromisesDefault, "writeFile").mockResolvedValue());
|
|
95
|
+
}
|
|
96
|
+
if (typeof fsPromisesDefault.mkdir.mockRestore === "function") {
|
|
97
|
+
fsPromisesDefault.mkdir.mockRestore();
|
|
98
|
+
restoreFunctions.push(() => spyOn(fsPromisesDefault, "mkdir").mockResolvedValue());
|
|
99
|
+
}
|
|
52
100
|
});
|
|
53
101
|
|
|
54
102
|
afterEach(async () => {
|
|
55
103
|
await teardownTestDir();
|
|
104
|
+
|
|
105
|
+
// Restore the original mocks that other tests might depend on
|
|
106
|
+
restoreFunctions.forEach((restoreFn) => {
|
|
107
|
+
try {
|
|
108
|
+
restoreFn();
|
|
109
|
+
} catch {
|
|
110
|
+
// Ignore errors when restoring mocks
|
|
111
|
+
}
|
|
112
|
+
});
|
|
56
113
|
});
|
|
57
114
|
|
|
58
115
|
test("Save string value to empty file", async () => {
|