mirror of https://github.com/zulip/zulip.git
list_widget: Fix unsafe unchecked casts in generic comparators.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
parent
a53231a1ae
commit
2f95c55df4
|
@ -8,7 +8,6 @@ import * as blueslip from "./blueslip";
|
||||||
import * as scroll_util from "./scroll_util";
|
import * as scroll_util from "./scroll_util";
|
||||||
|
|
||||||
type SortingFunction<T> = (a: T, b: T) => number;
|
type SortingFunction<T> = (a: T, b: T) => number;
|
||||||
type GenericSortingFunction<T = Record<string, unknown>> = (prop: string) => SortingFunction<T>;
|
|
||||||
|
|
||||||
type ListWidgetMeta<Key = unknown, Item = Key> = {
|
type ListWidgetMeta<Key = unknown, Item = Key> = {
|
||||||
sorting_function: SortingFunction<Item> | null;
|
sorting_function: SortingFunction<Item> | null;
|
||||||
|
@ -125,11 +124,13 @@ export function get_filtered_items<Key, Item>(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const alphabetic_sort: GenericSortingFunction = (prop) =>
|
export function alphabetic_sort<Prop extends string>(
|
||||||
function (a, b) {
|
prop: Prop,
|
||||||
|
): SortingFunction<Record<Prop, string>> {
|
||||||
|
return (a, b) => {
|
||||||
// The conversion to uppercase helps make the sorting case insensitive.
|
// The conversion to uppercase helps make the sorting case insensitive.
|
||||||
const str1 = (a[prop] as string).toUpperCase();
|
const str1 = a[prop].toUpperCase();
|
||||||
const str2 = (b[prop] as string).toUpperCase();
|
const str2 = b[prop].toUpperCase();
|
||||||
|
|
||||||
if (str1 === str2) {
|
if (str1 === str2) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -139,11 +140,14 @@ export const alphabetic_sort: GenericSortingFunction = (prop) =>
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export const numeric_sort: GenericSortingFunction = (prop) =>
|
export function numeric_sort<Prop extends string>(
|
||||||
function (a, b) {
|
prop: Prop,
|
||||||
const a_prop = Number.parseFloat(a[prop] as string);
|
): SortingFunction<Record<Prop, number>> {
|
||||||
const b_prop = Number.parseFloat(b[prop] as string);
|
return (a, b) => {
|
||||||
|
const a_prop = a[prop];
|
||||||
|
const b_prop = b[prop];
|
||||||
|
|
||||||
if (a_prop > b_prop) {
|
if (a_prop > b_prop) {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -153,23 +157,32 @@ export const numeric_sort: GenericSortingFunction = (prop) =>
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const generic_sorts = {
|
type GenericSortKeys = {
|
||||||
|
alphabetic: string;
|
||||||
|
numeric: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const generic_sorts: {
|
||||||
|
[GenericFunc in keyof GenericSortKeys]: <Prop extends string>(
|
||||||
|
prop: Prop,
|
||||||
|
) => SortingFunction<Record<Prop, GenericSortKeys[GenericFunc]>>;
|
||||||
|
} = {
|
||||||
alphabetic: alphabetic_sort,
|
alphabetic: alphabetic_sort,
|
||||||
numeric: numeric_sort,
|
numeric: numeric_sort,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function generic_sort_functions<T extends Record<string, unknown>>(
|
export function generic_sort_functions<
|
||||||
generic_func: keyof typeof generic_sorts,
|
GenericFunc extends keyof GenericSortKeys,
|
||||||
props: string[],
|
Prop extends string,
|
||||||
): Record<string, SortingFunction<T>> {
|
>(
|
||||||
const sorting_functions: Record<string, SortingFunction<T>> = {};
|
generic_func: GenericFunc,
|
||||||
for (const prop of props) {
|
props: Prop[],
|
||||||
const key = `${prop}_${generic_func}`;
|
): Record<string, SortingFunction<Record<Prop, GenericSortKeys[GenericFunc]>>> {
|
||||||
sorting_functions[key] = generic_sorts[generic_func](prop);
|
return Object.fromEntries(
|
||||||
}
|
props.map((prop) => [`${prop}_${generic_func}`, generic_sorts[generic_func](prop)]),
|
||||||
|
);
|
||||||
return sorting_functions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_scroll_position_for_render(scroll_container: HTMLElement): boolean {
|
function is_scroll_position_for_render(scroll_container: HTMLElement): boolean {
|
||||||
|
|
|
@ -24,6 +24,7 @@ run_test("settings", ({override}) => {
|
||||||
override(list_widget, "create", (_$container, list) => {
|
override(list_widget, "create", (_$container, list) => {
|
||||||
assert.deepEqual(list, [
|
assert.deepEqual(list, [
|
||||||
{
|
{
|
||||||
|
date_muted: 1577836800000,
|
||||||
date_muted_str: "Jan 1, 2020",
|
date_muted_str: "Jan 1, 2020",
|
||||||
user_id: 5,
|
user_id: 5,
|
||||||
user_name: "Feivel Fiverson",
|
user_name: "Feivel Fiverson",
|
||||||
|
|
Loading…
Reference in New Issue