@aigne/doc-smith 0.8.12-beta.8 → 0.8.12
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 +15 -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,646 +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
|
-
checkD2Content,
|
|
13
|
-
ensureTmpDir,
|
|
14
|
-
getChart,
|
|
15
|
-
getD2Svg,
|
|
16
|
-
saveD2Assets,
|
|
17
|
-
} from "../../utils/kroki-utils.mjs";
|
|
18
|
-
|
|
19
|
-
describe.skip("kroki-utils", () => {
|
|
20
|
-
let tempDir;
|
|
21
|
-
|
|
22
|
-
beforeEach(async () => {
|
|
23
|
-
tempDir = await new Promise((resolve, reject) => {
|
|
24
|
-
mkdtemp(path.join(tmpdir(), "kroki-test-"), (err, dir) => {
|
|
25
|
-
if (err) reject(err);
|
|
26
|
-
else resolve(dir);
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
afterEach(async () => {
|
|
32
|
-
if (tempDir && existsSync(tempDir)) {
|
|
33
|
-
await new Promise((resolve) => {
|
|
34
|
-
rmdir(tempDir, { recursive: true }, () => resolve());
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
describe("getChart", () => {
|
|
40
|
-
test("should fetch chart with default parameters", async () => {
|
|
41
|
-
const content = "A -> B";
|
|
42
|
-
const result = await getChart({ content });
|
|
43
|
-
|
|
44
|
-
// Should either return SVG content or null (if network fails)
|
|
45
|
-
expect(result === null || typeof result === "string").toBe(true);
|
|
46
|
-
|
|
47
|
-
if (result !== null) {
|
|
48
|
-
// Basic SVG validation
|
|
49
|
-
expect(result).toContain("svg");
|
|
50
|
-
}
|
|
51
|
-
}, 15000);
|
|
52
|
-
|
|
53
|
-
test("should handle different chart types", async () => {
|
|
54
|
-
const content = "A -> B";
|
|
55
|
-
const result = await getChart({
|
|
56
|
-
chart: "d2",
|
|
57
|
-
format: "svg",
|
|
58
|
-
content,
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
expect(result === null || typeof result === "string").toBe(true);
|
|
62
|
-
}, 15000);
|
|
63
|
-
|
|
64
|
-
test("should handle different formats", async () => {
|
|
65
|
-
const content = "A -> B";
|
|
66
|
-
const result = await getChart({
|
|
67
|
-
chart: "d2",
|
|
68
|
-
format: "png",
|
|
69
|
-
content,
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
expect(result === null || typeof result === "string").toBe(true);
|
|
73
|
-
}, 15000);
|
|
74
|
-
|
|
75
|
-
test("should handle network errors gracefully when strict=false", async () => {
|
|
76
|
-
// Test with invalid base URL by mocking fetch
|
|
77
|
-
const originalFetch = global.fetch;
|
|
78
|
-
global.fetch = () => Promise.reject(new Error("Network error"));
|
|
79
|
-
|
|
80
|
-
try {
|
|
81
|
-
const result = await getChart({ content: "A -> B", strict: false });
|
|
82
|
-
expect(result).toBe(null);
|
|
83
|
-
} finally {
|
|
84
|
-
global.fetch = originalFetch;
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
test("should throw error when strict=true and request fails", async () => {
|
|
89
|
-
// Mock fetch to return error response
|
|
90
|
-
const originalFetch = global.fetch;
|
|
91
|
-
global.fetch = () =>
|
|
92
|
-
Promise.resolve({
|
|
93
|
-
ok: false,
|
|
94
|
-
status: 400,
|
|
95
|
-
statusText: "Bad Request",
|
|
96
|
-
text: () => Promise.resolve("Error response"),
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
try {
|
|
100
|
-
await expect(getChart({ content: "invalid content", strict: true })).rejects.toThrow(
|
|
101
|
-
"Failed to fetch chart: 400 Bad Request",
|
|
102
|
-
);
|
|
103
|
-
} finally {
|
|
104
|
-
global.fetch = originalFetch;
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
test("should handle empty content", async () => {
|
|
109
|
-
const result = await getChart({ content: "" });
|
|
110
|
-
expect(result === null || typeof result === "string").toBe(true);
|
|
111
|
-
}, 10000);
|
|
112
|
-
|
|
113
|
-
test("should handle malformed content", async () => {
|
|
114
|
-
const malformedContent = "A -> B -> C -> [invalid syntax";
|
|
115
|
-
const result = await getChart({ content: malformedContent, strict: false });
|
|
116
|
-
|
|
117
|
-
// Should not crash, may return error SVG or null
|
|
118
|
-
expect(result === null || typeof result === "string").toBe(true);
|
|
119
|
-
}, 10000);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
describe("getD2Svg", () => {
|
|
123
|
-
test("should generate D2 SVG content", async () => {
|
|
124
|
-
const content = "A -> B: label";
|
|
125
|
-
const result = await getD2Svg({ content });
|
|
126
|
-
|
|
127
|
-
expect(result === null || typeof result === "string").toBe(true);
|
|
128
|
-
|
|
129
|
-
if (result !== null) {
|
|
130
|
-
expect(result).toContain("svg");
|
|
131
|
-
}
|
|
132
|
-
}, 15000);
|
|
133
|
-
|
|
134
|
-
test("should handle strict mode correctly", async () => {
|
|
135
|
-
// Mock fetch to simulate server error
|
|
136
|
-
const originalFetch = global.fetch;
|
|
137
|
-
global.fetch = () =>
|
|
138
|
-
Promise.resolve({
|
|
139
|
-
ok: false,
|
|
140
|
-
status: 500,
|
|
141
|
-
statusText: "Internal Server Error",
|
|
142
|
-
text: () => Promise.resolve("Error response"),
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
try {
|
|
146
|
-
// Should throw in strict mode
|
|
147
|
-
await expect(getD2Svg({ content: "A -> B", strict: true })).rejects.toThrow();
|
|
148
|
-
|
|
149
|
-
// Should return error response (not null) in non-strict mode
|
|
150
|
-
const result = await getD2Svg({ content: "A -> B", strict: false });
|
|
151
|
-
expect(result).toBe("Error response");
|
|
152
|
-
} finally {
|
|
153
|
-
global.fetch = originalFetch;
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
describe("saveD2Assets", () => {
|
|
159
|
-
test("should process markdown with D2 code blocks", async () => {
|
|
160
|
-
const docsDir = path.join(tempDir, "docs");
|
|
161
|
-
await mkdir(docsDir, { recursive: true });
|
|
162
|
-
|
|
163
|
-
const markdown = `# Test Document
|
|
164
|
-
|
|
165
|
-
This is a test document with D2 diagram:
|
|
166
|
-
|
|
167
|
-
\`\`\`d2
|
|
168
|
-
A -> B: connection
|
|
169
|
-
B -> C: another connection
|
|
170
|
-
\`\`\`
|
|
171
|
-
|
|
172
|
-
Some more content here.
|
|
173
|
-
`;
|
|
174
|
-
|
|
175
|
-
const result = await saveD2Assets({ markdown, docsDir });
|
|
176
|
-
|
|
177
|
-
expect(typeof result).toBe("string");
|
|
178
|
-
expect(result).toContain("# Test Document");
|
|
179
|
-
expect(result).toContain("Some more content here");
|
|
180
|
-
|
|
181
|
-
// Should replace D2 code block with image reference
|
|
182
|
-
expect(result).not.toContain("```d2");
|
|
183
|
-
expect(result).toContain(";
|
|
184
|
-
expect(result).toContain(".svg)");
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
test("should handle markdown without D2 blocks", async () => {
|
|
188
|
-
const docsDir = path.join(tempDir, "docs");
|
|
189
|
-
await mkdir(docsDir, { recursive: true });
|
|
190
|
-
|
|
191
|
-
const markdown = `# Test Document
|
|
192
|
-
|
|
193
|
-
This document has no D2 diagrams.
|
|
194
|
-
|
|
195
|
-
\`\`\`javascript
|
|
196
|
-
console.log('hello world');
|
|
197
|
-
\`\`\`
|
|
198
|
-
`;
|
|
199
|
-
|
|
200
|
-
const result = await saveD2Assets({ markdown, docsDir });
|
|
201
|
-
|
|
202
|
-
expect(result).toBe(markdown); // Should remain unchanged
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
test("should handle multiple D2 blocks", async () => {
|
|
206
|
-
const docsDir = path.join(tempDir, "docs");
|
|
207
|
-
await mkdir(docsDir, { recursive: true });
|
|
208
|
-
|
|
209
|
-
const markdown = `# Test
|
|
210
|
-
|
|
211
|
-
\`\`\`d2
|
|
212
|
-
A -> B
|
|
213
|
-
\`\`\`
|
|
214
|
-
|
|
215
|
-
Some text.
|
|
216
|
-
|
|
217
|
-
\`\`\`d2
|
|
218
|
-
C -> D
|
|
219
|
-
E -> F
|
|
220
|
-
\`\`\`
|
|
221
|
-
`;
|
|
222
|
-
|
|
223
|
-
const result = await saveD2Assets({ markdown, docsDir });
|
|
224
|
-
|
|
225
|
-
expect(typeof result).toBe("string");
|
|
226
|
-
expect(result).not.toContain("```d2");
|
|
227
|
-
|
|
228
|
-
// Should have two image references
|
|
229
|
-
const imageMatches = result.match(/!\[\]\(\.\.\/assets\/d2\/.*\.svg\)/g);
|
|
230
|
-
expect(imageMatches).toBeTruthy();
|
|
231
|
-
expect(imageMatches.length).toBe(2);
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
test("should handle empty markdown", async () => {
|
|
235
|
-
const docsDir = path.join(tempDir, "docs");
|
|
236
|
-
await mkdir(docsDir, { recursive: true });
|
|
237
|
-
|
|
238
|
-
const result = await saveD2Assets({ markdown: "", docsDir });
|
|
239
|
-
expect(result).toBe("");
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
test("should skip generation if SVG file already exists", async () => {
|
|
243
|
-
const docsDir = path.join(tempDir, "docs");
|
|
244
|
-
await mkdir(docsDir, { recursive: true });
|
|
245
|
-
const markdown = `\`\`\`d2\nA -> B\n\`\`\``;
|
|
246
|
-
|
|
247
|
-
// 1. First run to generate the file
|
|
248
|
-
await saveD2Assets({ markdown, docsDir });
|
|
249
|
-
|
|
250
|
-
// 2. Second run to check if cache is used
|
|
251
|
-
const debugLogs = [];
|
|
252
|
-
const originalWrite = process.stderr.write;
|
|
253
|
-
process.stderr.write = (chunk) => {
|
|
254
|
-
debugLogs.push(chunk.toString());
|
|
255
|
-
return true;
|
|
256
|
-
};
|
|
257
|
-
Debug.enable("doc-smith");
|
|
258
|
-
|
|
259
|
-
try {
|
|
260
|
-
const result = await saveD2Assets({ markdown, docsDir });
|
|
261
|
-
|
|
262
|
-
expect(typeof result).toBe("string");
|
|
263
|
-
expect(result).toContain(`}`);
|
|
264
|
-
} finally {
|
|
265
|
-
process.stderr.write = originalWrite;
|
|
266
|
-
Debug.disable();
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
test("should handle D2 generation errors gracefully", async () => {
|
|
271
|
-
const docsDir = path.join(tempDir, "docs");
|
|
272
|
-
await mkdir(docsDir, { recursive: true });
|
|
273
|
-
|
|
274
|
-
const markdown = `\`\`\`d2\nA -> B\n\`\`\``;
|
|
275
|
-
|
|
276
|
-
// Mock getD2Svg to throw error
|
|
277
|
-
const originalFetch = global.fetch;
|
|
278
|
-
global.fetch = () => Promise.reject(new Error("Network error"));
|
|
279
|
-
|
|
280
|
-
try {
|
|
281
|
-
const result = await saveD2Assets({ markdown, docsDir });
|
|
282
|
-
|
|
283
|
-
// TODO: When retry still fails, it will use a non-existent image
|
|
284
|
-
expect(result).toContain(";
|
|
285
|
-
} finally {
|
|
286
|
-
global.fetch = originalFetch;
|
|
287
|
-
}
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
test("should write .d2 file when debug is enabled", async () => {
|
|
291
|
-
const docsDir = path.join(tempDir, "docs");
|
|
292
|
-
await mkdir(docsDir, { recursive: true });
|
|
293
|
-
|
|
294
|
-
const markdown = `\`\`\`d2\nA -> B\n\`\`\``;
|
|
295
|
-
|
|
296
|
-
// Enable debug mode
|
|
297
|
-
Debug.enable("doc-smith");
|
|
298
|
-
|
|
299
|
-
try {
|
|
300
|
-
await saveD2Assets({ markdown, docsDir });
|
|
301
|
-
|
|
302
|
-
const assetDir = path.join(docsDir, "../", TMP_ASSETS_DIR, "d2");
|
|
303
|
-
const files = await readdir(assetDir);
|
|
304
|
-
const d2File = files.find((file) => file.endsWith(".d2"));
|
|
305
|
-
expect(d2File).toBeDefined();
|
|
306
|
-
} finally {
|
|
307
|
-
// Restore debug mode
|
|
308
|
-
Debug.disable();
|
|
309
|
-
}
|
|
310
|
-
});
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
describe("beforePublishHook", () => {
|
|
314
|
-
test("should process all markdown files in directory", async () => {
|
|
315
|
-
const docsDir = path.join(tempDir, "docs");
|
|
316
|
-
await mkdir(docsDir, { recursive: true });
|
|
317
|
-
|
|
318
|
-
// Create test markdown files
|
|
319
|
-
const file1Content = `# Doc 1\n\`\`\`d2\nA -> B\n\`\`\``;
|
|
320
|
-
const file2Content = `# Doc 2\n\`\`\`d2\nC -> D\n\`\`\``;
|
|
321
|
-
const file3Content = `# Doc 3\nNo diagrams here.`;
|
|
322
|
-
|
|
323
|
-
await writeFile(path.join(docsDir, "doc1.md"), file1Content);
|
|
324
|
-
await writeFile(path.join(docsDir, "doc2.md"), file2Content);
|
|
325
|
-
await writeFile(path.join(docsDir, "doc3.md"), file3Content);
|
|
326
|
-
|
|
327
|
-
await beforePublishHook({ docsDir });
|
|
328
|
-
|
|
329
|
-
// Check that files were processed
|
|
330
|
-
const processedFile1 = await readFile(path.join(docsDir, "doc1.md"), "utf8");
|
|
331
|
-
const processedFile2 = await readFile(path.join(docsDir, "doc2.md"), "utf8");
|
|
332
|
-
const processedFile3 = await readFile(path.join(docsDir, "doc3.md"), "utf8");
|
|
333
|
-
|
|
334
|
-
expect(processedFile1).not.toContain("```d2");
|
|
335
|
-
expect(processedFile2).not.toContain("```d2");
|
|
336
|
-
expect(processedFile3).toBe(file3Content); // Unchanged
|
|
337
|
-
|
|
338
|
-
expect(processedFile1).toContain(";
|
|
339
|
-
expect(processedFile2).toContain(";
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
test("should handle nested directories", async () => {
|
|
343
|
-
const docsDir = path.join(tempDir, "docs");
|
|
344
|
-
const subDir = path.join(docsDir, "subdir");
|
|
345
|
-
await mkdir(subDir, { recursive: true });
|
|
346
|
-
|
|
347
|
-
const fileContent = `# Nested Doc\n\`\`\`d2\nA -> B\n\`\`\``;
|
|
348
|
-
await writeFile(path.join(subDir, "nested.md"), fileContent);
|
|
349
|
-
|
|
350
|
-
await beforePublishHook({ docsDir });
|
|
351
|
-
|
|
352
|
-
const processedFile = await readFile(path.join(subDir, "nested.md"), "utf8");
|
|
353
|
-
expect(processedFile).not.toContain("```d2");
|
|
354
|
-
expect(processedFile).toContain(";
|
|
355
|
-
});
|
|
356
|
-
|
|
357
|
-
test("should handle empty docs directory", async () => {
|
|
358
|
-
const docsDir = path.join(tempDir, "empty-docs");
|
|
359
|
-
await mkdir(docsDir, { recursive: true });
|
|
360
|
-
|
|
361
|
-
// Should not throw error
|
|
362
|
-
await expect(beforePublishHook({ docsDir })).resolves.toBeUndefined();
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
test("should handle non-existent directory", async () => {
|
|
366
|
-
const nonExistentDir = path.join(tempDir, "non-existent");
|
|
367
|
-
|
|
368
|
-
const result = await beforePublishHook({ docsDir: nonExistentDir });
|
|
369
|
-
|
|
370
|
-
expect(result).toBeUndefined();
|
|
371
|
-
});
|
|
372
|
-
});
|
|
373
|
-
|
|
374
|
-
describe("checkD2Content", () => {
|
|
375
|
-
test("should generate and cache D2 SVG", async () => {
|
|
376
|
-
const content = "A -> B: test connection";
|
|
377
|
-
|
|
378
|
-
// Should not throw in normal operation
|
|
379
|
-
await expect(checkD2Content({ content })).resolves.toBeUndefined();
|
|
380
|
-
});
|
|
381
|
-
|
|
382
|
-
test("should use cached file when available", async () => {
|
|
383
|
-
const content = "A -> B: cached test";
|
|
384
|
-
|
|
385
|
-
// First call should generate
|
|
386
|
-
await checkD2Content({ content });
|
|
387
|
-
|
|
388
|
-
// Second call should use cache
|
|
389
|
-
const debugLogs = [];
|
|
390
|
-
const originalWrite = process.stderr.write;
|
|
391
|
-
process.stderr.write = (chunk) => {
|
|
392
|
-
debugLogs.push(chunk.toString());
|
|
393
|
-
return true;
|
|
394
|
-
};
|
|
395
|
-
Debug.enable("doc-smith");
|
|
396
|
-
|
|
397
|
-
try {
|
|
398
|
-
const startTime = Date.now();
|
|
399
|
-
await checkD2Content({ content });
|
|
400
|
-
const endTime = Date.now();
|
|
401
|
-
|
|
402
|
-
// Cache hit should be very fast (< 100ms)
|
|
403
|
-
expect(endTime - startTime).toBeLessThan(100);
|
|
404
|
-
expect(
|
|
405
|
-
debugLogs.some((log) => log.includes("Found assets cache, skipping generation")),
|
|
406
|
-
).toBe(true);
|
|
407
|
-
} finally {
|
|
408
|
-
process.stderr.write = originalWrite;
|
|
409
|
-
Debug.disable();
|
|
410
|
-
}
|
|
411
|
-
});
|
|
412
|
-
|
|
413
|
-
test("should handle generation errors in strict mode", async () => {
|
|
414
|
-
// Mock fetch to simulate server error
|
|
415
|
-
const originalFetch = global.fetch;
|
|
416
|
-
global.fetch = () =>
|
|
417
|
-
Promise.resolve({
|
|
418
|
-
ok: false,
|
|
419
|
-
status: 500,
|
|
420
|
-
statusText: "Internal Server Error",
|
|
421
|
-
text: () => Promise.resolve("Error response"),
|
|
422
|
-
});
|
|
423
|
-
|
|
424
|
-
try {
|
|
425
|
-
await expect(checkD2Content({ content: "A -> B" })).rejects.toThrow();
|
|
426
|
-
} finally {
|
|
427
|
-
global.fetch = originalFetch;
|
|
428
|
-
}
|
|
429
|
-
});
|
|
430
|
-
|
|
431
|
-
test("should handle empty content", async () => {
|
|
432
|
-
await expect(checkD2Content({ content: "" })).resolves.toBeUndefined();
|
|
433
|
-
});
|
|
434
|
-
|
|
435
|
-
test("should handle malformed D2 content", async () => {
|
|
436
|
-
const malformedContent = "A -> B -> [invalid";
|
|
437
|
-
|
|
438
|
-
// May throw depending on D2 server validation
|
|
439
|
-
try {
|
|
440
|
-
await checkD2Content({ content: malformedContent });
|
|
441
|
-
} catch (error) {
|
|
442
|
-
expect(error).toBeDefined();
|
|
443
|
-
}
|
|
444
|
-
});
|
|
445
|
-
|
|
446
|
-
test("should write .d2 file when debug is enabled", async () => {
|
|
447
|
-
const content = "A -> B: debug test";
|
|
448
|
-
|
|
449
|
-
Debug.enable("doc-smith");
|
|
450
|
-
|
|
451
|
-
try {
|
|
452
|
-
await checkD2Content({ content });
|
|
453
|
-
|
|
454
|
-
const assetDir = path.join(process.cwd(), DOC_SMITH_DIR, TMP_DIR, TMP_ASSETS_DIR, "d2");
|
|
455
|
-
const files = await readdir(assetDir);
|
|
456
|
-
const d2File = files.find((file) => file.endsWith(".d2"));
|
|
457
|
-
expect(d2File).toBeDefined();
|
|
458
|
-
} finally {
|
|
459
|
-
Debug.disable();
|
|
460
|
-
}
|
|
461
|
-
});
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
describe("ensureTmpDir", () => {
|
|
465
|
-
test("should create tmp directory structure", async () => {
|
|
466
|
-
// Change to temp directory for testing
|
|
467
|
-
const originalCwd = process.cwd();
|
|
468
|
-
process.chdir(tempDir);
|
|
469
|
-
|
|
470
|
-
try {
|
|
471
|
-
await ensureTmpDir();
|
|
472
|
-
|
|
473
|
-
const tmpDir = path.join(tempDir, DOC_SMITH_DIR, TMP_DIR);
|
|
474
|
-
const gitignorePath = path.join(tmpDir, ".gitignore");
|
|
475
|
-
|
|
476
|
-
expect(existsSync(tmpDir)).toBe(true);
|
|
477
|
-
expect(existsSync(gitignorePath)).toBe(true);
|
|
478
|
-
|
|
479
|
-
const gitignoreContent = await readFile(gitignorePath, "utf8");
|
|
480
|
-
expect(gitignoreContent).toBe("**/*");
|
|
481
|
-
} finally {
|
|
482
|
-
process.chdir(originalCwd);
|
|
483
|
-
}
|
|
484
|
-
});
|
|
485
|
-
|
|
486
|
-
test("should not recreate if already exists", async () => {
|
|
487
|
-
const originalCwd = process.cwd();
|
|
488
|
-
process.chdir(tempDir);
|
|
489
|
-
|
|
490
|
-
try {
|
|
491
|
-
// First call
|
|
492
|
-
await ensureTmpDir();
|
|
493
|
-
|
|
494
|
-
const tmpDir = path.join(tempDir, DOC_SMITH_DIR, TMP_DIR);
|
|
495
|
-
const gitignorePath = path.join(tmpDir, ".gitignore");
|
|
496
|
-
|
|
497
|
-
// Modify .gitignore to test if it gets overwritten
|
|
498
|
-
await writeFile(gitignorePath, "modified content");
|
|
499
|
-
|
|
500
|
-
// Second call
|
|
501
|
-
await ensureTmpDir();
|
|
502
|
-
|
|
503
|
-
const gitignoreContent = await readFile(gitignorePath, "utf8");
|
|
504
|
-
expect(gitignoreContent).toBe("modified content"); // Should not be overwritten
|
|
505
|
-
} finally {
|
|
506
|
-
process.chdir(originalCwd);
|
|
507
|
-
}
|
|
508
|
-
});
|
|
509
|
-
|
|
510
|
-
test("should handle directory creation errors", async () => {
|
|
511
|
-
// Try to create in a read-only location
|
|
512
|
-
const originalCwd = process.cwd();
|
|
513
|
-
|
|
514
|
-
try {
|
|
515
|
-
process.chdir("/root"); // Typically read-only
|
|
516
|
-
await expect(ensureTmpDir()).rejects.toThrow();
|
|
517
|
-
} catch (error) {
|
|
518
|
-
// Expected to fail in read-only directory
|
|
519
|
-
expect(error).toBeDefined();
|
|
520
|
-
} finally {
|
|
521
|
-
process.chdir(originalCwd);
|
|
522
|
-
}
|
|
523
|
-
});
|
|
524
|
-
});
|
|
525
|
-
|
|
526
|
-
describe("edge cases and error handling", () => {
|
|
527
|
-
test("should handle very large D2 content", async () => {
|
|
528
|
-
// Generate large D2 content
|
|
529
|
-
const largeContent = Array.from({ length: 1000 }, (_, i) => `Node${i} -> Node${i + 1}`).join(
|
|
530
|
-
"\n",
|
|
531
|
-
);
|
|
532
|
-
|
|
533
|
-
const result = await getD2Svg({ content: largeContent, strict: false });
|
|
534
|
-
expect(result === null || typeof result === "string").toBe(true);
|
|
535
|
-
}, 20000);
|
|
536
|
-
|
|
537
|
-
test("should handle special characters in D2 content", async () => {
|
|
538
|
-
const specialContent = `
|
|
539
|
-
"Node with spaces" -> "Node with 中文"
|
|
540
|
-
"Node with emoji 🎉" -> "Node with symbols @#$%"
|
|
541
|
-
`;
|
|
542
|
-
|
|
543
|
-
const result = await getD2Svg({ content: specialContent, strict: false });
|
|
544
|
-
expect(result === null || typeof result === "string").toBe(true);
|
|
545
|
-
}, 15000);
|
|
546
|
-
|
|
547
|
-
test("should handle concurrent D2 processing", async () => {
|
|
548
|
-
const contents = ["A -> B", "C -> D", "E -> F", "G -> H", "I -> J"];
|
|
549
|
-
|
|
550
|
-
// Process multiple D2 contents concurrently
|
|
551
|
-
const promises = contents.map((content) => getD2Svg({ content, strict: false }));
|
|
552
|
-
const results = await Promise.all(promises);
|
|
553
|
-
|
|
554
|
-
expect(results).toHaveLength(5);
|
|
555
|
-
results.forEach((result) => {
|
|
556
|
-
expect(result === null || typeof result === "string").toBe(true);
|
|
557
|
-
});
|
|
558
|
-
}, 20000);
|
|
559
|
-
|
|
560
|
-
test("should handle malformed regex in saveD2Assets", async () => {
|
|
561
|
-
const docsDir = path.join(tempDir, "docs");
|
|
562
|
-
await mkdir(docsDir, { recursive: true });
|
|
563
|
-
|
|
564
|
-
// Test with malformed D2 blocks (unclosed)
|
|
565
|
-
const malformedMarkdown = `# Test\n\`\`\`d2\nA -> B\n\`\`\`\n\`\`\`d2\nUnclosed block`;
|
|
566
|
-
|
|
567
|
-
const result = await saveD2Assets({ markdown: malformedMarkdown, docsDir });
|
|
568
|
-
|
|
569
|
-
// Should handle gracefully and process what it can
|
|
570
|
-
expect(typeof result).toBe("string");
|
|
571
|
-
});
|
|
572
|
-
|
|
573
|
-
test("should handle empty markdown input", async () => {
|
|
574
|
-
const docsDir = path.join(tempDir, "docs");
|
|
575
|
-
await mkdir(docsDir, { recursive: true });
|
|
576
|
-
|
|
577
|
-
const result = await saveD2Assets({ markdown: "", docsDir });
|
|
578
|
-
expect(result).toBe("");
|
|
579
|
-
});
|
|
580
|
-
|
|
581
|
-
test("should handle null and undefined markdown input", async () => {
|
|
582
|
-
const docsDir = path.join(tempDir, "docs");
|
|
583
|
-
await mkdir(docsDir, { recursive: true });
|
|
584
|
-
|
|
585
|
-
const result1 = await saveD2Assets({ markdown: null, docsDir });
|
|
586
|
-
expect(result1).toBe(null);
|
|
587
|
-
|
|
588
|
-
const result2 = await saveD2Assets({ markdown: undefined, docsDir });
|
|
589
|
-
expect(result2).toBe(undefined);
|
|
590
|
-
});
|
|
591
|
-
|
|
592
|
-
test("should handle getChart network errors in non-strict mode", async () => {
|
|
593
|
-
// Mock fetch to return error response
|
|
594
|
-
const originalFetch = global.fetch;
|
|
595
|
-
global.fetch = () =>
|
|
596
|
-
Promise.resolve({
|
|
597
|
-
ok: false,
|
|
598
|
-
status: 500,
|
|
599
|
-
statusText: "Internal Server Error",
|
|
600
|
-
text: () => Promise.resolve("Error response"),
|
|
601
|
-
});
|
|
602
|
-
|
|
603
|
-
try {
|
|
604
|
-
const result = await getChart({ content: "A -> B", strict: false });
|
|
605
|
-
// Should handle error gracefully in non-strict mode
|
|
606
|
-
expect(result === null || typeof result === "string").toBe(true);
|
|
607
|
-
} finally {
|
|
608
|
-
global.fetch = originalFetch;
|
|
609
|
-
}
|
|
610
|
-
});
|
|
611
|
-
|
|
612
|
-
test("should preserve line endings and whitespace in saveD2Assets", async () => {
|
|
613
|
-
const docsDir = path.join(tempDir, "docs");
|
|
614
|
-
await mkdir(docsDir, { recursive: true });
|
|
615
|
-
|
|
616
|
-
const markdown = `# Title\r\n\r\n\`\`\`d2\nA -> B\n\`\`\`\r\n\r\nEnd`;
|
|
617
|
-
|
|
618
|
-
const result = await saveD2Assets({ markdown, docsDir });
|
|
619
|
-
|
|
620
|
-
// Should preserve original line endings and spacing
|
|
621
|
-
expect(result).toContain("\r\n\r\n");
|
|
622
|
-
expect(result.split("\n").length).toBeGreaterThan(3);
|
|
623
|
-
});
|
|
624
|
-
|
|
625
|
-
test("should handle multiple concurrent calls to ensureTmpDir", async () => {
|
|
626
|
-
const originalCwd = process.cwd();
|
|
627
|
-
process.chdir(tempDir);
|
|
628
|
-
|
|
629
|
-
try {
|
|
630
|
-
// Multiple concurrent calls should not interfere
|
|
631
|
-
const promises = Array.from({ length: 5 }, () => ensureTmpDir());
|
|
632
|
-
await Promise.all(promises);
|
|
633
|
-
|
|
634
|
-
// Should only create directory once
|
|
635
|
-
const tmpDir = path.join(tempDir, DOC_SMITH_DIR, TMP_DIR);
|
|
636
|
-
expect(existsSync(tmpDir)).toBe(true);
|
|
637
|
-
|
|
638
|
-
// .gitignore should be created properly
|
|
639
|
-
const gitignoreContent = await readFile(path.join(tmpDir, ".gitignore"), "utf8");
|
|
640
|
-
expect(gitignoreContent).toBe("**/*");
|
|
641
|
-
} finally {
|
|
642
|
-
process.chdir(originalCwd);
|
|
643
|
-
}
|
|
644
|
-
});
|
|
645
|
-
});
|
|
646
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
body { color: }
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
body { color: red }
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
body { color: red;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
body { content: var(--undefined); }
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
body { color: red; }
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
FRM alpine
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
ARG UNDECLARED
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
ARG UNUSED
|