use std::path::Path;
use crate::{
generate::{self, AuthOptions},
new::Starter,
output::CliError,
project::Project,
};
const EVENT_FIELDS: [&str; 3] = ["name:string", "public_id:token", "user:references"];
const QUESTION_FIELDS: [&str; 4] = ["event:references", "body:text", "votes:integer", "answered:boolean"];
const QA_FILES: &[(&str, &str)] = &[
("src/events.rs", include_str!("../templates/starters/qa/src/events.rs")),
("src/questions.rs", include_str!("../templates/starters/qa/src/questions.rs")),
("src/realtime.rs", include_str!("../templates/starters/qa/src/realtime.rs")),
("src/models/question.rs", include_str!("../templates/starters/qa/src/models/question.rs")),
("templates/layout.html", include_str!("../templates/starters/qa/templates/layout.html")),
("templates/home.html", include_str!("../templates/starters/qa/templates/home.html")),
("templates/events/index.html", include_str!("../templates/starters/qa/templates/events/index.html")),
("templates/events/show.html", include_str!("../templates/starters/qa/templates/events/show.html")),
("templates/events/_form.html", include_str!("../templates/starters/qa/templates/events/_form.html")),
("templates/questions/_list.html", include_str!("../templates/starters/qa/templates/questions/_list.html")),
("tests/app.rs", include_str!("../templates/starters/qa/tests/app.rs")),
("tests/events.rs", include_str!("../templates/starters/qa/tests/events.rs")),
("tests/questions.rs", include_str!("../templates/starters/qa/tests/questions.rs")),
];
const QA_REMOVED: [&str; 6] = [
"templates/questions/index.html",
"templates/questions/show.html",
"templates/questions/new.html",
"templates/questions/edit.html",
"templates/questions/_form.html",
"templates/questions/_row.html",
];
pub fn apply(starter: Starter, root: &Path, api: bool) -> Result<Vec<String>, CliError> {
match starter {
Starter::Empty => Ok(Vec::new()),
Starter::Blog => blog(root, api),
Starter::Qa => qa(root),
}
}
fn blog(root: &Path, api: bool) -> Result<Vec<String>, CliError> {
let fields = strings(&["title:string", "body:text", "published:boolean"]);
let generator = if api { "api" } else { "scaffold" };
let project = project(root, &[&["g", generator, "Post"], &fields.iter().map(String::as_str).collect::<Vec<_>>()])?;
let report = if api {
generate::api(&project, "Post", &fields, false)?
} else {
generate::scaffold(&project, "Post", &fields, false)?
};
Ok(report.created)
}
fn qa(root: &Path) -> Result<Vec<String>, CliError> {
let mut created = generate::auth(&project(root, &[&["g", "auth"]])?, &AuthOptions::default())?.created;
let fields = strings(&EVENT_FIELDS);
let project_event = project(root, &[&["g", "scaffold", "Event"], &EVENT_FIELDS])?;
created.extend(generate::scaffold(&project_event, "Event", &fields, false)?.created);
let fields = strings(&QUESTION_FIELDS);
let project_question = project(root, &[&["g", "scaffold", "Question"], &QUESTION_FIELDS, &["--realtime"]])?;
created.extend(generate::scaffold(&project_question, "Question", &fields, true)?.created);
for (path, contents) in QA_FILES {
std::fs::write(root.join(path), contents)?;
if !created.iter().any(|created| created == path) {
created.push((*path).to_owned());
}
}
for path in QA_REMOVED {
std::fs::remove_file(root.join(path))?;
created.retain(|created| created != path);
}
Ok(created)
}
fn project(root: &Path, invocation: &[&[&str]]) -> Result<Project, CliError> {
let mut project = Project::at(root.to_path_buf())?;
project.generate.invocation = invocation.iter().flat_map(|part| part.iter().map(|arg| (*arg).to_owned())).collect();
Ok(project)
}
fn strings(values: &[&str]) -> Vec<String> {
values.iter().map(|value| (*value).to_owned()).collect()
}