diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..762d1bd --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +.idea/ +.vscode/ + +target/ + +Cargo.lock + +*.pdb +**/*.rs.bk diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..c816dc1 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "pmp" +description = "PHP Macro Pre-processor (PMP) written in Rust." + +version = "0.1.0-alpha" +edition = "2024" + +[dependencies] +clap = { version = "^4", features = ["derive"] } + +rayon = "^1" + +once_cell = "^1" + +mago-syntax = "^1.13" +mago-interner = "^1.0.0-alpha" +mago-source = "^1.0.0-alpha" +mago-span = "^1.13" +mago-names = "^1.13" +mago-project = "^0.26" +mago-semantics = "^1.13" + +regex = "^1" +walkdir = "^2" diff --git a/src/cli/flags.rs b/src/cli/flags.rs new file mode 100644 index 0000000..a7d5e2c --- /dev/null +++ b/src/cli/flags.rs @@ -0,0 +1,49 @@ +use std::{ + ffi::OsStr, + path::PathBuf +}; +use clap::{ + Parser, + ValueHint::FilePath, +}; + +use crate::util::fs; + +#[derive(Parser, Debug)] +#[command(name = "pmp", about, version)] +pub struct Args { + #[arg(long, value_hint = FilePath, value_parser = fs::path_exists, help = "Path to PHP binary")] + php: Option, + + #[arg(long, short = 'd', hide = true)] + debug: bool, + #[arg(long, short = 'v', help = "Verbose output")] + verbose: bool, + #[arg(long, short = 'n', help = "Dry run, does not modify files or cache")] + dry_run: bool, + + #[arg(long, short = 'e', value_hint = FilePath, value_parser = fs::path_exists, default_values_os = [OsStr::new(".gitignore"), OsStr::new("vendor/")], help = "Exclude files from pre-processing, e.g. vendor/")] + exclude: Vec, + #[arg(long, short = 'c', value_hint = FilePath, value_parser = fs::valid_possible_path, default_value_os = OsStr::new(".cache"), help = "Cache directory location")] + cache_dir: Option, + #[arg(long, short = 'o', value_hint = FilePath, value_parser = fs::valid_possible_path, default_value_os = OsStr::new("."), help = "Output directory location")] + output_dir: Option, + #[arg(long, short = 'i', conflicts_with = "dry_run", help = "Invalidate cache and re-process all files")] + invalidate_cache: bool, + + #[arg(value_hint = FilePath, value_parser = fs::path_exists, default_value_os = OsStr::new("."), help = "Directory to recursively scan and pre-process")] + directory: Option, + #[arg(last = true)] + passthrough: Vec, +} + +// todo: ignore .gitignore marked content per default +// todo: diff output with verbose and ofc trace for warnings/errors +// todo: cache with file hashes and system last edited timestamp + +impl Args +{ + pub fn parse() -> Self { + ::parse() + } +} diff --git a/src/cli/mod.rs b/src/cli/mod.rs new file mode 100644 index 0000000..741db5a --- /dev/null +++ b/src/cli/mod.rs @@ -0,0 +1,3 @@ +mod flags; + +pub use flags::Args; diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..714f64a --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,2 @@ +pub mod cli; +pub mod util; diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..fcbf818 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,8 @@ +use pmp::{ cli::Args }; + +fn main() +{ + let args = Args::parse(); + + println!("{:#?}", args); +} diff --git a/src/util/fs.rs b/src/util/fs.rs new file mode 100644 index 0000000..29a2fd2 --- /dev/null +++ b/src/util/fs.rs @@ -0,0 +1,27 @@ +use regex::Regex; +use std::path::PathBuf; +use once_cell::sync::Lazy; + +static PATH_REGEX: Lazy = Lazy::new(|| { + Regex::new(r"^[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?$").unwrap() +}); + +pub fn path_exists(s: &str) -> Result { + let p = PathBuf::from(s); + p.exists().then_some(p).ok_or("path does not exist".to_string()) +} + +pub fn valid_possible_path(s: &str) -> Result +{ + let lower = s.to_ascii_lowercase(); + + if lower == "true" || lower == "false" { + return Err("boolean literal is not allowed".into()); + } + + if PATH_REGEX.is_match(s) { + return Err("numeric literal is not allowed".into()); + } + + Ok(PathBuf::from(s)) +} diff --git a/src/util/mod.rs b/src/util/mod.rs new file mode 100644 index 0000000..d521fbd --- /dev/null +++ b/src/util/mod.rs @@ -0,0 +1 @@ +pub mod fs;