-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
234 additions
and
16 deletions.
There are no files selected for viewing
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
[package] | ||
name = "cddl-linter" | ||
version = "0.1.0" | ||
edition.workspace = true | ||
license.workspace = true | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[lints] | ||
workspace = true | ||
|
||
[dependencies] | ||
cddl-parser = { path = "../cddl-parser", version = "0.1.0" } | ||
clap = { version = "4.5.3", features = ["derive", "env"] } | ||
anyhow = "1.0.71" | ||
console = "0.15.8" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# CDDL linter | ||
|
||
[CDDL](https://datatracker.ietf.org/doc/html/rfc8610) (Concise Data Definition Language) | ||
linting cli tool, | ||
enabling users to check their CDDL code for errors, inconsistencies, and compliance with the CDDL specification. | ||
|
||
## Install | ||
|
||
To install this tool run | ||
|
||
```shell | ||
cargo install --git https://github.com/input-output-hk/hermes.git cddl-linter | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
//! CLI interpreter for the cbork lint tool | ||
|
||
use std::{path::PathBuf, process::exit}; | ||
|
||
use clap::Parser; | ||
use console::{style, Emoji}; | ||
|
||
/// CDDL linter cli tool | ||
#[derive(Parser)] | ||
pub(crate) struct Cli { | ||
/// Path to the CDDL files definition. | ||
/// It could path to the standalone file, or to the directory. | ||
/// So all files with the `.cddl` extension inside the directory will be linted. | ||
path: PathBuf, | ||
} | ||
|
||
impl Cli { | ||
/// Execute the CLI | ||
pub(crate) fn exec(self) { | ||
let res = if self.path.is_file() { | ||
check_file_with_print(&self.path) | ||
} else { | ||
check_dir_with_print(&self.path) | ||
}; | ||
|
||
if !res { | ||
exit(1); | ||
} | ||
} | ||
} | ||
|
||
/// Check the CDDL file, return any errors | ||
fn check_file(file_path: &PathBuf) -> anyhow::Result<()> { | ||
let mut content = std::fs::read_to_string(file_path)?; | ||
cddl_parser::parse_cddl(&mut content, &cddl_parser::Extension::CDDLParser)?; | ||
Ok(()) | ||
} | ||
|
||
/// Check the CDDL file, prints any errors into the stdout | ||
fn check_file_with_print(file_path: &PathBuf) -> bool { | ||
if let Err(e) = check_file(file_path) { | ||
println!( | ||
"{} {}:\n{}", | ||
Emoji::new("🚨", "Errors"), | ||
file_path.display(), | ||
style(e).red() | ||
); | ||
false | ||
} else { | ||
println!("{} {}", Emoji::new("✅", "Success"), file_path.display(),); | ||
true | ||
} | ||
} | ||
|
||
/// CDDL file extension. Filter directory files to apply the linter only on the CDDL | ||
/// files. | ||
const CDDL_FILE_EXTENSION: &str = "cddl"; | ||
|
||
/// Check the directory, prints any errors into the stdout | ||
fn check_dir_with_print(dir_path: &PathBuf) -> bool { | ||
let fun = |dir_path| -> anyhow::Result<bool> { | ||
let mut res = true; | ||
for entry in std::fs::read_dir(dir_path)? { | ||
let entry = entry?; | ||
let path = entry.path(); | ||
if path.is_file() { | ||
if path.extension().is_some_and(|e| e.eq(CDDL_FILE_EXTENSION)) { | ||
res = check_file_with_print(&path); | ||
} | ||
} else if path.is_dir() { | ||
res = check_dir_with_print(&path); | ||
} | ||
} | ||
Ok(res) | ||
}; | ||
|
||
if let Err(e) = fun(dir_path) { | ||
println!( | ||
"{} {}:\n{}", | ||
Emoji::new("🚨", "Errors"), | ||
dir_path.display(), | ||
style(e).red() | ||
); | ||
false | ||
} else { | ||
true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
//! Errors module. | ||
|
||
#![allow(dead_code)] | ||
|
||
use std::{error::Error, fmt::Display}; | ||
|
||
/// Errors struct which holds a collection of errors | ||
#[derive(Debug)] | ||
pub(crate) struct Errors(Vec<anyhow::Error>); | ||
|
||
impl Error for Errors {} | ||
|
||
impl Display for Errors { | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
for err in &self.0 { | ||
write!(f, "- ")?; | ||
let err_str = err.to_string(); | ||
let mut err_lines = err_str.lines(); | ||
if let Some(first_line) = err_lines.next() { | ||
writeln!(f, "{first_line}")?; | ||
for line in err_lines { | ||
writeln!(f, " {line}")?; | ||
} | ||
} | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl Errors { | ||
/// Create a new empty `Errors` | ||
pub(crate) fn new() -> Self { | ||
Self(Vec::new()) | ||
} | ||
|
||
/// Returns `true` if the `Errors` contains no elements. | ||
pub(crate) fn is_empty(&self) -> bool { | ||
self.0.is_empty() | ||
} | ||
|
||
/// Add an error to the `Errors` | ||
pub(crate) fn add_err<E>(&mut self, err: E) | ||
where E: Into<anyhow::Error> { | ||
let err = err.into(); | ||
match err.downcast::<Errors>() { | ||
Ok(errs) => self.0.extend(errs.0), | ||
Err(err) => self.0.push(err), | ||
} | ||
} | ||
|
||
/// Return a closure that adds an error to the `Errors` | ||
pub(crate) fn get_add_err_fn<E>(&mut self) -> impl FnOnce(E) + '_ | ||
where E: Into<anyhow::Error> { | ||
|err| self.add_err(err) | ||
} | ||
|
||
/// Return errors if `Errors` is not empty or return `Ok(val)` | ||
pub(crate) fn return_result<T>(self, val: T) -> anyhow::Result<T> { | ||
if self.0.is_empty() { | ||
Ok(val) | ||
} else { | ||
Err(self.into()) | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn test_errors() { | ||
let mut errors_1 = Errors::new(); | ||
errors_1.add_err(anyhow::anyhow!("error 1")); | ||
errors_1.add_err(anyhow::anyhow!("error 2")); | ||
|
||
let mut errors_2 = Errors::new(); | ||
errors_2.add_err(anyhow::anyhow!("error 3")); | ||
errors_2.add_err(anyhow::anyhow!("error 4")); | ||
|
||
let mut combined_errors = Errors::new(); | ||
combined_errors.add_err(errors_1); | ||
combined_errors.add_err(errors_2); | ||
|
||
assert_eq!( | ||
combined_errors.to_string(), | ||
"- error 1\n- error 2\n- error 3\n- error 4\n" | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
//! CDDL linter cli tool | ||
|
||
mod cli; | ||
|
||
fn main() { | ||
use clap::Parser; | ||
|
||
cli::Cli::parse().exec(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters