1mod error;
16mod ipynb;
17mod outputs;
18mod parser;
19
20pub use error::{SyncError, SyncResult};
21pub use ipynb::{IpynbGenerator, JupyterNotebook};
22pub use outputs::OutputCache;
23pub use parser::{NotebookCell, NotebookMetadata, RsParser};
24
25use std::path::Path;
26
27pub fn sync_to_ipynb(
29 rs_path: impl AsRef<Path>,
30 ipynb_path: impl AsRef<Path>,
31 cache: Option<&OutputCache>,
32) -> SyncResult<()> {
33 let rs_path = rs_path.as_ref();
34 let ipynb_path = ipynb_path.as_ref();
35
36 let parser = RsParser::new();
38 let (metadata, cells) = parser.parse_file(rs_path)?;
39
40 let mut generator = IpynbGenerator::new();
42 let notebook = generator.generate(&metadata, &cells, cache)?;
43
44 notebook.write_to_file(ipynb_path)?;
46
47 tracing::info!(
48 "Synced {} → {} ({} cells)",
49 rs_path.display(),
50 ipynb_path.display(),
51 cells.len()
52 );
53
54 Ok(())
55}
56
57pub fn default_ipynb_path(rs_path: impl AsRef<Path>) -> std::path::PathBuf {
59 let rs_path = rs_path.as_ref();
60 rs_path.with_extension("ipynb")
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66
67 #[test]
68 fn test_default_ipynb_path() {
69 assert_eq!(
70 default_ipynb_path("notebook.rs"),
71 std::path::PathBuf::from("notebook.ipynb")
72 );
73 assert_eq!(
74 default_ipynb_path("/path/to/my_notebook.rs"),
75 std::path::PathBuf::from("/path/to/my_notebook.ipynb")
76 );
77 }
78}