From 0dd35ff2b2ceffdb926953fdacc7d30e1968047d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 25 Oct 2019 14:16:46 +0300 Subject: auto-generate assists docs and tests --- xtask/src/codegen/gen_assists_docs.rs | 123 ++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 xtask/src/codegen/gen_assists_docs.rs (limited to 'xtask/src/codegen/gen_assists_docs.rs') diff --git a/xtask/src/codegen/gen_assists_docs.rs b/xtask/src/codegen/gen_assists_docs.rs new file mode 100644 index 000000000..654ae09d6 --- /dev/null +++ b/xtask/src/codegen/gen_assists_docs.rs @@ -0,0 +1,123 @@ +use std::{fs, path::Path}; + +use crate::{ + codegen::{self, extract_comment_blocks, Mode}, + project_root, Result, +}; + +pub fn generate_assists_docs(mode: Mode) -> Result<()> { + let assists = collect_assists()?; + generate_tests(&assists, mode)?; + generate_docs(&assists, mode)?; + Ok(()) +} + +#[derive(Debug)] +struct Assist { + id: String, + doc: String, + before: String, + after: String, +} + +fn collect_assists() -> Result> { + let mut res = Vec::new(); + for entry in fs::read_dir(project_root().join(codegen::ASSISTS_DIR))? { + let entry = entry?; + let path = entry.path(); + if path.is_file() { + collect_file(&mut res, path.as_path())?; + } + } + res.sort_by(|lhs, rhs| lhs.id.cmp(&rhs.id)); + return Ok(res); + + fn collect_file(acc: &mut Vec, path: &Path) -> Result<()> { + let text = fs::read_to_string(path)?; + let comment_blocks = extract_comment_blocks(&text); + + for block in comment_blocks { + // FIXME: doesn't support blank lines yet, need to tweak + // `extract_comment_blocks` for that. + let mut lines = block.iter(); + let first_line = lines.next().unwrap(); + if !first_line.starts_with("Assist: ") { + continue; + } + let id = first_line["Assist: ".len()..].to_string(); + assert!(id.chars().all(|it| it.is_ascii_lowercase() || it == '_')); + + let doc = take_until(lines.by_ref(), "```"); + let before = take_until(lines.by_ref(), "```"); + + assert_eq!(lines.next().unwrap().as_str(), "->"); + assert_eq!(lines.next().unwrap().as_str(), "```"); + let after = take_until(lines.by_ref(), "```"); + acc.push(Assist { id, doc, before, after }) + } + + fn take_until<'a>(lines: impl Iterator, marker: &str) -> String { + let mut buf = Vec::new(); + for line in lines { + if line == marker { + break; + } + buf.push(line.clone()); + } + buf.join("\n") + } + Ok(()) + } +} + +fn generate_tests(assists: &[Assist], mode: Mode) -> Result<()> { + let mut buf = String::from("use super::check;\n"); + + for assist in assists.iter() { + let test = format!( + r######" +#[test] +fn doctest_{}() {{ + check( + "{}", +r#####" +{} +"#####, r#####" +{} +"#####) +}} +"######, + assist.id, assist.id, assist.before, assist.after + ); + + buf.push_str(&test) + } + let buf = codegen::reformat(buf)?; + codegen::update(&project_root().join(codegen::ASSISTS_TESTS), &buf, mode) +} + +fn generate_docs(assists: &[Assist], mode: Mode) -> Result<()> { + let mut buf = String::from("# Assists\n"); + + for assist in assists { + let docs = format!( + " +## `{}` + +{} + +```rust +// BEFORE +{} + +// AFTER +{} +``` +", + assist.id, assist.doc, assist.before, assist.after + ); + buf.push_str(&docs); + } + + codegen::update(&project_root().join(codegen::ASSISTS_DOCS), &buf, mode) +} -- cgit v1.2.3