feat(expo-router): add Expo Router support for Screens and navigations and introduce Steps API
- Adds Expo Router integration with a new Screens view and a Steps API to surface screens and their transitions. - Extends codegraph extraction/resolution to handle namespace objects, React hook bindings for handlers, and Swift RN bridge evidence; introduces per-site guard arguments and trigger metadata, enabling richer flow analysis across JS ↔ native boundaries. - Introduces UI and data-model changes to represent conditions as words (WHEN/AND/OR/NOT), display per-site call arguments, and show what fires a site (triggers). Adds new utilities (ui/conditions.ts) and updates ScreensView and StepsView to render scenarios with multiple sites and “ways” counts. - Implements site readers for WHEN/ARGS/TRIGGER, and wiring to expose steps via API endpoints (including /api/steps); enhances tests to cover namespace resolution, useCallback-driven handlers, and inline RN event listeners. - Updates styling and templates to reflect the new wording, scenario rows, and per-site details, including NOT instead of leading negation strings and multi-way links. - Documents and reflects changes in changelog and design docs to describe Expo Router integration and the Steps surface.
This commit is contained in:
@@ -73,6 +73,7 @@ beforeAll(async () => {
|
||||
' const handleZipComplete = useCallback(async (data: { uri: string }) => {\n' +
|
||||
' setZipUri(data.uri)\n' +
|
||||
' await uploadARCapture(data.uri)\n' +
|
||||
" Alert.alert('Uploaded', data.uri, [{ text: 'OK' }])\n" +
|
||||
" if (unlimited) router.replace('/')\n" +
|
||||
' }, [unlimited])\n' +
|
||||
' useEffect(() => {\n' +
|
||||
@@ -192,6 +193,7 @@ describe('buildSteps', () => {
|
||||
|
||||
const link = (from: string, to: string) =>
|
||||
payload.links.find((l) => l.from === byLabel.get(from)!.id && l.to === byLabel.get(to)!.id);
|
||||
const req = link('handleZipComplete', 'client.post +1');
|
||||
expect(link('/capture/review', 'handleApprove')?.kind).toBe('handler');
|
||||
expect(link('handleApprove', 'finalizeCaptureSession')?.kind).toBe('bridge');
|
||||
const evt = link('finalizeCaptureSession', 'handleZipComplete');
|
||||
@@ -200,14 +202,26 @@ describe('buildSteps', () => {
|
||||
expect(evt?.via.map((v) => v.name)).toEqual(['emitZipComplete']);
|
||||
expect(evt?.when).toBe('result');
|
||||
expect(evt?.label).toContain('event onZipComplete');
|
||||
expect(link('handleZipComplete', 'setZipUri')?.kind).toBe('store');
|
||||
const req = link('handleZipComplete', 'client.post +1');
|
||||
const storeLink = link('handleZipComplete', 'setZipUri');
|
||||
expect(storeLink?.kind).toBe('store');
|
||||
// Every call-shaped site says what it passes.
|
||||
expect(storeLink?.sites[0]?.args).toBe('data.uri');
|
||||
expect(link('handleApprove', 'finalizeCaptureSession')?.sites[0]?.args).toBe('');
|
||||
// One call behind an effect box: the box says it. Several: the panel does.
|
||||
const alert = payload.steps.find((s) => s.kind === 'effect' && s.effect?.category === 'device')!;
|
||||
expect(alert.label).toBe("Alert.alert('Uploaded', data.uri, […])");
|
||||
expect(network.label).toBe('client.post +1');
|
||||
expect(req?.sites.map((s) => `${s.text}(${s.args})`)).toEqual(["client.post('/frames', { uri })", "client.get('/frames/status')"]);
|
||||
expect(req?.kind).toBe('effect');
|
||||
expect(req?.via.map((v) => v.name)).toEqual(['uploadARCapture']);
|
||||
const nav = link('handleZipComplete', '/');
|
||||
expect(nav?.kind).toBe('navigates');
|
||||
expect(nav?.when).toBe('unlimited');
|
||||
expect(nav?.sites[0]?.text).toBe('replace /');
|
||||
// Every site carries the whole condition it runs under — one scenario each.
|
||||
expect(nav?.sites[0]?.when).toBe('unlimited');
|
||||
expect(evt?.sites[0]?.when).toBe('result');
|
||||
expect(storeLink?.sites[0]?.when).toBe('');
|
||||
|
||||
// Rows: the anchor on 0, then one more step away each. The listener is
|
||||
// registered BY the screen (`addListener('onZipComplete', handleZipComplete)`),
|
||||
|
||||
Reference in New Issue
Block a user