use std::collections::HashSet;
use std::path::Path;
use harn_modules::WildcardResolution;
use harn_parser::SNode;
mod complexity;
mod decls;
mod diagnostic;
mod fixes;
mod harndoc;
mod linter;
mod naming;
mod rules;
#[cfg(test)]
mod tests;
pub use diagnostic::{LintDiagnostic, LintOptions, LintSeverity, DEFAULT_COMPLEXITY_THRESHOLD};
pub use naming::simplify_bool_comparison;
pub use rules::file_header::derive_file_header_title;
use linter::Linter;
use rules::file_header::check_require_file_header;
pub fn lint(program: &[SNode]) -> Vec<LintDiagnostic> {
lint_with_config_and_source(program, &[], None)
}
pub fn lint_with_source(program: &[SNode], source: &str) -> Vec<LintDiagnostic> {
lint_with_config_and_source(program, &[], Some(source))
}
pub fn lint_with_config(program: &[SNode], disabled_rules: &[String]) -> Vec<LintDiagnostic> {
lint_with_config_and_source(program, disabled_rules, None)
}
pub fn lint_with_config_and_source(
program: &[SNode],
disabled_rules: &[String],
source: Option<&str>,
) -> Vec<LintDiagnostic> {
lint_full(
program,
disabled_rules,
source,
&HashSet::new(),
&LintOptions::default(),
None,
)
}
pub fn lint_with_cross_file_imports(
program: &[SNode],
disabled_rules: &[String],
source: Option<&str>,
externally_imported_names: &HashSet<String>,
) -> Vec<LintDiagnostic> {
lint_full(
program,
disabled_rules,
source,
externally_imported_names,
&LintOptions::default(),
None,
)
}
pub fn lint_with_module_graph(
program: &[SNode],
disabled_rules: &[String],
source: Option<&str>,
externally_imported_names: &HashSet<String>,
module_graph: &harn_modules::ModuleGraph,
file_path: &Path,
options: &LintOptions<'_>,
) -> Vec<LintDiagnostic> {
lint_full(
program,
disabled_rules,
source,
externally_imported_names,
options,
Some((module_graph, file_path)),
)
}
pub fn lint_with_options(
program: &[SNode],
disabled_rules: &[String],
source: Option<&str>,
externally_imported_names: &HashSet<String>,
options: &LintOptions<'_>,
) -> Vec<LintDiagnostic> {
lint_full(
program,
disabled_rules,
source,
externally_imported_names,
options,
None,
)
}
fn lint_full(
program: &[SNode],
disabled_rules: &[String],
source: Option<&str>,
externally_imported_names: &HashSet<String>,
options: &LintOptions<'_>,
module_graph: Option<(&harn_modules::ModuleGraph, &Path)>,
) -> Vec<LintDiagnostic> {
let mut linter = Linter::new(source);
linter
.externally_imported_names
.clone_from(externally_imported_names);
if let Some((module_graph, file_path)) = module_graph {
linter.use_module_graph_for_wildcards = true;
linter.module_graph_wildcard_exports = match module_graph.wildcard_exports_for(file_path) {
WildcardResolution::Resolved(exports) => Some(exports),
WildcardResolution::Unknown => None,
};
}
if let Some(threshold) = options.complexity_threshold {
linter.complexity_threshold = threshold;
}
linter.lint_program(program);
if let Some(src) = source {
if options.require_file_header {
check_require_file_header(src, options.file_path, &mut linter.diagnostics);
}
}
linter.finalize();
if disabled_rules.is_empty() {
linter.diagnostics
} else {
linter
.diagnostics
.into_iter()
.filter(|d| !disabled_rules.iter().any(|r| r == d.rule))
.collect()
}
}
pub fn collect_selective_import_names(program: &[SNode]) -> HashSet<String> {
let mut names = HashSet::new();
for snode in program {
if let harn_parser::Node::SelectiveImport {
names: imported, ..
} = &snode.node
{
names.extend(imported.iter().cloned());
}
}
names
}