use std::sync::LazyLock;
use regex::Regex;
pub const NODE_KINDS: &[&str] = &[];
static TS_JS_RE: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(
r"^(createSlice|configureStore|createStore|combineReducers|createAsyncThunk|createReducer|createAction|createSignal|createEffect|createMemo|createResource)\(|^use(Selector|Dispatch|Store)\b|^create\(|^(atom|selector|atomFamily|selectorFamily)\(|^(observable|action|computed|makeObservable|makeAutoObservable|runInAction|signal|effect|batch)\(",
)
.expect("state_store 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 redux_rtk_factories_match() {
for callee in [
"createSlice({})",
"configureStore({})",
"createStore(rootReducer)",
"combineReducers({})",
"createAsyncThunk('fetch', async () => {})",
"createReducer(init, builder => {})",
"createAction('increment')",
] {
assert!(
matches_callee(callee, "typescript"),
"{callee:?} should match for typescript"
);
}
}
#[test]
fn react_redux_hooks_match() {
assert!(matches_callee("useSelector(s => s.user)", "typescript"));
assert!(matches_callee("useDispatch()", "typescript"));
assert!(matches_callee("useStore()", "javascript"));
}
#[test]
fn zustand_create_matches() {
assert!(matches_callee("create((set) => ({}))", "typescript"));
assert!(matches_callee("create(() => ({count: 0}))", "javascript"));
}
#[test]
fn jotai_recoil_match() {
assert!(matches_callee("atom(0)", "typescript"));
assert!(matches_callee(
"selector({key: 'x', get: () => 1})",
"typescript"
));
assert!(matches_callee("atomFamily((id) => atom(id))", "typescript"));
assert!(matches_callee(
"selectorFamily({key: 'x', get: () => () => 1})",
"typescript"
));
}
#[test]
fn mobx_primitives_match() {
assert!(matches_callee("observable({})", "typescript"));
assert!(matches_callee("action(() => {})", "typescript"));
assert!(matches_callee("computed(() => x + 1)", "typescript"));
assert!(matches_callee("makeObservable(this, {})", "typescript"));
assert!(matches_callee("makeAutoObservable(this)", "typescript"));
assert!(matches_callee("runInAction(() => {})", "typescript"));
}
#[test]
fn signals_match() {
assert!(matches_callee("signal(0)", "typescript"));
assert!(matches_callee(
"computed(() => count.value * 2)",
"typescript"
));
assert!(matches_callee("effect(() => {})", "typescript"));
assert!(matches_callee("batch(() => {})", "typescript"));
}
#[test]
fn solid_createx_match() {
assert!(matches_callee("createSignal(0)", "typescript"));
assert!(matches_callee("createEffect(() => {})", "typescript"));
assert!(matches_callee("createMemo(() => x)", "typescript"));
assert!(matches_callee("createStore({})", "typescript"));
assert!(matches_callee("createResource(fetcher)", "typescript"));
}
#[test]
fn member_access_calls_do_not_match() {
assert!(!matches_callee("prisma.user.create(data)", "typescript"));
assert!(!matches_callee("db.create(record)", "typescript"));
assert!(!matches_callee(
"document.createElement('div')",
"typescript"
));
assert!(!matches_callee("repo.createMany(items)", "typescript"));
}
#[test]
fn unrelated_use_hooks_do_not_match() {
assert!(!matches_callee("useEffect(fn, [])", "typescript"));
assert!(!matches_callee("useState(0)", "typescript"));
assert!(!matches_callee("useMemo(() => v, [])", "typescript"));
assert!(!matches_callee("useCustomHook()", "typescript"));
}
#[test]
fn other_languages_return_false() {
for lang in ["python", "rust", "go", "java"] {
assert!(
!matches_callee("atom(0)", lang),
"atom should not match for {lang}"
);
assert!(
!matches_callee("createSlice({})", lang),
"createSlice should not match for {lang}"
);
}
}
#[test]
fn node_kinds_is_empty() {
#[allow(clippy::const_is_empty)]
let empty = NODE_KINDS.is_empty();
assert!(empty);
}
}