1mod layout;
4mod manifest;
5
6use std::fs;
7use std::path::Path;
8
9pub use layout::{ModuleFile, Role, discover, find_root, is_snake_case};
10pub use manifest::{
11 ConfigOverride, ConfigValue, Kind, Manifest, Target, is_kebab_case, parse_manifest,
12};
13
14pub fn create(dir: &Path, name: &str, kind: Kind) -> Result<(), String> {
16 if !is_kebab_case(name) {
17 return Err(format!(
18 "invalid project name `{name}`: use lower-case words separated by `-`, for example `my-app`"
19 ));
20 }
21 if dir.exists() {
22 let empty = fs::read_dir(dir)
23 .map(|mut entries| entries.next().is_none())
24 .unwrap_or(false);
25 if !empty {
26 return Err(format!(
27 "`{}` already exists and is not empty",
28 dir.display()
29 ));
30 }
31 }
32 let kind_name = match kind {
33 Kind::Cli => "cli",
34 Kind::Lib => "lib",
35 };
36 let manifest = format!(
37 "[package]\nname = \"{name}\"\nversion = \"0.1.0\"\nkind = \"{kind_name}\"\n\n[targets]\ndefault = \"ts\"\nenabled = [\"ts\", \"go\", \"rust\"]\n"
38 );
39 let (entry, source) = match kind {
40 Kind::Cli => (
41 "main.wolf",
42 "module main\n\nfunctions {\n fn main() {\n print(\"Hello, wolfpack!\")\n }\n}\n",
43 ),
44 Kind::Lib => (
45 "lib.wolf",
46 "module lib\n\nfunctions {\n /// Returns a greeting for `name`.\n pub fn greet(name: String) -> String {\n \"Hello, \" + name + \"!\"\n }\n}\n",
47 ),
48 };
49 let write = |path: &Path, text: &str| {
50 fs::write(path, text).map_err(|e| format!("cannot write `{}`: {e}", path.display()))
51 };
52 let mkdir = |path: &Path| {
53 fs::create_dir_all(path).map_err(|e| format!("cannot create `{}`: {e}", path.display()))
54 };
55 mkdir(&dir.join("src"))?;
56 mkdir(&dir.join("tests"))?;
57 mkdir(&dir.join("examples"))?;
58 write(&dir.join("wolfpack.toml"), &manifest)?;
59 write(&dir.join("src").join(entry), source)?;
60 write(&dir.join(".gitignore"), "/out/\n")?;
61 Ok(())
62}