@aigne/doc-smith 0.8.11-beta.3 → 0.8.11-beta.5
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/config.yaml +1 -3
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +21 -0
- package/agents/clear/index.yaml +1 -0
- package/agents/evaluate/index.yaml +1 -0
- package/agents/generate/check-d2-diagram-valid.mjs +26 -0
- package/agents/generate/generate-d2-diagram.yaml +23 -0
- package/agents/generate/merge-d2-diagram.yaml +39 -0
- package/agents/init/index.mjs +42 -11
- package/agents/publish/index.yaml +1 -0
- package/agents/publish/publish-docs.mjs +17 -20
- package/agents/translate/index.yaml +1 -0
- package/agents/update/generate-document.yaml +25 -0
- package/agents/update/index.yaml +1 -0
- package/agents/update/update-single-document.yaml +1 -0
- package/agents/utils/choose-docs.mjs +22 -11
- package/package.json +2 -2
- package/prompts/detail/{d2-chart/rules.md → d2-diagram/rules-system.md} +41 -5
- package/prompts/detail/d2-diagram/rules-user.md +4 -0
- package/prompts/detail/document-rules.md +2 -3
- package/prompts/detail/generate-document.md +8 -2
- package/prompts/detail/update-document.md +1 -3
- package/prompts/translate/code-block.md +16 -0
- package/prompts/translate/translate-document.md +116 -20
- package/tests/agents/init/init.test.mjs +147 -19
- package/tests/agents/publish/publish-docs.test.mjs +99 -0
- package/tests/agents/utils/check-detail-result.test.mjs +2 -15
- package/tests/agents/utils/choose-docs.test.mjs +2 -9
- package/tests/utils/auth-utils.test.mjs +1 -1
- package/tests/utils/d2-utils.test.mjs +4 -4
- package/tests/utils/deploy.test.mjs +3 -10
- package/tests/utils/docs-finder-utils.test.mjs +12 -0
- package/tests/utils/kroki-utils.test.mjs +5 -5
- package/tests/utils/preferences-utils.test.mjs +5 -3
- package/tests/utils/save-value-to-config.test.mjs +3 -1
- package/utils/auth-utils.mjs +4 -0
- package/utils/constants/index.mjs +3 -0
- package/utils/d2-utils.mjs +11 -6
- package/utils/deploy.mjs +4 -20
- package/utils/docs-finder-utils.mjs +12 -1
- package/utils/kroki-utils.mjs +5 -4
- package/utils/markdown-checker.mjs +0 -20
- /package/prompts/detail/{d2-chart → d2-diagram}/official-examples.md +0 -0
|
@@ -91,15 +91,8 @@ describe("deploy", () => {
|
|
|
91
91
|
|
|
92
92
|
// Verify BrokerClient was constructed with correct config
|
|
93
93
|
expect(mockBrokerClientConstructor).toHaveBeenCalledWith({
|
|
94
|
-
baseUrl: "",
|
|
95
94
|
authToken: "mock-auth-token",
|
|
96
|
-
|
|
97
|
-
timeout: 300000,
|
|
98
|
-
polling: {
|
|
99
|
-
interval: 3000,
|
|
100
|
-
maxAttempts: 100,
|
|
101
|
-
backoffStrategy: "linear",
|
|
102
|
-
},
|
|
95
|
+
baseUrl: "https://docsmith.aigne.io",
|
|
103
96
|
});
|
|
104
97
|
|
|
105
98
|
// Verify deploy was called with correct parameters
|
|
@@ -120,7 +113,6 @@ describe("deploy", () => {
|
|
|
120
113
|
ACCESS_PREPARING: expect.any(Function),
|
|
121
114
|
ACCESS_READY: expect.any(Function),
|
|
122
115
|
}),
|
|
123
|
-
onError: expect.any(Function),
|
|
124
116
|
}),
|
|
125
117
|
);
|
|
126
118
|
|
|
@@ -348,7 +340,8 @@ describe("deploy", () => {
|
|
|
348
340
|
// Verify BrokerClient was constructed with empty baseUrl
|
|
349
341
|
expect(mockBrokerClientConstructor).toHaveBeenCalledWith(
|
|
350
342
|
expect.objectContaining({
|
|
351
|
-
|
|
343
|
+
authToken: "mock-auth-token",
|
|
344
|
+
baseUrl: "https://docsmith.aigne.io",
|
|
352
345
|
}),
|
|
353
346
|
);
|
|
354
347
|
});
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
describe("docs-finder-utils", () => {
|
|
16
16
|
let readdirSpy;
|
|
17
17
|
let readFileSpy;
|
|
18
|
+
let accessSpy;
|
|
18
19
|
let joinSpy;
|
|
19
20
|
let consoleWarnSpy;
|
|
20
21
|
|
|
@@ -22,6 +23,7 @@ describe("docs-finder-utils", () => {
|
|
|
22
23
|
// Mock file system operations
|
|
23
24
|
readdirSpy = spyOn(fs, "readdir").mockResolvedValue([]);
|
|
24
25
|
readFileSpy = spyOn(fs, "readFile").mockResolvedValue("test content");
|
|
26
|
+
accessSpy = spyOn(fs, "access").mockResolvedValue(undefined);
|
|
25
27
|
joinSpy = spyOn(path, "join").mockImplementation((...paths) => paths.join("/"));
|
|
26
28
|
|
|
27
29
|
// Mock console methods
|
|
@@ -31,6 +33,7 @@ describe("docs-finder-utils", () => {
|
|
|
31
33
|
afterEach(() => {
|
|
32
34
|
readdirSpy?.mockRestore();
|
|
33
35
|
readFileSpy?.mockRestore();
|
|
36
|
+
accessSpy?.mockRestore();
|
|
34
37
|
joinSpy?.mockRestore();
|
|
35
38
|
consoleWarnSpy?.mockRestore();
|
|
36
39
|
});
|
|
@@ -606,11 +609,20 @@ describe("docs-finder-utils", () => {
|
|
|
606
609
|
});
|
|
607
610
|
|
|
608
611
|
test("getMainLanguageFiles should handle readdir errors", async () => {
|
|
612
|
+
accessSpy.mockResolvedValue(undefined); // Directory exists
|
|
609
613
|
readdirSpy.mockRejectedValue(new Error("Permission denied"));
|
|
610
614
|
|
|
611
615
|
await expect(getMainLanguageFiles("/denied", "en")).rejects.toThrow("Permission denied");
|
|
612
616
|
});
|
|
613
617
|
|
|
618
|
+
test("getMainLanguageFiles should throw non-ENOENT access errors", async () => {
|
|
619
|
+
const permissionError = new Error("Permission denied");
|
|
620
|
+
permissionError.code = "EACCES";
|
|
621
|
+
accessSpy.mockRejectedValue(permissionError);
|
|
622
|
+
|
|
623
|
+
await expect(getMainLanguageFiles("/denied", "en")).rejects.toThrow("Permission denied");
|
|
624
|
+
});
|
|
625
|
+
|
|
614
626
|
test("processSelectedFiles should handle empty document structure", async () => {
|
|
615
627
|
readFileSpy.mockResolvedValue("content");
|
|
616
628
|
|
|
@@ -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 "../../utils/constants/index.mjs";
|
|
9
|
+
import { DOC_SMITH_DIR, TMP_ASSETS_DIR, TMP_DIR } from "../../utils/constants/index.mjs";
|
|
10
10
|
import {
|
|
11
11
|
beforePublishHook,
|
|
12
12
|
checkD2Content,
|
|
@@ -451,7 +451,7 @@ E -> F
|
|
|
451
451
|
try {
|
|
452
452
|
await checkD2Content({ content });
|
|
453
453
|
|
|
454
|
-
const assetDir = path.join(process.cwd(),
|
|
454
|
+
const assetDir = path.join(process.cwd(), DOC_SMITH_DIR, TMP_DIR, TMP_ASSETS_DIR, "d2");
|
|
455
455
|
const files = await readdir(assetDir);
|
|
456
456
|
const d2File = files.find((file) => file.endsWith(".d2"));
|
|
457
457
|
expect(d2File).toBeDefined();
|
|
@@ -470,7 +470,7 @@ E -> F
|
|
|
470
470
|
try {
|
|
471
471
|
await ensureTmpDir();
|
|
472
472
|
|
|
473
|
-
const tmpDir = path.join(tempDir,
|
|
473
|
+
const tmpDir = path.join(tempDir, DOC_SMITH_DIR, TMP_DIR);
|
|
474
474
|
const gitignorePath = path.join(tmpDir, ".gitignore");
|
|
475
475
|
|
|
476
476
|
expect(existsSync(tmpDir)).toBe(true);
|
|
@@ -491,7 +491,7 @@ E -> F
|
|
|
491
491
|
// First call
|
|
492
492
|
await ensureTmpDir();
|
|
493
493
|
|
|
494
|
-
const tmpDir = path.join(tempDir,
|
|
494
|
+
const tmpDir = path.join(tempDir, DOC_SMITH_DIR, TMP_DIR);
|
|
495
495
|
const gitignorePath = path.join(tmpDir, ".gitignore");
|
|
496
496
|
|
|
497
497
|
// Modify .gitignore to test if it gets overwritten
|
|
@@ -632,7 +632,7 @@ E -> F
|
|
|
632
632
|
await Promise.all(promises);
|
|
633
633
|
|
|
634
634
|
// Should only create directory once
|
|
635
|
-
const tmpDir = path.join(tempDir,
|
|
635
|
+
const tmpDir = path.join(tempDir, DOC_SMITH_DIR, TMP_DIR);
|
|
636
636
|
expect(existsSync(tmpDir)).toBe(true);
|
|
637
637
|
|
|
638
638
|
// .gitignore should be created properly
|
|
@@ -3,6 +3,8 @@ import { existsSync } from "node:fs";
|
|
|
3
3
|
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
+
|
|
7
|
+
import { DOC_SMITH_DIR } from "../../utils/constants/index.mjs";
|
|
6
8
|
import {
|
|
7
9
|
addPreferenceRule,
|
|
8
10
|
deactivateRule,
|
|
@@ -44,7 +46,7 @@ describe("preferences-utils", () => {
|
|
|
44
46
|
|
|
45
47
|
test("should read existing preferences file", async () => {
|
|
46
48
|
// Create preferences directory and file
|
|
47
|
-
const prefsDir = join(testDir,
|
|
49
|
+
const prefsDir = join(testDir, DOC_SMITH_DIR);
|
|
48
50
|
await mkdir(prefsDir, { recursive: true });
|
|
49
51
|
|
|
50
52
|
await writeFile(
|
|
@@ -69,7 +71,7 @@ describe("preferences-utils", () => {
|
|
|
69
71
|
|
|
70
72
|
test("should handle malformed YAML gracefully", async () => {
|
|
71
73
|
// Create preferences directory and invalid file
|
|
72
|
-
const prefsDir = join(testDir,
|
|
74
|
+
const prefsDir = join(testDir, DOC_SMITH_DIR);
|
|
73
75
|
await mkdir(prefsDir, { recursive: true });
|
|
74
76
|
|
|
75
77
|
await writeFile(join(prefsDir, "preferences.yml"), "invalid: yaml: content: [", "utf8");
|
|
@@ -85,7 +87,7 @@ describe("preferences-utils", () => {
|
|
|
85
87
|
|
|
86
88
|
writePreferences(testPreferences);
|
|
87
89
|
|
|
88
|
-
const prefsDir = join(testDir,
|
|
90
|
+
const prefsDir = join(testDir, DOC_SMITH_DIR);
|
|
89
91
|
expect(existsSync(prefsDir)).toBe(true);
|
|
90
92
|
expect(existsSync(join(prefsDir, "preferences.yml"))).toBe(true);
|
|
91
93
|
});
|
|
@@ -5,6 +5,8 @@ import fsPromisesDefault, * as fsPromises from "node:fs/promises";
|
|
|
5
5
|
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
6
6
|
import { dirname, join } from "node:path";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
|
+
|
|
9
|
+
import { DOC_SMITH_DIR } from "../../utils/constants/index.mjs";
|
|
8
10
|
import { saveValueToConfig } from "../../utils/utils.mjs";
|
|
9
11
|
|
|
10
12
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -12,7 +14,7 @@ const __dirname = dirname(__filename);
|
|
|
12
14
|
|
|
13
15
|
// Test directory for isolated testing
|
|
14
16
|
const TEST_DIR = join(__dirname, "temp-config-test");
|
|
15
|
-
const TEST_CONFIG_DIR = join(TEST_DIR,
|
|
17
|
+
const TEST_CONFIG_DIR = join(TEST_DIR, DOC_SMITH_DIR);
|
|
16
18
|
const TEST_CONFIG_PATH = join(TEST_CONFIG_DIR, "config.yaml");
|
|
17
19
|
|
|
18
20
|
// Store original working directory
|
package/utils/auth-utils.mjs
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
} from "./blocklet.mjs";
|
|
16
16
|
import {
|
|
17
17
|
BLOCKLET_ADD_COMPONENT_DOCS,
|
|
18
|
+
DEFAULT_APP_URL,
|
|
18
19
|
DISCUSS_KIT_DID,
|
|
19
20
|
DISCUSS_KIT_STORE_URL,
|
|
20
21
|
DOC_OFFICIAL_ACCESS_TOKEN,
|
|
@@ -97,6 +98,9 @@ export async function getAccessToken(appUrl, ltToken = "") {
|
|
|
97
98
|
appLogo: "https://docsmith.aigne.io/image-bin/uploads/9645caf64b4232699982c4d940b03b90.svg",
|
|
98
99
|
openPage: (pageUrl) => {
|
|
99
100
|
const url = new URL(pageUrl);
|
|
101
|
+
if (url.hostname !== DEFAULT_APP_URL) {
|
|
102
|
+
url.searchParams.set("required_roles", "owner,admin");
|
|
103
|
+
}
|
|
100
104
|
if (ltToken) {
|
|
101
105
|
url.searchParams.set("__lt", ltToken);
|
|
102
106
|
}
|
|
@@ -334,6 +334,9 @@ export const PAYMENT_KIT_DID = "z2qaCNvKMv5GjouKdcDWexv6WqtHbpNPQDnAk";
|
|
|
334
334
|
|
|
335
335
|
export const DOC_OFFICIAL_ACCESS_TOKEN = "DOC_OFFICIAL_ACCESS_TOKEN";
|
|
336
336
|
|
|
337
|
+
// Default application URL for the document deployment website.
|
|
338
|
+
export const DEFAULT_APP_URL = "https://docsmith.aigne.io";
|
|
339
|
+
|
|
337
340
|
// Discuss Kit related URLs
|
|
338
341
|
export const DISCUSS_KIT_STORE_URL =
|
|
339
342
|
"https://store.blocklet.dev/blocklets/z8ia1WEiBZ7hxURf6LwH21Wpg99vophFwSJdu";
|
package/utils/d2-utils.mjs
CHANGED
|
@@ -17,6 +17,8 @@ import { debug } from "./debug.mjs";
|
|
|
17
17
|
import { iconMap } from "./icon-map.mjs";
|
|
18
18
|
import { getContentHash } from "./utils.mjs";
|
|
19
19
|
|
|
20
|
+
const codeBlockRegex = /```d2.*\n([\s\S]*?)```/g;
|
|
21
|
+
|
|
20
22
|
export async function getChart({ content, strict }) {
|
|
21
23
|
const d2 = new D2();
|
|
22
24
|
const iconUrlList = Object.keys(iconMap);
|
|
@@ -60,7 +62,7 @@ export async function getChart({ content, strict }) {
|
|
|
60
62
|
} catch (err) {
|
|
61
63
|
if (strict) throw err;
|
|
62
64
|
|
|
63
|
-
console.error("Failed to generate D2
|
|
65
|
+
console.error("Failed to generate D2 diagram. Content:", content, "Error:", err);
|
|
64
66
|
return null;
|
|
65
67
|
} finally {
|
|
66
68
|
d2.worker.terminate();
|
|
@@ -73,8 +75,6 @@ export async function saveAssets({ markdown, docsDir }) {
|
|
|
73
75
|
return markdown;
|
|
74
76
|
}
|
|
75
77
|
|
|
76
|
-
const codeBlockRegex = /```d2.*\n([\s\S]*?)```/g;
|
|
77
|
-
|
|
78
78
|
const { replaced } = await runIterator({
|
|
79
79
|
input: markdown,
|
|
80
80
|
regexp: codeBlockRegex,
|
|
@@ -90,7 +90,7 @@ export async function saveAssets({ markdown, docsDir }) {
|
|
|
90
90
|
debug("Found assets cache, skipping generation", svgPath);
|
|
91
91
|
} else {
|
|
92
92
|
try {
|
|
93
|
-
debug("start generate d2
|
|
93
|
+
debug("start generate d2 diagram", svgPath);
|
|
94
94
|
if (debug.enabled) {
|
|
95
95
|
const d2FileName = `${getContentHash(d2Content)}.d2`;
|
|
96
96
|
const d2Path = path.join(assetDir, d2FileName);
|
|
@@ -102,7 +102,7 @@ export async function saveAssets({ markdown, docsDir }) {
|
|
|
102
102
|
await fs.writeFile(svgPath, svg, { encoding: "utf8" });
|
|
103
103
|
}
|
|
104
104
|
} catch (error) {
|
|
105
|
-
debug("Failed to generate D2
|
|
105
|
+
debug("Failed to generate D2 diagram. Content:", d2Content, "Error:", error);
|
|
106
106
|
return _code;
|
|
107
107
|
}
|
|
108
108
|
}
|
|
@@ -156,7 +156,12 @@ async function runIterator({ input, regexp, fn = () => {}, options, replace = fa
|
|
|
156
156
|
};
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
export async function checkContent({ content }) {
|
|
159
|
+
export async function checkContent({ content: _content }) {
|
|
160
|
+
const matches = Array.from(_content.matchAll(codeBlockRegex));
|
|
161
|
+
let content = _content;
|
|
162
|
+
if (matches.length > 0) {
|
|
163
|
+
content = matches[0][1];
|
|
164
|
+
}
|
|
160
165
|
await ensureTmpDir();
|
|
161
166
|
const assetDir = path.join(DOC_SMITH_DIR, TMP_DIR, TMP_ASSETS_DIR, "d2");
|
|
162
167
|
await fs.ensureDir(assetDir);
|
package/utils/deploy.mjs
CHANGED
|
@@ -2,10 +2,11 @@ import { BrokerClient, STEPS } from "@blocklet/payment-broker-client/node";
|
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
import open from "open";
|
|
4
4
|
import { getOfficialAccessToken } from "./auth-utils.mjs";
|
|
5
|
+
import { DEFAULT_APP_URL } from "./constants/index.mjs";
|
|
5
6
|
import { saveValueToConfig } from "./utils.mjs";
|
|
6
7
|
|
|
7
8
|
// ==================== Configuration ====================
|
|
8
|
-
const BASE_URL = process.env.DOC_SMITH_BASE_URL ||
|
|
9
|
+
const BASE_URL = process.env.DOC_SMITH_BASE_URL || DEFAULT_APP_URL;
|
|
9
10
|
const SUCCESS_MESSAGE = {
|
|
10
11
|
en: "Congratulations! Your website has been successfully installed. You can return to the command-line tool to continue the next steps.",
|
|
11
12
|
zh: "恭喜您,你的网站已安装成功!可以返回命令行工具继续后续操作!",
|
|
@@ -24,26 +25,14 @@ export async function deploy(id, cachedUrl) {
|
|
|
24
25
|
throw new Error("Failed to get official access token");
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
const client = new BrokerClient({
|
|
28
|
-
baseUrl: BASE_URL,
|
|
29
|
-
authToken,
|
|
30
|
-
paymentLinkKey: "PAYMENT_LINK_ID",
|
|
31
|
-
timeout: 300000,
|
|
32
|
-
polling: {
|
|
33
|
-
interval: 3000,
|
|
34
|
-
maxAttempts: 100,
|
|
35
|
-
backoffStrategy: "linear",
|
|
36
|
-
},
|
|
37
|
-
});
|
|
28
|
+
const client = new BrokerClient({ baseUrl: BASE_URL, authToken });
|
|
38
29
|
|
|
39
30
|
console.log(`🚀 Starting deployment...`);
|
|
40
31
|
|
|
41
32
|
const result = await client.deploy({
|
|
42
33
|
cachedCheckoutId: id,
|
|
43
34
|
cachedPaymentUrl: cachedUrl,
|
|
44
|
-
pageInfo: {
|
|
45
|
-
successMessage: SUCCESS_MESSAGE,
|
|
46
|
-
},
|
|
35
|
+
pageInfo: { successMessage: SUCCESS_MESSAGE },
|
|
47
36
|
hooks: {
|
|
48
37
|
[STEPS.PAYMENT_PENDING]: async ({ sessionId, paymentUrl, isResuming }) => {
|
|
49
38
|
console.log(`⏳ Step 1/4: Waiting for payment...`);
|
|
@@ -86,11 +75,6 @@ export async function deploy(id, cachedUrl) {
|
|
|
86
75
|
}
|
|
87
76
|
},
|
|
88
77
|
},
|
|
89
|
-
|
|
90
|
-
onError: (error, step) => {
|
|
91
|
-
console.error(`${chalk.red("❌")} Deployment failed at ${step || "unknown step"}:`);
|
|
92
|
-
console.error(` ${error.message}`);
|
|
93
|
-
},
|
|
94
78
|
});
|
|
95
79
|
|
|
96
80
|
const { appUrl, homeUrl, subscriptionUrl, dashboardUrl, vendors } = result;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readdir, readFile } from "node:fs/promises";
|
|
1
|
+
import { access, readdir, readFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -120,6 +120,17 @@ export async function readFileContent(docsDir, fileName) {
|
|
|
120
120
|
* @returns {Promise<string[]>} Array of main language .md files ordered by documentExecutionStructure
|
|
121
121
|
*/
|
|
122
122
|
export async function getMainLanguageFiles(docsDir, locale, documentExecutionStructure = null) {
|
|
123
|
+
// Check if docsDir exists
|
|
124
|
+
try {
|
|
125
|
+
await access(docsDir);
|
|
126
|
+
} catch (error) {
|
|
127
|
+
if (error.code === "ENOENT") {
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
|
|
123
134
|
const files = await readdir(docsDir);
|
|
124
135
|
|
|
125
136
|
// Filter for main language .md files (exclude _sidebar.md)
|
package/utils/kroki-utils.mjs
CHANGED
|
@@ -8,6 +8,7 @@ import { joinURL } from "ufo";
|
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
10
|
D2_CONFIG,
|
|
11
|
+
DOC_SMITH_DIR,
|
|
11
12
|
FILE_CONCURRENCY,
|
|
12
13
|
KROKI_CONCURRENCY,
|
|
13
14
|
TMP_ASSETS_DIR,
|
|
@@ -76,7 +77,7 @@ export async function saveD2Assets({ markdown, docsDir }) {
|
|
|
76
77
|
debug("Found assets cache, skipping generation", svgPath);
|
|
77
78
|
} else {
|
|
78
79
|
try {
|
|
79
|
-
debug("
|
|
80
|
+
debug("Start generate d2 diagram", svgPath);
|
|
80
81
|
if (debug.enabled) {
|
|
81
82
|
const d2FileName = `${getContentHash(d2Content)}.d2`;
|
|
82
83
|
const d2Path = path.join(assetDir, d2FileName);
|
|
@@ -88,7 +89,7 @@ export async function saveD2Assets({ markdown, docsDir }) {
|
|
|
88
89
|
await fs.writeFile(svgPath, svg, { encoding: "utf8" });
|
|
89
90
|
}
|
|
90
91
|
} catch (error) {
|
|
91
|
-
debug("Failed to generate D2
|
|
92
|
+
debug("Failed to generate D2 diagram:", error);
|
|
92
93
|
return _code;
|
|
93
94
|
}
|
|
94
95
|
}
|
|
@@ -144,7 +145,7 @@ async function runIterator({ input, regexp, fn = () => {}, options, replace = fa
|
|
|
144
145
|
|
|
145
146
|
export async function checkD2Content({ content }) {
|
|
146
147
|
await ensureTmpDir();
|
|
147
|
-
const assetDir = path.join(
|
|
148
|
+
const assetDir = path.join(DOC_SMITH_DIR, TMP_DIR, TMP_ASSETS_DIR, "d2");
|
|
148
149
|
await fs.ensureDir(assetDir);
|
|
149
150
|
const d2Content = [D2_CONFIG, content].join("\n");
|
|
150
151
|
const fileName = `${getContentHash(d2Content)}.svg`;
|
|
@@ -166,7 +167,7 @@ export async function checkD2Content({ content }) {
|
|
|
166
167
|
}
|
|
167
168
|
|
|
168
169
|
export async function ensureTmpDir() {
|
|
169
|
-
const tmpDir = path.join(
|
|
170
|
+
const tmpDir = path.join(DOC_SMITH_DIR, TMP_DIR);
|
|
170
171
|
if (!(await fs.pathExists(path.join(tmpDir, ".gitignore")))) {
|
|
171
172
|
await fs.ensureDir(tmpDir);
|
|
172
173
|
await fs.writeFile(path.join(tmpDir, ".gitignore"), "**/*", { encoding: "utf8" });
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import pMap from "p-map";
|
|
4
3
|
import remarkGfm from "remark-gfm";
|
|
5
4
|
import remarkLint from "remark-lint";
|
|
6
5
|
import remarkParse from "remark-parse";
|
|
7
6
|
import { unified } from "unified";
|
|
8
7
|
import { visit } from "unist-util-visit";
|
|
9
8
|
import { VFile } from "vfile";
|
|
10
|
-
import { KROKI_CONCURRENCY } from "./constants/index.mjs";
|
|
11
|
-
import { checkContent, isValidCode } from "./d2-utils.mjs";
|
|
12
9
|
import { validateMermaidSyntax } from "./mermaid-validator.mjs";
|
|
13
10
|
|
|
14
11
|
/**
|
|
@@ -378,7 +375,6 @@ export async function checkMarkdown(markdown, source = "content", options = {})
|
|
|
378
375
|
|
|
379
376
|
// Check mermaid code blocks and other custom validations
|
|
380
377
|
const mermaidChecks = [];
|
|
381
|
-
const d2ChecksList = [];
|
|
382
378
|
visit(ast, "code", (node) => {
|
|
383
379
|
if (node.lang) {
|
|
384
380
|
const line = node.position?.start?.line || "unknown";
|
|
@@ -467,13 +463,6 @@ export async function checkMarkdown(markdown, source = "content", options = {})
|
|
|
467
463
|
specialCharMatch = nodeWithSpecialCharsRegex.exec(mermaidContent);
|
|
468
464
|
}
|
|
469
465
|
}
|
|
470
|
-
if (isValidCode(node.lang)) {
|
|
471
|
-
d2ChecksList.push({
|
|
472
|
-
content: node.value,
|
|
473
|
-
line,
|
|
474
|
-
});
|
|
475
|
-
}
|
|
476
|
-
// TODO: @zhanghan need to check correctness of every code language
|
|
477
466
|
}
|
|
478
467
|
});
|
|
479
468
|
|
|
@@ -524,15 +513,6 @@ export async function checkMarkdown(markdown, source = "content", options = {})
|
|
|
524
513
|
|
|
525
514
|
// Wait for all mermaid checks to complete
|
|
526
515
|
await Promise.all(mermaidChecks);
|
|
527
|
-
await pMap(
|
|
528
|
-
d2ChecksList,
|
|
529
|
-
async ({ content, line }) =>
|
|
530
|
-
checkContent({ content }).catch((err) => {
|
|
531
|
-
const errorMessage = err?.message || String(err) || "Unknown d2 syntax error";
|
|
532
|
-
errorMessages.push(`Found D2 syntax error in ${source} at line ${line}: ${errorMessage}`);
|
|
533
|
-
}),
|
|
534
|
-
{ concurrency: KROKI_CONCURRENCY },
|
|
535
|
-
);
|
|
536
516
|
|
|
537
517
|
// Run markdown linting rules
|
|
538
518
|
await processor.run(ast, file);
|
|
File without changes
|