/** Slice C-cell-v4 — auto-emit React hook imports for body-statement cells. * * Slice C-cell-v3 (commit 1ce4953) shipped the native `cell` body-stmt that * lowers to `const [name, setName] = useState(initial);`. The codegen * emits the call but NOT the `import { useState } from 'react'` — that has * always been author-emitted via file-level KERN `import` / `extern` nodes. * * Authoring a `cell`-using `fn` from scratch (no surrounding `screen` to * carry a hand-written react import) produced TS with `useState` references * but no import — a tsc/tsx-time error. This module closes that gap with * the same architecture as `stdlib-preamble.ts` for `Result` / `Option`: * * 1. `detectReactHookDeps(root)` — walk IR for body-stmt cell usage and * return the set of React hook names the generated TS will reference. * (Only `useState` today; `useEffect` / `useMemo` / `useCallback` etc. * will land when their corresponding body-stmt forms ship.) * * 2. `injectReactHookImports(code, deps)` — merge the required names into * any existing `from 'react'` import in the generated TS, or insert a * new line after the prologue (hashbang, directives, comments) so it * lands above other imports without disturbing line-1-required content. * * Why a separate module from `stdlib-preamble.ts`: hook imports are package * imports (`from 'react'`), not type-alias preambles. Merging with existing * imports requires fundamentally different inject logic than prepending * helper definitions. Keeping the concerns split also keeps the React-hook * scan from triggering on `Result` / `Option` typed handler params (which * the stdlib walker is tuned for). */ import type { IRNode } from '../types.js'; /** Set of React hook names that the generated TS will reference and that * need to be in scope. Grows in lockstep with body-statement nodes that * lower to React hooks. */ export type ReactHookDep = 'useState'; /** Walk the IR for body-statement nodes that lower to React hooks. Returns * the set of hook names that the generated TS will reference. Empty set * means no injection needed. * * Current scope (slice C-cell-v4): only `cell` → `useState`. Top-level * `state` nodes inside `screen` also lower to `useState`, but those have * always been served by author-emitted file-level react imports — this * walker stays narrow to avoid double-emission with hand-written imports * that already cover the screen case. */ export declare function detectReactHookDeps(root: IRNode): Set; /** Smart-merge the required React hook imports into a finished TS module. * * Three cases: * 1. Generated TS already imports the required names from 'react' (in * ANY existing `from 'react'` line) — no-op for those names. * 2. Generated TS has at least one `from 'react'` import but it's * missing some required names — merge the missing names into the * FIRST react import's named list, preserving its default import + * existing-name ordering. * 3. No `from 'react'` import present — insert a new line after the * module prologue (hashbang, directives, leading comments) so the * directive `'use client'` (Next.js / RSC) stays on the file's first * non-comment line. * * Codex P2 fix: a module with multiple `from 'react'` imports (e.g. from * an `extern react` block with several child `import names=...` lines) * used to merge into the first match without checking the OTHER react * imports for the required binding — duplicating `useState` and tripping * TS2300 (duplicate identifier). The names-already-imported check now * unions across every `from 'react'` line. * * The function is conservative on import shape: it only matches single- * line react imports with a default and/or named list. Multi-line `import * { a,\n b } from 'react';` is not parsed (treated as no-match in case 3 * and a duplicate line is emitted — TS allows it but it's ugly; rare in * generated code). Namespace imports (`import * as R from 'react'`) are * also not parsed — the function inserts a separate `import { useState * } from 'react'` which TS accepts alongside a namespace import. */ export declare function injectReactHookImports(code: string, deps: Set): string;