use std::sync::LazyLock;
use regex::Regex;
pub const NODE_KINDS: &[&str] = &[];
static TS_JS_RE: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"^use[A-Z]").expect("framework_hooks TS/JS regex is valid"));
pub fn matches_callee(text: &str, language: &str) -> bool {
match language {
"typescript" | "javascript" => TS_JS_RE.is_match(text),
_ => false,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn built_in_hooks_match_typescript() {
for callee in [
"useState(0)",
"useEffect(fn, [])",
"useMemo(() => val, [])",
"useCallback(fn, [])",
"useRef(null)",
"useContext(MyCtx)",
"useReducer(reducer, state)",
"useLayoutEffect(fn, [])",
] {
assert!(
matches_callee(callee, "typescript"),
"{callee:?} should match for typescript"
);
}
}
#[test]
fn custom_hooks_match() {
assert!(matches_callee("useAuth()", "typescript"));
assert!(matches_callee("useStore()", "javascript"));
assert!(matches_callee("useCustomThing(opts)", "typescript"));
assert!(matches_callee("useMutation(fn)", "javascript"));
}
#[test]
fn lowercase_second_char_does_not_match() {
assert!(!matches_callee("user()", "typescript"));
assert!(!matches_callee("useful(x)", "javascript"));
assert!(!matches_callee("username()", "typescript"));
assert!(!matches_callee("fuse(x)", "typescript"));
}
#[test]
fn non_use_prefix_does_not_match() {
assert!(!matches_callee("getUser()", "typescript"));
assert!(!matches_callee("setState(x)", "typescript"));
assert!(!matches_callee("Math.max(a, b)", "typescript"));
assert!(!matches_callee("console.log(x)", "typescript"));
assert!(!matches_callee("fetch(url)", "typescript"));
}
#[test]
fn other_languages_return_false() {
for lang in ["rust", "python", "go", "java"] {
assert!(
!matches_callee("useState(0)", lang),
"useState should not match for {lang}"
);
}
}
#[test]
fn node_kinds_is_empty() {
#[allow(clippy::const_is_empty)]
let empty = NODE_KINDS.is_empty();
assert!(empty);
}
}