@cleya/plugin-react-navigation
v0.1.1
Published
Indexes React Navigation screens, routes and navigation edges
Readme
@cleya/plugin-react-navigation
Indexes a React Navigation app so you can ask which screens exist, what renders each one, and which screen can reach which other.
It reads the source, not the running app: no instrumentation, no navigation container, nothing to add to the project being indexed.
What it writes
(Route)-[:SERVES]->(Screen)-[:RENDERS]->(Symbol)
(Screen)-[:NAVIGATES_TO]->(Route)
(Screen)-[:GATED_BY]->(Predicate)| Node | One per |
| --- | --- |
| Route | destination name — "Settings" |
| Screen | registration of a route — the same route registered in two navigators is two screens |
| Predicate | named mount condition — a guard, or a feature flag read in the component |
| Symbol | code symbol rendering the screen. Written by the code indexer, joined here. |
Route and Screen are separate on purpose: a route registered twice keeps two
positions, two guards and two components, which a single node would flatten.
Use
bun add @cleya/plugin-react-navigation// cleya.config.ts
import { defineConfig, defineProjectConfig } from "@cleya/config";
import { tsScipIndexer } from "@cleya/plugin-ts-scip";
import { reactNavigationIndexer } from "@cleya/plugin-react-navigation";
export default defineConfig({
projectSettings: { db: "./.cleya/graph.lbug" },
projects: [
defineProjectConfig({
id: "my-app",
scope: { root: "/abs/path/to/app", globs: ["src/**/*.ts", "src/**/*.tsx"] },
// Order matters: the code indexer declares the component symbols this
// plugin links screens to, and both share one run.
contributors: [tsScipIndexer(), reactNavigationIndexer()],
}),
],
});cleya indexAsk it things
-- every screen, and what renders it
MATCH (r:Route)-[:SERVES]->(s:Screen)
RETURN r.name AS route, s.graph AS navigator, s.component AS component
ORDER BY route
-- where can I get to from the settings screen, and by clicking what
MATCH (:Route {name: "Settings"})-[:SERVES]->(:Screen)-[n:NAVIGATES_TO]->(target:Route)
RETURN target.name, n.trigger, n.label, n.file, n.line
-- screens nothing navigates to: dead ends, or entry points
MATCH (r:Route)-[:SERVES]->(s:Screen)
WHERE NOT (:Screen)-[:NAVIGATES_TO]->(r)
RETURN r.name
-- what does this feature flag gate?
MATCH (s:Screen)-[:GATED_BY]->(p:Predicate {name: "canUseTravel"})
RETURN s.routeIs the graph complete?
That is the question this plugin takes seriously, because the honest answer is often "no". Every run prints a coverage report:
[react-navigation] couverture des appels `navigate` : 1503/1711 (88 %)
208 sans arête : 12+ hors registre · 61 avec motif d'URL · 135 opaques
cible lisible mais absente du registre — inscription probablement ratée :
src/pages/Search.tsx:88 ROUTES.SEARCH_ADVANCED
[react-navigation] 214 routes / 231 screens / 229 rendered / …The denominator matters more than the count. A plugin that finds nothing reports zero edges, and zero looks exactly like "this app has no navigation" — so the report always says how many navigation-shaped sites it saw, and gives the address of the ones it could not use.
If a run comes back partial, read the diagnostics before reading the graph.
A project that does not look like the defaults
The core is the React Navigation API and needs no configuration. Anything the project invented — its own navigation helpers, its own registry keys, screens named by URL rather than by name — is a dialect, and it is configured:
reactNavigationIndexer({
// `goToOffer(id)` navigates; group 1 is the route name
helperCalls: [/goTo(\w+)\s*\(/g],
// the app navigates by URL, and only the linking config relates the two
routeAliasFiles: ["navigation/linkingConfig.ts"],
})Requirements
- Runs after a code indexer such as
@cleya/plugin-ts-scip, in the same project. Screens link to the symbols it declares; without them the plugin refuses to run rather than write a graph with no components. typescriptis a peer dependency: route names are resolved by the compiler, using the project's own version.- No
tsconfig.jsonis not fatal — resolution falls back to enums and constant paths, and literal route names are still found.
Further
CLAUDE.md— architecture, invariants, module map. Lives alongside the source, not in the published package.
