chore: clear the six code smells SonarQube reported (#181)
The list finally arrived from the reporting added earlier, and confirmed what #181 could only suspect: these are not the five eslint-plugin-sonarjs warnings that issue lists. Those were fixed under #261 and the count staying at five was a coincidence. It is six now, 25 minutes of debt, and one of them was mine. admin.ts imported '../utils' twice — I added readId in #207 without noticing the file already imported from there. One import now. filters.ts had a redundant `as ItemStatus[]`. TypeScript narrows an array through `.every()` with a type predicate from 5.5, and this project is on 5.9, so the assertion stopped telling the compiler anything. Removed, and the build confirms the narrowing holds without it. adminSettings.ts was the only CRITICAL: cognitive complexity 18 against a limit of 15, almost all of it three near-identical loops differing only in how they validated. Each validation is now a small pure reader returning a refusal rather than sending one, and the handler is one loop over a table. Adding a setting type means adding a row. That refactor is deliberately behaviour-preserving. Two things were left alone on purpose: the blanket rejection of empty text, which is wrong for the two settings whose documented default is empty and is filed as #280 rather than folded in where it would be invisible; and the absence of the `count` settings, which no caller submits and which the admin screen has no control for. I had started adding count validation and reverted it — widening behaviour under cover of a complexity fix is how a refactor stops being reviewable. The three S6478s are render props, not components defined during render. ErrorBoundary's `fallback` is typed `(error: Error) => React.ReactNode` and called as `this.props.fallback(...)`, so React only ever sees returned elements and never a new component type — the subtree destruction the rule describes does not happen, and the rule's own message offers `allowAsProps` for this shape, which cannot be set from here. Hoisted rather than suppressed because none of them closes over anything local, so at module level each is one stable function instead of a new closure per render. That is a mild improvement, not a contortion. Verified: 402 backend unit, 358 backend integration, 30 frontend unit, 157 e2e, both lints clean, both builds clean. The e2e run matters most here — storefront-errors.spec.ts exercises all three hoisted fallbacks, and it was run on its own first. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+68
-47
@@ -69,6 +69,72 @@ function usePrefersReducedMotion(): boolean {
|
||||
// looking at, rather than a page of its own. It stays a real, linkable URL —
|
||||
// bookmarkable, refreshable, and closed by the browser's Back button — while
|
||||
// never being a place with no way out of it.
|
||||
// Both hoisted out of the components that declared them inline.
|
||||
//
|
||||
// S6478 flags a function-returning-JSX in a prop as "defining a component
|
||||
// during render". These are render props — ErrorBoundary's `fallback` is typed
|
||||
// `(error: Error) => React.ReactNode` and called as `this.props.fallback(...)`
|
||||
// — so React only ever sees the returned elements, never a new component type,
|
||||
// and the subtree destruction the rule warns about does not happen. The rule's
|
||||
// own message offers `allowAsProps` for exactly this shape, which cannot be set
|
||||
// from here.
|
||||
//
|
||||
// Hoisting rather than suppressing because it costs nothing: neither closes
|
||||
// over anything local, so at module level each is one stable function instead
|
||||
// of a new closure per render. See #181.
|
||||
function modalErrorFallback(error: Error) {
|
||||
return (
|
||||
<ModalDialog
|
||||
open
|
||||
// No `title` here: ErrorFallback renders the same string as an <h3>, and
|
||||
// antd would otherwise announce the dialog's accessible name and then the
|
||||
// identical heading right after it.
|
||||
footer={null}
|
||||
onCancel={() => {
|
||||
window.location.href = '/';
|
||||
}}
|
||||
>
|
||||
<ErrorFallback
|
||||
error={error}
|
||||
title="Couldn't open that"
|
||||
actions={
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
window.location.href = '/';
|
||||
}}
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</ModalDialog>
|
||||
);
|
||||
}
|
||||
|
||||
function pageErrorFallback(error: Error) {
|
||||
return (
|
||||
<ErrorFallback
|
||||
error={error}
|
||||
title="Something went wrong"
|
||||
fullPage
|
||||
actions={[
|
||||
<Button key="reload" type="primary" onClick={() => window.location.reload()}>
|
||||
Reload
|
||||
</Button>,
|
||||
<Button
|
||||
key="home"
|
||||
onClick={() => {
|
||||
window.location.href = '/';
|
||||
}}
|
||||
>
|
||||
Back to the shop
|
||||
</Button>
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function AppRoutes() {
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
@@ -114,33 +180,7 @@ function AppRoutes() {
|
||||
{/* Rendered outside the Routes above, which are showing the backdrop. */}
|
||||
<ErrorBoundary
|
||||
context="modal"
|
||||
fallback={(error) => (
|
||||
<ModalDialog
|
||||
open
|
||||
// No `title` here: ErrorFallback renders the same string as an
|
||||
// <h3>, and antd would otherwise announce the dialog's accessible
|
||||
// name and then the identical heading right after it.
|
||||
footer={null}
|
||||
onCancel={() => {
|
||||
window.location.href = '/';
|
||||
}}
|
||||
>
|
||||
<ErrorFallback
|
||||
error={error}
|
||||
title="Couldn't open that"
|
||||
actions={
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
window.location.href = '/';
|
||||
}}
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</ModalDialog>
|
||||
)}
|
||||
fallback={modalErrorFallback}
|
||||
>
|
||||
{/* Unconditional, so /?boom=modal fires this boundary with the
|
||||
storefront rendered behind it — no session needed. */}
|
||||
@@ -190,26 +230,7 @@ function Root() {
|
||||
<BrowserRouter>
|
||||
<ErrorBoundary
|
||||
context="page"
|
||||
fallback={(error) => (
|
||||
<ErrorFallback
|
||||
error={error}
|
||||
title="Something went wrong"
|
||||
fullPage
|
||||
actions={[
|
||||
<Button key="reload" type="primary" onClick={() => window.location.reload()}>
|
||||
Reload
|
||||
</Button>,
|
||||
<Button
|
||||
key="home"
|
||||
onClick={() => {
|
||||
window.location.href = '/';
|
||||
}}
|
||||
>
|
||||
Back to the shop
|
||||
</Button>
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
fallback={pageErrorFallback}
|
||||
>
|
||||
<AppRoutes />
|
||||
</ErrorBoundary>
|
||||
|
||||
Reference in New Issue
Block a user