@aigne/doc-smith 0.7.1 → 0.8.0
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/.github/workflows/ci.yml +9 -1
- package/CHANGELOG.md +15 -0
- package/README.md +5 -0
- package/agents/check-detail-result.mjs +7 -0
- package/agents/check-detail.mjs +3 -1
- package/agents/detail-regenerator.yaml +3 -0
- package/agents/find-items-by-paths.mjs +9 -1
- package/agents/input-generator.mjs +3 -3
- package/agents/load-sources.mjs +2 -1
- package/agents/save-docs.mjs +1 -5
- package/codecov.yml +15 -0
- package/package.json +1 -1
- package/prompts/content-detail-generator.md +1 -0
- package/prompts/document/custom-components.md +36 -12
- package/tests/check-detail-result.test.mjs +656 -17
- package/tests/conflict-resolution.test.mjs +118 -0
- package/tests/input-generator.test.mjs +594 -1
- package/tests/kroki-utils.test.mjs +588 -0
- package/tests/load-sources.test.mjs +362 -2
- package/tests/mermaid-validation.test.mjs +541 -0
- package/tests/save-docs.test.mjs +1 -1
- package/tests/utils.test.mjs +2020 -2
- package/utils/conflict-detector.mjs +0 -59
- package/utils/file-utils.mjs +5 -0
- package/utils/kroki-utils.mjs +4 -0
- package/utils/markdown-checker.mjs +3 -3
- package/utils/mermaid-validator.mjs +0 -13
- package/utils/utils.mjs +11 -5
- package/tests/all-validation-cases.test.mjs +0 -686
|
@@ -1,40 +1,5 @@
|
|
|
1
1
|
import { CONFLICT_RESOLUTION_RULES, CONFLICT_RULES, RESOLUTION_STRATEGIES } from "./constants.mjs";
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Detect internal conflicts within the same question (multi-select conflicts)
|
|
5
|
-
* @param {string} questionType - Question type (documentPurpose, targetAudienceTypes)
|
|
6
|
-
* @param {Array} selectedValues - User selected values
|
|
7
|
-
* @returns {Array} List of conflicts
|
|
8
|
-
*/
|
|
9
|
-
export function detectInternalConflicts(questionType, selectedValues) {
|
|
10
|
-
const rules = CONFLICT_RULES.internalConflicts[questionType] || [];
|
|
11
|
-
|
|
12
|
-
// Extract values from the selected items (handle both string arrays and object arrays)
|
|
13
|
-
const selectedValueStrings = selectedValues.map((item) =>
|
|
14
|
-
typeof item === "object" && item.value ? item.value : item,
|
|
15
|
-
);
|
|
16
|
-
|
|
17
|
-
const conflicts = [];
|
|
18
|
-
|
|
19
|
-
rules.forEach((rule) => {
|
|
20
|
-
// Check if all conflict items are selected
|
|
21
|
-
const hasConflict = rule.conflictItems.every((item) => selectedValueStrings.includes(item));
|
|
22
|
-
|
|
23
|
-
if (hasConflict) {
|
|
24
|
-
conflicts.push({
|
|
25
|
-
type: "internal",
|
|
26
|
-
questionType,
|
|
27
|
-
severity: rule.severity,
|
|
28
|
-
reason: rule.reason,
|
|
29
|
-
suggestion: rule.suggestion,
|
|
30
|
-
items: rule.conflictItems,
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
return conflicts;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
3
|
/**
|
|
39
4
|
* Get filtered options based on cross-question conflict rules
|
|
40
5
|
* @param {string} targetQuestion - Target question type to filter
|
|
@@ -106,30 +71,6 @@ export function getFilteredOptions(targetQuestion, currentSelections, allOptions
|
|
|
106
71
|
};
|
|
107
72
|
}
|
|
108
73
|
|
|
109
|
-
/**
|
|
110
|
-
* Validate user selection for internal conflicts and return validation message
|
|
111
|
-
* @param {string} questionType - Question type (documentPurpose, targetAudienceTypes)
|
|
112
|
-
* @param {Array} selectedValues - User selected values
|
|
113
|
-
* @returns {string|boolean} Error message if conflicts exist, true if valid
|
|
114
|
-
*/
|
|
115
|
-
export function validateSelection(questionType, selectedValues) {
|
|
116
|
-
const conflicts = detectInternalConflicts(questionType, selectedValues);
|
|
117
|
-
|
|
118
|
-
if (conflicts.length === 0) {
|
|
119
|
-
return true;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Return error message for severe conflicts
|
|
123
|
-
const severeConflicts = conflicts.filter((c) => c.severity === "severe");
|
|
124
|
-
if (severeConflicts.length > 0) {
|
|
125
|
-
const conflict = severeConflicts[0];
|
|
126
|
-
return `Conflict detected: ${conflict.reason}. ${conflict.suggestion}`;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// For moderate conflicts, allow but warn
|
|
130
|
-
return true;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
74
|
/**
|
|
134
75
|
* Detect conflicts in user configuration selections that can be resolved through structure planning
|
|
135
76
|
* @param {Object} config - User configuration
|
package/utils/file-utils.mjs
CHANGED
|
@@ -159,6 +159,11 @@ export async function loadGitignore(dir) {
|
|
|
159
159
|
* @returns {Promise<string[]>} Array of file paths
|
|
160
160
|
*/
|
|
161
161
|
export async function getFilesWithGlob(dir, includePatterns, excludePatterns, gitignorePatterns) {
|
|
162
|
+
if (!includePatterns || includePatterns.length === 0) {
|
|
163
|
+
console.warn("No include patterns provided");
|
|
164
|
+
return [];
|
|
165
|
+
}
|
|
166
|
+
|
|
162
167
|
// Prepare all ignore patterns
|
|
163
168
|
const allIgnorePatterns = [];
|
|
164
169
|
|
package/utils/kroki-utils.mjs
CHANGED
|
@@ -52,6 +52,10 @@ export async function getD2Svg({ content, strict = false }) {
|
|
|
52
52
|
|
|
53
53
|
// Helper: save d2 svg assets alongside document
|
|
54
54
|
export async function saveD2Assets({ markdown, docsDir }) {
|
|
55
|
+
if (!markdown) {
|
|
56
|
+
return markdown;
|
|
57
|
+
}
|
|
58
|
+
|
|
55
59
|
const codeBlockRegex = /```d2\n([\s\S]*?)```/g;
|
|
56
60
|
|
|
57
61
|
const { replaced } = await runIterator({
|
|
@@ -88,7 +88,7 @@ function checkDeadLinks(markdown, source, allowedLinks, errorMessages) {
|
|
|
88
88
|
if (!path) continue;
|
|
89
89
|
|
|
90
90
|
// Check if this link is in the allowed links set
|
|
91
|
-
if (!allowedLinks.has(
|
|
91
|
+
if (!allowedLinks.has(path)) {
|
|
92
92
|
errorMessages.push(
|
|
93
93
|
`Found a dead link in ${source}: [${match[1]}](${trimLink}), ensure the link exists in the structure plan path`,
|
|
94
94
|
);
|
|
@@ -243,7 +243,7 @@ function checkLocalImages(markdown, source, errorMessages, markdownFilePath, bas
|
|
|
243
243
|
*/
|
|
244
244
|
function checkContentStructure(markdown, source, errorMessages) {
|
|
245
245
|
const lines = markdown.split("\n");
|
|
246
|
-
const allCodeBlockRegex = /^\s*```(
|
|
246
|
+
const allCodeBlockRegex = /^\s*```(?:[a-zA-Z0-9_,\-+.#/:=]+)?$/;
|
|
247
247
|
|
|
248
248
|
// State variables for different checks
|
|
249
249
|
let inCodeBlock = false;
|
|
@@ -300,7 +300,7 @@ function checkContentStructure(markdown, source, errorMessages) {
|
|
|
300
300
|
}
|
|
301
301
|
|
|
302
302
|
// Check if content ends with proper punctuation (indicating completeness)
|
|
303
|
-
const validEndingPunctuation = [".", "。", ")", "|", "*"];
|
|
303
|
+
const validEndingPunctuation = [".", "。", ")", "|", "*", ">", "`"];
|
|
304
304
|
const trimmedText = markdown.trim();
|
|
305
305
|
const hasValidEnding = validEndingPunctuation.some((punct) => trimmedText.endsWith(punct));
|
|
306
306
|
|
|
@@ -5,19 +5,6 @@
|
|
|
5
5
|
|
|
6
6
|
import { getMermaidWorkerPool, shutdownMermaidWorkerPool } from "./mermaid-worker-pool.mjs";
|
|
7
7
|
|
|
8
|
-
/**
|
|
9
|
-
* Worker-based mermaid validation - DEPRECATED but kept for compatibility
|
|
10
|
-
* This function now delegates to the worker pool implementation
|
|
11
|
-
* @param {string} content - Mermaid diagram content
|
|
12
|
-
* @returns {boolean} - True if syntax is valid
|
|
13
|
-
* @throws {Error} - If syntax is invalid
|
|
14
|
-
* @deprecated Use validateMermaidSyntax instead which uses worker pool
|
|
15
|
-
*/
|
|
16
|
-
export async function validateMermaidWithOfficialParser(content) {
|
|
17
|
-
// Delegate to the new worker-based implementation
|
|
18
|
-
return await validateMermaidSyntax(content);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
8
|
/**
|
|
22
9
|
* Basic mermaid syntax validation fallback
|
|
23
10
|
* Used when worker validation fails due to environment issues
|
package/utils/utils.mjs
CHANGED
|
@@ -674,13 +674,15 @@ export function getAvailablePaths(userInput = "") {
|
|
|
674
674
|
addExactPathMatch(searchTerm, results);
|
|
675
675
|
}
|
|
676
676
|
|
|
677
|
-
// Remove duplicates based on
|
|
677
|
+
// Remove duplicates based on absolute path (real deduplication)
|
|
678
678
|
const uniqueResults = [];
|
|
679
|
-
const
|
|
679
|
+
const seenAbsolutePaths = new Set();
|
|
680
680
|
|
|
681
681
|
for (const item of results) {
|
|
682
|
-
|
|
683
|
-
|
|
682
|
+
// Normalize to absolute path for proper deduplication
|
|
683
|
+
const absolutePath = normalizePath(item.value);
|
|
684
|
+
if (!seenAbsolutePaths.has(absolutePath)) {
|
|
685
|
+
seenAbsolutePaths.add(absolutePath);
|
|
684
686
|
uniqueResults.push(item);
|
|
685
687
|
}
|
|
686
688
|
}
|
|
@@ -809,7 +811,11 @@ export async function getGitHubRepoInfo(repoUrl) {
|
|
|
809
811
|
const apiUrl = `https://api.github.com/repos/${owner}/${repo}`;
|
|
810
812
|
|
|
811
813
|
const response = await fetch(apiUrl);
|
|
812
|
-
|
|
814
|
+
|
|
815
|
+
if (!response.ok) {
|
|
816
|
+
console.warn("Failed to fetch GitHub repository info:", repoUrl, response.statusText);
|
|
817
|
+
return null;
|
|
818
|
+
}
|
|
813
819
|
|
|
814
820
|
const data = await response.json();
|
|
815
821
|
return {
|