init
This commit is contained in:
commit
e76f1e4419
5 changed files with 704 additions and 0 deletions
32
src/args.rs
Normal file
32
src/args.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
use clap::{arg, command, Arg, ArgMatches};
|
||||
|
||||
pub fn get_args() -> ArgMatches {
|
||||
command!()
|
||||
.about("Generate json patch file for two markdown files with frontmatter")
|
||||
.arg(arg!([file] "First File").required(true))
|
||||
.arg(arg!([file2] "Second File").required(true))
|
||||
.arg(arg!(-p --pretty "Output formatted json patch").required(false))
|
||||
.arg(arg!(-a --add "Only output add operations").required(false))
|
||||
.arg(arg!(-m --modify "Only output modify operations").required(false))
|
||||
.arg(arg!(-d --delete "Only output delete operations").required(false))
|
||||
.arg(
|
||||
Arg::new("test")
|
||||
.short('t')
|
||||
.long("test")
|
||||
.required(false)
|
||||
.value_names(&["key", "val"])
|
||||
.number_of_values(2)
|
||||
.help("Add test case to json patch"),
|
||||
)
|
||||
.arg(
|
||||
arg!(-x --exclude <JSONPATH>... "Exclude json path from diff")
|
||||
.required(false)
|
||||
.conflicts_with("keys"),
|
||||
)
|
||||
.arg(
|
||||
arg!(-k --keys <JSONPATH>... "Only include the specified json paths in diff")
|
||||
.required(false)
|
||||
.conflicts_with("exclude"),
|
||||
)
|
||||
.get_matches()
|
||||
}
|
170
src/main.rs
Normal file
170
src/main.rs
Normal file
|
@ -0,0 +1,170 @@
|
|||
use json_patch::PatchOperation;
|
||||
|
||||
mod args;
|
||||
|
||||
trait ErrorExit {
|
||||
type T;
|
||||
|
||||
fn quit_on_error(self, msg: &str) -> Self::T;
|
||||
}
|
||||
|
||||
impl<T, E> ErrorExit for Result<T, E> {
|
||||
type T = T;
|
||||
|
||||
fn quit_on_error(self, msg: &str) -> T {
|
||||
self.map_or_else(
|
||||
|_| {
|
||||
eprintln!("{} {msg}", console::Style::new().red().apply_to("Error:"));
|
||||
std::process::exit(1);
|
||||
},
|
||||
|res| res,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// get frontmatter from markdown document
|
||||
#[must_use]
|
||||
pub fn get_frontmatter(markdown: &str) -> Option<String> {
|
||||
let frontmatter_regex = regex::Regex::new(r"(?s)^---\s*\n(.*?)\n---").unwrap();
|
||||
|
||||
frontmatter_regex.captures(markdown).and_then(|captures| {
|
||||
let frontmatter = captures.get(1).map(|m| m.as_str().to_string());
|
||||
|
||||
frontmatter
|
||||
})
|
||||
}
|
||||
|
||||
fn get_frontmatter_from_file(path: &str) -> serde_yaml::Value {
|
||||
serde_yaml::from_str(
|
||||
&get_frontmatter(&std::fs::read_to_string(path).quit_on_error("Could not read file"))
|
||||
.ok_or(0)
|
||||
.quit_on_error("Could not get frontmatter"),
|
||||
)
|
||||
.quit_on_error("Could not deserialize frontmatter")
|
||||
}
|
||||
|
||||
fn remove_add_operations(patch: Vec<PatchOperation>) -> Vec<PatchOperation> {
|
||||
patch
|
||||
.into_iter()
|
||||
.filter(|x| !matches!(x, json_patch::PatchOperation::Add(_)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn remove_modify_operations(patch: Vec<PatchOperation>) -> Vec<PatchOperation> {
|
||||
patch
|
||||
.into_iter()
|
||||
.filter(|x| {
|
||||
!matches!(
|
||||
x,
|
||||
json_patch::PatchOperation::Replace(_)
|
||||
| json_patch::PatchOperation::Move(_)
|
||||
| json_patch::PatchOperation::Copy(_)
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn remove_delete_operations(patch: Vec<PatchOperation>) -> Vec<PatchOperation> {
|
||||
patch
|
||||
.into_iter()
|
||||
.filter(|x| !matches!(x, json_patch::PatchOperation::Remove(_)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn exclude_json_paths(patch: &serde_json::Value, paths: &[String]) -> serde_json::Value {
|
||||
let filtered: Vec<serde_json::Value> = patch
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.filter(|x| {
|
||||
let mut is_excluded = false;
|
||||
for exclude in paths {
|
||||
if x.as_object()
|
||||
.unwrap()
|
||||
.get("path")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.starts_with(exclude)
|
||||
{
|
||||
is_excluded = true;
|
||||
}
|
||||
}
|
||||
!is_excluded
|
||||
})
|
||||
.cloned()
|
||||
.collect();
|
||||
serde_json::to_value(filtered).unwrap()
|
||||
}
|
||||
|
||||
fn include_only_json_paths(patch: &serde_json::Value, paths: &[String]) -> serde_json::Value {
|
||||
let filtered: Vec<serde_json::Value> = patch
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.filter(|x| {
|
||||
let mut is_included = false;
|
||||
for include in paths {
|
||||
if x.as_object()
|
||||
.unwrap()
|
||||
.get("path")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.starts_with(include)
|
||||
{
|
||||
is_included = true;
|
||||
}
|
||||
}
|
||||
is_included
|
||||
})
|
||||
.cloned()
|
||||
.collect();
|
||||
serde_json::to_value(filtered).unwrap()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = args::get_args();
|
||||
|
||||
let f1 = get_frontmatter_from_file(args.get_one::<String>("file").unwrap());
|
||||
let f2 = get_frontmatter_from_file(args.get_one::<String>("file2").unwrap());
|
||||
|
||||
let mut diff = json_patch::diff(
|
||||
&serde_json::to_value(f1).unwrap(),
|
||||
&serde_json::to_value(f2).unwrap(),
|
||||
)
|
||||
.to_vec();
|
||||
|
||||
if args.get_flag("add") | args.get_flag("modify") | args.get_flag("delete") {
|
||||
if !args.get_flag("add") {
|
||||
diff = remove_add_operations(diff);
|
||||
}
|
||||
if !args.get_flag("modify") {
|
||||
diff = remove_modify_operations(diff);
|
||||
}
|
||||
if !args.get_flag("delete") {
|
||||
diff = remove_delete_operations(diff);
|
||||
}
|
||||
}
|
||||
|
||||
let mut diff = serde_json::to_value(diff).unwrap();
|
||||
|
||||
if let Some(excludes) = args.get_many::<String>("exclude") {
|
||||
let excludes: Vec<String> = excludes.cloned().collect();
|
||||
diff = exclude_json_paths(&diff, &excludes);
|
||||
}
|
||||
|
||||
if let Some(includes) = args.get_many::<String>("keys") {
|
||||
let includes: Vec<String> = includes.cloned().collect();
|
||||
diff = include_only_json_paths(&diff, &includes);
|
||||
}
|
||||
|
||||
println!(
|
||||
"{}",
|
||||
if args.get_flag("pretty") {
|
||||
serde_json::to_string_pretty(&diff).unwrap()
|
||||
} else {
|
||||
serde_json::to_string(&diff).unwrap()
|
||||
}
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue