Skip to main content

sdivi_patterns/queries/
async_patterns.rs

1//! Node kinds classified as async-concurrency patterns.
2//!
3//! These node kinds correspond to the `async_patterns` category in the
4//! [`PatternCatalog`](crate::catalog::PatternCatalog).
5
6use std::sync::LazyLock;
7
8use regex::Regex;
9
10/// Tree-sitter node kinds for async-concurrency patterns.
11///
12/// - `await_expression`: `.await` on a `Future`
13pub const NODE_KINDS: &[&str] = &["await_expression"];
14
15// TypeScript / JavaScript:
16//   \.(then|catch|finally)\(  — Promise chain calls.
17// No ^ anchor: the receiver expression precedes the dot, so the match is
18// suffix-anchored to the method name. This deliberately matches
19// "promise.then(" and "fetch(...).then(" without matching "getNextValue(".
20static TS_JS_RE: LazyLock<Regex> = LazyLock::new(|| {
21    Regex::new(r"\.(then|catch|finally)\(").expect("async_patterns TS/JS regex is valid")
22});
23
24/// Return `true` when `text` looks like an async-pattern call callee for `language`.
25///
26/// Covers Promise-chain `call_expression` shapes (`.then`, `.catch`, `.finally`)
27/// in TypeScript and JavaScript. `await_expression` nodes are routed via
28/// [`NODE_KINDS`] already; this function handles the remaining callee shapes.
29/// Other languages return `false` — their async primitives are node-kind-routed.
30///
31/// # Examples
32///
33/// ```rust
34/// use sdivi_patterns::queries::async_patterns::matches_callee;
35///
36/// assert!(matches_callee("promise.then(resolve)", "typescript"));
37/// assert!(matches_callee("fetch(url).catch(err => {})", "javascript"));
38/// assert!(!matches_callee("Math.max(a, b)", "typescript"));
39/// assert!(!matches_callee("promise.then(resolve)", "rust"));
40/// ```
41pub fn matches_callee(text: &str, language: &str) -> bool {
42    match language {
43        "typescript" | "javascript" => TS_JS_RE.is_match(text),
44        _ => false,
45    }
46}