use super::definitions::Definition;
use super::identifiers::IdentifierReference;
use crate::cache::ModuleCache;
use crate::load::ModuleLoader;
use crate::model::modules::Module;
use crate::model::HasBody;
pub trait MaybeIncomplete {
fn is_incomplete(&self, top: &Module, cache: &ModuleCache) -> bool;
}
pub trait Validate {
fn validate(
&self,
top: &Module,
cache: &ModuleCache,
loader: &impl ModuleLoader,
check_constraints: bool,
);
}
pub fn find_definition<'a>(
name: &IdentifierReference,
current: &'a Module,
cache: &'a ModuleCache,
) -> Option<&'a Definition> {
match name {
IdentifierReference::Identifier(ref name) => current.body().get_definition(name),
IdentifierReference::QualifiedIdentifier(ref name) => {
if let Some(module) = cache.get(name.module()) {
module.body().get_definition(name.member())
} else {
None
}
}
}
}
#[cfg(feature = "terms")]
pub mod terms {
use std::collections::HashMap;
use crate::load::ModuleLoader;
use crate::model::*;
use crate::model::annotations::*;
use crate::model::constraints::*;
use crate::model::definitions::*;
use crate::model::identifiers::*;
use crate::model::members::*;
use crate::model::modules::*;
use sdml_error::Error;
use sdml_error::diagnostics::functions::deprecated_term_used;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug)]
#[derive(Deserialize, Serialize)]
pub struct TermSet {
name: String,
#[serde(skip_serializing_if = "Option::is_none")]
version: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
description: Option<String>,
terms: HashMap<String, Term>,
}
#[derive(Clone, Debug)]
#[derive(Deserialize, Serialize)]
pub struct Term {
#[serde(skip_serializing_if = "Option::is_none", with = "serde_regex")]
regex: Option<regex::Regex>,
alternative_terms: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
reason: Option<String>,
}
const DEFAULT_RULES: &str = include_str!("default_terms.json");
pub fn default_term_set() -> Result<TermSet, Error> {
Ok(serde_json::from_str(DEFAULT_RULES).unwrap())
}
pub fn validate_module_terms(module: &Module, term_set: &TermSet, loader: &impl ModuleLoader) {
let mut validator = Validator::from(term_set);
module.name().validate_terms(&mut validator, module, loader);
for annotation in module.body().annotations() {
annotation.validate_terms(&mut validator, module, loader);
}
for definition in module.body().definitions() {
definition.validate_terms(&mut validator, module, loader);
}
}
#[derive(Clone, Debug)]
struct TermInfo<'a> {
regex: regex::Regex,
alternative_terms: &'a Vec<String>,
reason: &'a Option<String>,
}
#[derive(Clone, Debug)]
struct Validator<'a> {
term_map: HashMap<String, TermInfo<'a>>,
seen: HashSet<String>,
}
impl<'a> From<&'a TermSet> for Validator<'a> {
fn from(term_set: &'a TermSet) -> Self {
let mut term_map: HashMap<String, TermInfo<'a>> = Default::default();
for (term, info) in &term_set.terms {
let regex = if let Some(regex) = &info.regex {
regex.clone()
} else {
regex::Regex::new(&format!("(?i)\\b{}\\b", term)).unwrap()
};
let new_info = TermInfo {
regex,
alternative_terms: &info.alternative_terms,
reason: &info.reason,
};
term_map.insert(term.clone(), new_info);
}
Self { term_map, seen: Default::default() }
}
}
impl Validator<'_> {
fn check_for_matches<S>(&mut self, value: S, span: Option<&Span>, top: &Module, loader: &impl ModuleLoader)
where
S: Into<String>
{
let value = value.into();
if self.seen.insert(value.clone()) {
for (term, info) in &self.term_map {
if info.regex.is_match(value.as_ref()) {
loader.report(&deprecated_term_used(
top.file_id().copied().unwrap_or_default(),
span.map(|span| span.byte_range()),
&value,
term,
info.alternative_terms,
info.reason.as_ref(),
)).unwrap()
}
}
}
}
}
trait ValidateTerms {
fn validate_terms(&self, validator: &mut Validator<'_>, top: &Module, loader: &impl ModuleLoader);
}
impl ValidateTerms for Identifier {
fn validate_terms(&self, validator: &mut Validator<'_>, top: &Module, loader: &impl ModuleLoader) {
validator.check_for_matches(self, self.source_span(), top, loader);
}
}
impl ValidateTerms for QualifiedIdentifier {
fn validate_terms(&self, validator: &mut Validator<'_>, top: &Module, loader: &impl ModuleLoader) {
self.module().validate_terms(validator, top, loader);
self.member().validate_terms(validator, top, loader);
}
}
impl ValidateTerms for IdentifierReference {
fn validate_terms(&self, validator: &mut Validator<'_>, top: &Module, loader: &impl ModuleLoader) {
match self {
Self::Identifier(v) => v.validate_terms(validator, top, loader),
Self::QualifiedIdentifier(v) => v.validate_terms(validator, top, loader),
}
}
}
impl ValidateTerms for Annotation {
fn validate_terms(&self, validator: &mut Validator<'_>, top: &Module, loader: &impl ModuleLoader) {
match self {
Self::Property(v) => v.validate_terms(validator, top, loader),
Self::Constraint(v) => v.validate_terms(validator, top, loader),
}
}
}
impl ValidateTerms for AnnotationProperty {
fn validate_terms(&self, validator: &mut Validator<'_>, top: &Module, loader: &impl ModuleLoader) {
self.name_reference().validate_terms(validator, top, loader);
}
}
impl ValidateTerms for AnnotationOnlyBody {
fn validate_terms(&self, validator: &mut Validator<'_>, top: &Module, loader: &impl ModuleLoader) {
for annotation in self.annotations() {
annotation.validate_terms(validator, top, loader);
}
}
}
impl ValidateTerms for Constraint {
fn validate_terms(&self, validator: &mut Validator<'_>, top: &Module, loader: &impl ModuleLoader) {
self.name().validate_terms(validator, top, loader);
}
}
impl ValidateTerms for Definition {
fn validate_terms(&self, validator: &mut Validator<'_>, top: &Module, loader: &impl ModuleLoader) {
match self {
Self::Datatype(v) => v.validate_terms(validator, top, loader),
Self::Entity(v) => v.validate_terms(validator, top, loader),
Self::Enum(v) => v.validate_terms(validator, top, loader),
Self::Event(v) => v.validate_terms(validator, top, loader),
Self::Property(v) => v.validate_terms(validator, top, loader),
Self::Rdf(v) => v.validate_terms(validator, top, loader),
Self::Structure(v) => v.validate_terms(validator, top, loader),
Self::TypeClass(v) => v.validate_terms(validator, top, loader),
Self::Union(v) => v.validate_terms(validator, top, loader),
}
}
}
impl ValidateTerms for DatatypeDef {
fn validate_terms(&self, validator: &mut Validator<'_>, top: &Module, loader: &impl ModuleLoader) {
self.name().validate_terms(validator, top, loader);
self.base_type().validate_terms(validator, top, loader);
if let Some(body) = self.body() {
body.validate_terms(validator, top, loader);
}
}
}
impl ValidateTerms for EntityDef {
fn validate_terms(&self, validator: &mut Validator<'_>, top: &Module, loader: &impl ModuleLoader) {
self.name().validate_terms(validator, top, loader);
if let Some(body) = self.body() {
for annotation in body.annotations() {
annotation.validate_terms(validator, top, loader);
}
for member in body.members() {
member.validate_terms(validator, top, loader);
}
}
}
}
impl ValidateTerms for EnumDef {
fn validate_terms(&self, validator: &mut Validator<'_>, top: &Module, loader: &impl ModuleLoader) {
self.name().validate_terms(validator, top, loader);
if let Some(body) = self.body() {
for annotation in body.annotations() {
annotation.validate_terms(validator, top, loader);
}
}
todo!("validate variants")
}
}
impl ValidateTerms for EventDef {
fn validate_terms(&self, validator: &mut Validator<'_>, top: &Module, loader: &impl ModuleLoader) {
self.name().validate_terms(validator, top, loader);
self.event_source().validate_terms(validator, top, loader);
if let Some(body) = self.body() {
for annotation in body.annotations() {
annotation.validate_terms(validator, top, loader);
for member in body.members() {
member.validate_terms(validator, top, loader);
}
}
}
}
}
impl ValidateTerms for PropertyDef {
fn validate_terms(&self, validator: &mut Validator<'_>, top: &Module, loader: &impl ModuleLoader) {
self.name().validate_terms(validator, top, loader);
if let Some(body) = self.body() {
for annotation in body.annotations() {
annotation.validate_terms(validator, top, loader);
}
}
todo!("validate roles")
}
}
impl ValidateTerms for RdfDef {
fn validate_terms(&self, validator: &mut Validator<'_>, top: &Module, loader: &impl ModuleLoader) {
self.name().validate_terms(validator, top, loader);
for annotation in self.body().annotations() {
annotation.validate_terms(validator, top, loader);
}
}
}
impl ValidateTerms for StructureDef {
fn validate_terms(&self, validator: &mut Validator<'_>, top: &Module, loader: &impl ModuleLoader) {
self.name().validate_terms(validator, top, loader);
if let Some(body) = self.body() {
for annotation in body.annotations() {
annotation.validate_terms(validator, top, loader);
}
for member in body.members() {
member.validate_terms(validator, top, loader);
}
}
}
}
impl ValidateTerms for TypeClassDef {
fn validate_terms(&self, validator: &mut Validator<'_>, top: &Module, loader: &impl ModuleLoader) {
self.name().validate_terms(validator, top, loader);
if let Some(body) = self.body() {
for annotation in body.annotations() {
annotation.validate_terms(validator, top, loader);
}
}
todo!("validate all")
}
}
impl ValidateTerms for UnionDef {
fn validate_terms(&self, validator: &mut Validator<'_>, top: &Module, loader: &impl ModuleLoader) {
self.name().validate_terms(validator, top, loader);
if let Some(body) = self.body() {
for annotation in body.annotations() {
annotation.validate_terms(validator, top, loader);
}
}
todo!("validate variants")
}
}
impl ValidateTerms for Member {
fn validate_terms(&self, validator: &mut Validator<'_>, top: &Module, loader: &impl ModuleLoader) {
self.name().validate_terms(validator, top, loader);
match self.kind() {
MemberKind::PropertyReference(v) => v.validate_terms(validator, top, loader),
MemberKind::Definition(v) => v.validate_terms(validator, top, loader),
}
}
}
impl ValidateTerms for MemberDef {
fn validate_terms(&self, validator: &mut Validator<'_>, top: &Module, loader: &impl ModuleLoader) {
if let Some(inverse_name) = self.inverse_name() {
inverse_name.validate_terms(validator, top, loader);
}
self.target_type().validate_terms(validator, top, loader);
if let Some(body) = self.body() {
body.validate_terms(validator, top, loader);
}
}
}
impl ValidateTerms for TypeReference {
fn validate_terms(&self, validator: &mut Validator<'_>, top: &Module, loader: &impl ModuleLoader) {
match self {
Self::Unknown => {},
Self::Type(v) => v.validate_terms(validator, top, loader),
Self::FeatureSet(v) => v.validate_terms(validator, top, loader),
Self::MappingType(v) => {
v.domain().validate_terms(validator, top, loader);
v.range().validate_terms(validator, top, loader);
},
}
}
}
}