use crate::context::LintContext;
use crate::diagnostic::{LintDiagnostic, Severity};
use crate::rule::{Rule, RuleCategory, RuleMeta};
use vize_relief::ast::RootNode;
static META: RuleMeta = RuleMeta {
name: "vue/warn-custom-block",
description: "Warn about custom blocks in SFC files",
category: RuleCategory::Recommended,
fixable: false,
default_severity: Severity::Warning,
};
const STANDARD_BLOCKS: &[&str] = &["script", "template", "style"];
#[derive(Default)]
pub struct WarnCustomBlock;
impl Rule for WarnCustomBlock {
fn meta(&self) -> &'static RuleMeta {
&META
}
fn run_on_template<'a>(&self, ctx: &mut LintContext<'a>, _root: &RootNode<'a>) {
let source = ctx.source;
let mut pos = 0;
while pos < source.len() {
if let Some(tag_start) = source[pos..].find('<') {
let abs_pos = pos + tag_start;
if source[abs_pos..].starts_with("</") {
pos = abs_pos + 2;
continue;
}
let rest = &source[abs_pos + 1..];
let tag_end = rest
.find(|c: char| c.is_whitespace() || c == '>' || c == '/')
.unwrap_or(rest.len());
let tag_name = &rest[..tag_end];
let before = &source[..abs_pos];
let is_root_level = before.is_empty()
|| before.ends_with('\n')
|| before.trim_end().ends_with('>') && !before.contains('<');
if is_root_level
&& !tag_name.is_empty()
&& !STANDARD_BLOCKS.contains(&tag_name)
&& tag_name
.chars()
.next()
.map(|c| c.is_lowercase())
.unwrap_or(false)
{
let close_pos = source[abs_pos..]
.find('>')
.map(|p| abs_pos + p + 1)
.unwrap_or(abs_pos + tag_end + 1);
ctx.report(
LintDiagnostic::warn(
META.name,
"Custom block detected. Ensure proper plugin configuration.",
abs_pos as u32,
close_pos as u32,
)
.with_help(
"Custom blocks require corresponding Vite/Webpack plugins to be processed",
),
);
}
pos = abs_pos + 1;
} else {
break;
}
}
}
}
#[cfg(test)]
mod tests {
}