pub mod code_block_collector;
pub mod diagnostics;
#[cfg(not(target_arch = "wasm32"))]
pub mod external_linters;
#[cfg(not(target_arch = "wasm32"))]
pub mod external_linters_sync;
pub mod index;
pub mod metadata_diagnostics;
pub(crate) mod offsets;
pub mod rules;
pub mod runner;
pub use diagnostics::{
Diagnostic, DiagnosticNote, DiagnosticNoteKind, DiagnosticOrigin, Fix, Location, Severity,
};
pub use rules::{DiagnosticCode, Requirement, Rule, RuleMeta, RuleRegistry};
pub use runner::LintRunner;
use crate::config::Config;
use crate::syntax::SyntaxNode;
pub fn lint(tree: &SyntaxNode, input: &str, config: &Config) -> Vec<Diagnostic> {
let registry = default_registry(config);
let runner = LintRunner::new(registry);
runner.run(tree, input, config)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn lint_with_external_sync(tree: &SyntaxNode, input: &str, config: &Config) -> Vec<Diagnostic> {
let registry = default_registry(config);
let runner = LintRunner::new(registry);
runner.run_with_external_linters_sync(tree, input, config, None)
}
pub fn lint_with_metadata(
tree: &SyntaxNode,
input: &str,
config: &Config,
metadata: Option<&crate::metadata::DocumentMetadata>,
) -> Vec<Diagnostic> {
let registry = default_registry(config);
let runner = LintRunner::new(registry);
runner.run_with_metadata(tree, input, config, metadata)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn lint_with_external_sync_and_metadata(
tree: &SyntaxNode,
input: &str,
config: &Config,
metadata: Option<&crate::metadata::DocumentMetadata>,
) -> Vec<Diagnostic> {
let registry = default_registry(config);
let runner = LintRunner::new(registry);
runner.run_with_external_linters_sync(tree, input, config, metadata)
}
fn all_rules() -> Vec<Box<dyn Rule>> {
vec![
Box::new(rules::heading_hierarchy::HeadingHierarchyRule),
Box::new(rules::empty_list_item::EmptyListItemRule),
Box::new(rules::math_content::MathContentRule),
Box::new(rules::heading_eaten_attrs::HeadingEatenAttrsRule),
Box::new(rules::heading_strip_comments_residue::HeadingStripCommentsResidueRule),
Box::new(rules::adjacent_footnote_refs::AdjacentFootnoteRefsRule),
Box::new(rules::footnote_ref_in_footnote_def::FootnoteRefInFootnoteDefRule),
Box::new(rules::duplicate_references::DuplicateReferencesRule),
Box::new(rules::undefined_references::UndefinedReferencesRule),
Box::new(rules::undefined_anchor::UndefinedAnchorRule),
Box::new(rules::unused_definitions::UnusedDefinitionsRule),
Box::new(rules::citation_keys::CitationKeysRule),
Box::new(rules::crossref_as_link_target::CrossrefAsLinkTargetRule),
Box::new(rules::chunk_label_spaces::ChunkLabelSpacesRule),
Box::new(rules::missing_chunk_labels::MissingChunkLabelsRule),
Box::new(rules::figure_crossref_captions::FigureCrossrefCaptionsRule),
Box::new(rules::emoji_aliases::EmojiAliasesRule),
Box::new(rules::html_entities::HtmlEntitiesRule),
Box::new(rules::link_text_is_url::LinkTextIsUrlRule),
Box::new(rules::stray_fenced_div_markers::StrayFencedDivMarkersRule),
]
}
pub fn builtin_rule_metadata() -> Vec<RuleMeta> {
all_rules().iter().map(|rule| rule.metadata()).collect()
}
fn default_registry(config: &Config) -> RuleRegistry {
let mut registry = RuleRegistry::new();
for rule in all_rules() {
let meta = rule.metadata();
let enabled = if meta.default_on {
config.lint.is_rule_enabled(meta.name)
} else {
config.lint.is_rule_explicitly_enabled(meta.name)
};
if enabled && meta.requires.is_satisfied(config) {
registry.register(rule);
}
}
registry
}