@aigne/doc-smith 0.2.5 → 0.2.6

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.
@@ -0,0 +1,707 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { checkMarkdown } from "../utils/markdown-checker.mjs";
4
+ import checkDetailResult from "../agents/check-detail-result.mjs";
5
+ import { shutdownValidation } from "../utils/mermaid-validator.mjs";
6
+
7
+ // Mock structure plan for link validation
8
+ const mockStructurePlan = [
9
+ { path: "./getting-started" },
10
+ { path: "/api/overview" },
11
+ { path: "./advanced/configuration" },
12
+ { path: "./tutorials/basic" },
13
+ { path: "/reference/api" },
14
+ ];
15
+
16
+ // Create allowed links set
17
+ const allowedLinks = new Set();
18
+ mockStructurePlan.forEach((item) => {
19
+ allowedLinks.add(item.path);
20
+ // Add processed .md path
21
+ let processedPath = item.path;
22
+ if (processedPath.startsWith(".")) {
23
+ processedPath = processedPath.replace(/^\./, "");
24
+ }
25
+ let flatPath = processedPath.replace(/^\//, "").replace(/\//g, "-");
26
+ flatPath = `./${flatPath}.md`;
27
+ allowedLinks.add(flatPath);
28
+ });
29
+
30
+ const testCases = [
31
+ // ========== PASSING CASES ==========
32
+ {
33
+ category: "✅ PASSING CASES",
34
+ name: "Perfect valid document",
35
+ expectPass: true,
36
+ content: `# Getting Started Guide
37
+
38
+ This is a complete document with proper structure and formatting.
39
+
40
+ ## Introduction
41
+
42
+ Welcome to our comprehensive guide. This document follows all markdown best practices.
43
+
44
+ ## Code Examples
45
+
46
+ Here's a properly formatted code block:
47
+
48
+ \`\`\`javascript
49
+ function validateInput(data) {
50
+ if (!data) {
51
+ throw new Error("Data is required");
52
+ }
53
+ return data.trim();
54
+ }
55
+
56
+ // Export the function
57
+ export { validateInput };
58
+ \`\`\`
59
+
60
+ ## Data Tables
61
+
62
+ Our API supports the following data types:
63
+
64
+ |Type|Description|Example|
65
+ |----|-----------|-------|
66
+ |String|Text data|"Hello"|
67
+ |Number|Numeric values|42|
68
+ |Boolean|True/false|true|
69
+
70
+ ## Process Flow
71
+
72
+ The following diagram shows our validation process:
73
+
74
+ \`\`\`mermaid
75
+ flowchart TD
76
+ A[Start] --> B{Valid Input?}
77
+ B -->|Yes| C[Process Data]
78
+ B -->|No| D[Return Error]
79
+ C --> E[Save Results]
80
+ D --> F[Log Error]
81
+ E --> G[End]
82
+ F --> G
83
+ \`\`\`
84
+
85
+ ## Related Documentation
86
+
87
+ For more information, see our [API reference](/reference/api) and [advanced configuration](./advanced/configuration).
88
+
89
+ This document ends with proper punctuation and formatting.
90
+ `,
91
+ },
92
+
93
+ {
94
+ category: "✅ PASSING CASES",
95
+ name: "Simple valid content",
96
+ expectPass: true,
97
+ content: `# Simple Document
98
+
99
+ This is a simple but valid document.
100
+
101
+ It has multiple paragraphs and proper structure.
102
+
103
+ The content ends with a period.
104
+ `,
105
+ },
106
+
107
+ {
108
+ category: "✅ PASSING CASES",
109
+ name: "Valid content with Chinese punctuation",
110
+ expectPass: true,
111
+ content: `# 中文文档
112
+
113
+ 这是一个中文文档的示例。
114
+
115
+ ## 内容说明
116
+
117
+ 文档内容使用中文标点符号。
118
+
119
+ 这个文档以中文句号结尾。
120
+ `,
121
+ },
122
+
123
+ // ========== LINK VALIDATION CASES ==========
124
+ {
125
+ category: "🔗 LINK VALIDATION",
126
+ name: "Dead internal link",
127
+ expectPass: false,
128
+ expectedErrors: ["dead link"],
129
+ content: `# Test Document
130
+
131
+ Check out this [broken link](./non-existent-page) for more info.
132
+
133
+ This content ends properly.
134
+ `,
135
+ },
136
+
137
+ {
138
+ category: "🔗 LINK VALIDATION",
139
+ name: "Multiple dead links",
140
+ expectPass: false,
141
+ expectedErrors: ["dead link"],
142
+ content: `# Test Document
143
+
144
+ See [invalid page](./invalid) and [another broken link](/broken/path).
145
+
146
+ External links like [Google](https://google.com) should be ignored.
147
+
148
+ This content ends properly.
149
+ `,
150
+ },
151
+
152
+ {
153
+ category: "🔗 LINK VALIDATION",
154
+ name: "Valid internal links",
155
+ expectPass: true,
156
+ content: `# Test Document
157
+
158
+ Check out our [getting started guide](./getting-started) and [API overview](/api/overview).
159
+
160
+ External links like [GitHub](https://github.com) and [email](mailto:test@example.com) are fine.
161
+
162
+ This content ends properly.
163
+ `,
164
+ },
165
+
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
+ {
187
+ category: "💻 CODE BLOCK VALIDATION",
188
+ name: "Incomplete code block",
189
+ expectPass: false,
190
+ expectedErrors: ["incomplete code block"],
191
+ content: `# Test Document
192
+
193
+ Here's incomplete code:
194
+
195
+ \`\`\`javascript
196
+ function incomplete() {
197
+ console.log("missing closing");
198
+ `,
199
+ },
200
+
201
+ {
202
+ category: "💻 CODE BLOCK VALIDATION",
203
+ name: "Valid indented code block",
204
+ expectPass: true,
205
+ content: `# Test Document
206
+
207
+ Here's properly indented code:
208
+
209
+ \`\`\`javascript
210
+ function test() {
211
+ return "properly indented";
212
+ }
213
+ \`\`\`
214
+
215
+ This content ends properly.
216
+ `,
217
+ },
218
+
219
+ // ========== CONTENT STRUCTURE CASES ==========
220
+ {
221
+ category: "📝 CONTENT STRUCTURE",
222
+ name: "Single line content",
223
+ expectPass: false,
224
+ expectedErrors: ["single line content"],
225
+ content: `This is just one line without any line breaks or proper structure`,
226
+ },
227
+
228
+ {
229
+ category: "📝 CONTENT STRUCTURE",
230
+ name: "Missing punctuation ending",
231
+ expectPass: false,
232
+ expectedErrors: ["incomplete content"],
233
+ content: `# Test Document
234
+
235
+ This content doesn't end with proper punctuation`,
236
+ },
237
+
238
+ {
239
+ category: "📝 CONTENT STRUCTURE",
240
+ name: "Content with proper line breaks",
241
+ expectPass: true,
242
+ content: `# Test Document
243
+
244
+ This content has proper line breaks.
245
+
246
+ Multiple paragraphs are formatted correctly.
247
+
248
+ The document ends with proper punctuation.
249
+ `,
250
+ },
251
+
252
+ // ========== TABLE VALIDATION CASES ==========
253
+ {
254
+ category: "📊 TABLE VALIDATION",
255
+ name: "Table separator with fewer columns",
256
+ expectPass: false,
257
+ expectedErrors: ["table separator with mismatched column count"],
258
+ content: `# Test Document
259
+
260
+ | Column 1 | Column 2 | Column 3 |
261
+ | - | - |
262
+ | Data 1 | Data 2 | Data 3 |
263
+
264
+ This content ends properly.
265
+ `,
266
+ },
267
+
268
+ {
269
+ category: "📊 TABLE VALIDATION",
270
+ name: "Table separator with more columns",
271
+ expectPass: false,
272
+ expectedErrors: ["table separator with mismatched column count"],
273
+ content: `# Test Document
274
+
275
+ | Column 1 | Column 2 |
276
+ |----------|----------|----------|
277
+ | Data 1 | Data 2 |
278
+
279
+ This content ends properly.
280
+ `,
281
+ },
282
+
283
+ {
284
+ category: "📊 TABLE VALIDATION",
285
+ name: "Table data row with mismatched columns",
286
+ expectPass: false,
287
+ expectedErrors: ["table data row with mismatched column count"],
288
+ content: `# Test Document
289
+
290
+ | Column 1 | Column 2 |
291
+ |----------|----------|
292
+ | Data 1 | Data 2 | Data 3 |
293
+
294
+ This content ends properly.
295
+ `,
296
+ },
297
+
298
+ {
299
+ category: "📊 TABLE VALIDATION",
300
+ name: "Valid table with consistent columns",
301
+ expectPass: true,
302
+ content: `# Test Document
303
+
304
+ |Column 1|Column 2|Column 3|
305
+ |--------|--------|--------|
306
+ |Data 1|Data 2|Data 3|
307
+ |Row 2|More|Data|
308
+
309
+ This content ends properly.
310
+
311
+ | 参数 | 类型 | 描述 |
312
+ |---|---|---|
313
+ | callback | () => void \\| Promise<void> | Payment Kit 组件运行后要执行的函数。这可以是一个异步函数。 |
314
+ | wait | boolean | 可选。如果为 ,稍后在组件启动时执行回调。 |
315
+
316
+ This document demonstrates escaped pipe handling.
317
+ `,
318
+ },
319
+
320
+ // ========== MERMAID VALIDATION CASES ==========
321
+ {
322
+ category: "🧩 MERMAID VALIDATION",
323
+ name: "Invalid Mermaid syntax",
324
+ expectPass: false,
325
+ expectedErrors: ["Mermaid syntax error"],
326
+ content: `# Test Document
327
+
328
+ \`\`\`mermaid
329
+ invalid diagram type
330
+ A --> B
331
+ \`\`\`
332
+
333
+ This content ends properly.
334
+ `,
335
+ },
336
+
337
+ {
338
+ category: "🧩 MERMAID VALIDATION",
339
+ name: "Mermaid with backticks in node labels",
340
+ expectPass: false,
341
+ expectedErrors: ["backticks in Mermaid node label"],
342
+ content: `# Test Document
343
+
344
+ \`\`\`mermaid
345
+ flowchart TD
346
+ A["label with \`backticks\`"] --> B[End]
347
+ C{"another \`label\` with backticks"} --> D[Final]
348
+ \`\`\`
349
+
350
+ This content ends properly.
351
+ `,
352
+ },
353
+
354
+ {
355
+ category: "🧩 MERMAID VALIDATION",
356
+ name: "Mermaid with numbered edge descriptions",
357
+ expectPass: false,
358
+ expectedErrors: ["numbered list format in Mermaid edge description"],
359
+ content: `# Test Document
360
+
361
+ \`\`\`mermaid
362
+ flowchart TD
363
+ A[Start] -- "1. First step" --> B[Middle]
364
+ B -- "2. Second step" --> C[End]
365
+ \`\`\`
366
+
367
+ This content ends properly.
368
+ `,
369
+ },
370
+
371
+ {
372
+ category: "🧩 MERMAID VALIDATION",
373
+ name: "Mermaid with unquoted special characters",
374
+ expectPass: false,
375
+ expectedErrors: ["unquoted special characters"],
376
+ content: `# Test Document
377
+
378
+ \`\`\`mermaid
379
+ flowchart LR
380
+ A[Start] --> B[Response.raw (file-like) is available]
381
+ B --> C[End]
382
+ \`\`\`
383
+
384
+ This content ends properly.
385
+ `,
386
+ },
387
+
388
+ {
389
+ category: "🧩 MERMAID VALIDATION",
390
+ name: "Valid Mermaid diagrams",
391
+ expectPass: true,
392
+ content: `# Test Document
393
+
394
+ \`\`\`mermaid
395
+ flowchart TD
396
+ A[Start] --> B{Decision}
397
+ B -->|Yes| C[Process]
398
+ B -->|No| D[End]
399
+ C --> E[Save]
400
+ E --> D
401
+ \`\`\`
402
+
403
+ \`\`\`mermaid
404
+ sequenceDiagram
405
+ participant A as Alice
406
+ participant B as Bob
407
+ A->>B: Hello Bob
408
+ B-->>A: Hello Alice
409
+ \`\`\`
410
+
411
+ This content ends properly.
412
+ `,
413
+ },
414
+
415
+ {
416
+ category: "🧩 MERMAID VALIDATION",
417
+ name: "Mermaid with subgraph reference issues (rendering failure)",
418
+ expectPass: false,
419
+ expectedErrors: ["subgraph reference"],
420
+ content: `# Test Document
421
+
422
+ \`\`\`mermaid
423
+ flowchart TD
424
+ A["FastAPI Application"] --> B["Security & Authentication"];
425
+ A --> C["Error Handling"];
426
+ A --> D["WebSockets"];
427
+ A --> E["Middleware"];
428
+ A --> F["Lifespan Events"];
429
+ A --> G["Database Integration"];
430
+ H["Project Structure"] -- "Organizes" --> A;
431
+ I["Application Settings"] -- "Configures" --> A;
432
+ J["Testing FastAPI Applications"] -- "Ensures Reliability" --> A;
433
+ A --> K["Deployment"];
434
+
435
+ subgraph Advanced Capabilities
436
+ B
437
+ C
438
+ D
439
+ E
440
+ F
441
+ G
442
+ end
443
+
444
+ subgraph Operational Excellence
445
+ H
446
+ I
447
+ J
448
+ K
449
+ end
450
+
451
+ AdvancedCapabilities --> "Robustness" --> L["Production-Ready API"];
452
+ OperationalExcellence --> "Maintainability & Scalability" --> L;
453
+ \`\`\`
454
+
455
+ This content ends properly.
456
+ `,
457
+ },
458
+
459
+ // ========== COMPLEX MIXED CASES ==========
460
+ {
461
+ category: "🔄 COMPLEX MIXED CASES",
462
+ name: "Multiple issues in one document",
463
+ expectPass: false,
464
+ expectedErrors: [
465
+ "dead link",
466
+ "table separator with mismatched column count",
467
+ "incomplete content",
468
+ ],
469
+ content: `# Complex Test Document
470
+
471
+ This document has [multiple issues](./broken-link).
472
+
473
+ | Column 1 | Column 2 | Column 3 |
474
+ | - | - |
475
+ | Data 1 | Data 2 | Data 3 |
476
+
477
+ \`\`\`mermaid
478
+ flowchart TD
479
+ A["node with \`backticks\`"] --> B[End]
480
+ \`\`\`
481
+
482
+ This content doesn't end properly`,
483
+ },
484
+
485
+ {
486
+ category: "🔄 COMPLEX MIXED CASES",
487
+ name: "Complex valid document with all elements",
488
+ expectPass: true,
489
+ content: `# Comprehensive Test Document
490
+
491
+ This document contains all supported elements in their correct form.
492
+
493
+ ## Links Section
494
+
495
+ Internal links: [Getting Started](./getting-started) and [API Reference](/api/overview).
496
+ External links: [GitHub](https://github.com) and [Email](mailto:support@example.com).
497
+
498
+ ## Code Examples
499
+
500
+ Standard code block:
501
+
502
+ \`\`\`javascript
503
+ function processData(input) {
504
+ const result = input.map(item => ({
505
+ id: item.id,
506
+ value: item.value * 2
507
+ }));
508
+ return result;
509
+ }
510
+ \`\`\`
511
+
512
+ ## Data Tables
513
+
514
+ |Feature|Status|Notes|
515
+ |-------|------|-----|
516
+ |API v1|Active|Current version|
517
+ |API v2|Beta|Testing phase|
518
+ |Dashboard|Complete|Ready for use|
519
+
520
+ ## Process Diagrams
521
+
522
+ Main workflow:
523
+
524
+ \`\`\`mermaid
525
+ flowchart TD
526
+ A[User Request] --> B{Validate Input}
527
+ B -->|Valid| C[Process Request]
528
+ B -->|Invalid| D[Return Error]
529
+ C --> E[Generate Response]
530
+ D --> F[Log Error]
531
+ E --> G[Send Response]
532
+ F --> G
533
+ \`\`\`
534
+
535
+ Sequence diagram:
536
+
537
+ \`\`\`mermaid
538
+ sequenceDiagram
539
+ participant U as User
540
+ participant A as API
541
+ participant D as Database
542
+
543
+ U->>A: Send Request
544
+ A->>D: Query Data
545
+ D-->>A: Return Results
546
+ A-->>U: Send Response
547
+ \`\`\`
548
+
549
+ ## Conclusion
550
+
551
+ This comprehensive document demonstrates all validation rules in their correct usage.
552
+ `,
553
+ },
554
+ ];
555
+
556
+ async function runValidationTests() {
557
+ console.log("🧪 Comprehensive Markdown Validation Test Suite\n");
558
+ console.log("=".repeat(80));
559
+
560
+ let totalTests = 0;
561
+ let passedTests = 0;
562
+ let failedTests = 0;
563
+
564
+ let currentCategory = "";
565
+
566
+ for (const testCase of testCases) {
567
+ // Print category header if it changed
568
+ if (testCase.category !== currentCategory) {
569
+ currentCategory = testCase.category;
570
+ console.log(`\n${currentCategory}`);
571
+ console.log("-".repeat(80));
572
+ }
573
+
574
+ console.log(`\n📝 Testing: ${testCase.name}`);
575
+ totalTests++;
576
+
577
+ try {
578
+ // Test with checkMarkdown directly
579
+ const errors = await checkMarkdown(testCase.content, "test", {
580
+ allowedLinks,
581
+ });
582
+
583
+ // Test with checkDetailResult wrapper
584
+ const wrapperResult = await checkDetailResult({
585
+ structurePlan: mockStructurePlan,
586
+ reviewContent: testCase.content,
587
+ });
588
+
589
+ const hasErrors = errors.length > 0;
590
+ const expectPass = testCase.expectPass;
591
+
592
+ // Verify test expectation
593
+ if (expectPass && !hasErrors) {
594
+ console.log("✅ PASS - Content correctly passed validation");
595
+ passedTests++;
596
+ } else if (!expectPass && hasErrors) {
597
+ console.log("✅ PASS - Content correctly failed validation");
598
+
599
+ // Check if expected error types are present
600
+ if (testCase.expectedErrors) {
601
+ const foundExpectedErrors = testCase.expectedErrors.every(
602
+ (expectedError) =>
603
+ errors.some((error) =>
604
+ error.toLowerCase().includes(expectedError.toLowerCase())
605
+ )
606
+ );
607
+
608
+ if (foundExpectedErrors) {
609
+ console.log("✅ Expected error types found");
610
+ } else {
611
+ console.log("⚠️ Expected error types not all found");
612
+ console.log(` Expected: ${testCase.expectedErrors.join(", ")}`);
613
+ }
614
+ }
615
+
616
+ passedTests++;
617
+ } else {
618
+ console.log(
619
+ `❌ FAIL - Expected ${expectPass ? "PASS" : "FAIL"} but got ${
620
+ hasErrors ? "FAIL" : "PASS"
621
+ }`
622
+ );
623
+ failedTests++;
624
+ }
625
+
626
+ // Show error details for failing cases
627
+ if (hasErrors) {
628
+ console.log(` Found ${errors.length} issue(s):`);
629
+ errors.slice(0, 3).forEach((error) => {
630
+ console.log(` • ${error}`);
631
+ });
632
+ if (errors.length > 3) {
633
+ console.log(` ... and ${errors.length - 3} more issues`);
634
+ }
635
+ }
636
+
637
+ // Verify consistency between direct call and wrapper
638
+ const wrapperErrors = wrapperResult.detailFeedback
639
+ ? wrapperResult.detailFeedback.split("\n").filter((line) => line.trim())
640
+ : [];
641
+
642
+ if (errors.length === wrapperErrors.length) {
643
+ console.log("✅ Direct call and wrapper consistent");
644
+ } else {
645
+ console.log(
646
+ `⚠️ Inconsistent results: direct=${errors.length}, wrapper=${wrapperErrors.length}`
647
+ );
648
+ }
649
+ } catch (error) {
650
+ console.log(`❌ ERROR: ${error.message}`);
651
+ failedTests++;
652
+ }
653
+ }
654
+
655
+ // Final summary
656
+ console.log("\n" + "=".repeat(80));
657
+ console.log("📊 TEST SUMMARY");
658
+ console.log("=".repeat(80));
659
+ console.log(`Total Tests: ${totalTests}`);
660
+ console.log(`Passed: ${passedTests} ✅`);
661
+ console.log(`Failed: ${failedTests} ❌`);
662
+ console.log(
663
+ `Success Rate: ${((passedTests / totalTests) * 100).toFixed(1)}%`
664
+ );
665
+
666
+ console.log("\n🔍 VALIDATION COVERAGE:");
667
+ console.log("✅ Link validation (dead links, allowed links)");
668
+ console.log("✅ Code block validation (indentation, completeness)");
669
+ console.log("✅ Content structure (line breaks, punctuation)");
670
+ console.log("✅ Table validation (column count consistency)");
671
+ console.log("✅ Mermaid validation (syntax, rendering issues)");
672
+ console.log("✅ Standard markdown linting (formatting rules)");
673
+ console.log("✅ Complex mixed scenarios");
674
+ console.log("✅ Edge cases and error conditions");
675
+
676
+ if (failedTests === 0) {
677
+ console.log(
678
+ "\n🎉 ALL TESTS PASSED! Validation system is working correctly."
679
+ );
680
+ } else {
681
+ console.log(
682
+ `\n⚠️ ${failedTests} test(s) failed. Please review the validation logic.`
683
+ );
684
+ }
685
+
686
+ // Shutdown worker pool to ensure clean exit
687
+ try {
688
+ await shutdownValidation();
689
+ } catch (error) {
690
+ console.error("Error shutting down validation:", error);
691
+ }
692
+ }
693
+
694
+ // Export test cases for external use
695
+ export { testCases, mockStructurePlan, allowedLinks };
696
+
697
+ // Run tests if this file is executed directly
698
+ if (import.meta.url === `file://${process.argv[1]}`) {
699
+ runValidationTests()
700
+ .then(() => {
701
+ process.exit(0);
702
+ })
703
+ .catch((error) => {
704
+ console.error("Test suite error:", error);
705
+ process.exit(1);
706
+ });
707
+ }