1#![doc = include_str!("../RULES.md")]
27#![warn(missing_docs)]
28#![warn(rust_2018_idioms)]
29#![warn(rust_2021_compatibility)]
30#![warn(missing_debug_implementations)]
31#![warn(clippy::missing_docs_in_private_items)]
32#![warn(rustdoc::broken_intra_doc_links)]
33
34use std::collections::HashSet;
35
36use wdl_ast::AstToken;
37use wdl_ast::Comment;
38use wdl_ast::Direction;
39use wdl_ast::Directive;
40use wdl_ast::SyntaxKind;
41use wdl_ast::SyntaxNode;
42
43mod analyzer;
44pub mod config;
45pub mod diagnostics;
46pub mod document;
47pub mod eval;
48mod graph;
49pub mod handlers;
50mod queue;
51mod rayon;
52mod rules;
53pub mod stdlib;
54pub mod types;
55mod validation;
56mod visitor;
57
58pub use analyzer::*;
59pub use config::Config;
60pub use config::DiagnosticsConfig;
61pub use config::FeatureFlags;
62pub use document::Document;
63pub use rules::*;
64pub use validation::*;
65pub use visitor::*;
66
67pub trait Exceptable {
69 fn rule_exceptions(&self) -> HashSet<String> {
74 HashSet::new()
75 }
76
77 fn is_rule_excepted(&self, _id: &str) -> bool {
79 true
80 }
81}
82
83impl Exceptable for SyntaxNode {
84 fn rule_exceptions(&self) -> HashSet<String> {
85 self.siblings_with_tokens(Direction::Prev)
86 .skip(1) .map_while(|s| {
88 if s.kind() == SyntaxKind::Whitespace || s.kind() == SyntaxKind::Comment {
89 s.into_token()
90 } else {
91 None
92 }
93 })
94 .filter_map(Comment::cast)
95 .filter_map(|c| c.directive())
96 .flat_map(|d| match d {
97 Directive::Except(e) => e,
98 })
99 .collect()
100 }
101
102 fn is_rule_excepted(&self, id: &str) -> bool {
103 self.rule_exceptions().contains(id)
104 }
105}