fix(docs): markdown code fence violations and formatting
This commit is contained in:
parent
17ef93ed23
commit
35acc1987e
103
scripts/fix-markdown-fences.nu
Normal file → Executable file
103
scripts/fix-markdown-fences.nu
Normal file → Executable file
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user