use fix_engine_core::{PlannedFix, RenameMapping};
use konveyor_core::incident::Incident;
use std::path::Path;
pub trait LanguageFixProvider: Send + Sync {
fn should_skip_path(&self, path: &Path) -> bool;
fn post_process_lines(&self, lines: &mut [String]);
fn plan_remove_attribute(
&self,
rule_id: &str,
incident: &Incident,
file_path: &Path,
) -> Option<PlannedFix>;
fn plan_ensure_dependency(
&self,
rule_id: &str,
incident: &Incident,
package: &str,
new_version: &str,
file_path: &Path,
) -> Vec<PlannedFix>;
fn get_matched_text(&self, incident: &Incident) -> String;
fn get_matched_text_for_rename(
&self,
incident: &Incident,
mappings: &[RenameMapping],
) -> String;
fn is_whole_file_rename(&self, incident: &Incident) -> bool;
fn pre_apply(&self, _project_root: &Path) -> Option<Box<dyn std::any::Any>> {
None
}
fn post_apply(
&self,
_project_root: &Path,
_modified_files: &[std::path::PathBuf],
_pre_state: Option<Box<dyn std::any::Any>>,
) -> anyhow::Result<()> {
Ok(())
}
}
pub struct NoOpLanguageFixProvider;
impl LanguageFixProvider for NoOpLanguageFixProvider {
fn should_skip_path(&self, _path: &Path) -> bool {
false
}
fn post_process_lines(&self, _lines: &mut [String]) {
}
fn plan_remove_attribute(
&self,
_rule_id: &str,
_incident: &Incident,
_file_path: &Path,
) -> Option<PlannedFix> {
None
}
fn plan_ensure_dependency(
&self,
_rule_id: &str,
_incident: &Incident,
_package: &str,
_new_version: &str,
_file_path: &Path,
) -> Vec<PlannedFix> {
Vec::new()
}
fn get_matched_text(&self, _incident: &Incident) -> String {
String::new()
}
fn get_matched_text_for_rename(
&self,
_incident: &Incident,
_mappings: &[RenameMapping],
) -> String {
String::new()
}
fn is_whole_file_rename(&self, _incident: &Incident) -> bool {
false
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_noop_provider_skips_nothing() {
let provider = NoOpLanguageFixProvider;
assert!(!provider.should_skip_path(Path::new("/some/path")));
assert!(!provider.should_skip_path(Path::new("/node_modules/foo")));
}
#[test]
fn test_noop_provider_no_post_processing() {
let provider = NoOpLanguageFixProvider;
let mut lines = vec!["import { Foo, Foo } from 'bar';".to_string()];
provider.post_process_lines(&mut lines);
assert_eq!(lines[0], "import { Foo, Foo } from 'bar';");
}
#[test]
fn test_noop_provider_returns_none_for_remove() {
let provider = NoOpLanguageFixProvider;
let incident = konveyor_core::incident::Incident {
file_uri: "file:///test.rs".to_string(),
line_number: Some(1),
code_location: None,
message: String::new(),
code_snip: None,
variables: std::collections::BTreeMap::new(),
effort: None,
links: Vec::new(),
is_dependency_incident: false,
};
assert!(provider
.plan_remove_attribute("rule", &incident, Path::new("/test.rs"))
.is_none());
}
#[test]
fn test_noop_provider_returns_empty_for_ensure_dependency() {
let provider = NoOpLanguageFixProvider;
let incident = konveyor_core::incident::Incident {
file_uri: "file:///test.rs".to_string(),
line_number: Some(1),
code_location: None,
message: String::new(),
code_snip: None,
variables: std::collections::BTreeMap::new(),
effort: None,
links: Vec::new(),
is_dependency_incident: false,
};
assert!(provider
.plan_ensure_dependency("rule", &incident, "pkg", "1.0.0", Path::new("/test.rs"))
.is_empty());
}
#[test]
fn test_noop_provider_empty_matched_text() {
let provider = NoOpLanguageFixProvider;
let incident = konveyor_core::incident::Incident {
file_uri: String::new(),
line_number: Some(1),
code_location: None,
message: String::new(),
code_snip: None,
variables: std::collections::BTreeMap::new(),
effort: None,
links: Vec::new(),
is_dependency_incident: false,
};
assert_eq!(provider.get_matched_text(&incident), "");
assert_eq!(provider.get_matched_text_for_rename(&incident, &[]), "");
assert!(!provider.is_whole_file_rename(&incident));
}
}