use crate::lint::helpers::{
validate_namespace_and_name, validate_semantic_version_requirement_literal,
VersionLiteralLintFailureOrWarning,
};
use crate::lint::{
common_error_literals::NO_ROOT_PREFIX, lint_failure, lint_success, Lint, LintResult,
};
use crate::{Linter, MultiReaderRdfGraph};
use field33_rdftk_iri_temporary_fork::IRI as RDFTK_IRI;
use plow_ontology::constants::REGISTRY_DEPENDENCY;
use plow_package_management::metadata::get_root_prefix;
use std::any::Any;
use std::collections::HashSet;
use std::str::FromStr;
const RELATED_FIELD: &str = "`registry:dependency`";
#[derive(Debug, Default)]
pub struct ValidRegistryDependencies;
impl Lint for ValidRegistryDependencies {
fn as_any(&self) -> &dyn Any {
self
}
fn short_description(&self) -> &str {
"Check the validity of the values associated to `registry:dependency` fields."
}
fn run(
&self,
Linter {
document,
graph: MultiReaderRdfGraph { inner: rdf_graph },
..
}: &Linter,
) -> LintResult {
let rdf_factory = field33_rdftk_core_temporary_fork::simple::statement::statement_factory();
if let Some(root_prefix) = get_root_prefix(document) {
let graph_ref = rdf_graph;
let graph = graph_ref.borrow();
#[allow(clippy::unwrap_used)]
let annotations = graph
.statements()
.filter(|statement| {
statement.subject()
== &rdf_factory
.named_subject(RDFTK_IRI::from_str(root_prefix).unwrap().into())
&& statement.predicate()
== &RDFTK_IRI::from_str(REGISTRY_DEPENDENCY).unwrap().into()
})
.collect::<HashSet<_>>();
if annotations.is_empty() {
return lint_success!("Your file does not have any dependencies.");
}
let mut failures = vec![];
let mut warnings = vec![];
for annotation in &annotations {
if let Some(literal) = annotation.object().as_literal() {
let dependency_literal = literal.lexical_form();
let lint_prefix =
format!("The {RELATED_FIELD} with stated dependency {dependency_literal},");
let (dependency_name, mut version) =
literal.lexical_form().split(' ').enumerate().fold(
(String::default(), String::default()),
|(mut name, mut version), (index, part)| {
if index > 0 {
version.push(' ');
version.push_str(part);
} else {
name = part.to_owned();
}
(name, version)
},
);
version.remove(0);
if dependency_name.is_empty() || version.is_empty() {
failures.push(format!(
"{lint_prefix} should have both name and version separated by a single space."
));
continue;
}
if let Err(failure) = validate_namespace_and_name(&dependency_name) {
failures.push(format!("{lint_prefix} {failure}"));
}
if let Err(failures_or_warnings) =
validate_semantic_version_requirement_literal(&version)
{
use VersionLiteralLintFailureOrWarning::*;
for failure_or_warning in failures_or_warnings {
match failure_or_warning {
Warning(warning) => {
warnings.push(format!("{lint_prefix} {warning}"));
}
Failure(failure) => {
failures.push(format!("{lint_prefix} {failure}"));
}
}
}
}
} else {
failures.push(format!(
"The value for {RELATED_FIELD} with stated dependency should be a literal."
));
}
}
if !failures.is_empty() {
return LintResult::Failure(failures);
}
if !warnings.is_empty() {
return LintResult::Warning(warnings);
}
lint_success!(format!(
"All values attached to {RELATED_FIELD} fields are valid."
))
} else {
lint_failure!(NO_ROOT_PREFIX)
}
}
}