Skip to main content

wdl_analysis/
lib.rs

1//! Analysis of Workflow Description Language (WDL) documents.
2//!
3//! An analyzer can be used to implement the [Language Server Protocol (LSP)](https://microsoft.github.io/language-server-protocol/).
4//!
5//! # Examples
6//!
7//! ```no_run
8//! use url::Url;
9//! use wdl_analysis::Analyzer;
10//!
11//! #[tokio::main]
12//! async fn main() {
13//!     let analyzer = Analyzer::default();
14//!     // Add a document to the analyzer
15//!     analyzer
16//!         .add_document(Url::parse("file:///path/to/file.wdl").unwrap())
17//!         .await
18//!         .unwrap();
19//!     let results = analyzer.analyze(()).await.unwrap();
20//!     // Process the results
21//!     for result in results {
22//!         // Do something
23//!     }
24//! }
25//! ```
26#![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
69/// An extension trait for syntax nodes.
70pub trait Exceptable {
71    /// Gets the AST node's rule exceptions set.
72    ///
73    /// The set is the comma-delimited list of rule identifiers that follows a
74    /// `#@ except:` comment.
75    fn rule_exceptions(&self) -> HashSet<ExceptRule> {
76        HashSet::new()
77    }
78
79    /// Determines if a given rule id is excepted for the syntax node.
80    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) // self is included with siblings
89            .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}