Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/ci-js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
- uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0

- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
Expand Down Expand Up @@ -129,7 +129,7 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
- uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0

- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
Expand Down Expand Up @@ -158,7 +158,7 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
- uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0

- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
Expand Down Expand Up @@ -213,7 +213,7 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
- uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0

- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
Expand Down
32 changes: 16 additions & 16 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,28 @@
"@fontsource-variable/geist": "^5.3.0",
"@fontsource-variable/geist-mono": "^5.3.0",
"@kurze-url/api-client": "workspace:*",
"@sentry/tanstackstart-react": "^10.74.0",
"@sentry/tanstackstart-react": "^10.75.2",
"@supabase/ssr": "^0.12.7",
"@supabase/supabase-js": "^2.116.0",
"@supabase/supabase-js": "^2.117.0",
"@tailwindcss/vite": "^4.3.3",
"@tanstack/react-devtools": "^0.10.12",
"@tanstack/react-form": "^1.33.5",
"@tanstack/react-query": "^5.102.8",
"@tanstack/react-router": "^1.170.35",
"@tanstack/react-router-devtools": "^1.167.1",
"@tanstack/react-router-ssr-query": "^1.167.2",
"@tanstack/react-start": "^1.168.52",
"@tanstack/react-query": "^5.103.2",
"@tanstack/react-router": "1.170.35",
"@tanstack/react-router-devtools": "1.167.1",
"@tanstack/react-router-ssr-query": "1.167.2",
"@tanstack/react-start": "1.168.52",
"@vercel/related-projects": "^1.1.1",
"class-variance-authority": "^0.7.1",
"cn": "^0.2.6",
"cn": "^0.4.0",
"date-fns": "^4.4.0",
"i18next": "^26.4.2",
"lucide-react": "^1.44.0",
"lucide-react": "^1.47.0",
"react": "^19.3.0",
"react-day-picker": "^10.0.1",
"react-dom": "^19.3.0",
"react-i18next": "^17.0.13",
"recharts": "3.8.0",
"react-i18next": "^17.0.15",
"recharts": "3.10.1",
"tailwindcss": "^4.3.3",
"tw-animate-css": "^1.4.0"
},
Expand All @@ -57,20 +57,20 @@
"@testing-library/jest-dom": "^7.0.1",
"@testing-library/react": "^16.3.3",
"@testing-library/user-event": "^14.6.7",
"@types/node": "^26.5.1",
"@types/node": "^26.6.2",
"@types/pg": "^8.23.1",
"@types/react": "^19.3.0",
"@types/react-dom": "^19.3.0",
"@vitejs/plugin-react": "^6.1.1",
"@vitest/browser": "5.0.0",
"@vitest/browser-playwright": "5.0.0",
"@vitest/browser": "5.0.1",
"@vitest/browser-playwright": "5.0.1",
"axe-core": "^4.13.0",
"jsdom": "^30.0.1",
"jsdom": "^30.1.1",
"msw": "^2.15.0",
"pg": "^8.23.0",
"shadcn": "^4.21.0",
"storybook": "^10.6.0",
"vite": "^8.3.0",
"vitest": "^5.0.0"
"vitest": "^5.0.1"
}
}
8 changes: 7 additions & 1 deletion apps/web/src/components/stat-series-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,13 @@ export function StatSeriesChart({
content={
// oxlint-disable-next-line react-perf/jsx-no-jsx-as-prop -- Recharts' own `content` render-prop idiom: `ChartTooltip`/`ChartLegend` clone and merge their own props onto this element. A stable reference would need a `useMemo` around a one-line static element per chart.
<ChartTooltipContent
labelFormatter={(value) => formatDay(String(value), language)}
labelFormatter={(value) =>
// Recharts types the label as `ReactNode`, which admits objects — and, in
// React 19, promises — so a bare `String()` could print `[object Object]`.
// Here it is always the X axis' ISO day; anything else has no meaning for
// this chart and renders no label.
typeof value === 'string' ? formatDay(value, language) : null
}
/>
}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,31 @@ function rejectingFetchLinkWith(
};
}

/**
* A `query` fake that always resolves with `STATS_FIXTURE` — the resolving
* counterpart of `rejectingQueryWith`, kept at module level for the same
* reason. Three tests used to declare this stub inline, each with its own copy
* of the suppression it carries, and oxlint 1.85's `consistent-function-scoping`
* began flagging those copies as closures that capture nothing.
*
* @returns The fixture statistics.
*/
// oxlint-disable-next-line typescript/require-await -- must satisfy `StatsDataSource.query`, which returns a `Promise<LinkStats>`; nothing here needs an `await`.
async function resolveStats(): Promise<LinkStats> {
return STATS_FIXTURE;
}

/**
* A `fetchLink` fake that always resolves with the default `link()` — same
* reasoning as `resolveStats` above, for `loadLink`'s own parameter shape.
*
* @returns The fixture link.
*/
// oxlint-disable-next-line typescript/require-await -- must satisfy `loadLink`'s `LinkFetcher`-shaped parameter; nothing here needs an `await`.
async function resolveLink(): Promise<Link> {
return link();
}

describe(statsView, () => {
// The single easiest thing to get wrong on this page. An empty document
// from a link with counting off means "not counted", not "not clicked",
Expand Down Expand Up @@ -182,10 +207,7 @@ describe(statsView, () => {

describe(loadStats, () => {
it('returns the fetched stats when the API call succeeds', async () => {
// oxlint-disable-next-line typescript/require-await -- must satisfy `StatsDataSource.query`, which returns a `Promise<LinkStats>`; nothing here needs an `await`.
const query = async (): Promise<LinkStats> => STATS_FIXTURE;

await expect(loadStats({ query }, 'link-a', {})).resolves.toBe(STATS_FIXTURE);
await expect(loadStats({ query: resolveStats }, 'link-a', {})).resolves.toBe(STATS_FIXTURE);
});

/**
Expand Down Expand Up @@ -254,15 +276,10 @@ describe('a missing link 404s the same way regardless of which fetch reports it'

describe(loadStatsPage, () => {
it('reports the loaded link together with its statistics', async () => {
// oxlint-disable-next-line typescript/require-await -- must satisfy `StatsDataSource.query`, which returns a `Promise<LinkStats>`; nothing here needs an `await`.
const query = async (): Promise<LinkStats> => STATS_FIXTURE;
// oxlint-disable-next-line typescript/require-await -- must satisfy `loadLink`'s `LinkFetcher`-shaped parameter; nothing here needs an `await`.
const fetchLink = async (): Promise<Link> => link();

const result = await loadStatsPage({
fetchLink,
fetchLink: resolveLink,
linkId: 'link-a',
queryClient: { query },
queryClient: { query: resolveStats },
window: {},
});

Expand All @@ -283,15 +300,11 @@ describe(loadStatsPage, () => {
*/
it('returns the instant it ran at, not one the caller has to supply', async () => {
const before = Date.now();
// oxlint-disable-next-line typescript/require-await -- must satisfy `StatsDataSource.query`, which returns a `Promise<LinkStats>`; nothing here needs an `await`.
const query = async (): Promise<LinkStats> => STATS_FIXTURE;
// oxlint-disable-next-line typescript/require-await -- must satisfy `loadLink`'s `LinkFetcher`-shaped parameter; nothing here needs an `await`.
const fetchLink = async (): Promise<Link> => link();

const { today } = await loadStatsPage({
fetchLink,
fetchLink: resolveLink,
linkId: 'link-a',
queryClient: { query },
queryClient: { query: resolveStats },
window: {},
});
const after = Date.now();
Expand Down
16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,21 @@
"devDependencies": {
"@mheob/oxfmt-config": "^1.3.3",
"@mheob/oxlint-config": "^4.0.1",
"@types/node": "^26.5.1",
"cve-lite-cli": "^1.34.0",
"@types/node": "^26.6.2",
"cve-lite-cli": "^1.36.1",
"eslint-plugin-better-tailwindcss": "^4.7.0",
"eslint-plugin-jsonc": "^3.4.2",
"eslint-plugin-regexp": "^3.3.0",
"eslint-plugin-regexp": "^3.3.1",
"eslint-plugin-storybook": "^10.6.0",
"eslint-plugin-yml": "^3.8.1",
"lefthook": "^2.1.12",
"oxfmt": "^0.67.0",
"oxlint": "^1.82.0",
"oxlint-tsgolint": "^7.0.2001",
"lefthook": "^2.1.14",
"oxfmt": "^0.70.0",
"oxlint": "^1.85.0",
"oxlint-tsgolint": "^7.0.2002",
"typescript": "^7.0.2"
},
"engines": {
"node": ">=24"
},
"packageManager": "pnpm@11.25.0"
"packageManager": "pnpm@12.6.0"
}
Loading
Loading