use skif_core::{Fix, FixSafety, RuleMeta, diagnostic};
use skif_js_syntax::{Export, ExportKind, Member};
use skif_lint::Emitter;
use super::support::{delete_range, module_location};
use crate::analysis::JsAnalysis;
pub(super) fn report(
meta: &'static RuleMeta,
kind: ExportKind,
members_of: fn(&Export) -> &[Member],
noun: &str,
analysis: &JsAnalysis<'_>,
out: &mut Emitter<'_>,
) {
for module in analysis.graph.modules() {
if !analysis.reports_exports_of(module) {
continue;
}
for export in module.info.exports.iter().filter(|export| export.kind == kind) {
if analysis.is_tagged_public(export) || !analysis.exports.is_used(module.id, &export.name) {
continue;
}
for member in members_of(export) {
if analysis.exempts_tags(&member.tags) || analysis.member_in_use(module, export, member) {
continue;
}
let mut builder = diagnostic(
meta,
format!("{noun} member `{}.{}` is never used", export.name, member.name),
module_location(module, Some(member.span)),
)
.help("remove the member, or tag it `@public`");
if let Some(package) = analysis.workspace.package(module.owner) {
builder = builder.package(package.display_name());
}
if let Some((start, end)) = member.removal {
builder = builder.fix(Fix::new(
format!("Remove the {noun} member `{}`", member.name),
FixSafety::Unsafe,
vec![delete_range(module, start, end)],
));
}
out.emit(builder.build());
}
}
}
}