use crate::types::{
Fix as PluginFix, LintError as PluginLintError, Plugin, Severity as PluginSeverity,
};
use nginx_lint_common::linter::{
Fix as CommonFix, LintError as CommonLintError, LintRule, Severity as CommonSeverity,
};
use nginx_lint_common::parser::ast::Config;
use std::path::Path;
fn convert_fix(fix: PluginFix) -> CommonFix {
CommonFix {
line: fix.line,
old_text: fix.old_text,
new_text: fix.new_text,
delete_line: fix.delete_line,
insert_after: fix.insert_after,
start_offset: fix.start_offset,
end_offset: fix.end_offset,
}
}
fn convert_lint_error(err: PluginLintError) -> CommonLintError {
let severity = match err.severity {
PluginSeverity::Error => CommonSeverity::Error,
PluginSeverity::Warning => CommonSeverity::Warning,
};
let mut common = CommonLintError::new(&err.rule, &err.category, &err.message, severity);
if let (Some(line), Some(column)) = (err.line, err.column) {
common = common.with_location(line, column);
} else if let Some(line) = err.line {
common = common.with_location(line, 1);
}
for fix in err.fixes {
common = common.with_fix(convert_fix(fix));
}
common
}
pub struct NativePluginRule<P: Plugin> {
plugin: P,
name: &'static str,
category: &'static str,
description: &'static str,
severity: Option<&'static str>,
why: Option<&'static str>,
bad_example: Option<&'static str>,
good_example: Option<&'static str>,
references: Option<Vec<String>>,
min_nginx_version: Option<&'static str>,
max_nginx_version: Option<&'static str>,
}
impl<P: Plugin> Default for NativePluginRule<P> {
fn default() -> Self {
Self::new()
}
}
impl<P: Plugin> NativePluginRule<P> {
pub fn new() -> Self {
Self::with_plugin(P::default())
}
pub fn with_plugin(plugin: P) -> Self {
let spec = plugin.spec();
let name: &'static str = Box::leak(spec.name.into_boxed_str());
let category: &'static str = Box::leak(spec.category.into_boxed_str());
let description: &'static str = Box::leak(spec.description.into_boxed_str());
let severity: Option<&'static str> = spec.severity.map(|s| &*Box::leak(s.into_boxed_str()));
let why: Option<&'static str> = spec.why.map(|s| &*Box::leak(s.into_boxed_str()));
let bad_example: Option<&'static str> =
spec.bad_example.map(|s| &*Box::leak(s.into_boxed_str()));
let good_example: Option<&'static str> =
spec.good_example.map(|s| &*Box::leak(s.into_boxed_str()));
let references = spec.references;
let min_nginx_version: Option<&'static str> = spec
.min_nginx_version
.map(|s| &*Box::leak(s.into_boxed_str()));
let max_nginx_version: Option<&'static str> = spec
.max_nginx_version
.map(|s| &*Box::leak(s.into_boxed_str()));
Self {
plugin,
name,
category,
description,
severity,
why,
bad_example,
good_example,
references,
min_nginx_version,
max_nginx_version,
}
}
}
impl<P: Plugin + Send + Sync> LintRule for NativePluginRule<P> {
fn name(&self) -> &'static str {
self.name
}
fn category(&self) -> &'static str {
self.category
}
fn description(&self) -> &'static str {
self.description
}
fn check(&self, config: &Config, path: &Path) -> Vec<CommonLintError> {
let path_str = path.to_string_lossy();
let errors = self.plugin.check(config, &path_str);
errors.into_iter().map(convert_lint_error).collect()
}
fn severity(&self) -> Option<&str> {
self.severity
}
fn why(&self) -> Option<&str> {
self.why
}
fn bad_example(&self) -> Option<&str> {
self.bad_example
}
fn good_example(&self) -> Option<&str> {
self.good_example
}
fn references(&self) -> Option<Vec<String>> {
self.references.clone()
}
fn min_nginx_version(&self) -> Option<&str> {
self.min_nginx_version
}
fn max_nginx_version(&self) -> Option<&str> {
self.max_nginx_version
}
}