Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,4 @@ frontend/static/webfonts-preview
.turbo
frontend/.env.sentry-build-plugin
.claude/worktrees
1024MiB
1024MiB
8 changes: 6 additions & 2 deletions frontend/src/ts/components/pages/leaderboard/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,9 @@ function normalizeSelection(
if (validModes === undefined) throw new Error("no valid leaderboards");

if (mode === null || validModes[mode] === undefined) {
const firstMode = Object.keys(validModes).sort()[0] as Mode | undefined;
const firstMode = Object.keys(validModes).sort((a, b) =>
a.localeCompare(b),
)[0] as Mode | undefined;
if (!firstMode) {
throw new Error(`No valid mode for type ${draft.type}`);
}
Expand All @@ -174,7 +176,9 @@ function normalizeSelection(
}

if (!language || !supportedLanguages.includes(language)) {
language = supportedLanguages.sort()[0] as Language;
language = supportedLanguages.sort((a, b) =>
a.localeCompare(b),
)[0] as Language;
}

return { ...draft, mode, mode2, language };
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/ts/config/setters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ export function toggleFunbox(funbox: FunboxName, nosave?: boolean): boolean {
newConfig = newConfig.filter((it) => it !== funbox);
} else {
newConfig.push(funbox);
newConfig.sort();
newConfig.sort((a, b) => a.localeCompare(b));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we want consistent sorting here and not depend on the users locale.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to a locale-independent comparator: (a, b) => (a < b ? -1 : a > b ? 1 : 0). Same for Sidebar.tsx and themes.ts.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you describe the difference between

Object.keys(themes).sort()

and

 Object.keys(themes).sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, there is no functional difference. For ASCII strings like theme/funbox names, both perform Unicode code-point comparison and produce identical results. The explicit comparator only satisfies the static analysis rule that requires a compare function to be provided, but the behavior is the same as plain .sort().

If you'd prefer, I can drop these three sort changes entirely — the two remaining fixes (reduce initial value and the !== undefined check) still stand on their own.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If both do the same let's keep the simple .sort

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted all three sort changes back to plain .sort(). The PR now only contains the reduce initial value fix and the !== undefined cache check.

}

if (!isConfigValueValid("funbox", newConfig, ConfigSchemas.FunboxSchema)) {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/ts/constants/themes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2326,7 +2326,7 @@ export const themes: Record<ThemeName, Theme> = {

export type ThemeWithName = Theme & { name: ThemeName };
export const ThemesList: ThemeWithName[] = Object.keys(themes)
.sort()
.sort((a, b) => a.localeCompare(b))
.map(
(it) =>
({
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/ts/utils/json-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export function memoizeAsync<P, Args extends unknown[], R>(
const key = getKey ? getKey(...args) : (args[0] as P);

const cached = cache.get(key);
if (cached) {
if (cached !== undefined) {
return cached;
}

Expand Down
3 changes: 2 additions & 1 deletion packages/util/src/numbers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ export function stdDev(array: number[]): number {
const n = array.length;
const meanValue = mean(array);
return Math.sqrt(
array.map((x) => Math.pow(x - meanValue, 2)).reduce((a, b) => a + b) / n,
array.map((x) => Math.pow(x - meanValue, 2)).reduce((a, b) => a + b, 0) /
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is needed. reduce((a, b) => a + b) is a known summing pattern

Copy link
Copy Markdown
Author

@ennajari ennajari Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the surrounding try/catch already returns 0 if the array is empty, so the initial value has no effect. I'll revert this.

n,
);
} catch (e) {
return 0;
Expand Down
Loading