opencrates 3.0.1

Enterprise-grade AI-powered Rust development companion with comprehensive automation, monitoring, and deployment capabilities
#!/usr/bin/env python3
"""
Insert a one-line `/// TODO:` doc comment before every *public* item.
Safe to run repeatedly; it will skip items that already have docs.
"""
import pathlib, re, textwrap

# Match top-level public items
RE_ITEM = re.compile(
    r'(?m)^(\s*)(pub\s+(?:async\s+)?(?:const\s+)?(?:fn|struct|enum|trait|type|union|mod)\s+)',
)

# Match public struct/enum fields and enum variant fields
RE_FIELD = re.compile(
    r'(?m)^(\s*)(pub\s+[\w_]+\s*:|[\w_]+\s*:\s*[\w<>]+,?|[\w_]+\s*\{\s*[\w_]+\s*:\s*[\w<>]+)',
)

# Match trait methods (async fn, fn in trait blocks)
RE_TRAIT_METHOD = re.compile(
    r'(?m)^(\s*)((?:async\s+)?fn\s+[\w_]+)',
)

# Match associated functions and methods in impl blocks
RE_IMPL_FN = re.compile(
    r'(?m)^(\s*)((?:#\[[^\]]*\]\s*)*pub\s+(?:async\s+)?(?:const\s+)?fn\s+)',
)

def has_doc_comment(lines, line_idx):
    """Check if the line before has a doc comment"""
    if line_idx == 0:
        return False
    i = line_idx - 1
    while i >= 0 and lines[i].strip() == '':
        i -= 1
    if i < 0:
        return False
    prev_line = lines[i].strip()
    return prev_line.startswith('///') or prev_line.startswith('//!')

def ensure_doc_toplevel(match: re.Match[str]) -> str:
    indent, decl = match.groups()
    return f'{indent}/// TODO: document this\n{indent}{decl}'

def ensure_doc_field(match: re.Match[str]) -> str:
    indent, decl = match.groups()
    return f'{indent}/// TODO: document this\n{indent}{decl}'

def ensure_doc_impl_fn(match: re.Match[str]) -> str:
    indent, decl = match.groups()
    return f'{indent}/// TODO: document this\n{indent}{decl}'

def ensure_doc_trait_method(match: re.Match[str]) -> str:
    indent, decl = match.groups()
    return f'{indent}/// TODO: document this\n{indent}{decl}'

def process_variants_in_enum(content: str) -> str:
    """Process enum variants specifically within enum blocks"""
    lines = content.splitlines()
    result_lines = []
    in_enum = False
    enum_indent = 0
    
    for i, line in enumerate(lines):
        stripped = line.strip()
        
        # Detect enum start
        if re.match(r'pub\s+enum\s+', stripped) or re.match(r'enum\s+', stripped):
            in_enum = True
            enum_indent = len(line) - len(line.lstrip())
            result_lines.append(line)
            continue
            
        # Detect enum end
        if in_enum and stripped == '}' and len(line) - len(line.lstrip()) == enum_indent:
            in_enum = False
            result_lines.append(line)
            continue
            
        # Process variants within enum
        if in_enum and stripped and not stripped.startswith('//') and not stripped.startswith('#['):
            # Check if this looks like a variant (starts with capital letter)
            variant_match = re.match(r'^(\s*)([A-Z][A-Za-z0-9_]*)', line)
            if variant_match and not has_doc_comment(lines, i):
                indent = variant_match.group(1)
                result_lines.append(f'{indent}/// TODO: document this')
                result_lines.append(line)
                continue
                
        result_lines.append(line)
    
    return '\n'.join(result_lines)

def process_trait_methods(content: str) -> str:
    """Process trait method definitions specifically within trait blocks"""
    lines = content.splitlines()
    result_lines = []
    in_trait = False
    trait_indent = 0
    
    for i, line in enumerate(lines):
        stripped = line.strip()
        
        # Detect trait start
        if re.match(r'pub\s+trait\s+', stripped) or re.match(r'trait\s+', stripped):
            in_trait = True
            trait_indent = len(line) - len(line.lstrip())
            result_lines.append(line)
            continue
            
        # Detect trait end
        if in_trait and stripped == '}' and len(line) - len(line.lstrip()) == trait_indent:
            in_trait = False
            result_lines.append(line)
            continue
            
        # Process trait methods
        if in_trait and (re.match(r'^\s*async\s+fn\s+', line) or re.match(r'^\s*fn\s+', line)):
            if not has_doc_comment(lines, i):
                indent = re.match(r'^(\s*)', line).group(1)
                result_lines.append(f'{indent}/// TODO: document this')
                result_lines.append(line)
                continue
                
        result_lines.append(line)
    
    return '\n'.join(result_lines)

def process_struct_fields(content: str) -> str:
    """Process struct fields specifically within struct blocks"""
    lines = content.splitlines()
    result_lines = []
    
    for i, line in enumerate(lines):
        # Check for struct fields that look like field: Type or pub field: Type
        if re.match(r'^\s+[\w_]+\s*:\s*[\w<>(),\s]+[,}]?\s*$', line) or \
           re.match(r'^\s+pub\s+[\w_]+\s*:\s*[\w<>(),\s]+[,}]?\s*$', line):
            if not has_doc_comment(lines, i):
                indent = re.match(r'^(\s*)', line).group(1)
                result_lines.append(f'{indent}/// TODO: document this')
                result_lines.append(line)
                continue
                
        result_lines.append(line)
    
    return '\n'.join(result_lines)

for path in pathlib.Path("src").rglob("*.rs"):
    txt = path.read_text()
    # skip generated / vendor code if any
    if "target/" in str(path): 
        continue
    
    original_txt = txt
    
    # Process top-level items
    txt = RE_ITEM.sub(ensure_doc_toplevel, txt)
    
    # Process struct fields
    txt = RE_FIELD.sub(ensure_doc_field, txt)
    
    # Process associated functions in impl blocks
    txt = RE_IMPL_FN.sub(ensure_doc_impl_fn, txt)
    
    # Process enum variants
    txt = process_variants_in_enum(txt)
    
    # Process trait methods
    txt = process_trait_methods(txt)
    
    # Process struct fields more thoroughly
    txt = process_struct_fields(txt)
    
    if txt != original_txt:
        path.write_text(txt)
        print(f"Added stub docs to {path}")