#!/usr/bin/env nu # Check for malformed closing code fences in markdown files # CommonMark spec violation: Closing fences should be ``` without language specifiers def main [] { # Find all markdown files (excluding ignored directories) let md_files = ( glob **/*.md | where {|f| not ($f | str contains ".git") } | where {|f| not ($f | str contains "target") } | where {|f| not ($f | str contains "node_modules") } | where {|f| not ($f | str contains ".coder") } | where {|f| not ($f | str contains ".claude") } | where {|f| not ($f | str contains ".wrks") } ) mut total_issues = 0 mut files_with_issues = [] for file in $md_files { let issues = (check_file $file) if ($issues | length) > 0 { $total_issues = $total_issues + ($issues | length) $files_with_issues = ($files_with_issues | append {file: $file, issues: $issues}) } } if $total_issues > 0 { print $"❌ Found ($total_issues) malformed closing fence\(s\) in ($files_with_issues | length) file\(s\):\n" for item in $files_with_issues { print $" ($item.file):" for issue in $item.issues { print $" Line ($issue.line): ($issue.content)" } } print "\nFix: Remove language specifiers from closing fences (should be just ```)" exit 1 } else { print "✅ No malformed closing fences found" exit 0 } } def check_file [file: string] { mut issues = [] mut in_code_block = false mut line_num = 0 for line in (open $file | lines) { $line_num = $line_num + 1 # Check if line is a code fence let fence_match = ($line | parse --regex '^```(?P\w+)?\s*$') if ($fence_match | length) > 0 { if not $in_code_block { # Opening fence $in_code_block = true } else { # Closing fence let lang = ($fence_match | get 0.lang? | default "") if ($lang | str length) > 0 { # Malformed: has language on closing fence $issues = ($issues | append {line: $line_num, content: $line}) } $in_code_block = false } } } $issues }