use crate::diagnostic::LintDiagnostic;
use vize_carton::CompactString;
use vize_relief::{ast::SourceLocation, BindingType};
use super::{state::ElementContext, LintContext};
impl<'a> LintContext<'a> {
#[inline]
pub fn error(&mut self, message: impl Into<CompactString>, loc: &SourceLocation) {
self.report(LintDiagnostic::error(
self.current_rule,
message,
loc.start.offset,
loc.end.offset,
));
}
#[inline]
pub fn warn(&mut self, message: impl Into<CompactString>, loc: &SourceLocation) {
self.report(LintDiagnostic::warn(
self.current_rule,
message,
loc.start.offset,
loc.end.offset,
));
}
#[inline]
pub fn error_with_help(
&mut self,
message: impl Into<CompactString>,
loc: &SourceLocation,
help: impl Into<CompactString>,
) {
let mut diag =
LintDiagnostic::error(self.current_rule, message, loc.start.offset, loc.end.offset);
let help_str: CompactString = help.into();
if let Some(processed) = self.help_level.process(help_str.as_str()) {
diag = diag.with_help(processed);
}
self.report(diag);
}
#[inline]
pub fn warn_with_help(
&mut self,
message: impl Into<CompactString>,
loc: &SourceLocation,
help: impl Into<CompactString>,
) {
let mut diag =
LintDiagnostic::warn(self.current_rule, message, loc.start.offset, loc.end.offset);
let help_str: CompactString = help.into();
if let Some(processed) = self.help_level.process(help_str.as_str()) {
diag = diag.with_help(processed);
}
self.report(diag);
}
#[inline]
pub fn error_with_label(
&mut self,
message: impl Into<CompactString>,
loc: &SourceLocation,
label_message: impl Into<CompactString>,
label_loc: &SourceLocation,
) {
self.report(
LintDiagnostic::error(self.current_rule, message, loc.start.offset, loc.end.offset)
.with_label(label_message, label_loc.start.offset, label_loc.end.offset),
);
}
#[inline]
pub fn into_diagnostics(self) -> Vec<LintDiagnostic> {
self.diagnostics
}
#[inline]
pub fn diagnostics(&self) -> &[LintDiagnostic] {
&self.diagnostics
}
#[inline]
pub fn push_element(&mut self, ctx: ElementContext) {
for var in &ctx.v_for_vars {
self.scope_variables.insert(var.clone());
}
self.element_stack.push(ctx);
}
#[inline]
pub fn pop_element(&mut self) -> Option<ElementContext> {
if let Some(ctx) = self.element_stack.pop() {
for var in &ctx.v_for_vars {
self.scope_variables.remove(var);
}
Some(ctx)
} else {
None
}
}
#[inline]
pub fn is_in_v_for(&self) -> bool {
self.element_stack.iter().any(|e| e.has_v_for)
}
#[inline]
pub fn v_for_vars(&self) -> impl Iterator<Item = &str> {
self.element_stack
.iter()
.flat_map(|e| e.v_for_vars.iter().map(|s| s.as_str()))
}
#[inline]
pub fn is_v_for_var(&self, name: &str) -> bool {
self.scope_variables.contains(name)
}
#[inline]
pub fn is_parent_v_for_var(&self, name: &str) -> bool {
if self.element_stack.len() < 2 {
return false;
}
for elem in self.element_stack.iter().take(self.element_stack.len() - 1) {
for var in &elem.v_for_vars {
if var.as_str() == name {
return true;
}
}
}
false
}
#[inline]
pub fn current_element(&self) -> Option<&ElementContext> {
self.element_stack.last()
}
#[inline]
pub fn parent_element(&self) -> Option<&ElementContext> {
if self.element_stack.len() >= 2 {
self.element_stack.get(self.element_stack.len() - 2)
} else {
None
}
}
#[inline]
pub fn has_ancestor(&self, predicate: impl Fn(&ElementContext) -> bool) -> bool {
if self.element_stack.len() < 2 {
return false;
}
self.element_stack
.iter()
.take(self.element_stack.len() - 1)
.any(predicate)
}
#[inline]
pub fn error_count(&self) -> usize {
self.error_count
}
#[inline]
pub fn warning_count(&self) -> usize {
self.warning_count
}
#[inline]
pub fn is_variable_defined(&self, name: &str) -> bool {
if self.is_v_for_var(name) {
return true;
}
if let Some(analysis) = &self.analysis {
return analysis.is_defined(name);
}
false
}
#[inline]
pub fn get_binding_type(&self, name: &str) -> Option<BindingType> {
self.analysis.and_then(|a| a.get_binding_type(name))
}
#[inline]
pub fn has_script_binding(&self, name: &str) -> bool {
self.analysis
.map(|a| a.bindings.contains(name))
.unwrap_or(false)
}
#[inline]
pub fn is_component_registered(&self, name: &str) -> bool {
self.analysis
.map(|a| a.is_component_registered(name))
.unwrap_or(false)
}
#[inline]
pub fn has_prop(&self, name: &str) -> bool {
self.analysis
.map(|a| a.macros.props().iter().any(|p| p.name.as_str() == name))
.unwrap_or(false)
}
#[inline]
pub fn has_emit(&self, name: &str) -> bool {
self.analysis
.map(|a| a.macros.emits().iter().any(|e| e.name.as_str() == name))
.unwrap_or(false)
}
#[inline]
pub fn has_model(&self, name: &str) -> bool {
self.analysis
.map(|a| a.macros.models().iter().any(|m| m.name.as_str() == name))
.unwrap_or(false)
}
#[inline]
pub fn is_async_setup(&self) -> bool {
self.analysis.map(|a| a.is_async()).unwrap_or(false)
}
pub fn get_props(&self) -> Vec<&str> {
self.analysis
.map(|a| a.macros.props().iter().map(|p| p.name.as_str()).collect())
.unwrap_or_default()
}
pub fn get_emits(&self) -> Vec<&str> {
self.analysis
.map(|a| a.macros.emits().iter().map(|e| e.name.as_str()).collect())
.unwrap_or_default()
}
}