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::ExceptRule;
41use wdl_ast::SyntaxKind;
42use wdl_ast::SyntaxNode;
43
44mod analyzer;
45pub mod config;
46pub mod diagnostics;
47pub mod document;
48pub mod eval;
49mod graph;
50pub mod handlers;
51mod queue;
52mod rayon;
53mod rules;
54pub mod stdlib;
55pub mod types;
56mod validation;
57mod visitor;
58
59pub use analyzer::*;
60pub use config::Config;
61pub use config::DiagnosticsConfig;
62pub use config::FeatureFlags;
63pub use document::Document;
64pub use rules::*;
65pub use validation::*;
66pub use visitor::*;
67pub use wdl_format::Config as FormatConfig;
68
69pub trait Exceptable {
71 fn rule_exceptions(&self) -> HashSet<ExceptRule> {
76 HashSet::new()
77 }
78
79 fn is_rule_excepted(&self, _id: &str) -> bool {
81 true
82 }
83}
84
85impl Exceptable for SyntaxNode {
86 fn rule_exceptions(&self) -> HashSet<ExceptRule> {
87 self.siblings_with_tokens(Direction::Prev)
88 .skip(1) .map_while(|s| {
90 if s.kind() == SyntaxKind::Whitespace || s.kind() == SyntaxKind::Comment {
91 s.into_token()
92 } else {
93 None
94 }
95 })
96 .filter_map(Comment::cast)
97 .filter_map(|c| c.directive())
98 .flat_map(|d| match d {
99 Directive::Except(e) => e,
100 })
101 .collect()
102 }
103
104 fn is_rule_excepted(&self, id: &str) -> bool {
105 self.rule_exceptions().iter().any(|e| e.name == id)
106 }
107}