#![doc = include_str!("../RULES.md")]
#![doc = include_str!("../DEFINITIONS.md")]
#![warn(missing_docs)]
#![warn(rust_2018_idioms)]
#![warn(rust_2021_compatibility)]
#![warn(missing_debug_implementations)]
#![warn(clippy::missing_docs_in_private_items)]
#![warn(rustdoc::broken_intra_doc_links)]
use wdl_analysis::Visitor;
use wdl_ast::SyntaxKind;
pub(crate) mod fix;
mod linter;
pub mod rules;
mod tags;
pub(crate) mod util;
pub use linter::*;
pub use tags::*;
pub use util::find_nearest_rule;
pub use wdl_analysis as analysis;
pub use wdl_ast as ast;
pub const DEFINITIONS_TEXT: &str = include_str!("../DEFINITIONS.md");
pub trait Rule: Visitor {
fn id(&self) -> &'static str;
fn description(&self) -> &'static str;
fn explanation(&self) -> &'static str;
fn tags(&self) -> TagSet;
fn url(&self) -> Option<&'static str> {
None
}
fn exceptable_nodes(&self) -> Option<&'static [SyntaxKind]>;
fn related_rules(&self) -> &[&'static str];
}
pub fn rules() -> Vec<Box<dyn Rule>> {
let rules: Vec<Box<dyn Rule>> = vec![
Box::<rules::DoubleQuotesRule>::default(),
Box::<rules::HereDocCommandsRule>::default(),
Box::<rules::SnakeCaseRule>::default(),
Box::<rules::RuntimeSectionRule>::default(),
Box::<rules::EndingNewlineRule>::default(),
Box::<rules::PreambleFormattedRule>::default(),
Box::<rules::ParameterMetaMatchedRule>::default(),
Box::<rules::WhitespaceRule>::default(),
Box::<rules::CommandSectionIndentationRule>::default(),
Box::<rules::ImportPlacementRule>::default(),
Box::<rules::PascalCaseRule>::default(),
Box::<rules::ImportWhitespaceRule>::default(),
Box::<rules::MetaSectionsRule>::default(),
Box::<rules::ImportSortedRule>::default(),
Box::<rules::InputSortedRule>::default(),
Box::<rules::LineWidthRule>::default(),
Box::<rules::ConsistentNewlinesRule>::default(),
Box::<rules::CallInputSpacingRule>::default(),
Box::<rules::SectionOrderingRule>::default(),
Box::<rules::DeprecatedObjectRule>::default(),
Box::<rules::MetaDescriptionRule>::default(),
Box::<rules::DeprecatedPlaceholderRule>::default(),
Box::<rules::ExpectedRuntimeKeysRule>::default(),
Box::<rules::TodoCommentRule>::default(),
Box::<rules::MatchingOutputMetaRule<'_>>::default(),
Box::<rules::CommentWhitespaceRule>::default(),
Box::<rules::TrailingCommaRule>::default(),
Box::<rules::ElementSpacingRule>::default(),
Box::<rules::MetaKeyValueFormattingRule>::default(),
Box::<rules::ExpressionSpacingRule>::default(),
Box::<rules::InputNameRule>::default(),
Box::<rules::OutputNameRule>::default(),
Box::<rules::DeclarationNameRule>::default(),
Box::<rules::RedundantNone>::default(),
Box::<rules::ContainerUriRule>::default(),
Box::<rules::RequirementsSectionRule>::default(),
Box::<rules::KnownRulesRule>::default(),
Box::<rules::LintDirectiveValidRule>::default(),
Box::<rules::VersionStatementFormattedRule>::default(),
Box::<rules::PreambleCommentPlacementRule>::default(),
Box::<rules::LintDirectiveFormattedRule>::default(),
Box::<rules::ConciseInputRule>::default(),
Box::<rules::ShellCheckRule>::default(),
];
#[cfg(debug_assertions)]
{
use std::collections::HashSet;
use convert_case::Case;
use convert_case::Casing;
let mut lint_set = HashSet::new();
let analysis_set: HashSet<&str> =
HashSet::from_iter(analysis::rules().iter().map(|r| r.id()));
for r in &rules {
if r.id().to_case(Case::Pascal) != r.id() {
panic!("lint rule id `{id}` is not pascal case", id = r.id());
}
if !lint_set.insert(r.id()) {
panic!("duplicate rule id `{id}`", id = r.id());
}
if analysis_set.contains(r.id()) {
panic!("rule id `{id}` is in use by wdl-analysis", id = r.id());
}
let self_id = &r.id();
for related_id in r.related_rules() {
if related_id == self_id {
panic!(
"Rule `{self_id}` refers to itself in its related rules. This is not \
allowed."
);
}
}
}
}
rules
}