1extern crate pest;
2#[macro_use]
3extern crate pest_derive;
4
5use std::fs;
6use std::fs::File;
7use std::io::{BufRead, BufReader};
8use std::path::{Path, PathBuf};
9
10use thiserror::Error;
11
12pub use parser::*;
13
14use crate::code_reader::CodeReader;
15
16pub mod parser;
17pub mod code_reader;
18
19#[derive(Error, Debug)]
20pub enum WritingError {
21 #[error("io error: `{0}` ")]
22 IOError(String),
23 #[error("read file error: `{0}` ")]
24 ReadFileError(String),
25 #[error("unknown data store error")]
26 Unknown,
27}
28
29pub struct Writing {}
30
31impl Writing {
32 pub fn process_file<P: AsRef<Path>>(path: P) -> Result<String, WritingError> {
33 let path = path.as_ref().to_path_buf();
34
35 if let Err(err) = Writing::pre_process_file(&path) {
36 return Err(err);
37 };
38
39 let result = Writing::write_it(path).join("\n");
40
41 Ok(result)
42 }
43
44 fn write_it(path: PathBuf) -> Vec<String> {
45 let file = File::open(path).expect("cannot open file");
46 let reader = BufReader::new(file);
47 let mut is_lang = false;
48
49 let mut results = vec![];
50 for res in reader.lines() {
51 let line = res.expect("cannot parse line");
52 if line.starts_with("```") {
53 is_lang = !is_lang
54 }
55
56 if is_lang && line.starts_with("// doc-") {
58 let writing = parser::parse(line.replace("//", "").as_str());
59
60 if writing.code_docs.len() > 0 {
61 results.append(&mut CodeReader::read_doc_code(&writing.code_docs[0]));
62 } else if writing.code_sections.len() > 0 {
63 results.append(&mut CodeReader::read_doc_section(&writing.code_sections[0]));
64 } else if writing.code_funcs.len() > 0 {
65 results.append(&mut CodeReader::read_code_func(&writing.code_funcs[0]));
66 } else {
67 results.push(String::from(line));
68 };
69 } else {
70 results.push(String::from(line));
71 }
72 }
73
74 results
75 }
76
77fn pre_process_file(path: &PathBuf) -> Result<(), WritingError> {
79 if path.is_dir() {
80 return Err(WritingError::IOError(format!("path: {:?} is a dir", path)));
81 }
82
83 if let Err(e) = fs::read(path) {
84 return Err(WritingError::IOError(format!("read file error: {:?}", e)));
85 }
86
87 Ok(())
88 }
89}
91
92#[cfg(test)]
93mod tests {
94 use std::path::PathBuf;
95
96 use crate::Writing;
97
98 #[test]
99 fn should_convert_doc_code() {
100 let path = PathBuf::from("samples").join("doc-code.md");
101 let content = Writing::process_file(path);
102
103 assert_eq!("```writing
104extern crate pest;
105#[macro_use]
106extern crate pest_derive;
107
108use std::fs;
109```", content.expect(""));
110 }
111
112 #[test]
113 fn should_convert_doc_section() {
114 let path = PathBuf::from("samples").join("doc-section.md");
115 let content = Writing::process_file(path);
116
117 assert_eq!("```writing
118 fn pre_process_file(path: &PathBuf) -> Result<(), WritingError> {
119 if path.is_dir() {
120 return Err(WritingError::IOError(format!(\"path: {:?} is a dir\", path)));
121 }
122
123 if let Err(e) = fs::read(path) {
124 return Err(WritingError::IOError(format!(\"read file error: {:?}\", e)));
125 }
126
127 Ok(())
128 }
129```", content.expect(""));
130 }
131}