Fix the following React Review diagnostics in my codebase.
## Errors (2)
1. [error] rules-of-hooks — packages/openstory/tests/renderers/react.test.ts:26
React Hook "useState" is called in function "Anonymous" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use".
2. [error] rules-of-hooks — packages/openstory/tests/renderers/react.test.ts:48
React Hook "useState" is called in function "Anonymous" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use".
## Warnings (67)
3. [warning] nextjs-missing-metadata — apps/website/src/app/page.tsx:1
Page without metadata or generateMetadata export — hurts SEO
4. [warning] design-no-redundant-size-axes — packages/openstory/src/shell/src/components/top-bar.tsx:45
w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)
5. [warning] no-children-prop — packages/openstory/src/react/renderer.ts:104
Avoid passing children using a prop.
6. [warning] async-defer-await — packages/openstory/src/react/renderer.ts:124
await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast
7. [warning] js-set-map-lookups — packages/openstory/src/boot/boot.ts:120
array.indexOf() in a loop is O(n) per call — convert to a Set for O(1) lookups
8. [warning] anchor-is-valid — packages/openstory/tests/integration/fixtures/react-grab-like/stories/playground/composite-dashboard.stories.tsx:106
Use of incorrect `href` for the 'a' element.
9. [warning] no-inline-exhaustive-style — packages/openstory/tests/integration/fixtures/react-grab-like/stories/playground/composite-dashboard.stories.tsx:109
9 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse
10. [warning] no-inline-exhaustive-style — packages/openstory/tests/integration/fixtures/react-grab-like/stories/playground/composite-dashboard.stories.tsx:129
8 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse
11. [warning] no-inline-exhaustive-style — packages/openstory/tests/integration/fixtures/react-grab-like/stories/playground/composite-dashboard.stories.tsx:233
8 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse
12. [warning] design-no-redundant-size-axes — packages/openstory/src/shell/src/components/canvas.tsx:39
w-3 h-3 → use the shorthand size-3 (Tailwind v3.4+)
13. [warning] js-set-map-lookups — packages/openstory/src/shell/src/lib/url-state.ts:25
array.indexOf() in a loop is O(n) per call — convert to a Set for O(1) lookups
14. [warning] anchor-is-valid — packages/openstory/tests/integration/fixtures/react-grab-like/stories/renderer.stories.tsx:163
Use of incorrect `href` for the 'a' element.
15. [warning] anchor-is-valid — packages/openstory/tests/integration/fixtures/react-grab-like/stories/renderer.stories.tsx:172
Use of incorrect `href` for the 'a' element.
16. [warning] label-has-associated-control — packages/openstory/tests/integration/fixtures/react-grab-like/stories/renderer.stories.tsx:250
A form label must be associated with a control.
17. [warning] no-many-boolean-props — packages/openstory/tests/integration/fixtures/react-grab-like/stories/renderer.stories.tsx:56
Component "Scene" takes 5 boolean-like props (showContextMenu, isPromptMode, isPendingDismiss…) — consider compound components or explicit variants instead of stacking flags
18. [warning] no-inline-exhaustive-style — packages/openstory/tests/integration/fixtures/react-grab-like/stories/renderer.stories.tsx:222
8 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse
19. [warning] no-inline-exhaustive-style — packages/openstory/tests/integration/fixtures/react-grab-like/stories/renderer.stories.tsx:266
8 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse
20. [warning] no-outline-none — packages/openstory/tests/integration/fixtures/react-grab-like/stories/renderer.stories.tsx:274
outline: none removes keyboard focus visibility — use :focus-visible styling instead, or provide a box-shadow focus ring
21. [warning] no-inline-exhaustive-style — packages/openstory/tests/integration/fixtures/react-grab-like/stories/renderer.stories.tsx:281
8 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse
22. [warning] no-cascading-set-state — packages/openstory/src/shell/src/state/use-manifest.ts:26
5 setState calls in a single useEffect — consider using useReducer or deriving state
23. [warning] js-length-check-first — packages/openstory/src/utils/deep-equal.ts:8
.every() over an array compared to another array — short-circuit with `a.length === b.length && a.every(...)` so unequal-length arrays exit immediately
24. [warning] server-sequential-independent-await — packages/openstory/src/plugin/manifest.ts:147
Sequential `await` without a data dependency on the previous result — wrap the independent calls in `Promise.all([...])` so they race instead of waterfalling
25. [warning] async-await-in-loop — packages/openstory/src/plugin/manifest.ts:114
await inside a for…of loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently
26. [warning] async-await-in-loop — packages/openstory/src/utils/extract-props.ts:263
await inside a for…of loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently
27. [warning] async-await-in-loop — packages/openstory/src/utils/extract-props.ts:286
await inside a for…of loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently
28. [warning] async-await-in-loop — packages/openstory/src/utils/extract-props.ts:778
await inside a for…of loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently
29. [warning] async-await-in-loop — packages/openstory/src/utils/extract-props.ts:800
await inside a for…of loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently
30. [warning] async-await-in-loop — packages/openstory/src/utils/extract-props.ts:811
await inside a for…of loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently
31. [warning] async-await-in-loop — packages/openstory/src/utils/extract-props.ts:1493
await inside a for…of loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently
32. [warning] js-index-maps — packages/openstory/src/utils/render-csf-story.ts:145
array.find() in a loop is O(n*m) — build a Map for O(1) lookups
33. [warning] design-no-redundant-size-axes — packages/openstory/src/shell/src/components/ui/select.tsx:23
w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)
34. [warning] design-no-redundant-size-axes — packages/openstory/src/shell/src/components/ui/select.tsx:71
w-3.5 h-3.5 → use the shorthand size-3.5 (Tailwind v3.4+)
35. [warning] design-no-redundant-size-axes — packages/openstory/src/shell/src/components/ui/select.tsx:73
w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)
36. [warning] no-cascading-set-state — packages/openstory/src/shell/src/state/use-iframe-comms.ts:32
3 setState calls in a single useEffect — consider using useReducer or deriving state
37. [warning] no-cascading-set-state — packages/openstory/tests/integration/fixtures/react-grab-like/stories/playground/bouncing-timer.react.tsx:33
3 setState calls in a single useEffect — consider using useReducer or deriving state
38. [warning] no-inline-exhaustive-style — packages/openstory/tests/integration/fixtures/react-grab-like/stories/playground/bouncing-timer.react.tsx:86
10 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse
39. [warning] rerender-lazy-state-init — packages/openstory/tests/integration/fixtures/react-grab-like/stories/playground/live-counter.react.tsx:39
useState(now()) calls initializer on every render — use useState(() => now()) for lazy initialization
40. [warning] no-cascading-set-state — packages/openstory/tests/integration/fixtures/react-grab-like/stories/playground/live-counter.react.tsx:47
4 setState calls in a single useEffect — consider using useReducer or deriving state
41. [warning] no-inline-exhaustive-style — packages/openstory/tests/integration/fixtures/react-grab-like/stories/playground/live-counter.react.tsx:66
8 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse
42. [warning] no-barrel-import — packages/openstory/src/utils/build-inline-vite-config.ts:5
Import from barrel/index file — import directly from "../plugin/plugin" for better tree-shaking
43. [warning] server-sequential-independent-await — packages/openstory/src/cli/build.ts:171
Sequential `await` without a data dependency on the previous result — wrap the independent calls in `Promise.all([...])` so they race instead of waterfalling
44. [warning] async-parallel — packages/openstory/src/cli/build.ts:165
3 sequential await statements that appear independent — use Promise.all() for parallel execution
45. [warning] async-await-in-loop — packages/openstory/src/cli/build.ts:226
await inside a for…of loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently
46. [warning] async-await-in-loop — packages/openstory/src/utils/generate-stories.ts:52
await inside a for…of loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently
47. [warning] js-tosorted-immutable — packages/openstory/src/utils/generate-stories.ts:65
[...array].sort() — use array.toSorted() for immutable sorting (ES2023)
48. [warning] async-await-in-loop — packages/openstory/src/utils/generate-stories.ts:106
await inside a for-loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently
49. [warning] server-sequential-independent-await — packages/openstory/src/cli/inspect.ts:36
Sequential `await` without a data dependency on the previous result — wrap the independent calls in `Promise.all([...])` so they race instead of waterfalling
50. [warning] async-await-in-loop — packages/openstory/src/plugin/preview-discovery.ts:11
await inside a for…of loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently
51. [warning] async-await-in-loop — packages/openstory/src/utils/resolve-tsconfig-paths.ts:76
await inside a for-loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently
52. [warning] server-sequential-independent-await — packages/openstory/src/cli/dev.ts:20
Sequential `await` without a data dependency on the previous result — wrap the independent calls in `Promise.all([...])` so they race instead of waterfalling
53. [warning] async-parallel — packages/openstory/src/cli/dev.ts:14
4 sequential await statements that appear independent — use Promise.all() for parallel execution
54. [warning] no-effect-chain — packages/openstory/src/shell/src/app.tsx:80
useEffect reacts to "selectedStoryId" which is set by another useEffect — chains of effects add an extra render per link and become rigid as code evolves. Compute what you can during render and write all related state inside the event handler that originally fires the chain
55. [warning] prefer-useReducer — packages/openstory/src/shell/src/app.tsx:35
Component "App" has 5 useState calls — consider useReducer for related state
56. [warning] js-tosorted-immutable — packages/openstory/src/cli/list.ts:26
[...array].sort() — use array.toSorted() for immutable sorting (ES2023)
57. [warning] server-sequential-independent-await — packages/openstory/src/cli/list.ts:38
Sequential `await` without a data dependency on the previous result — wrap the independent calls in `Promise.all([...])` so they race instead of waterfalling
58. [warning] no-inline-exhaustive-style — packages/openstory/tests/integration/fixtures/react-grab-like/stories/target-box.tsx:6
15 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse
59. [warning] server-sequential-independent-await — packages/openstory/tests/utils/extract-props.test.ts:178
Sequential `await` without a data dependency on the previous result — wrap the independent calls in `Promise.all([...])` so they race instead of waterfalling
60. [warning] server-sequential-independent-await — packages/openstory/tests/utils/extract-props.test.ts:193
Sequential `await` without a data dependency on the previous result — wrap the independent calls in `Promise.all([...])` so they race instead of waterfalling
61. [warning] async-await-in-loop — packages/openstory/tests/renderers/test-utils.ts:27
await inside a for-loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently
62. [warning] async-await-in-loop — packages/openstory/tests/renderers/test-utils.ts:40
await inside a for-loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently
63. [warning] js-combine-iterations — packages/openstory/tests/utils/generate-stories.test.ts:126
.filter().map() iterates the array twice — combine into a single loop with .reduce() or for...of
64. [warning] no-barrel-import — packages/openstory/tests/integration/plugin-smoke.test.ts:8
Import from barrel/index file — import directly from "../../src/plugin/plugin" for better tree-shaking
65. [warning] no-barrel-import — packages/openstory/tests/integration/react-grab-render.test.ts:16
Import from barrel/index file — import directly from "../../src/plugin/plugin" for better tree-shaking
66. [warning] async-await-in-loop — packages/openstory/tests/integration/react-grab-render.test.ts:64
await inside a while-loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently
67. [warning] async-defer-await — packages/openstory/tests/integration/react-grab-render.test.ts:95
await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast
68. [warning] no-barrel-import — packages/openstory/tests/plugin/plugin-config-hook.test.ts:6
Import from barrel/index file — import directly from "../../src/plugin/plugin" for better tree-shaking
69. [warning] async-await-in-loop — packages/openstory/tests/integration/parse-fixture.test.ts:33
await inside a for…of loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently
Copy as prompt
❌ Errors (2)
React Hook "useState" is called in function "Anonymous" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". · 2 in 1 file
rules-of-hookspackages/openstory/tests/renderers/react.test.tsawait inside a for…of loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently · 16 in 9 files
async-await-in-looppackages/openstory/src/utils/extract-props.tspackages/openstory/src/utils/generate-stories.tspackages/openstory/tests/renderers/test-utils.tspackages/openstory/src/plugin/manifest.tspackages/openstory/src/cli/build.ts9 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse · 9 in 5 files
no-inline-exhaustive-stylepackages/openstory/tests/integration/fixtures/react-grab-like/stories/playground/composite-dashboard.stories.tsxpackages/openstory/tests/integration/fixtures/react-grab-like/stories/renderer.stories.tsxpackages/openstory/tests/integration/fixtures/react-grab-like/stories/playground/bouncing-timer.react.tsxpackages/openstory/tests/integration/fixtures/react-grab-like/stories/playground/live-counter.react.tsxpackages/openstory/tests/integration/fixtures/react-grab-like/stories/target-box.tsxSequential `await` without a data dependency on the previous result — wrap the independent calls in `Promise.all([...])` so they race instead of waterfalling · 7 in 6 files
server-sequential-independent-awaitpackages/openstory/tests/utils/extract-props.test.tspackages/openstory/src/plugin/manifest.tspackages/openstory/src/cli/build.tspackages/openstory/src/cli/inspect.tspackages/openstory/src/cli/dev.tsw-4 h-4 → use the shorthand size-4 (Tailwind v3.4+) · 5 in 3 files
design-no-redundant-size-axespackages/openstory/src/shell/src/components/ui/select.tsxpackages/openstory/src/shell/src/components/top-bar.tsxpackages/openstory/src/shell/src/components/canvas.tsx5 setState calls in a single useEffect — consider using useReducer or deriving state · 4 in 4 files
no-cascading-set-statepackages/openstory/src/shell/src/state/use-manifest.tspackages/openstory/src/shell/src/state/use-iframe-comms.tspackages/openstory/tests/integration/fixtures/react-grab-like/stories/playground/bouncing-timer.react.tsxpackages/openstory/tests/integration/fixtures/react-grab-like/stories/playground/live-counter.react.tsxImport from barrel/index file — import directly from "../plugin/plugin" for better tree-shaking · 4 in 4 files
no-barrel-importpackages/openstory/src/utils/build-inline-vite-config.tspackages/openstory/tests/integration/plugin-smoke.test.tspackages/openstory/tests/integration/react-grab-render.test.tspackages/openstory/tests/plugin/plugin-config-hook.test.tsUse of incorrect `href` for the 'a' element. · 3 in 2 files
anchor-is-validpackages/openstory/tests/integration/fixtures/react-grab-like/stories/renderer.stories.tsxpackages/openstory/tests/integration/fixtures/react-grab-like/stories/playground/composite-dashboard.stories.tsxawait blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast · 2 in 2 files
async-defer-awaitpackages/openstory/src/react/renderer.tspackages/openstory/tests/integration/react-grab-render.test.tsarray.indexOf() in a loop is O(n) per call — convert to a Set for O(1) lookups · 2 in 2 files
js-set-map-lookupspackages/openstory/src/boot/boot.tspackages/openstory/src/shell/src/lib/url-state.ts3 sequential await statements that appear independent — use Promise.all() for parallel execution · 2 in 2 files
async-parallelpackages/openstory/src/cli/build.tspackages/openstory/src/cli/dev.ts[...array].sort() — use array.toSorted() for immutable sorting (ES2023) · 2 in 2 files
js-tosorted-immutablepackages/openstory/src/utils/generate-stories.tspackages/openstory/src/cli/list.tsPage without metadata or generateMetadata export — hurts SEO · 1 in 1 file
nextjs-missing-metadataapps/website/src/app/page.tsxAvoid passing children using a prop. · 1 in 1 file
no-children-proppackages/openstory/src/react/renderer.tsA form label must be associated with a control. · 1 in 1 file
label-has-associated-controlpackages/openstory/tests/integration/fixtures/react-grab-like/stories/renderer.stories.tsxComponent "Scene" takes 5 boolean-like props (showContextMenu, isPromptMode, isPendingDismiss…) — consider compound components or explicit variants instead of stacking flags · 1 in 1 file
no-many-boolean-propspackages/openstory/tests/integration/fixtures/react-grab-like/stories/renderer.stories.tsxoutline: none removes keyboard focus visibility — use :focus-visible styling instead, or provide a box-shadow focus ring · 1 in 1 file
no-outline-nonepackages/openstory/tests/integration/fixtures/react-grab-like/stories/renderer.stories.tsx.every() over an array compared to another array — short-circuit with `a.length === b.length && a.every(...)` so unequal-length arrays exit immediately · 1 in 1 file
js-length-check-firstpackages/openstory/src/utils/deep-equal.tsarray.find() in a loop is O(n*m) — build a Map for O(1) lookups · 1 in 1 file
js-index-mapspackages/openstory/src/utils/render-csf-story.tsuseState(now()) calls initializer on every render — use useState(() => now()) for lazy initialization · 1 in 1 file
rerender-lazy-state-initpackages/openstory/tests/integration/fixtures/react-grab-like/stories/playground/live-counter.react.tsxuseEffect reacts to "selectedStoryId" which is set by another useEffect — chains of effects add an extra render per link and become rigid as code evolves. Compute what you can during render and write all related state inside the event handler that originally fires the chain · 1 in 1 file
no-effect-chainpackages/openstory/src/shell/src/app.tsxComponent "App" has 5 useState calls — consider useReducer for related state · 1 in 1 file
prefer-useReducerpackages/openstory/src/shell/src/app.tsx.filter().map() iterates the array twice — combine into a single loop with .reduce() or for...of · 1 in 1 file
js-combine-iterationspackages/openstory/tests/utils/generate-stories.test.tsReviewed by reactreview for commit 9937de8. Configure here.