/** * React handler hooks name the function they wrap. * * `const handleSubmit = useCallback(() => {…}, [])` is how nearly every * handler in a React / React Native component is written, and the arrow is * anonymous only syntactically — the declarator is the name every * `onPress={handleSubmit}` and `addListener('x', handleSubmit)` uses. Without * a node the handler's calls attribute to the component and the trigger of a * flow (the tap, the native event) has nothing to resolve to. */ import { describe, it, expect, beforeAll } from 'vitest'; import { extractFromSource } from '../src/extraction'; import { initGrammars, loadAllGrammars } from '../src/extraction/grammars'; beforeAll(async () => { await initGrammars(); await loadAllGrammars(); }); const refsFrom = (result: ReturnType, id: string) => result.unresolvedReferences.filter((r) => r.fromNodeId === id).map((r) => r.referenceName); describe('useCallback handlers', () => { it('extracts the wrapped arrow as a function named by the declarator, inside the component', () => { const code = ` import { useCallback, useMemo, useEffect } from 'react' import { finalize, upload, log } from './api' export default function ReviewScreen() { const handleApprove = useCallback(() => { finalize() }, []) const handleZip = useCallback(async (data: { uri: string }) => { await upload(data.uri) }, []) const total = useMemo(() => 1 + 1, []) useEffect(() => { log('mounted') }, []) return