pub mod executor;
pub mod markers;
pub mod parser;
pub mod standardize;
use anyhow::{Context, Result};
use std::fs;
use std::path::Path;
pub use executor::Language;
pub use markers::WARNING;
pub use parser::{process_markdown, BacktickOptions, ProcessingState, Section};
pub use standardize::standardize_code_fences;
pub fn update_markdown_file(
input_filepath: &Path,
output_filepath: Option<&Path>,
verbose: bool,
backtick_standardize: bool,
execute: bool,
standardize: bool,
) -> Result<()> {
let content = fs::read_to_string(input_filepath)
.with_context(|| format!("Failed to read input file: {:?}", input_filepath))?;
if verbose {
eprintln!("Processing input file: {:?}", input_filepath);
}
let lines: Vec<String> = content.lines().map(|s| s.to_string()).collect();
let new_lines = process_markdown(&lines, verbose, backtick_standardize, execute)?;
let mut updated_content = new_lines.join("\n");
updated_content = updated_content.trim_end().to_string();
updated_content.push('\n');
if standardize {
if verbose {
eprintln!("Standardizing all code fences...");
}
updated_content = standardize_code_fences(&updated_content);
}
let output_path = output_filepath.unwrap_or(input_filepath);
if verbose {
eprintln!("Writing output to: {:?}", output_path);
}
fs::write(output_path, &updated_content)
.with_context(|| format!("Failed to write output file: {:?}", output_path))?;
if verbose {
eprintln!("Done!");
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
use tempfile::tempdir;
#[test]
fn test_update_markdown_file() {
let dir = tempdir().unwrap();
let input_path = dir.path().join("test.md");
let output_path = dir.path().join("output.md");
let content = r#"# Test
```python markdown-code-runner
print('Hello')
```
<!-- OUTPUT:START -->
old
<!-- OUTPUT:END -->
"#;
fs::write(&input_path, content).unwrap();
update_markdown_file(&input_path, Some(&output_path), false, false, true, false).unwrap();
let result = fs::read_to_string(&output_path).unwrap();
assert!(result.contains("Hello"));
assert!(!result.contains("old"));
}
#[test]
fn test_update_markdown_file_no_execute() {
let dir = tempdir().unwrap();
let input_path = dir.path().join("test.md");
let content = r#"# Test
```python markdown-code-runner
print('Hello')
```
<!-- OUTPUT:START -->
old
<!-- OUTPUT:END -->
"#;
fs::write(&input_path, content).unwrap();
update_markdown_file(&input_path, None, false, false, false, false).unwrap();
let result = fs::read_to_string(&input_path).unwrap();
assert!(result.contains("old"));
}
#[test]
fn test_update_markdown_file_standardize() {
let dir = tempdir().unwrap();
let input_path = dir.path().join("test.md");
let output_path = dir.path().join("output.md");
let content = r#"# Test
```python markdown-code-runner
print('Hello')
```
<!-- OUTPUT:START -->
old
<!-- OUTPUT:END -->
"#;
fs::write(&input_path, content).unwrap();
update_markdown_file(&input_path, Some(&output_path), false, false, true, true).unwrap();
let result = fs::read_to_string(&output_path).unwrap();
assert!(result.contains("```python\n"));
assert!(!result.contains("```python markdown-code-runner"));
}
}