markdown-code-runner 0.1.0

Automatically update Markdown files with code block output
Documentation
//! Code fence standardization utilities.

use once_cell::sync::Lazy;
use regex::Regex;

/// Pattern to match code fence with markdown-code-runner and optional options.
static STANDARDIZE_PATTERN: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"^(```\w+)\s+markdown-code-runner(?:\s+\S+=\S+)*\s*$").unwrap());

/// Strip markdown-code-runner modifiers from all code fence language identifiers.
///
/// This is useful for making markdown files compatible with standard markdown
/// processors like mkdocs and pandoc, which don't understand the
/// `python markdown-code-runner` syntax.
///
/// # Examples
///
/// ```
/// use markdown_code_runner::standardize::standardize_code_fences;
///
/// let content = "```python markdown-code-runner\nprint(\"hello\")\n```";
/// let result = standardize_code_fences(content);
/// assert_eq!(result, "```python\nprint(\"hello\")\n```");
/// ```
pub fn standardize_code_fences(content: &str) -> String {
    let mut result = String::new();
    for line in content.lines() {
        if let Some(caps) = STANDARDIZE_PATTERN.captures(line) {
            result.push_str(&caps[1]);
        } else {
            result.push_str(line);
        }
        result.push('\n');
    }
    // Remove the trailing newline we added if the original content didn't have one
    if !content.ends_with('\n') && result.ends_with('\n') {
        result.pop();
    }
    result
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_standardize_basic() {
        let content = "```python markdown-code-runner\nprint('hello')\n```";
        let expected = "```python\nprint('hello')\n```";
        assert_eq!(standardize_code_fences(content), expected);
    }

    #[test]
    fn test_standardize_with_options() {
        let content = "```python markdown-code-runner filename=test.py debug=true\ncode here\n```";
        let expected = "```python\ncode here\n```";
        assert_eq!(standardize_code_fences(content), expected);
    }

    #[test]
    fn test_standardize_multiple() {
        let content = r#"```python markdown-code-runner
first
```
text
```bash markdown-code-runner
second
```
more text
```rust markdown-code-runner filename=test.rs
third
```"#;
        let expected = r#"```python
first
```
text
```bash
second
```
more text
```rust
third
```"#;
        assert_eq!(standardize_code_fences(content), expected);
    }

    #[test]
    fn test_standardize_preserves_text_references() {
        let content =
            "Using `markdown-code-runner` is easy.\n```python markdown-code-runner\ncode\n```";
        let expected = "Using `markdown-code-runner` is easy.\n```python\ncode\n```";
        assert_eq!(standardize_code_fences(content), expected);
    }

    #[test]
    fn test_standardize_leaves_normal_fences() {
        let content = "```python\ncode\n```\n```javascript\nmore\n```";
        assert_eq!(standardize_code_fences(content), content);
    }
}