@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,437 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
-
import { existsSync, mkdtemp, rmdir } from "node:fs";
|
|
3
|
-
import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
import path from "node:path";
|
|
6
|
-
|
|
7
|
-
import Debug from "debug";
|
|
8
|
-
|
|
9
|
-
import { DOC_SMITH_DIR, TMP_ASSETS_DIR, TMP_DIR } from "../../utils/constants/index.mjs";
|
|
10
|
-
import {
|
|
11
|
-
beforePublishHook,
|
|
12
|
-
checkContent,
|
|
13
|
-
ensureTmpDir,
|
|
14
|
-
getChart,
|
|
15
|
-
isValidCode,
|
|
16
|
-
saveAssets,
|
|
17
|
-
wrapCode,
|
|
18
|
-
} from "../../utils/d2-utils.mjs";
|
|
19
|
-
|
|
20
|
-
describe("d2-utils", () => {
|
|
21
|
-
let tempDir;
|
|
22
|
-
|
|
23
|
-
beforeEach(async () => {
|
|
24
|
-
tempDir = await new Promise((resolve, reject) => {
|
|
25
|
-
mkdtemp(path.join(tmpdir(), "d2-test-"), (err, dir) => {
|
|
26
|
-
if (err) reject(err);
|
|
27
|
-
else resolve(dir);
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
afterEach(async () => {
|
|
33
|
-
if (tempDir && existsSync(tempDir)) {
|
|
34
|
-
await new Promise((resolve) => {
|
|
35
|
-
rmdir(tempDir, { recursive: true }, () => resolve());
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
describe("getChart", () => {
|
|
41
|
-
test("should generate chart for valid d2 content", async () => {
|
|
42
|
-
const content = "A -> B";
|
|
43
|
-
const result = await getChart({ content });
|
|
44
|
-
expect(typeof result).toBe("string");
|
|
45
|
-
expect(result).toContain("<svg");
|
|
46
|
-
}, 15000);
|
|
47
|
-
|
|
48
|
-
test("should return null for invalid d2 content with strict=false", async () => {
|
|
49
|
-
const content = "A -> B -> C -> [invalid syntax";
|
|
50
|
-
const result = await getChart({ content, strict: false });
|
|
51
|
-
expect(result).toBe(null);
|
|
52
|
-
}, 15000);
|
|
53
|
-
|
|
54
|
-
test("should throw for invalid d2 content with strict=true", async () => {
|
|
55
|
-
const content = "A -> B -> C -> [invalid syntax";
|
|
56
|
-
await expect(getChart({ content, strict: true })).rejects.toThrow();
|
|
57
|
-
}, 15000);
|
|
58
|
-
|
|
59
|
-
test("should handle empty content", async () => {
|
|
60
|
-
const result = await getChart({ content: "" });
|
|
61
|
-
expect(typeof result).toBe("string");
|
|
62
|
-
expect(result).toContain("<svg");
|
|
63
|
-
}, 10000);
|
|
64
|
-
|
|
65
|
-
test("should add stroke-dash to container shapes", async () => {
|
|
66
|
-
const content = `
|
|
67
|
-
container {
|
|
68
|
-
A -> B
|
|
69
|
-
}
|
|
70
|
-
`;
|
|
71
|
-
const result = await getChart({ content });
|
|
72
|
-
expect(typeof result).toBe("string");
|
|
73
|
-
// d2 will convert `strokeDash: 3` to `stroke-dasharray:6.000000,5.919384;`
|
|
74
|
-
expect(result).toContain("stroke-dasharray:6.000000");
|
|
75
|
-
}, 15000);
|
|
76
|
-
|
|
77
|
-
test("should not add stroke-dash to sequence diagrams", async () => {
|
|
78
|
-
const content = `
|
|
79
|
-
shape: sequence_diagram
|
|
80
|
-
A -> B: Hello
|
|
81
|
-
`;
|
|
82
|
-
const result = await getChart({ content });
|
|
83
|
-
expect(typeof result).toBe("string");
|
|
84
|
-
// d2 will convert `strokeDash: 3` to `stroke-dasharray:6.000000,5.919384;`
|
|
85
|
-
expect(result).not.toContain("stroke-dasharray:6.000000");
|
|
86
|
-
}, 15000);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
describe("saveAssets", () => {
|
|
90
|
-
test("should process markdown with D2 code blocks", async () => {
|
|
91
|
-
const docsDir = path.join(tempDir, "docs");
|
|
92
|
-
await mkdir(docsDir, { recursive: true });
|
|
93
|
-
|
|
94
|
-
const markdown = `# Test Document
|
|
95
|
-
|
|
96
|
-
This is a test document with D2 diagram:
|
|
97
|
-
|
|
98
|
-
\`\`\`d2
|
|
99
|
-
A -> B: connection
|
|
100
|
-
B -> C: another connection
|
|
101
|
-
\`\`\`
|
|
102
|
-
|
|
103
|
-
Some more content here.
|
|
104
|
-
`;
|
|
105
|
-
|
|
106
|
-
const result = await saveAssets({ markdown, docsDir });
|
|
107
|
-
|
|
108
|
-
expect(typeof result).toBe("string");
|
|
109
|
-
expect(result).toContain("# Test Document");
|
|
110
|
-
expect(result).toContain("Some more content here");
|
|
111
|
-
|
|
112
|
-
// Should replace D2 code block with image reference
|
|
113
|
-
expect(result).not.toContain("```d2");
|
|
114
|
-
expect(result).toContain(";
|
|
115
|
-
expect(result).toContain(".svg)");
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
test("should handle markdown without D2 blocks", async () => {
|
|
119
|
-
const docsDir = path.join(tempDir, "docs");
|
|
120
|
-
await mkdir(docsDir, { recursive: true });
|
|
121
|
-
|
|
122
|
-
const markdown = `# Test Document
|
|
123
|
-
|
|
124
|
-
This document has no D2 diagrams.
|
|
125
|
-
|
|
126
|
-
\`\`\`javascript
|
|
127
|
-
console.log('hello world');
|
|
128
|
-
\`\`\`
|
|
129
|
-
`;
|
|
130
|
-
|
|
131
|
-
const result = await saveAssets({ markdown, docsDir });
|
|
132
|
-
|
|
133
|
-
expect(result).toBe(markdown); // Should remain unchanged
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
test("should handle multiple D2 blocks", async () => {
|
|
137
|
-
const docsDir = path.join(tempDir, "docs");
|
|
138
|
-
await mkdir(docsDir, { recursive: true });
|
|
139
|
-
|
|
140
|
-
const markdown = `# Test
|
|
141
|
-
|
|
142
|
-
\`\`\`d2
|
|
143
|
-
A -> B
|
|
144
|
-
\`\`\`
|
|
145
|
-
|
|
146
|
-
Some text.
|
|
147
|
-
|
|
148
|
-
\`\`\`d2
|
|
149
|
-
C -> D
|
|
150
|
-
E -> F
|
|
151
|
-
\`\`\`
|
|
152
|
-
`;
|
|
153
|
-
|
|
154
|
-
const result = await saveAssets({ markdown, docsDir });
|
|
155
|
-
|
|
156
|
-
expect(typeof result).toBe("string");
|
|
157
|
-
expect(result).not.toContain("```d2");
|
|
158
|
-
|
|
159
|
-
// Should have two image references
|
|
160
|
-
const imageMatches = result.match(/!\[\]\(\.\.\/assets\/d2\/.*\.svg\)/g);
|
|
161
|
-
expect(imageMatches).toBeTruthy();
|
|
162
|
-
expect(imageMatches.length).toBe(2);
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
test("should handle empty markdown", async () => {
|
|
166
|
-
const docsDir = path.join(tempDir, "docs");
|
|
167
|
-
await mkdir(docsDir, { recursive: true });
|
|
168
|
-
|
|
169
|
-
const result = await saveAssets({ markdown: "", docsDir });
|
|
170
|
-
expect(result).toBe("");
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
test("should skip generation if SVG file already exists", async () => {
|
|
174
|
-
const docsDir = path.join(tempDir, "docs");
|
|
175
|
-
await mkdir(docsDir, { recursive: true });
|
|
176
|
-
const markdown = `\`\`\`d2\nA -> B\n\`\`\``;
|
|
177
|
-
|
|
178
|
-
// 1. First run to generate the file
|
|
179
|
-
await saveAssets({ markdown, docsDir });
|
|
180
|
-
|
|
181
|
-
// 2. Second run to check if cache is used
|
|
182
|
-
const debugLogs = [];
|
|
183
|
-
const originalWrite = process.stderr.write;
|
|
184
|
-
process.stderr.write = (chunk) => {
|
|
185
|
-
debugLogs.push(chunk.toString());
|
|
186
|
-
return true;
|
|
187
|
-
};
|
|
188
|
-
Debug.enable("doc-smith");
|
|
189
|
-
|
|
190
|
-
try {
|
|
191
|
-
const result = await saveAssets({ markdown, docsDir });
|
|
192
|
-
|
|
193
|
-
expect(typeof result).toBe("string");
|
|
194
|
-
expect(result).toContain(`}`);
|
|
195
|
-
expect(
|
|
196
|
-
debugLogs.some((log) => log.includes("Found assets cache, skipping generation")),
|
|
197
|
-
).toBe(true);
|
|
198
|
-
} finally {
|
|
199
|
-
process.stderr.write = originalWrite;
|
|
200
|
-
Debug.disable();
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
test("should handle D2 generation errors gracefully", async () => {
|
|
205
|
-
const docsDir = path.join(tempDir, "docs");
|
|
206
|
-
await mkdir(docsDir, { recursive: true });
|
|
207
|
-
|
|
208
|
-
const markdown = `\`\`\`d2\nA -> B -> [invalid\n\`\`\``;
|
|
209
|
-
|
|
210
|
-
const result = await saveAssets({ markdown, docsDir });
|
|
211
|
-
expect(result).toContain(";
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
test("should write .d2 file when debug is enabled", async () => {
|
|
215
|
-
const docsDir = path.join(tempDir, "docs");
|
|
216
|
-
await mkdir(docsDir, { recursive: true });
|
|
217
|
-
|
|
218
|
-
const markdown = `\`\`\`d2\nA -> B\n\`\`\``;
|
|
219
|
-
|
|
220
|
-
// Enable debug mode
|
|
221
|
-
Debug.enable("doc-smith");
|
|
222
|
-
|
|
223
|
-
try {
|
|
224
|
-
await saveAssets({ markdown, docsDir });
|
|
225
|
-
|
|
226
|
-
const assetDir = path.join(docsDir, "../", TMP_ASSETS_DIR, "d2");
|
|
227
|
-
const files = await readdir(assetDir);
|
|
228
|
-
const d2File = files.find((file) => file.endsWith(".d2"));
|
|
229
|
-
expect(d2File).toBeDefined();
|
|
230
|
-
} finally {
|
|
231
|
-
// Restore debug mode
|
|
232
|
-
Debug.disable();
|
|
233
|
-
}
|
|
234
|
-
});
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
describe("beforePublishHook", () => {
|
|
238
|
-
test("should process all markdown files in directory", async () => {
|
|
239
|
-
const docsDir = path.join(tempDir, "docs");
|
|
240
|
-
await mkdir(docsDir, { recursive: true });
|
|
241
|
-
|
|
242
|
-
// Create test markdown files
|
|
243
|
-
const file1Content = `# Doc 1\n\`\`\`d2\nA -> B\n\`\`\``;
|
|
244
|
-
const file2Content = `# Doc 2\n\`\`\`d2\nC -> D\n\`\`\``;
|
|
245
|
-
const file3Content = `# Doc 3\nNo diagrams here.`;
|
|
246
|
-
|
|
247
|
-
await writeFile(path.join(docsDir, "doc1.md"), file1Content);
|
|
248
|
-
await writeFile(path.join(docsDir, "doc2.md"), file2Content);
|
|
249
|
-
await writeFile(path.join(docsDir, "doc3.md"), file3Content);
|
|
250
|
-
|
|
251
|
-
await beforePublishHook({ docsDir });
|
|
252
|
-
|
|
253
|
-
// Check that files were processed
|
|
254
|
-
const processedFile1 = await readFile(path.join(docsDir, "doc1.md"), "utf8");
|
|
255
|
-
const processedFile2 = await readFile(path.join(docsDir, "doc2.md"), "utf8");
|
|
256
|
-
const processedFile3 = await readFile(path.join(docsDir, "doc3.md"), "utf8");
|
|
257
|
-
|
|
258
|
-
expect(processedFile1).not.toContain("```d2");
|
|
259
|
-
expect(processedFile2).not.toContain("```d2");
|
|
260
|
-
expect(processedFile3).toBe(file3Content); // Unchanged
|
|
261
|
-
|
|
262
|
-
expect(processedFile1).toContain(";
|
|
263
|
-
expect(processedFile2).toContain(";
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
test("should handle nested directories", async () => {
|
|
267
|
-
const docsDir = path.join(tempDir, "docs");
|
|
268
|
-
const subDir = path.join(docsDir, "subdir");
|
|
269
|
-
await mkdir(subDir, { recursive: true });
|
|
270
|
-
|
|
271
|
-
const fileContent = `# Nested Doc\n\`\`\`d2\nA -> B\n\`\`\``;
|
|
272
|
-
await writeFile(path.join(subDir, "nested.md"), fileContent);
|
|
273
|
-
|
|
274
|
-
await beforePublishHook({ docsDir });
|
|
275
|
-
|
|
276
|
-
const processedFile = await readFile(path.join(subDir, "nested.md"), "utf8");
|
|
277
|
-
expect(processedFile).not.toContain("```d2");
|
|
278
|
-
expect(processedFile).toContain(";
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
test("should handle empty docs directory", async () => {
|
|
282
|
-
const docsDir = path.join(tempDir, "empty-docs");
|
|
283
|
-
await mkdir(docsDir, { recursive: true });
|
|
284
|
-
|
|
285
|
-
// Should not throw error
|
|
286
|
-
await expect(beforePublishHook({ docsDir })).resolves.toBeUndefined();
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
test("should handle non-existent directory", async () => {
|
|
290
|
-
const nonExistentDir = path.join(tempDir, "non-existent");
|
|
291
|
-
// glob will just return an empty array, so no error should be thrown.
|
|
292
|
-
await expect(beforePublishHook({ docsDir: nonExistentDir })).resolves.toBeUndefined();
|
|
293
|
-
});
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
describe("checkContent", () => {
|
|
297
|
-
test("should generate and cache D2 SVG", async () => {
|
|
298
|
-
const content = "A -> B: test connection";
|
|
299
|
-
await expect(checkContent({ content })).resolves.toBeUndefined();
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
test("should use cached file when available", async () => {
|
|
303
|
-
const content = "A -> B: cached test";
|
|
304
|
-
|
|
305
|
-
// First call should generate
|
|
306
|
-
await checkContent({ content });
|
|
307
|
-
|
|
308
|
-
// Second call should use cache
|
|
309
|
-
const debugLogs = [];
|
|
310
|
-
const originalWrite = process.stderr.write;
|
|
311
|
-
process.stderr.write = (chunk) => {
|
|
312
|
-
debugLogs.push(chunk.toString());
|
|
313
|
-
return true;
|
|
314
|
-
};
|
|
315
|
-
Debug.enable("doc-smith");
|
|
316
|
-
|
|
317
|
-
try {
|
|
318
|
-
const startTime = Date.now();
|
|
319
|
-
await checkContent({ content });
|
|
320
|
-
const endTime = Date.now();
|
|
321
|
-
|
|
322
|
-
// Cache hit should be very fast (< 100ms)
|
|
323
|
-
expect(endTime - startTime).toBeLessThan(100);
|
|
324
|
-
expect(
|
|
325
|
-
debugLogs.some((log) => log.includes("Found assets cache, skipping generation")),
|
|
326
|
-
).toBe(true);
|
|
327
|
-
} finally {
|
|
328
|
-
process.stderr.write = originalWrite;
|
|
329
|
-
Debug.disable();
|
|
330
|
-
}
|
|
331
|
-
});
|
|
332
|
-
|
|
333
|
-
test("should handle generation errors in strict mode", async () => {
|
|
334
|
-
const malformedContent = "A -> B -> [invalid";
|
|
335
|
-
await expect(checkContent({ content: malformedContent })).rejects.toThrow();
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
test("should handle empty content", async () => {
|
|
339
|
-
await expect(checkContent({ content: "" })).resolves.toBeUndefined();
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
test("should write .d2 file when debug is enabled", async () => {
|
|
343
|
-
const content = "A -> B: debug test";
|
|
344
|
-
|
|
345
|
-
Debug.enable("doc-smith");
|
|
346
|
-
|
|
347
|
-
try {
|
|
348
|
-
await checkContent({ content });
|
|
349
|
-
|
|
350
|
-
const assetDir = path.join(process.cwd(), DOC_SMITH_DIR, TMP_DIR, TMP_ASSETS_DIR, "d2");
|
|
351
|
-
const files = await readdir(assetDir);
|
|
352
|
-
const d2File = files.find((file) => file.endsWith(".d2"));
|
|
353
|
-
expect(d2File).toBeDefined();
|
|
354
|
-
} finally {
|
|
355
|
-
Debug.disable();
|
|
356
|
-
}
|
|
357
|
-
});
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
describe("ensureTmpDir", () => {
|
|
361
|
-
test("should create tmp directory structure", async () => {
|
|
362
|
-
// Change to temp directory for testing
|
|
363
|
-
const originalCwd = process.cwd();
|
|
364
|
-
process.chdir(tempDir);
|
|
365
|
-
|
|
366
|
-
try {
|
|
367
|
-
await ensureTmpDir();
|
|
368
|
-
|
|
369
|
-
const tmpDir = path.join(tempDir, DOC_SMITH_DIR, TMP_DIR);
|
|
370
|
-
const gitignorePath = path.join(tmpDir, ".gitignore");
|
|
371
|
-
|
|
372
|
-
expect(existsSync(tmpDir)).toBe(true);
|
|
373
|
-
expect(existsSync(gitignorePath)).toBe(true);
|
|
374
|
-
|
|
375
|
-
const gitignoreContent = await readFile(gitignorePath, "utf8");
|
|
376
|
-
expect(gitignoreContent).toBe("**/*");
|
|
377
|
-
} finally {
|
|
378
|
-
process.chdir(originalCwd);
|
|
379
|
-
}
|
|
380
|
-
});
|
|
381
|
-
|
|
382
|
-
test("should not recreate if already exists", async () => {
|
|
383
|
-
const originalCwd = process.cwd();
|
|
384
|
-
process.chdir(tempDir);
|
|
385
|
-
|
|
386
|
-
try {
|
|
387
|
-
// First call
|
|
388
|
-
await ensureTmpDir();
|
|
389
|
-
|
|
390
|
-
const tmpDir = path.join(tempDir, DOC_SMITH_DIR, TMP_DIR);
|
|
391
|
-
const gitignorePath = path.join(tmpDir, ".gitignore");
|
|
392
|
-
|
|
393
|
-
// Modify .gitignore to test if it gets overwritten
|
|
394
|
-
await writeFile(gitignorePath, "modified content");
|
|
395
|
-
|
|
396
|
-
// Second call
|
|
397
|
-
await ensureTmpDir();
|
|
398
|
-
|
|
399
|
-
const gitignoreContent = await readFile(gitignorePath, "utf8");
|
|
400
|
-
expect(gitignoreContent).toBe("modified content"); // Should not be overwritten
|
|
401
|
-
} finally {
|
|
402
|
-
process.chdir(originalCwd);
|
|
403
|
-
}
|
|
404
|
-
});
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
describe("isValidCode", () => {
|
|
408
|
-
test("should return true for 'd2'", () => {
|
|
409
|
-
expect(isValidCode("d2")).toBe(true);
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
test("should return true for 'D2'", () => {
|
|
413
|
-
expect(isValidCode("D2")).toBe(true);
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
test("should return false for other languages", () => {
|
|
417
|
-
expect(isValidCode("javascript")).toBe(false);
|
|
418
|
-
expect(isValidCode("python")).toBe(false);
|
|
419
|
-
expect(isValidCode("")).toBe(false);
|
|
420
|
-
expect(isValidCode(null)).toBe(false);
|
|
421
|
-
expect(isValidCode(undefined)).toBe(false);
|
|
422
|
-
});
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
describe("wrapCode", () => {
|
|
426
|
-
test("should return original content when D2 block already exists", () => {
|
|
427
|
-
const content = "```d2\nA -> B\n```";
|
|
428
|
-
expect(wrapCode({ content })).toBe(content);
|
|
429
|
-
});
|
|
430
|
-
|
|
431
|
-
test("should wrap plain content in a D2 code block", () => {
|
|
432
|
-
const content = "A -> B";
|
|
433
|
-
const expected = "```d2\nA -> B\n```";
|
|
434
|
-
expect(wrapCode({ content })).toBe(expected);
|
|
435
|
-
});
|
|
436
|
-
});
|
|
437
|
-
});
|