use ryo_analysis::SymbolPath;
use crate::{OpportunityContext, OpportunityId, SuggestLocation, SuggestOpportunity};
mod bidirectional_relation;
mod generator;
mod group_inconsistency;
mod invalid_spec_relation;
mod missing_relation;
mod missing_spec;
mod orphan_spec;
mod parameterized;
mod relation_cycle;
mod relation_to_field;
pub use bidirectional_relation::BidirectionalRelation;
pub use generator::{DomainSpecGenerator, GeneratorOptions, SpecGenerator, SpecGeneratorRegistry};
pub use group_inconsistency::SpecGroupInconsistency;
pub use invalid_spec_relation::InvalidSpecRelation;
pub use missing_relation::MissingRelation;
pub use missing_spec::MissingSpecForDomainType;
pub use orphan_spec::OrphanSpec;
pub use parameterized::{ApiPatternSuggest, DomainStructSuggest};
pub use relation_cycle::SpecRelationCycle;
pub use relation_to_field::SpecRelationToField;
pub trait SpecSuggest {
fn spec_suffix(&self) -> &str {
"Spec"
}
fn is_spec_alias(&self, name: &str) -> bool {
let suffix = self.spec_suffix();
name.ends_with(suffix) && name.len() > suffix.len()
}
fn extract_base_type<'a>(&self, alias_name: &'a str) -> Option<&'a str> {
let suffix = self.spec_suffix();
if alias_name.ends_with(suffix) && alias_name.len() > suffix.len() {
Some(&alias_name[..alias_name.len() - suffix.len()])
} else {
None
}
}
fn get_module_path(&self, path: &SymbolPath) -> Option<SymbolPath> {
path.parent()
}
}
pub struct SpecDetails {
pub alias_name: Option<String>,
pub base_type: Option<String>,
pub group: Option<String>,
pub related_types: Vec<String>,
pub suggestion: Option<String>,
}
pub fn create_spec_opportunity(
code: &str,
id: OpportunityId,
targets: Vec<ryo_analysis::SymbolId>,
location: SuggestLocation,
message: impl Into<String>,
confidence: f32,
details: SpecDetails,
) -> SuggestOpportunity {
SuggestOpportunity::new(
id,
targets,
location,
message,
confidence,
OpportunityContext::Spec {
code: code.to_string(),
alias_name: details.alias_name,
base_type: details.base_type,
group: details.group,
related_types: details.related_types,
suggestion: details.suggestion,
},
)
}
pub fn is_framework_type(name: &str) -> bool {
matches!(
name,
"Spec"
| "DomainGroup"
| "Group"
| "Relations"
| "DependsOn"
| "RelatedTo"
| "PartOf"
| "String"
| "Vec"
| "Option"
| "Result"
| "Box"
| "Arc"
| "Rc"
| "HashMap"
| "HashSet"
| "BTreeMap"
| "BTreeSet"
| "u8"
| "u16"
| "u32"
| "u64"
| "u128"
| "usize"
| "i8"
| "i16"
| "i32"
| "i64"
| "i128"
| "isize"
| "f32"
| "f64"
| "bool"
| "char"
| "str"
)
}