nginx_lint_plugin/
native.rs1use crate::types::{
32 Fix as PluginFix, LintError as PluginLintError, Plugin, Severity as PluginSeverity,
33};
34use nginx_lint_common::linter::{
35 Fix as CommonFix, LintError as CommonLintError, LintRule, Severity as CommonSeverity,
36};
37use nginx_lint_common::parser::ast::Config;
38use std::path::Path;
39
40fn convert_fix(fix: PluginFix) -> CommonFix {
42 CommonFix {
43 line: fix.line,
44 old_text: fix.old_text,
45 new_text: fix.new_text,
46 delete_line: fix.delete_line,
47 insert_after: fix.insert_after,
48 start_offset: fix.start_offset,
49 end_offset: fix.end_offset,
50 }
51}
52
53fn convert_lint_error(err: PluginLintError) -> CommonLintError {
55 let severity = match err.severity {
56 PluginSeverity::Error => CommonSeverity::Error,
57 PluginSeverity::Warning => CommonSeverity::Warning,
58 };
59
60 let mut common = CommonLintError::new(&err.rule, &err.category, &err.message, severity);
61
62 if let (Some(line), Some(column)) = (err.line, err.column) {
63 common = common.with_location(line, column);
64 } else if let Some(line) = err.line {
65 common = common.with_location(line, 1);
66 }
67
68 for fix in err.fixes {
69 common = common.with_fix(convert_fix(fix));
70 }
71
72 common
73}
74
75pub struct NativePluginRule<P: Plugin> {
80 plugin: P,
81 name: &'static str,
82 category: &'static str,
83 description: &'static str,
84 severity: Option<&'static str>,
85 why: Option<&'static str>,
86 bad_example: Option<&'static str>,
87 good_example: Option<&'static str>,
88 references: Option<Vec<String>>,
89}
90
91impl<P: Plugin> Default for NativePluginRule<P> {
92 fn default() -> Self {
93 Self::new()
94 }
95}
96
97impl<P: Plugin> NativePluginRule<P> {
98 pub fn new() -> Self {
99 Self::with_plugin(P::default())
100 }
101
102 pub fn with_plugin(plugin: P) -> Self {
104 let spec = plugin.spec();
105
106 let name: &'static str = Box::leak(spec.name.into_boxed_str());
108 let category: &'static str = Box::leak(spec.category.into_boxed_str());
109 let description: &'static str = Box::leak(spec.description.into_boxed_str());
110 let severity: Option<&'static str> = spec.severity.map(|s| &*Box::leak(s.into_boxed_str()));
111 let why: Option<&'static str> = spec.why.map(|s| &*Box::leak(s.into_boxed_str()));
112 let bad_example: Option<&'static str> =
113 spec.bad_example.map(|s| &*Box::leak(s.into_boxed_str()));
114 let good_example: Option<&'static str> =
115 spec.good_example.map(|s| &*Box::leak(s.into_boxed_str()));
116 let references = spec.references;
117
118 Self {
119 plugin,
120 name,
121 category,
122 description,
123 severity,
124 why,
125 bad_example,
126 good_example,
127 references,
128 }
129 }
130}
131
132impl<P: Plugin + Send + Sync> LintRule for NativePluginRule<P> {
133 fn name(&self) -> &'static str {
134 self.name
135 }
136
137 fn category(&self) -> &'static str {
138 self.category
139 }
140
141 fn description(&self) -> &'static str {
142 self.description
143 }
144
145 fn check(&self, config: &Config, path: &Path) -> Vec<CommonLintError> {
146 let path_str = path.to_string_lossy();
147 let errors = self.plugin.check(config, &path_str);
148 errors.into_iter().map(convert_lint_error).collect()
149 }
150
151 fn severity(&self) -> Option<&str> {
152 self.severity
153 }
154
155 fn why(&self) -> Option<&str> {
156 self.why
157 }
158
159 fn bad_example(&self) -> Option<&str> {
160 self.bad_example
161 }
162
163 fn good_example(&self) -> Option<&str> {
164 self.good_example
165 }
166
167 fn references(&self) -> Option<Vec<String>> {
168 self.references.clone()
169 }
170}