@aigne/doc-smith 0.8.5 → 0.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.aigne/doc-smith/output/structure-plan.json +1 -5
- package/CHANGELOG.md +25 -0
- package/README.md +3 -3
- package/agents/{chat.yaml → chat/index.yaml} +7 -7
- package/agents/generate/check-document-structure.yaml +30 -0
- package/agents/{check-structure-plan.mjs → generate/check-need-generate-structure.mjs} +21 -21
- package/agents/generate/generate-structure.yaml +58 -0
- package/agents/{docs-generator.yaml → generate/index.yaml} +15 -16
- package/agents/generate/refine-document-structure.yaml +12 -0
- package/agents/{input-generator.mjs → init/index.mjs} +34 -27
- package/agents/{manage-prefs.mjs → prefs/index.mjs} +16 -16
- package/agents/publish/index.yaml +17 -0
- package/agents/{publish-docs.mjs → publish/publish-docs.mjs} +15 -16
- package/agents/schema/{structure-plan-result.yaml → document-execution-structure.yaml} +3 -3
- package/agents/schema/document-structure.yaml +26 -0
- package/agents/{language-selector.mjs → translate/choose-language.mjs} +5 -5
- package/agents/{retranslate.yaml → translate/index.yaml} +17 -18
- package/agents/translate/translate-document.yaml +32 -0
- package/agents/{batch-translate.yaml → translate/translate-multilingual.yaml} +5 -5
- package/agents/update/batch-generate-document.yaml +19 -0
- package/agents/{check-detail.mjs → update/check-document.mjs} +16 -16
- package/agents/{detail-generator-and-translate.yaml → update/generate-and-translate-document.yaml} +23 -23
- package/agents/update/generate-document.yaml +50 -0
- package/agents/{detail-regenerator.yaml → update/index.yaml} +16 -17
- package/agents/{action-success.mjs → utils/action-success.mjs} +2 -2
- package/agents/{check-detail-result.mjs → utils/check-detail-result.mjs} +3 -3
- package/agents/{check-feedback-refiner.mjs → utils/check-feedback-refiner.mjs} +6 -6
- package/agents/{find-items-by-paths.mjs → utils/choose-docs.mjs} +25 -10
- package/agents/{docs-fs.yaml → utils/docs-fs-actor.yaml} +3 -1
- package/agents/utils/feedback-refiner.yaml +50 -0
- package/agents/{find-item-by-path.mjs → utils/find-item-by-path.mjs} +17 -7
- package/agents/{find-user-preferences-by-path.mjs → utils/find-user-preferences-by-path.mjs} +1 -1
- package/agents/utils/format-document-structure.mjs +25 -0
- package/agents/{load-sources.mjs → utils/load-sources.mjs} +41 -28
- package/agents/{save-docs.mjs → utils/save-docs.mjs} +16 -16
- package/agents/{save-single-doc.mjs → utils/save-single-doc.mjs} +2 -2
- package/agents/{transform-detail-datasources.mjs → utils/transform-detail-datasources.mjs} +1 -1
- package/aigne.yaml +35 -35
- package/docs/cli-reference.md +1 -1
- package/docs/features-generate-documentation.md +1 -1
- package/docs/features-update-and-refine.md +2 -2
- package/docs-mcp/analyze-docs-relevance.yaml +10 -10
- package/docs-mcp/docs-search.yaml +5 -3
- package/package.json +10 -8
- package/prompts/{document → detail/custom}/custom-code-block.md +6 -6
- package/prompts/detail/custom/custom-components.md +172 -0
- package/prompts/{document → detail}/d2-chart/rules.md +95 -1
- package/prompts/{document → detail}/detail-example.md +80 -61
- package/prompts/{document/detail-generator.md → detail/document-rules.md} +4 -8
- package/prompts/{content-detail-generator.md → detail/generate-document.md} +48 -25
- package/prompts/{check-structure-planning-result.md → structure/check-document-structure.md} +23 -17
- package/prompts/{document/structure-planning.md → structure/document-rules.md} +0 -2
- package/prompts/{structure-planning.md → structure/generate-structure.md} +51 -30
- package/prompts/{document → structure}/structure-example.md +2 -2
- package/prompts/{document → structure}/structure-getting-started.md +2 -2
- package/prompts/translate/glossary.md +6 -0
- package/prompts/{translator.md → translate/translate-document.md} +29 -10
- package/prompts/{feedback-refiner.md → utils/feedback-refiner.md} +8 -8
- package/tests/agents/chat/chat.test.mjs +46 -0
- package/tests/agents/generate/check-document-structure.test.mjs +51 -0
- package/tests/agents/generate/check-need-generate-structure.test.mjs +292 -0
- package/tests/agents/generate/generate-structure.test.mjs +51 -0
- package/tests/{input-generator.test.mjs → agents/init/init.test.mjs} +19 -17
- package/tests/agents/prefs/prefs.test.mjs +431 -0
- package/tests/agents/publish/publish-docs.test.mjs +642 -0
- package/tests/agents/translate/choose-language.test.mjs +311 -0
- package/tests/agents/translate/translate-document.test.mjs +51 -0
- package/tests/agents/update/check-document.test.mjs +523 -0
- package/tests/agents/update/generate-document.test.mjs +51 -0
- package/tests/agents/utils/action-success.test.mjs +54 -0
- package/tests/{check-detail-result.test.mjs → agents/utils/check-detail-result.test.mjs} +98 -98
- package/tests/agents/utils/check-feedback-refiner.test.mjs +478 -0
- package/tests/agents/utils/choose-docs.test.mjs +417 -0
- package/tests/agents/utils/exit.test.mjs +70 -0
- package/tests/agents/utils/feedback-refiner.test.mjs +51 -0
- package/tests/agents/utils/find-item-by-path.test.mjs +526 -0
- package/tests/agents/utils/find-user-preferences-by-path.test.mjs +382 -0
- package/tests/agents/utils/format-document-structure.test.mjs +264 -0
- package/tests/agents/utils/fs.test.mjs +267 -0
- package/tests/{load-sources.test.mjs → agents/utils/load-sources.test.mjs} +153 -25
- package/tests/{save-docs.test.mjs → agents/utils/save-docs.test.mjs} +11 -5
- package/tests/agents/utils/save-output.test.mjs +315 -0
- package/tests/agents/utils/save-single-doc.test.mjs +364 -0
- package/tests/agents/utils/transform-detail-datasources.test.mjs +363 -0
- package/tests/utils/auth-utils.test.mjs +358 -0
- package/tests/utils/blocklet.test.mjs +334 -0
- package/tests/{conflict-resolution.test.mjs → utils/conflict-detector.test.mjs} +3 -3
- package/tests/utils/constants.test.mjs +295 -0
- package/tests/utils/d2-utils.test.mjs +423 -0
- package/tests/utils/deploy.test.mjs +365 -0
- package/tests/utils/docs-finder-utils.test.mjs +625 -0
- package/tests/utils/file-utils.test.mjs +213 -0
- package/tests/{kroki-utils.test.mjs → utils/kroki-utils.test.mjs} +2 -2
- package/tests/utils/load-config.test.mjs +141 -0
- package/tests/{mermaid-validation.test.mjs → utils/mermaid-validator.test.mjs} +2 -2
- package/tests/utils/mock-chat-model.mjs +12 -0
- package/tests/{preferences-utils.test.mjs → utils/preferences-utils.test.mjs} +1 -1
- package/tests/{save-value-to-config.test.mjs → utils/save-value-to-config.test.mjs} +61 -4
- package/tests/utils/utils.test.mjs +939 -0
- package/utils/auth-utils.mjs +1 -1
- package/utils/conflict-detector.mjs +1 -1
- package/utils/constants.mjs +5 -3
- package/utils/d2-utils.mjs +194 -0
- package/utils/deploy.mjs +3 -3
- package/utils/docs-finder-utils.mjs +26 -26
- package/utils/icon-map.mjs +26 -0
- package/{agents → utils}/load-config.mjs +2 -18
- package/utils/markdown-checker.mjs +5 -5
- package/agents/batch-docs-detail-generator.yaml +0 -19
- package/agents/check-structure-planning-result.yaml +0 -30
- package/agents/content-detail-generator.yaml +0 -50
- package/agents/feedback-refiner.yaml +0 -52
- package/agents/format-structure-plan.mjs +0 -25
- package/agents/reflective-structure-planner.yaml +0 -12
- package/agents/schema/structure-plan.yaml +0 -26
- package/agents/structure-planning.yaml +0 -58
- package/agents/team-publish-docs.yaml +0 -18
- package/agents/translate.yaml +0 -31
- package/prompts/document/custom-components.md +0 -104
- package/tests/README.md +0 -93
- package/tests/utils.test.mjs +0 -2067
- /package/agents/{exit.mjs → utils/exit.mjs} +0 -0
- /package/agents/{fs.mjs → utils/fs.mjs} +0 -0
- /package/agents/{save-output.mjs → utils/save-output.mjs} +0 -0
- /package/prompts/{document → detail}/d2-chart/official-examples.md +0 -0
- /package/prompts/{document → detail}/jsx/rules.md +0 -0
package/utils/auth-utils.mjs
CHANGED
|
@@ -88,7 +88,7 @@ export async function getAccessToken(appUrl, ltToken = "") {
|
|
|
88
88
|
const result = await createConnect({
|
|
89
89
|
connectUrl: connectUrl,
|
|
90
90
|
connectAction: "gen-simple-access-key",
|
|
91
|
-
source: `AIGNE DocSmith connect to
|
|
91
|
+
source: `AIGNE DocSmith connect to website`,
|
|
92
92
|
closeOnSuccess: true,
|
|
93
93
|
appName: "AIGNE DocSmith",
|
|
94
94
|
appLogo: "https://docsmith.aigne.io/image-bin/uploads/a7910a71364ee15a27e86f869ad59009.svg",
|
|
@@ -72,7 +72,7 @@ export function getFilteredOptions(targetQuestion, currentSelections, allOptions
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
/**
|
|
75
|
-
* Detect conflicts in user configuration selections that can be resolved through structure
|
|
75
|
+
* Detect conflicts in user configuration selections that can be resolved through document structure
|
|
76
76
|
* @param {Object} config - User configuration
|
|
77
77
|
* @returns {Array} Array of detected conflicts with resolution strategies
|
|
78
78
|
*/
|
package/utils/constants.mjs
CHANGED
|
@@ -345,7 +345,7 @@ export const SUPPORTED_FILE_EXTENSIONS = [".txt", ".md", ".json", ".yaml", ".yml
|
|
|
345
345
|
export const CONFLICT_RULES = {
|
|
346
346
|
// Internal conflicts within the same question (multi-select conflicts)
|
|
347
347
|
internalConflicts: {
|
|
348
|
-
// Note: Most conflicts can be resolved through intelligent document structure
|
|
348
|
+
// Note: Most conflicts can be resolved through intelligent document structure
|
|
349
349
|
// Only keeping conflicts that represent fundamental incompatibilities
|
|
350
350
|
},
|
|
351
351
|
|
|
@@ -419,7 +419,7 @@ export const CONFLICT_RULES = {
|
|
|
419
419
|
|
|
420
420
|
// Conflict resolution rules - defines how to handle conflicts when users select conflicting options
|
|
421
421
|
export const CONFLICT_RESOLUTION_RULES = {
|
|
422
|
-
// Document purpose conflicts that can be resolved through structure
|
|
422
|
+
// Document purpose conflicts that can be resolved through document structure
|
|
423
423
|
documentPurpose: [
|
|
424
424
|
{
|
|
425
425
|
conflictItems: ["getStarted", "findAnswers"],
|
|
@@ -446,7 +446,7 @@ export const CONFLICT_RESOLUTION_RULES = {
|
|
|
446
446
|
},
|
|
447
447
|
],
|
|
448
448
|
|
|
449
|
-
// Target audience conflicts that can be resolved through structure
|
|
449
|
+
// Target audience conflicts that can be resolved through document structure
|
|
450
450
|
targetAudienceTypes: [
|
|
451
451
|
{
|
|
452
452
|
conflictItems: ["endUsers", "developers"],
|
|
@@ -534,7 +534,9 @@ export const D2_CONFIG = `vars: {
|
|
|
534
534
|
}`;
|
|
535
535
|
|
|
536
536
|
export const KROKI_CONCURRENCY = 5;
|
|
537
|
+
export const D2_CONCURRENCY = 10;
|
|
537
538
|
export const FILE_CONCURRENCY = 3;
|
|
539
|
+
export const DOC_SMITH_DIR = ".aigne/doc-smith";
|
|
538
540
|
export const TMP_DIR = ".tmp";
|
|
539
541
|
export const TMP_DOCS_DIR = "docs";
|
|
540
542
|
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
import { D2 } from "@terrastruct/d2";
|
|
4
|
+
import Debug from "debug";
|
|
5
|
+
import fs from "fs-extra";
|
|
6
|
+
import { glob } from "glob";
|
|
7
|
+
import pMap from "p-map";
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
D2_CONCURRENCY,
|
|
11
|
+
D2_CONFIG,
|
|
12
|
+
DOC_SMITH_DIR,
|
|
13
|
+
FILE_CONCURRENCY,
|
|
14
|
+
TMP_ASSETS_DIR,
|
|
15
|
+
TMP_DIR,
|
|
16
|
+
} from "./constants.mjs";
|
|
17
|
+
import { iconMap } from "./icon-map.mjs";
|
|
18
|
+
import { getContentHash } from "./utils.mjs";
|
|
19
|
+
|
|
20
|
+
const debug = Debug("doc-smith");
|
|
21
|
+
|
|
22
|
+
export async function getChart({ content, strict }) {
|
|
23
|
+
const d2 = new D2();
|
|
24
|
+
const iconUrlList = Object.keys(iconMap);
|
|
25
|
+
const escapedUrls = iconUrlList.map((url) => url.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
|
|
26
|
+
const regexPattern = escapedUrls.join("|");
|
|
27
|
+
const regex = new RegExp(regexPattern, "g");
|
|
28
|
+
|
|
29
|
+
const contentWithBase64Img = content.replace(regex, (match) => {
|
|
30
|
+
return iconMap[match];
|
|
31
|
+
});
|
|
32
|
+
try {
|
|
33
|
+
const { diagram, renderOptions, graph } = await d2.compile(contentWithBase64Img);
|
|
34
|
+
|
|
35
|
+
// Ignore stroke-dash in sequence diagram
|
|
36
|
+
if (
|
|
37
|
+
graph?.root?.attributes?.shape &&
|
|
38
|
+
graph.root.attributes.shape.value !== "sequence_diagram"
|
|
39
|
+
) {
|
|
40
|
+
// Save first level container
|
|
41
|
+
const firstLevelContainer = new Set();
|
|
42
|
+
diagram.shapes.forEach((x) => {
|
|
43
|
+
const idList = x.id.split(".");
|
|
44
|
+
if (idList.length > 1) {
|
|
45
|
+
const targetShape = diagram.shapes.find((x) => x.id === idList[0]);
|
|
46
|
+
if (targetShape && !["c4-person", "cylinder", "queue"].includes(targetShape.type)) {
|
|
47
|
+
firstLevelContainer.add(targetShape);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
firstLevelContainer.forEach((shape) => {
|
|
52
|
+
if (!shape.strokeDash) {
|
|
53
|
+
// NOTICE: The data structure here is different from the d2 source code.
|
|
54
|
+
shape.strokeDash = 3;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const svg = await d2.render(diagram, renderOptions);
|
|
60
|
+
|
|
61
|
+
return svg;
|
|
62
|
+
} catch (err) {
|
|
63
|
+
if (strict) throw err;
|
|
64
|
+
|
|
65
|
+
console.error("Failed to generate D2 chart. Content:", content, "Error:", err);
|
|
66
|
+
return null;
|
|
67
|
+
} finally {
|
|
68
|
+
d2.worker.terminate();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Helper: save d2 svg assets alongside document
|
|
73
|
+
export async function saveAssets({ markdown, docsDir }) {
|
|
74
|
+
if (!markdown) {
|
|
75
|
+
return markdown;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const codeBlockRegex = /```d2.*\n([\s\S]*?)```/g;
|
|
79
|
+
|
|
80
|
+
const { replaced } = await runIterator({
|
|
81
|
+
input: markdown,
|
|
82
|
+
regexp: codeBlockRegex,
|
|
83
|
+
replace: true,
|
|
84
|
+
fn: async ([_match, _code]) => {
|
|
85
|
+
const assetDir = path.join(docsDir, "../", TMP_ASSETS_DIR, "d2");
|
|
86
|
+
await fs.ensureDir(assetDir);
|
|
87
|
+
const d2Content = [D2_CONFIG, _code].join("\n");
|
|
88
|
+
const fileName = `${getContentHash(d2Content)}.svg`;
|
|
89
|
+
const svgPath = path.join(assetDir, fileName);
|
|
90
|
+
|
|
91
|
+
if (await fs.pathExists(svgPath)) {
|
|
92
|
+
debug("Found assets cache, skipping generation", svgPath);
|
|
93
|
+
} else {
|
|
94
|
+
try {
|
|
95
|
+
debug("start generate d2 chart", svgPath);
|
|
96
|
+
if (debug.enabled) {
|
|
97
|
+
const d2FileName = `${getContentHash(d2Content)}.d2`;
|
|
98
|
+
const d2Path = path.join(assetDir, d2FileName);
|
|
99
|
+
await fs.writeFile(d2Path, d2Content, { encoding: "utf8" });
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const svg = await getChart({ content: d2Content });
|
|
103
|
+
if (svg) {
|
|
104
|
+
await fs.writeFile(svgPath, svg, { encoding: "utf8" });
|
|
105
|
+
}
|
|
106
|
+
} catch (error) {
|
|
107
|
+
debug("Failed to generate D2 chart. Content:", d2Content, "Error:", error);
|
|
108
|
+
return _code;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return `})`;
|
|
112
|
+
},
|
|
113
|
+
options: { concurrency: D2_CONCURRENCY },
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
return replaced;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export async function beforePublishHook({ docsDir }) {
|
|
120
|
+
// Example: process each markdown file (replace with your logic)
|
|
121
|
+
const mdFilePaths = await glob("**/*.md", { cwd: docsDir });
|
|
122
|
+
await pMap(
|
|
123
|
+
mdFilePaths,
|
|
124
|
+
async (filePath) => {
|
|
125
|
+
let finalContent = await fs.readFile(path.join(docsDir, filePath), { encoding: "utf8" });
|
|
126
|
+
finalContent = await saveAssets({ markdown: finalContent, docsDir });
|
|
127
|
+
|
|
128
|
+
await fs.writeFile(path.join(docsDir, filePath), finalContent, { encoding: "utf8" });
|
|
129
|
+
},
|
|
130
|
+
{ concurrency: FILE_CONCURRENCY },
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function runIterator({ input, regexp, fn = () => {}, options, replace = false }) {
|
|
135
|
+
if (!input) return input;
|
|
136
|
+
const matches = [...input.matchAll(regexp)];
|
|
137
|
+
const results = [];
|
|
138
|
+
await pMap(
|
|
139
|
+
matches,
|
|
140
|
+
async (...args) => {
|
|
141
|
+
const resultItem = await fn(...args);
|
|
142
|
+
results.push(resultItem);
|
|
143
|
+
},
|
|
144
|
+
options,
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
let replaced = input;
|
|
148
|
+
if (replace) {
|
|
149
|
+
let index = 0;
|
|
150
|
+
replaced = replaced.replace(regexp, () => {
|
|
151
|
+
return results[index++];
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
results,
|
|
157
|
+
replaced,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export async function checkContent({ content }) {
|
|
162
|
+
await ensureTmpDir();
|
|
163
|
+
const assetDir = path.join(DOC_SMITH_DIR, TMP_DIR, TMP_ASSETS_DIR, "d2");
|
|
164
|
+
await fs.ensureDir(assetDir);
|
|
165
|
+
const d2Content = [D2_CONFIG, content].join("\n");
|
|
166
|
+
const fileName = `${getContentHash(d2Content)}.svg`;
|
|
167
|
+
const svgPath = path.join(assetDir, fileName);
|
|
168
|
+
|
|
169
|
+
if (debug.enabled) {
|
|
170
|
+
const d2FileName = `${getContentHash(d2Content)}.d2`;
|
|
171
|
+
const d2Path = path.join(assetDir, d2FileName);
|
|
172
|
+
await fs.writeFile(d2Path, d2Content, { encoding: "utf8" });
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (await fs.pathExists(svgPath)) {
|
|
176
|
+
debug("Found assets cache, skipping generation", svgPath);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const svg = await getChart({ content: d2Content, strict: true });
|
|
181
|
+
await fs.writeFile(svgPath, svg, { encoding: "utf8" });
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export async function ensureTmpDir() {
|
|
185
|
+
const tmpDir = path.join(DOC_SMITH_DIR, TMP_DIR);
|
|
186
|
+
if (!(await fs.pathExists(path.join(tmpDir, ".gitignore")))) {
|
|
187
|
+
await fs.ensureDir(tmpDir);
|
|
188
|
+
await fs.writeFile(path.join(tmpDir, ".gitignore"), "**/*", { encoding: "utf8" });
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export function isValidCode(lang) {
|
|
193
|
+
return lang?.toLowerCase() === "d2";
|
|
194
|
+
}
|
package/utils/deploy.mjs
CHANGED
|
@@ -116,8 +116,8 @@ export async function deploy(id, cachedUrl) {
|
|
|
116
116
|
console.log(`${chalk.blue("⏳")} Step 1/4: Waiting for payment...`);
|
|
117
117
|
console.log(`${chalk.blue("🔗")} Payment link: ${chalk.cyan(paymentUrl)}\n`);
|
|
118
118
|
await pollPaymentStatus(checkoutId);
|
|
119
|
-
saveValueToConfig("checkoutId", checkoutId, "Checkout ID for document deployment service");
|
|
120
|
-
saveValueToConfig("paymentUrl", paymentUrl, "Payment URL for document deployment service");
|
|
119
|
+
await saveValueToConfig("checkoutId", checkoutId, "Checkout ID for document deployment service");
|
|
120
|
+
await saveValueToConfig("paymentUrl", paymentUrl, "Payment URL for document deployment service");
|
|
121
121
|
|
|
122
122
|
// Step 3: Wait for service installation
|
|
123
123
|
console.log(`${chalk.blue("📦")} Step 2/4: Installing service...`);
|
|
@@ -174,7 +174,7 @@ async function checkCacheCheckoutId(checkoutId) {
|
|
|
174
174
|
|
|
175
175
|
return isPaid ? checkoutId : "";
|
|
176
176
|
} catch (_error) {
|
|
177
|
-
saveValueToConfig("checkoutId", "", "Checkout ID for document deployment service");
|
|
177
|
+
await saveValueToConfig("checkoutId", "", "Checkout ID for document deployment service");
|
|
178
178
|
return "";
|
|
179
179
|
}
|
|
180
180
|
}
|
|
@@ -24,8 +24,8 @@ function generateFileName(flatName, locale) {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
* Find a single item by path in structure
|
|
28
|
-
* @param {Array}
|
|
27
|
+
* Find a single item by path in document structure result and read its content
|
|
28
|
+
* @param {Array} documentExecutionStructure - Array of document structure items
|
|
29
29
|
* @param {string} docPath - Document path to find (supports .md filenames)
|
|
30
30
|
* @param {string} boardId - Board ID for fallback matching
|
|
31
31
|
* @param {string} docsDir - Docs directory path for reading content
|
|
@@ -33,7 +33,7 @@ function generateFileName(flatName, locale) {
|
|
|
33
33
|
* @returns {Promise<Object|null>} Found item with content or null
|
|
34
34
|
*/
|
|
35
35
|
export async function findItemByPath(
|
|
36
|
-
|
|
36
|
+
documentExecutionStructure,
|
|
37
37
|
docPath,
|
|
38
38
|
boardId,
|
|
39
39
|
docsDir,
|
|
@@ -46,10 +46,10 @@ export async function findItemByPath(
|
|
|
46
46
|
if (docPath.endsWith(".md")) {
|
|
47
47
|
fileName = docPath;
|
|
48
48
|
const flatName = fileNameToFlatPath(docPath);
|
|
49
|
-
foundItem = findItemByFlatName(
|
|
49
|
+
foundItem = findItemByFlatName(documentExecutionStructure, flatName);
|
|
50
50
|
} else {
|
|
51
51
|
// First try direct path matching
|
|
52
|
-
foundItem =
|
|
52
|
+
foundItem = documentExecutionStructure.find((item) => item.path === docPath);
|
|
53
53
|
|
|
54
54
|
// If not found and boardId is provided, try boardId-flattenedPath format matching
|
|
55
55
|
if (!foundItem && boardId) {
|
|
@@ -59,7 +59,7 @@ export async function findItemByPath(
|
|
|
59
59
|
const flattenedPath = docPath.substring(boardId.length + 1);
|
|
60
60
|
|
|
61
61
|
// Find item by comparing flattened paths
|
|
62
|
-
foundItem =
|
|
62
|
+
foundItem = documentExecutionStructure.find((item) => {
|
|
63
63
|
// Convert item.path to flattened format (replace / with -)
|
|
64
64
|
const itemFlattenedPath = item.path.replace(/^\//, "").replace(/\//g, "-");
|
|
65
65
|
return itemFlattenedPath === flattenedPath;
|
|
@@ -116,10 +116,10 @@ export async function readFileContent(docsDir, fileName) {
|
|
|
116
116
|
* Get main language markdown files from docs directory
|
|
117
117
|
* @param {string} docsDir - Docs directory path
|
|
118
118
|
* @param {string} locale - Main language locale (e.g., 'en', 'zh', 'fr')
|
|
119
|
-
* @param {Array}
|
|
120
|
-
* @returns {Promise<string[]>} Array of main language .md files ordered by
|
|
119
|
+
* @param {Array} documentExecutionStructure - Array of document structure items to determine file order
|
|
120
|
+
* @returns {Promise<string[]>} Array of main language .md files ordered by documentExecutionStructure
|
|
121
121
|
*/
|
|
122
|
-
export async function getMainLanguageFiles(docsDir, locale,
|
|
122
|
+
export async function getMainLanguageFiles(docsDir, locale, documentExecutionStructure = null) {
|
|
123
123
|
const files = await readdir(docsDir);
|
|
124
124
|
|
|
125
125
|
// Filter for main language .md files (exclude _sidebar.md)
|
|
@@ -140,36 +140,36 @@ export async function getMainLanguageFiles(docsDir, locale, structurePlanResult
|
|
|
140
140
|
}
|
|
141
141
|
});
|
|
142
142
|
|
|
143
|
-
// If
|
|
144
|
-
if (
|
|
145
|
-
// Create a map from flat file name to structure
|
|
143
|
+
// If documentExecutionStructure is provided, sort files according to the order in documentExecutionStructure
|
|
144
|
+
if (documentExecutionStructure && Array.isArray(documentExecutionStructure)) {
|
|
145
|
+
// Create a map from flat file name to document structure order
|
|
146
146
|
const orderMap = new Map();
|
|
147
|
-
|
|
147
|
+
documentExecutionStructure.forEach((item, index) => {
|
|
148
148
|
const itemFlattenedPath = item.path.replace(/^\//, "").replace(/\//g, "-");
|
|
149
149
|
const expectedFileName = generateFileName(itemFlattenedPath, locale);
|
|
150
150
|
orderMap.set(expectedFileName, index);
|
|
151
151
|
});
|
|
152
152
|
|
|
153
|
-
// Sort filtered files based on their order in
|
|
153
|
+
// Sort filtered files based on their order in documentExecutionStructure
|
|
154
154
|
return filteredFiles.sort((a, b) => {
|
|
155
155
|
const orderA = orderMap.get(a);
|
|
156
156
|
const orderB = orderMap.get(b);
|
|
157
157
|
|
|
158
|
-
// If both files are in the structure
|
|
158
|
+
// If both files are in the document structure, sort by order
|
|
159
159
|
if (orderA !== undefined && orderB !== undefined) {
|
|
160
160
|
return orderA - orderB;
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
// If only one file is in the structure
|
|
163
|
+
// If only one file is in the document structure, it comes first
|
|
164
164
|
if (orderA !== undefined) return -1;
|
|
165
165
|
if (orderB !== undefined) return 1;
|
|
166
166
|
|
|
167
|
-
// If neither file is in the structure
|
|
167
|
+
// If neither file is in the document structure, maintain alphabetical order
|
|
168
168
|
return a.localeCompare(b);
|
|
169
169
|
});
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
// If no
|
|
172
|
+
// If no documentExecutionStructure provided, return files in alphabetical order
|
|
173
173
|
return filteredFiles.sort();
|
|
174
174
|
}
|
|
175
175
|
|
|
@@ -189,13 +189,13 @@ export function fileNameToFlatPath(fileName) {
|
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
/**
|
|
192
|
-
* Find structure
|
|
193
|
-
* @param {Array}
|
|
192
|
+
* Find document structure item by flattened file name
|
|
193
|
+
* @param {Array} documentExecutionStructure - Array of document structure items
|
|
194
194
|
* @param {string} flatName - Flattened file name
|
|
195
195
|
* @returns {Object|null} Found item or null
|
|
196
196
|
*/
|
|
197
|
-
export function findItemByFlatName(
|
|
198
|
-
return
|
|
197
|
+
export function findItemByFlatName(documentExecutionStructure, flatName) {
|
|
198
|
+
return documentExecutionStructure.find((item) => {
|
|
199
199
|
const itemFlattenedPath = item.path.replace(/^\//, "").replace(/\//g, "-");
|
|
200
200
|
return itemFlattenedPath === flatName;
|
|
201
201
|
});
|
|
@@ -204,11 +204,11 @@ export function findItemByFlatName(structurePlanResult, flatName) {
|
|
|
204
204
|
/**
|
|
205
205
|
* Process selected files and convert to found items with content
|
|
206
206
|
* @param {string[]} selectedFiles - Array of selected file names
|
|
207
|
-
* @param {Array}
|
|
207
|
+
* @param {Array} documentExecutionStructure - Array of document structure items
|
|
208
208
|
* @param {string} docsDir - Docs directory path
|
|
209
209
|
* @returns {Promise<Object[]>} Array of found items with content
|
|
210
210
|
*/
|
|
211
|
-
export async function processSelectedFiles(selectedFiles,
|
|
211
|
+
export async function processSelectedFiles(selectedFiles, documentExecutionStructure, docsDir) {
|
|
212
212
|
const foundItems = [];
|
|
213
213
|
|
|
214
214
|
for (const selectedFile of selectedFiles) {
|
|
@@ -219,7 +219,7 @@ export async function processSelectedFiles(selectedFiles, structurePlanResult, d
|
|
|
219
219
|
const flatName = fileNameToFlatPath(selectedFile);
|
|
220
220
|
|
|
221
221
|
// Try to find matching item by comparing flattened paths
|
|
222
|
-
const foundItemByFile = findItemByFlatName(
|
|
222
|
+
const foundItemByFile = findItemByFlatName(documentExecutionStructure, flatName);
|
|
223
223
|
|
|
224
224
|
if (foundItemByFile) {
|
|
225
225
|
const result = {
|
|
@@ -233,7 +233,7 @@ export async function processSelectedFiles(selectedFiles, structurePlanResult, d
|
|
|
233
233
|
|
|
234
234
|
foundItems.push(result);
|
|
235
235
|
} else {
|
|
236
|
-
console.warn(`⚠️ No structure
|
|
236
|
+
console.warn(`⚠️ No document structure item found for file: ${selectedFile}`);
|
|
237
237
|
}
|
|
238
238
|
}
|
|
239
239
|
|