#!/usr/bin/env python3 """Fix markdown linting errors: MD040 (code blocks), MD013 (line length), MD060 (tables).""" import re import sys from pathlib import Path def fix_code_block_languages(content): """Add language specifier to code blocks without one (MD040).""" # Pattern: opening fence with no language specifier (``` followed by newline or whitespace) pattern = r'(^```)\n' # Replace with ```text\n (default language for unspecified blocks) fixed = re.sub(pattern, r'\1text\n', content, flags=re.MULTILINE) return fixed def fix_line_length(content): """Break long lines to fit 150 character limit (MD013).""" lines = content.split('\n') fixed_lines = [] for line in lines: # Skip code blocks, tables, and links (these have different rules) if line.startswith('```') or line.startswith('|') or line.startswith('>'): fixed_lines.append(line) continue # If line is longer than 150 chars and not a special case if len(line) > 150: # For paragraphs, try to break at word boundaries if not line.startswith('#') and not line.startswith('-') and not line.startswith('*'): words = line.split(' ') current_line = '' for word in words: test_line = current_line + (' ' if current_line else '') + word if len(test_line) <= 150: current_line = test_line else: if current_line: fixed_lines.append(current_line) current_line = word if current_line: fixed_lines.append(current_line) continue fixed_lines.append(line) return '\n'.join(fixed_lines) def fix_table_formatting(content): """Fix table formatting: add spaces around pipes (MD060).""" lines = content.split('\n') fixed_lines = [] for line in lines: # Check if this is a table line (contains pipes) if '|' in line: # Fix spacing: |text| -> | text |, but preserve already-correct spacing # Match: | followed immediately by non-space or non-space followed immediately by | fixed_line = line # Fix cases like |column| -> | column | fixed_line = re.sub(r'\|\s*([^\s|][^|]*?[^\s|])\s*\|', r'| \1 |', fixed_line) # Fix edge case of single character: |a| -> | a | fixed_line = re.sub(r'\|\s*([^\s|])\s*\|', r'| \1 |', fixed_line) # Fix leading pipe spacing: |text -> | text fixed_line = re.sub(r'^\|\s*([^\s|])', r'| \1', fixed_line) # Fix trailing pipe spacing: text| -> text | fixed_line = re.sub(r'([^\s|])\s*\|$', r'\1 |', fixed_line) fixed_lines.append(fixed_line) else: fixed_lines.append(line) return '\n'.join(fixed_lines) def fix_file(filepath): """Fix all markdown linting errors in a single file.""" try: with open(filepath, 'r', encoding='utf-8') as f: content = f.read() # Apply fixes in order content = fix_code_block_languages(content) content = fix_line_length(content) content = fix_table_formatting(content) with open(filepath, 'w', encoding='utf-8') as f: f.write(content) return True except Exception as e: print(f"Error processing {filepath}: {e}", file=sys.stderr) return False def main(): """Fix markdown linting errors in all AI documentation files.""" docs_root = Path('provisioning/docs/src/ai') files_to_fix = [ 'ai-assisted-forms.md', 'architecture.md', 'config-generation.md', 'configuration.md', 'cost-management.md', 'mcp-integration.md', 'natural-language-config.md', 'rag-system.md', 'security-policies.md', ] success_count = 0 for filename in files_to_fix: filepath = docs_root / filename if filepath.exists(): if fix_file(filepath): print(f"āœ“ Fixed {filename}") success_count += 1 else: print(f"āœ— Failed to fix {filename}") else: print(f"⚠ File not found: {filename}") print(f"\nāœ“ Fixed {success_count}/{len(files_to_fix)} files") return 0 if success_count == len(files_to_fix) else 1 if __name__ == '__main__': sys.exit(main())