From 35acc1987ebbc45c97948b5aaa90f57c182b6448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20Pe=CC=81rez?= Date: Wed, 14 Jan 2026 04:55:23 +0000 Subject: [PATCH] fix(docs): markdown code fence violations and formatting --- scripts/fix-markdown-fences.nu | 103 ++++++++++++++++++++++++--------- 1 file changed, 75 insertions(+), 28 deletions(-) mode change 100644 => 100755 scripts/fix-markdown-fences.nu diff --git a/scripts/fix-markdown-fences.nu b/scripts/fix-markdown-fences.nu old mode 100644 new mode 100755 index 7051e39..db102b7 --- a/scripts/fix-markdown-fences.nu +++ b/scripts/fix-markdown-fences.nu @@ -1,19 +1,18 @@ #!/usr/bin/env nu -# Fix Markdown Issues: Newlines + Code Fence Violations (MD040 + CommonMark) +# Fix Markdown Issues: Newlines + Closing Code Fence Violations # Handles: # 1. Literal \n escape sequences → actual newlines # 2. Closing fences with language specifiers (malformed) -# 3. Opening fences without language specifiers (missing) # # Usage: -# nu fix-markdown-fences.nu # Fix: newlines + closing fences +# nu fix-markdown-fences.nu # Fix all: newlines + closing fences # nu fix-markdown-fences.nu --dry-run # Preview without changes # nu fix-markdown-fences.nu --phase newlines # Only fix literal \n # nu fix-markdown-fences.nu --phase closing # Only fix closing fences # nu fix-markdown-fences.nu --dry-run --report # Show detailed report # -# For opening fences: use sed instead -# find . -name "*.md" -exec sed -i 's/^```$/```text/g' {} \; +# For opening fences (manual): +# find . -name '*.md' -exec sed -i '' 's/^```$/```text/g; s/^```[a-z]*$/```/g' {} \; # # Phases: # newlines - Fix literal \n escape sequences → actual newlines @@ -22,12 +21,12 @@ def main [ --dry-run # Preview without making changes - --phase: string = "all" # Phase: newlines|closing|all + --phase: string = "all" # Phase: cleanup|newlines|closing|opening|all --report # Show detailed before/after report ] { # Validate phase argument - if $phase !~ '^(newlines|closing|all)$' { - print $"Error: Invalid phase '$phase'. Must be: newlines, closing, or all" + if $phase !~ '^(cleanup|newlines|closing|opening|all)$' { + print $"Error: Invalid phase '$phase'. Must be: cleanup, newlines, closing, opening, or all" exit 1 } @@ -44,6 +43,7 @@ def main [ print "" # Track statistics + mut total_cleanup_fixed = 0 mut total_newlines_fixed = 0 mut total_closing_fixed = 0 mut total_opening_fixed = 0 @@ -53,11 +53,20 @@ def main [ for file in $md_files { let original_content = open $file mut modified_content = $original_content + mut cleanup_fixed = 0 mut newlines_fixed = 0 mut closing_fixed = 0 mut opening_fixed = 0 - # Phase 0: Fix literal \n escape sequences + # Phase -1: Clean up corrupted {$detected_lang} literals (CRITICAL) + if ($phase == "cleanup" or $phase == "all") { + let cleanup_result = cleanup-corrupted-fences $modified_content + $cleanup_fixed = $cleanup_result.fixed_count + $total_cleanup_fixed += $cleanup_fixed + $modified_content = $cleanup_result.content + } + + # Phase 0: Fix literal \n escape sequences (Nushell - SAFE) if ($phase == "newlines" or $phase == "all") { if ($modified_content | str contains '\\n') { let newlines_result = fix-literal-newlines $modified_content @@ -67,7 +76,7 @@ def main [ } } - # Phase 1: Fix closing fences + # Phase 1: Fix closing fences (Nushell - SAFE) if ($phase == "closing" or $phase == "all") { let closing_result = fix-closing-fences $modified_content $closing_fixed = $closing_result.fixed_count @@ -76,16 +85,15 @@ def main [ } # Phase 2: Fix opening fences with language detection - # NOTE: Disabled - use sed instead due to Nushell string join newline corruption - # if ($phase == "opening" or $phase == "all") { - # let opening_result = fix-opening-fences $modified_content $file - # $opening_fixed = $opening_result.fixed_count - # $total_opening_fixed += $opening_fixed - # $modified_content = $opening_result.content - # } + if ($phase == "opening" or $phase == "all") { + let opening_result = fix-opening-fences $modified_content $file + $opening_fixed = $opening_result.fixed_count + $total_opening_fixed += $opening_fixed + $modified_content = $opening_result.content + } # Write changes if not dry-run AND if there were any fixes - let has_changes = ($newlines_fixed > 0) or ($closing_fixed > 0) or ($opening_fixed > 0) + let has_changes = ($cleanup_fixed > 0) or ($newlines_fixed > 0) or ($closing_fixed > 0) or ($opening_fixed > 0) if $has_changes { if (not $dry_run) { $modified_content | save --force $file @@ -94,6 +102,9 @@ def main [ if $report { print $"✏️ Modified: ($file)" + if $cleanup_fixed > 0 { + print $" Corrupted literals fixed: ($cleanup_fixed)" + } if $newlines_fixed > 0 { print $" Literal newlines fixed: ($newlines_fixed)" } @@ -111,7 +122,8 @@ def main [ print "═════════════════════════════════════" print "Summary" print "═════════════════════════════════════" - print $"Files modified: ($files_modified)" + print $"Files scanned: ($md_files | length)" + print $"Corrupted literals fixed: ($total_cleanup_fixed)" print $"Literal newlines fixed: ($total_newlines_fixed)" print $"Closing fences fixed: ($total_closing_fixed)" print $"Opening fences fixed: ($total_opening_fixed)" @@ -123,8 +135,7 @@ def main [ } else { print "✅ Changes applied successfully" print "Run: git diff # Review changes" - print "Run: nu scripts/check-malformed-fences.nu # Validate closing fences" - print "Run: markdownlint-cli2 '**/*.md' --fix # Validate and fix remaining issues" + print "Run: markdownlint-cli2 '**/*.md' # Validate (MD040, MD060)" } } @@ -136,6 +147,44 @@ def fix-literal-newlines [content] { } } +# Clean up corrupted {$detected_lang} literals and remnant text lines +def cleanup-corrupted-fences [content] { + let lines = $content | lines + mut fixed_lines = [] + mut fixed_count = 0 + + for idx in (0..<($lines | length)) { + let line = $lines | get $idx + + # Check for corrupted opening fence with {$detected_lang} + if ($line =~ '^```\{?\$detected_lang\}?$') { + # Replace with clean ``` + $fixed_lines = ($fixed_lines | append '```') + $fixed_count += 1 + } else { + # Check if this is a remnant "text" line after a language-tagged opening fence + let is_text_remnant = ( + $idx > 0 and + ($lines | get ($idx - 1)) =~ '^```\w+' and + $line == 'text' + ) + + if $is_text_remnant { + # Skip this garbage line + $fixed_count += 1 + } else { + # Keep the line + $fixed_lines = ($fixed_lines | append $line) + } + } + } + + { + content: ($fixed_lines | str join "\n") + fixed_count: $fixed_count + } +} + # Discover all markdown files with proper exclusions def discover-markdown-files [] { glob **/*.md @@ -187,7 +236,7 @@ def fix-closing-fences [content] { } { - content: ($fixed_lines | str join '\n') + content: ($fixed_lines | str join "\n") fixed_count: $fixed_count } } @@ -219,15 +268,13 @@ def fix-opening-fences [content, file_path] { # Get context before fence (3 lines) let context_start = if ($idx > 3) { $idx - 3 } else { 0 } - let context_before = $lines | skip $context_start | first ($idx - $context_start) | str join '\n' + let context_before = $lines | skip $context_start | first ($idx - $context_start) | str join "\n" # Detect language let detected_lang = detect-language $content_after $context_before $file_path - # Add language to fence - # NOTE: Using placeholder to avoid Nushell string join issues with newlines - # Will be processed with sed post-fix - $fixed_lines = ($fixed_lines | append $'```{$detected_lang}') + # Add language to fence with detected language (using double quotes for interpolation) + $fixed_lines = ($fixed_lines | append $"```($detected_lang)") $fixed_count += 1 } else { # Opening fence WITH language → no fix needed @@ -246,7 +293,7 @@ def fix-opening-fences [content, file_path] { } { - content: ($fixed_lines | str join '\n') + content: ($fixed_lines | str join "\n") fixed_count: $fixed_count } }