@aigne/doc-smith 0.2.6 → 0.2.8

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.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { checkMarkdown } from "../utils/markdown-checker.mjs";
4
3
  import checkDetailResult from "../agents/check-detail-result.mjs";
4
+ import { checkMarkdown } from "../utils/markdown-checker.mjs";
5
5
  import { shutdownValidation } from "../utils/mermaid-validator.mjs";
6
6
 
7
7
  // Mock structure plan for link validation
@@ -164,25 +164,6 @@ This content ends properly.
164
164
  },
165
165
 
166
166
  // ========== CODE BLOCK VALIDATION CASES ==========
167
- {
168
- category: "💻 CODE BLOCK VALIDATION",
169
- name: "Inconsistent code block indentation",
170
- expectPass: false,
171
- expectedErrors: ["code block with inconsistent indentation"],
172
- content: `# Test Document
173
-
174
- Here's incorrectly indented code:
175
-
176
- \`\`\`javascript
177
- function test() {
178
- return "content not properly indented";
179
- }
180
- \`\`\`
181
-
182
- This content ends properly.
183
- `,
184
- },
185
-
186
167
  {
187
168
  category: "💻 CODE BLOCK VALIDATION",
188
169
  name: "Incomplete code block",
@@ -216,6 +197,68 @@ This content ends properly.
216
197
  `,
217
198
  },
218
199
 
200
+ {
201
+ category: "💻 CODE BLOCK VALIDATION",
202
+ name: "Code block with inconsistent indentation (user case)",
203
+ expectPass: false,
204
+ expectedErrors: ["code block with inconsistent indentation"],
205
+ content: `# API Response Handling
206
+
207
+ You can retrieve the response body in various formats:
208
+
209
+ * **\`response.content\`**: Accesses the raw response body as bytes. This is useful for non-text data like images or binary files.
210
+ \`\`\`python
211
+ import requests
212
+
213
+ r = requests.get('https://httpbin.org/image/png')
214
+ print(type(r.content))
215
+ # Expected output: <class 'bytes'>
216
+ \`\`\`
217
+
218
+ * **\`response.text\`**: Accesses the response body as Unicode text. Requests automatically guesses the encoding, or you can explicitly set \`response.encoding\`.
219
+ \`\`\`python
220
+ import requests
221
+
222
+ r = requests.get('https://httpbin.org/get')
223
+ print(type(r.text))
224
+ # Expected output: <class 'str'>
225
+ print(r.text)
226
+ # Expected output: {"args": {}, "headers": ..., "origin": "...", "url": "https://httpbin.org/get"}
227
+ \`\`\`
228
+
229
+ * **\`response.json(**kwargs)\`**: Decodes the response body as JSON into a Python object (dictionary, list, etc.). This method raises \`requests.exceptions.JSONDecodeError\` if the content is not valid JSON.
230
+ \`\`\`python
231
+ import requests
232
+
233
+ r = requests.get('https://httpbin.org/json')
234
+ print(type(r.json()))
235
+ # Expected output: <class 'dict'>
236
+ print(r.json())
237
+ # Expected output: {'slideshow': {'author': 'Yours Truly', 'date': 'date of publication', 'slides': [...], 'title': 'Sample Slide Show'}}
238
+ \`\`\`
239
+
240
+ **Status and Error Handling**
241
+
242
+ * **\`response.ok\`**: A boolean property that returns \`True\` if \`status_code\` is less than 400, indicating no client or server error. It does *not* necessarily mean \`200 OK\`.
243
+
244
+ * **\`response.raise_for_status()\`**: Raises an \`HTTPError\` if the HTTP request returned an unsuccessful status code (4xx or 5xx). This is a convenient way to check for errors and is typically used after a request to ensure it was successful.
245
+
246
+ \`\`\`python
247
+ import requests
248
+ from requests.exceptions import HTTPError
249
+
250
+ try:
251
+ r = requests.get('https://httpbin.org/status/404')
252
+ r.raise_for_status() # This will raise an HTTPError for 404
253
+ except HTTPError as e:
254
+ print(f"HTTP Error occurred: {e}")
255
+ # Expected output: HTTP Error occurred: 404 Client Error: NOT FOUND for url: https://httpbin.org/status/404
256
+ \`\`\`
257
+
258
+ This document ends properly.
259
+ `,
260
+ },
261
+
219
262
  // ========== CONTENT STRUCTURE CASES ==========
220
263
  {
221
264
  category: "📝 CONTENT STRUCTURE",
@@ -598,11 +641,8 @@ async function runValidationTests() {
598
641
 
599
642
  // Check if expected error types are present
600
643
  if (testCase.expectedErrors) {
601
- const foundExpectedErrors = testCase.expectedErrors.every(
602
- (expectedError) =>
603
- errors.some((error) =>
604
- error.toLowerCase().includes(expectedError.toLowerCase())
605
- )
644
+ const foundExpectedErrors = testCase.expectedErrors.every((expectedError) =>
645
+ errors.some((error) => error.toLowerCase().includes(expectedError.toLowerCase())),
606
646
  );
607
647
 
608
648
  if (foundExpectedErrors) {
@@ -618,7 +658,7 @@ async function runValidationTests() {
618
658
  console.log(
619
659
  `❌ FAIL - Expected ${expectPass ? "PASS" : "FAIL"} but got ${
620
660
  hasErrors ? "FAIL" : "PASS"
621
- }`
661
+ }`,
622
662
  );
623
663
  failedTests++;
624
664
  }
@@ -643,7 +683,7 @@ async function runValidationTests() {
643
683
  console.log("✅ Direct call and wrapper consistent");
644
684
  } else {
645
685
  console.log(
646
- `⚠️ Inconsistent results: direct=${errors.length}, wrapper=${wrapperErrors.length}`
686
+ `⚠️ Inconsistent results: direct=${errors.length}, wrapper=${wrapperErrors.length}`,
647
687
  );
648
688
  }
649
689
  } catch (error) {
@@ -653,15 +693,13 @@ async function runValidationTests() {
653
693
  }
654
694
 
655
695
  // Final summary
656
- console.log("\n" + "=".repeat(80));
696
+ console.log(`\n${"=".repeat(80)}`);
657
697
  console.log("📊 TEST SUMMARY");
658
698
  console.log("=".repeat(80));
659
699
  console.log(`Total Tests: ${totalTests}`);
660
700
  console.log(`Passed: ${passedTests} ✅`);
661
701
  console.log(`Failed: ${failedTests} ❌`);
662
- console.log(
663
- `Success Rate: ${((passedTests / totalTests) * 100).toFixed(1)}%`
664
- );
702
+ console.log(`Success Rate: ${((passedTests / totalTests) * 100).toFixed(1)}%`);
665
703
 
666
704
  console.log("\n🔍 VALIDATION COVERAGE:");
667
705
  console.log("✅ Link validation (dead links, allowed links)");
@@ -674,13 +712,9 @@ async function runValidationTests() {
674
712
  console.log("✅ Edge cases and error conditions");
675
713
 
676
714
  if (failedTests === 0) {
677
- console.log(
678
- "\n🎉 ALL TESTS PASSED! Validation system is working correctly."
679
- );
715
+ console.log("\n🎉 ALL TESTS PASSED! Validation system is working correctly.");
680
716
  } else {
681
- console.log(
682
- `\n⚠️ ${failedTests} test(s) failed. Please review the validation logic.`
683
- );
717
+ console.log(`\n⚠️ ${failedTests} test(s) failed. Please review the validation logic.`);
684
718
  }
685
719
 
686
720
  // Shutdown worker pool to ensure clean exit
@@ -1,7 +1,6 @@
1
- import { writeFile, mkdir, readdir } from "node:fs/promises";
2
- import { join } from "node:path";
1
+ import { mkdir, readdir, writeFile } from "node:fs/promises";
2
+ import { dirname, join } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
- import { dirname } from "node:path";
5
4
  import saveDocs from "../agents/save-docs.mjs";
6
5
 
7
6
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -81,12 +80,8 @@ async function testSaveDocs() {
81
80
  "_sidebar.md",
82
81
  ];
83
82
 
84
- const missingFiles = expectedFiles.filter(
85
- (file) => !remainingFiles.includes(file)
86
- );
87
- const extraFiles = remainingFiles.filter(
88
- (file) => !expectedFiles.includes(file)
89
- );
83
+ const missingFiles = expectedFiles.filter((file) => !remainingFiles.includes(file));
84
+ const extraFiles = remainingFiles.filter((file) => !expectedFiles.includes(file));
90
85
 
91
86
  if (missingFiles.length === 0 && extraFiles.length === 0) {
92
87
  console.log("\n✅ Test passed! All files are as expected.");
@@ -101,14 +96,8 @@ async function testSaveDocs() {
101
96
  }
102
97
 
103
98
  // Verify that invalid files were deleted
104
- const deletedFiles = [
105
- "old-file.md",
106
- "another-old-file.md",
107
- "old-translation.zh.md",
108
- ];
109
- const stillExist = deletedFiles.filter((file) =>
110
- remainingFiles.includes(file)
111
- );
99
+ const deletedFiles = ["old-file.md", "another-old-file.md", "old-translation.zh.md"];
100
+ const stillExist = deletedFiles.filter((file) => remainingFiles.includes(file));
112
101
 
113
102
  if (stillExist.length === 0) {
114
103
  console.log("✅ All invalid files were successfully deleted.");
@@ -99,8 +99,7 @@ export const DOCUMENT_STYLES = {
99
99
  // Predefined target audiences
100
100
  export const TARGET_AUDIENCES = {
101
101
  actionFirst: "Developers, Implementation Engineers, DevOps",
102
- conceptFirst:
103
- "Architects, Technical Leads, Developers interested in principles",
102
+ conceptFirst: "Architects, Technical Leads, Developers interested in principles",
104
103
  generalUsers: "General Users",
105
104
  custom: "Enter your own target audience",
106
105
  };
@@ -1,9 +1,9 @@
1
- import { unified } from "unified";
2
- import remarkParse from "remark-parse";
3
1
  import remarkGfm from "remark-gfm";
4
2
  import remarkLint from "remark-lint";
5
- import { VFile } from "vfile";
3
+ import remarkParse from "remark-parse";
4
+ import { unified } from "unified";
6
5
  import { visit } from "unist-util-visit";
6
+ import { VFile } from "vfile";
7
7
  import { validateMermaidSyntax } from "./mermaid-validator.mjs";
8
8
 
9
9
  /**
@@ -16,10 +16,7 @@ function countTableColumns(line) {
16
16
  const trimmed = line.trim();
17
17
 
18
18
  // Remove leading and trailing pipes if present
19
- const content =
20
- trimmed.startsWith("|") && trimmed.endsWith("|")
21
- ? trimmed.slice(1, -1)
22
- : trimmed;
19
+ const content = trimmed.startsWith("|") && trimmed.endsWith("|") ? trimmed.slice(1, -1) : trimmed;
23
20
 
24
21
  if (!content.trim()) {
25
22
  return 0;
@@ -65,7 +62,7 @@ function countTableColumns(line) {
65
62
  * @param {Array} errorMessages - Array to push error messages to
66
63
  */
67
64
  function checkDeadLinks(markdown, source, allowedLinks, errorMessages) {
68
- const linkRegex = /(?<!\!)\[([^\]]+)\]\(([^)]+)\)/g;
65
+ const linkRegex = /(?<!!)\[([^\]]+)\]\(([^)]+)\)/g;
69
66
  let match;
70
67
 
71
68
  while ((match = linkRegex.exec(markdown)) !== null) {
@@ -77,7 +74,7 @@ function checkDeadLinks(markdown, source, allowedLinks, errorMessages) {
77
74
  if (/^(https?:\/\/|mailto:)/.test(trimLink)) continue;
78
75
 
79
76
  // Preserve anchors
80
- const [path, hash] = trimLink.split("#");
77
+ const [path, _hash] = trimLink.split("#");
81
78
 
82
79
  // Only process relative paths or paths starting with /
83
80
  if (!path) continue;
@@ -85,7 +82,89 @@ function checkDeadLinks(markdown, source, allowedLinks, errorMessages) {
85
82
  // Check if this link is in the allowed links set
86
83
  if (!allowedLinks.has(trimLink)) {
87
84
  errorMessages.push(
88
- `Found a dead link in ${source}: [${match[1]}](${trimLink}), ensure the link exists in the structure plan path`
85
+ `Found a dead link in ${source}: [${match[1]}](${trimLink}), ensure the link exists in the structure plan path`,
86
+ );
87
+ }
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Check code block content for indentation consistency issues
93
+ * @param {Array} codeBlockContent - Array of {line, lineNumber} objects from the code block
94
+ * @param {string} source - Source description for error reporting
95
+ * @param {Array} errorMessages - Array to push error messages to
96
+ */
97
+ function checkCodeBlockIndentation(codeBlockContent, source, errorMessages) {
98
+ if (codeBlockContent.length === 0) return;
99
+
100
+ // Filter out empty lines for base indentation calculation
101
+ const nonEmptyLines = codeBlockContent.filter((item) => item.line.trim().length > 0);
102
+ if (nonEmptyLines.length === 0) return;
103
+
104
+ // Find the base indentation from the first meaningful line
105
+ let baseCodeIndent = null;
106
+ const problematicLines = [];
107
+
108
+ for (const item of nonEmptyLines) {
109
+ const { line, lineNumber } = item;
110
+ const match = line.match(/^(\s*)/);
111
+ const currentIndent = match ? match[1].length : 0;
112
+ const trimmedLine = line.trim();
113
+
114
+ // Skip lines that are clearly comments (common pattern: # comment)
115
+ if (trimmedLine.startsWith("#") && !trimmedLine.includes("=") && !trimmedLine.includes("{")) {
116
+ continue;
117
+ }
118
+
119
+ // Establish base indentation from the first meaningful line
120
+ if (baseCodeIndent === null) {
121
+ baseCodeIndent = currentIndent;
122
+ continue;
123
+ }
124
+
125
+ // Check if current line has less indentation than the base
126
+ // This indicates inconsistent indentation that may cause rendering issues
127
+ if (currentIndent < baseCodeIndent && baseCodeIndent > 0) {
128
+ problematicLines.push({
129
+ lineNumber,
130
+ line: line.trimEnd(),
131
+ currentIndent,
132
+ baseIndent: baseCodeIndent,
133
+ });
134
+ }
135
+ }
136
+
137
+ // Report indentation issues if found
138
+ if (problematicLines.length > 0) {
139
+ // Group consecutive issues to avoid spam
140
+ const groupedIssues = [];
141
+ let currentGroup = [problematicLines[0]];
142
+
143
+ for (let i = 1; i < problematicLines.length; i++) {
144
+ const current = problematicLines[i];
145
+ const previous = problematicLines[i - 1];
146
+
147
+ if (current.lineNumber - previous.lineNumber <= 2) {
148
+ currentGroup.push(current);
149
+ } else {
150
+ groupedIssues.push(currentGroup);
151
+ currentGroup = [current];
152
+ }
153
+ }
154
+ groupedIssues.push(currentGroup);
155
+
156
+ // Report the most significant groups
157
+ for (const group of groupedIssues.slice(0, 2)) {
158
+ // Limit to avoid spam
159
+ const firstIssue = group[0];
160
+ const lineNumbers =
161
+ group.length > 1
162
+ ? `lines ${group[0].lineNumber}-${group[group.length - 1].lineNumber}`
163
+ : `line ${firstIssue.lineNumber}`;
164
+
165
+ const issue = `inconsistent indentation: ${firstIssue.currentIndent} spaces (base: ${firstIssue.baseIndent} spaces)`;
166
+ errorMessages.push(
167
+ `Found code block with inconsistent indentation in ${source} at ${lineNumbers}: ${issue}. This may cause rendering issues`,
89
168
  );
90
169
  }
91
170
  }
@@ -103,10 +182,9 @@ function checkContentStructure(markdown, source, errorMessages) {
103
182
 
104
183
  // State variables for different checks
105
184
  let inCodeBlock = false;
106
- let codeBlockIndentLevel = 0;
107
- let codeBlockStartLine = 0;
108
185
  let inAnyCodeBlock = false;
109
186
  let anyCodeBlockStartLine = 0;
187
+ let codeBlockContent = [];
110
188
 
111
189
  for (let i = 0; i < lines.length; i++) {
112
190
  const line = lines[i];
@@ -118,17 +196,28 @@ function checkContentStructure(markdown, source, errorMessages) {
118
196
  // Starting a new code block
119
197
  inAnyCodeBlock = true;
120
198
  anyCodeBlockStartLine = lineNumber;
199
+ inCodeBlock = true;
200
+ codeBlockContent = [];
121
201
  } else {
122
202
  // Ending the code block
123
203
  inAnyCodeBlock = false;
204
+
205
+ if (inCodeBlock) {
206
+ // Check code block content for indentation issues
207
+ checkCodeBlockIndentation(codeBlockContent, source, errorMessages);
208
+ inCodeBlock = false;
209
+ }
124
210
  }
211
+ } else if (inCodeBlock) {
212
+ // Collect code block content for indentation analysis
213
+ codeBlockContent.push({ line, lineNumber });
125
214
  }
126
215
  }
127
216
 
128
217
  // Check for incomplete code blocks (started but not closed)
129
218
  if (inAnyCodeBlock) {
130
219
  errorMessages.push(
131
- `Found incomplete code block in ${source} starting at line ${anyCodeBlockStartLine}: code block opened with \`\`\` but never closed. Please return the complete content`
220
+ `Found incomplete code block in ${source} starting at line ${anyCodeBlockStartLine}: code block opened with \`\`\` but never closed. Please return the complete content`,
132
221
  );
133
222
  }
134
223
 
@@ -136,19 +225,15 @@ function checkContentStructure(markdown, source, errorMessages) {
136
225
  const newlineCount = (markdown.match(/\n/g) || []).length;
137
226
  if (newlineCount === 0 && markdown.trim().length > 0) {
138
227
  errorMessages.push(
139
- `Found single line content in ${source}: content appears to be on only one line, check for missing line breaks`
228
+ `Found single line content in ${source}: content appears to be on only one line, check for missing line breaks`,
140
229
  );
141
230
  }
142
231
 
143
232
  // Check if content ends with proper punctuation (indicating completeness)
144
233
  const trimmedText = markdown.trim();
145
- if (
146
- trimmedText.length > 0 &&
147
- !trimmedText.endsWith(".") &&
148
- !trimmedText.endsWith("。")
149
- ) {
234
+ if (trimmedText.length > 0 && !trimmedText.endsWith(".") && !trimmedText.endsWith("。")) {
150
235
  errorMessages.push(
151
- `Found incomplete content in ${source}: content does not end with proper punctuation (. or 。). Please return the complete content`
236
+ `Found incomplete content in ${source}: content does not end with proper punctuation (. or 。). Please return the complete content`,
152
237
  );
153
238
  }
154
239
  }
@@ -161,11 +246,7 @@ function checkContentStructure(markdown, source, errorMessages) {
161
246
  * @param {Array} [options.allowedLinks] - Set of allowed links for link validation
162
247
  * @returns {Promise<Array<string>>} - Array of error messages in check-detail-result format
163
248
  */
164
- export async function checkMarkdown(
165
- markdown,
166
- source = "content",
167
- options = {}
168
- ) {
249
+ export async function checkMarkdown(markdown, source = "content", options = {}) {
169
250
  const file = new VFile({ value: markdown, path: source });
170
251
  const errorMessages = [];
171
252
 
@@ -224,15 +305,14 @@ export async function checkMarkdown(
224
305
  // Check for mermaid syntax errors
225
306
  mermaidChecks.push(
226
307
  validateMermaidSyntax(node.value).catch((error) => {
227
- const errorMessage =
228
- error?.message || String(error) || "Unknown mermaid syntax error";
308
+ const errorMessage = error?.message || String(error) || "Unknown mermaid syntax error";
229
309
 
230
310
  // Format mermaid error in check-detail-result style
231
311
  const line = node.position?.start?.line || "unknown";
232
312
  errorMessages.push(
233
- `Found Mermaid syntax error in ${source} at line ${line}: ${errorMessage}`
313
+ `Found Mermaid syntax error in ${source} at line ${line}: ${errorMessage}`,
234
314
  );
235
- })
315
+ }),
236
316
  );
237
317
 
238
318
  // Check for specific mermaid rendering issues
@@ -240,38 +320,31 @@ export async function checkMarkdown(
240
320
  const line = node.position?.start?.line || "unknown";
241
321
 
242
322
  // Check for backticks in node labels
243
- const nodeLabelRegex =
244
- /[A-Za-z0-9_]+\["([^"]*`[^"]*)"\]|[A-Za-z0-9_]+{"([^}]*`[^}]*)"}/g;
323
+ const nodeLabelRegex = /[A-Za-z0-9_]+\["([^"]*`[^"]*)"\]|[A-Za-z0-9_]+{"([^}]*`[^}]*)"}/g;
245
324
  let match;
246
325
  while ((match = nodeLabelRegex.exec(mermaidContent)) !== null) {
247
326
  const label = match[1] || match[2];
248
327
  errorMessages.push(
249
- `Found backticks in Mermaid node label in ${source} at line ${line}: "${label}" - backticks in node labels cause rendering issues in Mermaid diagrams`
328
+ `Found backticks in Mermaid node label in ${source} at line ${line}: "${label}" - backticks in node labels cause rendering issues in Mermaid diagrams`,
250
329
  );
251
330
  }
252
331
 
253
332
  // Check for numbered list format in edge descriptions
254
333
  const edgeDescriptionRegex = /--\s*"([^"]*)"\s*-->/g;
255
334
  let edgeMatch;
256
- while (
257
- (edgeMatch = edgeDescriptionRegex.exec(mermaidContent)) !== null
258
- ) {
335
+ while ((edgeMatch = edgeDescriptionRegex.exec(mermaidContent)) !== null) {
259
336
  const description = edgeMatch[1];
260
337
  if (/^\d+\.\s/.test(description)) {
261
338
  errorMessages.push(
262
- `Unsupported markdown: list - Found numbered list format in Mermaid edge description in ${source} at line ${line}: "${description}" - numbered lists in edge descriptions are not supported`
339
+ `Unsupported markdown: list - Found numbered list format in Mermaid edge description in ${source} at line ${line}: "${description}" - numbered lists in edge descriptions are not supported`,
263
340
  );
264
341
  }
265
342
  }
266
343
 
267
344
  // Check for special characters in node labels that should be quoted
268
- const nodeWithSpecialCharsRegex =
269
- /([A-Za-z0-9_]+)\[([^\]]*[(){}:;,\-\s\.][^\]]*)\]/g;
345
+ const nodeWithSpecialCharsRegex = /([A-Za-z0-9_]+)\[([^\]]*[(){}:;,\-\s.][^\]]*)\]/g;
270
346
  let specialCharMatch;
271
- while (
272
- (specialCharMatch =
273
- nodeWithSpecialCharsRegex.exec(mermaidContent)) !== null
274
- ) {
347
+ while ((specialCharMatch = nodeWithSpecialCharsRegex.exec(mermaidContent)) !== null) {
275
348
  const nodeId = specialCharMatch[1];
276
349
  const label = specialCharMatch[2];
277
350
 
@@ -279,15 +352,13 @@ export async function checkMarkdown(
279
352
  if (!/^".*"$/.test(label)) {
280
353
  // List of characters that typically need quoting
281
354
  const specialChars = ["(", ")", "{", "}", ":", ";", ",", "-", "."];
282
- const foundSpecialChars = specialChars.filter((char) =>
283
- label.includes(char)
284
- );
355
+ const foundSpecialChars = specialChars.filter((char) => label.includes(char));
285
356
 
286
357
  if (foundSpecialChars.length > 0) {
287
358
  errorMessages.push(
288
359
  `Found unquoted special characters in Mermaid node label in ${source} at line ${line}: "${label}" contains ${foundSpecialChars.join(
289
- ", "
290
- )} - node labels with special characters should be quoted like ${nodeId}["${label}"]`
360
+ ", ",
361
+ )} - node labels with special characters should be quoted like ${nodeId}["${label}"]`,
291
362
  );
292
363
  }
293
364
  }
@@ -317,7 +388,7 @@ export async function checkMarkdown(
317
388
  errorMessages.push(
318
389
  `Found table separator with mismatched column count in ${source} at line ${
319
390
  i + 1
320
- }: separator has ${separatorColumns} columns but header has ${headerColumns} columns - this causes table rendering issues`
391
+ }: separator has ${separatorColumns} columns but header has ${headerColumns} columns - this causes table rendering issues`,
321
392
  );
322
393
  }
323
394
 
@@ -330,7 +401,7 @@ export async function checkMarkdown(
330
401
  errorMessages.push(
331
402
  `Found table data row with mismatched column count in ${source} at line ${
332
403
  i + 2
333
- }: data row has ${dataColumns} columns but separator defines ${separatorColumns} columns - this causes table rendering issues`
404
+ }: data row has ${dataColumns} columns but separator defines ${separatorColumns} columns - this causes table rendering issues`,
334
405
  );
335
406
  }
336
407
  }
@@ -349,7 +420,7 @@ export async function checkMarkdown(
349
420
  // Format messages in check-detail-result style
350
421
  file.messages.forEach((message) => {
351
422
  const line = message.line || "unknown";
352
- const column = message.column || "unknown";
423
+ const _column = message.column || "unknown";
353
424
  const reason = message.reason || "Unknown markdown issue";
354
425
  const ruleId = message.ruleId || message.source || "markdown";
355
426
 
@@ -366,21 +437,17 @@ export async function checkMarkdown(
366
437
  // Format error message similar to check-detail-result style
367
438
  if (line !== "unknown") {
368
439
  errorMessages.push(
369
- `Found ${errorType} issue in ${source} at line ${line}: ${reason} (${ruleId})`
440
+ `Found ${errorType} issue in ${source} at line ${line}: ${reason} (${ruleId})`,
370
441
  );
371
442
  } else {
372
- errorMessages.push(
373
- `Found ${errorType} issue in ${source}: ${reason} (${ruleId})`
374
- );
443
+ errorMessages.push(`Found ${errorType} issue in ${source}: ${reason} (${ruleId})`);
375
444
  }
376
445
  });
377
446
 
378
447
  return errorMessages;
379
448
  } catch (error) {
380
449
  // Handle any unexpected errors during processing
381
- errorMessages.push(
382
- `Found markdown processing error in ${source}: ${error.message}`
383
- );
450
+ errorMessages.push(`Found markdown processing error in ${source}: ${error.message}`);
384
451
  return errorMessages;
385
452
  }
386
453
  }
@@ -3,10 +3,7 @@
3
3
  * Provides concurrent-safe validation with isolated worker environments
4
4
  */
5
5
 
6
- import {
7
- getMermaidWorkerPool,
8
- shutdownMermaidWorkerPool,
9
- } from "./mermaid-worker-pool.mjs";
6
+ import { getMermaidWorkerPool, shutdownMermaidWorkerPool } from "./mermaid-worker-pool.mjs";
10
7
 
11
8
  /**
12
9
  * Worker-based mermaid validation - DEPRECATED but kept for compatibility
@@ -55,17 +52,15 @@ export function validateBasicMermaidSyntax(content) {
55
52
  ];
56
53
 
57
54
  const firstLine = trimmedContent.split("\n")[0].trim();
58
- const hasValidType = validDiagramTypes.some((type) =>
59
- firstLine.includes(type)
60
- );
55
+ const hasValidType = validDiagramTypes.some((type) => firstLine.includes(type));
61
56
 
62
57
  if (!hasValidType) {
63
58
  throw new Error("Invalid or missing diagram type");
64
59
  }
65
60
 
66
61
  // Basic bracket matching
67
- const openBrackets = (content.match(/[\[\{\(]/g) || []).length;
68
- const closeBrackets = (content.match(/[\]\}\)]/g) || []).length;
62
+ const openBrackets = (content.match(/[[{(]/g) || []).length;
63
+ const closeBrackets = (content.match(/[\]})]/g) || []).length;
69
64
 
70
65
  if (openBrackets !== closeBrackets) {
71
66
  throw new Error("Unmatched brackets in diagram");
@@ -125,7 +120,7 @@ export async function validateMermaidSyntax(content) {
125
120
  // Fall back to basic validation for environment issues
126
121
  console.warn(
127
122
  "Worker-based mermaid validation failed, falling back to basic validation:",
128
- errorMsg
123
+ errorMsg,
129
124
  );
130
125
  return validateBasicMermaidSyntax(content);
131
126
  }
@@ -5,9 +5,9 @@
5
5
  * Manages worker threads for concurrent mermaid validation
6
6
  */
7
7
 
8
- import { Worker } from "worker_threads";
9
- import { fileURLToPath } from "url";
10
- import { dirname, join } from "path";
8
+ import { dirname, join } from "node:path";
9
+ import { fileURLToPath } from "node:url";
10
+ import { Worker } from "node:worker_threads";
11
11
 
12
12
  const __filename = fileURLToPath(import.meta.url);
13
13
  const __dirname = dirname(__filename);
@@ -51,18 +51,14 @@ class SimpleMermaidWorkerPool {
51
51
  // Handle worker errors more gracefully
52
52
  worker.on("error", (error) => {
53
53
  if (worker.currentRequest) {
54
- worker.currentRequest.reject(
55
- new Error(`Worker error: ${error.message}`)
56
- );
54
+ worker.currentRequest.reject(new Error(`Worker error: ${error.message}`));
57
55
  worker.currentRequest = null;
58
56
  }
59
57
  });
60
58
 
61
- worker.on("exit", (code) => {
59
+ worker.on("exit", (_code) => {
62
60
  if (worker.currentRequest) {
63
- worker.currentRequest.reject(
64
- new Error("Worker exited unexpectedly")
65
- );
61
+ worker.currentRequest.reject(new Error("Worker exited unexpectedly"));
66
62
  worker.currentRequest = null;
67
63
  }
68
64
  });
@@ -212,7 +208,7 @@ class SimpleMermaidWorkerPool {
212
208
  const terminationPromises = this.workers.map(async (worker) => {
213
209
  try {
214
210
  await worker.terminate();
215
- } catch (error) {
211
+ } catch (_error) {
216
212
  // Ignore termination errors
217
213
  }
218
214
  });