typeahead: Add typescript type definitions for typeahead.

This allows us to import typeahead from people.ts with types. This is
possible since #22586 was merged.

And since "sort_emojis" is always supposed to be called with valid emoji
objects that have "reaction_type" with an optional "emoji_code", we add
a check before we see if the emoji is popular to avoid poking
popular_set with an undefined value.

Signed-off-by: Zixuan James Li <p359101898@gmail.com>
This commit is contained in:
Zixuan James Li 2022-12-28 15:22:47 +08:00 committed by Tim Abbott
parent 9808bdf1d3
commit 53aa3f6c71
1 changed files with 41 additions and 13 deletions

View File

@ -28,7 +28,23 @@ export const popular_emojis = [
const unicode_marks = /\p{M}/gu;
export function remove_diacritics(s) {
type Emoji =
| {
emoji_name: string;
reaction_type: "realm_emoji" | "zulip_extra_emoji";
is_realm_emoji: true;
}
| UnicodeEmoji;
// emoji_code is only available for unicode emojis.
type UnicodeEmoji = {
emoji_name: string;
emoji_code: string;
reaction_type: "unicode_emoji";
is_realm_emoji: false;
};
export function remove_diacritics(s: string): string {
return s.normalize("NFKD").replace(unicode_marks, "");
}
@ -36,7 +52,11 @@ export function remove_diacritics(s) {
// * query is the user-entered search query
// * source_str is the string we're matching in, e.g. a user's name
// * split_char is the separator for this syntax (e.g. ' ').
export function query_matches_string(query, source_str, split_char) {
export function query_matches_string(
query: string,
source_str: string,
split_char: string,
): boolean {
source_str = source_str.toLowerCase();
source_str = remove_diacritics(source_str);
@ -53,7 +73,7 @@ export function query_matches_string(query, source_str, split_char) {
return source_str.startsWith(query) || source_str.includes(split_char + query);
}
function clean_query(query) {
function clean_query(query: string): string {
query = remove_diacritics(query);
// When `abc ` with a space at the end is typed in a
// contenteditable widget such as the composebox PM section, the
@ -64,19 +84,19 @@ function clean_query(query) {
return query;
}
export function clean_query_lowercase(query) {
export function clean_query_lowercase(query: string): string {
query = query.toLowerCase();
query = clean_query(query);
return query;
}
export const parse_unicode_emoji_code = (code) =>
export const parse_unicode_emoji_code = (code: string): string =>
code
.split("-")
.map((hex) => String.fromCodePoint(Number.parseInt(hex, 16)))
.join("");
export function get_emoji_matcher(query) {
export function get_emoji_matcher(query: string): (emoji: Emoji) => boolean {
// replace spaces with underscores for emoji matching
query = query.replace(/ /g, "_");
query = clean_query_lowercase(query);
@ -89,7 +109,11 @@ export function get_emoji_matcher(query) {
};
}
export function triage(query, objs, get_item) {
export function triage<T>(
query: string,
objs: T[],
get_item: (x: T) => string,
): {matches: T[]; rest: T[]} {
/*
We split objs into four groups:
@ -128,20 +152,24 @@ export function triage(query, objs, get_item) {
};
}
export function sort_emojis(objs, query) {
export function sort_emojis<T extends Emoji>(objs: T[], query: string): T[] {
// replace spaces with underscores for emoji matching
query = query.replace(/ /g, "_");
query = query.toLowerCase();
function decent_match(name) {
function decent_match(name: string): boolean {
const pieces = name.toLowerCase().split("_");
return pieces.some((piece) => piece.startsWith(query));
}
const popular_set = new Set(popular_emojis);
function is_popular(obj) {
return popular_set.has(obj.emoji_code) && decent_match(obj.emoji_name);
function is_popular(obj: Emoji): boolean {
return (
obj.reaction_type === "unicode_emoji" &&
popular_set.has(obj.emoji_code) &&
decent_match(obj.emoji_name)
);
}
const realm_emoji_names = new Set(
@ -153,7 +181,7 @@ export function sort_emojis(objs, query) {
const triage_results = triage(query, others, (x) => x.emoji_name);
function prioritise_realm_emojis(emojis) {
function prioritise_realm_emojis(emojis: T[]): T[] {
return [
...emojis.filter((emoji) => emoji.is_realm_emoji),
...emojis.filter((emoji) => !emoji.is_realm_emoji),
@ -168,7 +196,7 @@ export function sort_emojis(objs, query) {
// remove unicode emojis with same code but different names
// and unicode emojis overridden by realm emojis with same names
const unicode_emoji_codes = new Set();
const sorted_unique_results = [];
const sorted_unique_results: T[] = [];
for (const emoji of sorted_results_with_possible_duplicates) {
if (emoji.reaction_type !== "unicode_emoji") {
sorted_unique_results.push(emoji);