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::Direction;
37use wdl_ast::SyntaxKind;
38use wdl_ast::SyntaxNode;
39use wdl_ast::SyntaxToken;
40
41mod analyzer;
42mod config;
43pub mod diagnostics;
44pub mod document;
45pub mod eval;
46mod graph;
47mod queue;
48mod rayon;
49mod rules;
50pub mod stdlib;
51pub mod types;
52mod validation;
53mod visitor;
54
55pub use analyzer::*;
56pub use config::Config;
57pub use config::DiagnosticsConfig;
58pub use document::Document;
59pub use rules::*;
60pub use validation::*;
61pub use visitor::*;
62pub mod handlers;
63
64pub const EXCEPT_COMMENT_PREFIX: &str = "#@ except:";
66
67pub trait SyntaxNodeExt {
69 fn except_comments(&self) -> impl Iterator<Item = SyntaxToken> + '_;
71
72 fn rule_exceptions(&self) -> HashSet<String>;
77
78 fn is_rule_excepted(&self, id: &str) -> bool;
80}
81
82impl SyntaxNodeExt for SyntaxNode {
83 fn except_comments(&self) -> impl Iterator<Item = SyntaxToken> + '_ {
84 self.siblings_with_tokens(Direction::Prev)
85 .skip(1)
86 .map_while(|s| {
87 if s.kind() == SyntaxKind::Whitespace || s.kind() == SyntaxKind::Comment {
88 s.into_token()
89 } else {
90 None
91 }
92 })
93 .filter(|t| t.kind() == SyntaxKind::Comment)
94 }
95
96 fn rule_exceptions(&self) -> HashSet<String> {
97 let mut set = HashSet::default();
98 for comment in self.except_comments() {
99 if let Some(ids) = comment.text().strip_prefix(EXCEPT_COMMENT_PREFIX) {
100 for id in ids.split(',') {
101 let id = id.trim();
102 set.insert(id.to_string());
103 }
104 }
105 }
106
107 set
108 }
109
110 fn is_rule_excepted(&self, id: &str) -> bool {
111 for comment in self.except_comments() {
112 if let Some(ids) = comment.text().strip_prefix(EXCEPT_COMMENT_PREFIX) {
113 if ids.split(',').any(|i| i.trim() == id) {
114 return true;
115 }
116 }
117 }
118
119 false
120 }
121}