diff --git a/web/e2e-tests/lib/common.ts b/web/e2e-tests/lib/common.ts index 724755b5d4..378fb6b35f 100644 --- a/web/e2e-tests/lib/common.ts +++ b/web/e2e-tests/lib/common.ts @@ -66,19 +66,17 @@ export const window_size = { }; export async function ensure_browser(): Promise { - if (browser === null) { - browser = await puppeteer.launch({ - args: [ - `--window-size=${window_size.width},${window_size.height}`, - "--no-sandbox", - "--disable-setuid-sandbox", - ], - // TODO: Change defaultViewport to 1280x1024 when puppeteer fixes the window size issue with firefox. - // Here is link to the issue that is tracking the above problem https://github.com/puppeteer/puppeteer/issues/6442. - defaultViewport: null, - headless: true, - }); - } + browser ??= await puppeteer.launch({ + args: [ + `--window-size=${window_size.width},${window_size.height}`, + "--no-sandbox", + "--disable-setuid-sandbox", + ], + // TODO: Change defaultViewport to 1280x1024 when puppeteer fixes the window size issue with firefox. + // Here is link to the issue that is tracking the above problem https://github.com/puppeteer/puppeteer/issues/6442. + defaultViewport: null, + headless: true, + }); return browser; } @@ -256,14 +254,11 @@ export async function get_internal_email_from_name( export async function log_in( page: Page, - credentials: {username: string; password: string} | null = null, + credentials: {username: string; password: string} = test_credentials.default_user, ): Promise { console.log("Logging in"); await page.goto(realm_url + "login/"); assert.equal(realm_url + "login/", page.url()); - if (credentials === null) { - credentials = test_credentials.default_user; - } // fill login form const params = { username: credentials.username, diff --git a/web/src/browser_history.ts b/web/src/browser_history.ts index e509346c7d..23d83420a2 100644 --- a/web/src/browser_history.ts +++ b/web/src/browser_history.ts @@ -175,13 +175,10 @@ export function current_scroll_offset(): number | undefined { export function update_current_history_state_data( new_data: StateData, - url: string | undefined = undefined, + url: string = window.location.href, ): void { // The optional url parameter is for those rare situations where // we want to adjust the URL without adding a new history entry. - if (url === undefined) { - url = window.location.href; - } const current_state = state_data_schema.nullable().parse(window.history.state); const current_state_data = { narrow_pointer: current_state?.narrow_pointer, diff --git a/web/src/compose_recipient.ts b/web/src/compose_recipient.ts index 0d31ec005d..993ccd7d0e 100644 --- a/web/src/compose_recipient.ts +++ b/web/src/compose_recipient.ts @@ -344,13 +344,7 @@ export function update_topic_inputbox_on_mandatory_topics_change(): void { update_topic_displayed_text(compose_state.topic()); } -export function update_topic_displayed_text( - topic_name: string | undefined, - has_topic_focus = false, -): void { - if (topic_name === undefined) { - topic_name = ""; - } +export function update_topic_displayed_text(topic_name = "", has_topic_focus = false): void { compose_state.topic(topic_name); // When topics are mandatory, no additional adjustments are needed. diff --git a/web/src/copy_messages.ts b/web/src/copy_messages.ts index 07c1af3d6b..b00283fa5f 100644 --- a/web/src/copy_messages.ts +++ b/web/src/copy_messages.ts @@ -285,11 +285,9 @@ export function analyze_selection(selection: Selection): { // Skip any selection sections that don't intersect a message. continue; } - if (start_id === undefined) { - // start_id is the Zulip message ID of the first message - // touched by the selection. - start_id = start_data[0]; - } + // start_id is the Zulip message ID of the first message + // touched by the selection. + start_id ??= start_data[0]; $endc = $(range.endContainer); $initial_end_tr = get_end_tr_from_endc($endc); diff --git a/web/src/custom_profile_fields_ui.ts b/web/src/custom_profile_fields_ui.ts index 3526511aea..4215e3d7ce 100644 --- a/web/src/custom_profile_fields_ui.ts +++ b/web/src/custom_profile_fields_ui.ts @@ -37,14 +37,14 @@ export function append_custom_profile_fields(element_id: string, user_id: number ]); for (const field of all_custom_fields) { - let field_value = people.get_custom_profile_data(user_id, field.id); + const field_value = people.get_custom_profile_data(user_id, field.id) ?? { + value: "", + rendered_value: "", + }; const editable_by_user = current_user.is_admin || field.editable_by_user; const is_select_field = field.type === all_field_types.SELECT.id; const field_choices = []; - if (field_value === undefined || field_value === null) { - field_value = {value: "", rendered_value: ""}; - } if (is_select_field) { const field_choice_dict = settings_components.select_field_data_schema.parse( JSON.parse(field.field_data), diff --git a/web/src/drafts.ts b/web/src/drafts.ts index f3ef5b115b..69142625d4 100644 --- a/web/src/drafts.ts +++ b/web/src/drafts.ts @@ -145,9 +145,7 @@ export const draft_model = (function () { // since we expect bugged drafts will have either been run // through this code or been deleted by the previous // behavior of deleting them after 30 days. - if (draft.topic === undefined) { - draft.topic = ""; - } + draft.topic ??= ""; valid_drafts[draft_id] = { ...draft, diff --git a/web/src/filter.ts b/web/src/filter.ts index 34e87620bf..5ca8b4e1a2 100644 --- a/web/src/filter.ts +++ b/web/src/filter.ts @@ -1008,9 +1008,7 @@ export class Filter { } predicate(): (message: Message) => boolean { - if (this._predicate === undefined) { - this._predicate = this._build_predicate(); - } + this._predicate ??= this._build_predicate(); return this._predicate; } @@ -1154,9 +1152,7 @@ export class Filter { } can_mark_messages_read(): boolean { - if (this._can_mark_messages_read === undefined) { - this._can_mark_messages_read = this.calc_can_mark_messages_read(); - } + this._can_mark_messages_read ??= this.calc_can_mark_messages_read(); return this._can_mark_messages_read; } diff --git a/web/src/giphy.ts b/web/src/giphy.ts index ab0965568a..4143c4322d 100644 --- a/web/src/giphy.ts +++ b/web/src/giphy.ts @@ -61,9 +61,7 @@ async function renderGIPHYGrid(targetEl: HTMLElement): Promise<{remove: () => vo const {renderGrid} = await import(/* webpackChunkName: "giphy-sdk" */ "@giphy/js-components"); const {GiphyFetch} = await import(/* webpackChunkName: "giphy-sdk" */ "@giphy/js-fetch-api"); - if (giphy_fetch === undefined) { - giphy_fetch = new GiphyFetch(realm.giphy_api_key); - } + giphy_fetch ??= new GiphyFetch(realm.giphy_api_key); async function fetchGifs(offset: number): Promise { assert(giphy_fetch !== undefined); diff --git a/web/src/information_density.ts b/web/src/information_density.ts index 2ca0879cc5..54a660f575 100644 --- a/web/src/information_density.ts +++ b/web/src/information_density.ts @@ -291,12 +291,8 @@ export function update_information_density_settings( $elem: JQuery, changed_property: "web_font_size_px" | "web_line_height_percent", for_settings_ui = false, - new_value?: number, + new_value: number = get_new_value_for_information_density_settings($elem, changed_property), ): number { - if (new_value === undefined) { - new_value = get_new_value_for_information_density_settings($elem, changed_property); - } - user_settings[changed_property] = new_value; $elem.closest(".button-group").find(".current-value").val(new_value); if (for_settings_ui) { diff --git a/web/src/invite.ts b/web/src/invite.ts index 1a5f1bf2f8..81ca4e0edc 100644 --- a/web/src/invite.ts +++ b/web/src/invite.ts @@ -432,12 +432,11 @@ function open_invite_user_modal(e: JQuery.ClickEvent): void $(e.target).parent().remove(); }); - function toggle_invite_submit_button(selected_tab?: string): void { - if (selected_tab === undefined) { - selected_tab = $(".invite_users_option_tabs") - .find(".selected") - .attr("data-tab-key"); - } + function toggle_invite_submit_button( + selected_tab: string | undefined = $(".invite_users_option_tabs") + .find(".selected") + .attr("data-tab-key"), + ): void { const valid_custom_time = util.validate_custom_time_input( custom_expiration_time_input, false, diff --git a/web/src/lightbox.ts b/web/src/lightbox.ts index 780ac20283..d444ee6e60 100644 --- a/web/src/lightbox.ts +++ b/web/src/lightbox.ts @@ -373,17 +373,13 @@ function display_video(payload: Media): void { } export function build_open_media_function( - on_close: (() => void) | undefined, + on_close = (): void => { + remove_video_players(); + is_open = false; + assert(document.activeElement instanceof HTMLElement); + document.activeElement.blur(); + }, ): ($media: JQuery) => void { - if (on_close === undefined) { - on_close = function () { - remove_video_players(); - is_open = false; - assert(document.activeElement instanceof HTMLElement); - document.activeElement.blur(); - }; - } - return function ($media: JQuery): void { // This is used both for clicking on media in the messagelist, as well as clicking on images // in the media list under the lightbox when it is open. diff --git a/web/src/message_events.ts b/web/src/message_events.ts index c241841945..68124df279 100644 --- a/web/src/message_events.ts +++ b/web/src/message_events.ts @@ -449,12 +449,9 @@ export function update_messages(events: UpdateMessageEvent[]): void { // Add message's edit_history in message dict // For messages that are edited, edit_history needs to // be added to message in frontend. - if (anchor_message.edit_history === undefined) { - anchor_message.edit_history = []; - } anchor_message.edit_history = [ edit_history_entry, - ...anchor_message.edit_history, + ...(anchor_message.edit_history ?? []), ]; } any_message_content_edited = true; @@ -587,12 +584,9 @@ export function update_messages(events: UpdateMessageEvent[]): void { edit_history_entry.topic = new_topic; edit_history_entry.prev_topic = orig_topic; } - if (moved_message.edit_history === undefined) { - moved_message.edit_history = []; - } moved_message.edit_history = [ edit_history_entry, - ...moved_message.edit_history, + ...(moved_message.edit_history ?? []), ]; } diff --git a/web/src/message_helper.ts b/web/src/message_helper.ts index 744c6b25c3..2972ca095d 100644 --- a/web/src/message_helper.ts +++ b/web/src/message_helper.ts @@ -56,10 +56,7 @@ export function process_new_message(raw_message: RawMessage, deliver_locally = f let message: Message; if (message_with_booleans.type === "stream") { - let topic = message_with_booleans.topic; - if (topic === undefined) { - topic = message_with_booleans.subject; - } + const topic = message_with_booleans.topic ?? message_with_booleans.subject; assert(topic !== undefined); // We add fully delivered messages to stream_topic_history, diff --git a/web/src/message_list_data.ts b/web/src/message_list_data.ts index de4f8fcb05..9bab2cd47c 100644 --- a/web/src/message_list_data.ts +++ b/web/src/message_list_data.ts @@ -206,9 +206,7 @@ export class MessageListData { } _get_predicate(): (message: Message) => boolean { // We cache this. - if (!this.predicate) { - this.predicate = this.filter.predicate(); - } + this.predicate ??= this.filter.predicate(); return this.predicate; } diff --git a/web/src/message_view.ts b/web/src/message_view.ts index 2c5e61d5eb..28d173a5e8 100644 --- a/web/src/message_view.ts +++ b/web/src/message_view.ts @@ -1202,10 +1202,7 @@ export function render_message_list_with_selected_message(opts: { const id_info = opts.id_info; const select_offset = opts.select_offset; - let msg_id = id_info.final_select_id; - if (msg_id === undefined) { - msg_id = message_lists.current.first_unread_message_id(); - } + const msg_id = id_info.final_select_id ?? message_lists.current.first_unread_message_id(); // There should be something since it's not visibly empty. assert(msg_id !== undefined); diff --git a/web/src/people.ts b/web/src/people.ts index 03e75e6bb3..ed41d15e61 100644 --- a/web/src/people.ts +++ b/web/src/people.ts @@ -1237,9 +1237,7 @@ export function build_termlet_matcher(termlet: string): (user: User) => boolean let full_name = user.full_name; // Only ignore diacritics if the query is plain ascii if (is_ascii) { - if (user.name_with_diacritics_removed === undefined) { - user.name_with_diacritics_removed = typeahead.remove_diacritics(full_name); - } + user.name_with_diacritics_removed ??= typeahead.remove_diacritics(full_name); full_name = user.name_with_diacritics_removed; } const names = full_name.toLowerCase().split(" "); @@ -1576,11 +1574,7 @@ export function get_user_by_id_assert_valid( return get_by_user_id(user_id); } - let person = maybe_get_user_by_id(user_id, true); - if (person === undefined) { - person = add_inaccessible_user(user_id); - } - return person; + return maybe_get_user_by_id(user_id, true) ?? add_inaccessible_user(user_id); } function get_involved_people(message: MessageWithBooleans): DisplayRecipientUser[] { diff --git a/web/src/portico/showroom.ts b/web/src/portico/showroom.ts index e8ab5f0ba1..d4fda02e9c 100644 --- a/web/src/portico/showroom.ts +++ b/web/src/portico/showroom.ts @@ -1,5 +1,6 @@ import Handlebars from "handlebars/runtime.js"; import $ from "jquery"; +import assert from "minimalistic-assert"; import render_banner from "../../templates/components/banner.hbs"; import {$t, $t_html} from "../i18n.ts"; @@ -404,7 +405,8 @@ $(window).on("load", () => { return; } let label = $("input#primary_button_text").val(); - if (!label) { + assert(label !== undefined); + if (label === "") { label = "Primary Button"; } const is_icon_enabled = $("#enable_primary_button_icon").prop("checked") === true; @@ -498,7 +500,8 @@ $(window).on("load", () => { return; } let label = $("input#quiet_button_text").val(); - if (!label) { + assert(label !== undefined); + if (label === "") { label = "Quiet Button"; } const is_icon_enabled = $("#enable_quiet_button_icon").prop("checked") === true; @@ -587,7 +590,8 @@ $(window).on("load", () => { return; } let label = $("input#borderless_button_text").val(); - if (!label) { + assert(label !== undefined); + if (label === "") { label = "Borderless Button"; } const is_icon_enabled = $("#enable_borderless_button_icon").prop("checked") === true; diff --git a/web/src/postprocess_content.ts b/web/src/postprocess_content.ts index 1ad0d7fa35..abdc242bd5 100644 --- a/web/src/postprocess_content.ts +++ b/web/src/postprocess_content.ts @@ -8,9 +8,7 @@ import * as util from "./util.ts"; let inertDocument: Document | undefined; export function postprocess_content(html: string): string { - if (inertDocument === undefined) { - inertDocument = new DOMParser().parseFromString("", "text/html"); - } + inertDocument ??= new DOMParser().parseFromString("", "text/html"); const template = inertDocument.createElement("template"); template.innerHTML = html; diff --git a/web/src/recent_senders.ts b/web/src/recent_senders.ts index 361a4cfb7d..f557e8b0c6 100644 --- a/web/src/recent_senders.ts +++ b/web/src/recent_senders.ts @@ -31,9 +31,7 @@ export class IdTracker { } max_id(): number { - if (this._cached_max_id === undefined) { - this._cached_max_id = _.max([...this.ids]); - } + this._cached_max_id ??= _.max([...this.ids]); return this._cached_max_id ?? -1; } diff --git a/web/src/settings_notifications.ts b/web/src/settings_notifications.ts index 40074322ad..d6b9c529ad 100644 --- a/web/src/settings_notifications.ts +++ b/web/src/settings_notifications.ts @@ -160,10 +160,7 @@ function stream_notification_setting_changed(target: HTMLInputElement): void { const $status_element = $(target).closest(".subsection-parent").find(".alert-notification"); const setting = stream_specific_notification_settings_schema.keyof().parse(target.name); - if (sub[setting] === null) { - sub[setting] = - user_settings[settings_config.generalize_stream_notification_setting[setting]]; - } + sub[setting] ??= user_settings[settings_config.generalize_stream_notification_setting[setting]]; stream_settings_api.set_stream_property( sub, {property: setting, value: target.checked}, diff --git a/web/src/stream_data.ts b/web/src/stream_data.ts index bcef05e319..77b2eecd2d 100644 --- a/web/src/stream_data.ts +++ b/web/src/stream_data.ts @@ -209,11 +209,7 @@ export function get_stream_id(name: string): number | undefined { // Note: Only use this function for situations where // you are comfortable with a user dealing with an // old name of a stream (from prior to a rename). - let stream_id = stream_ids_by_name.get(name); - if (!stream_id) { - stream_id = stream_ids_by_old_names.get(name); - } - return stream_id; + return stream_ids_by_name.get(name) ?? stream_ids_by_old_names.get(name); } export function get_stream_name_from_id(stream_id: number): string { @@ -224,10 +220,7 @@ export let get_sub_by_name = (name: string): StreamSubscription | undefined => { // Note: Only use this function for situations where // you are comfortable with a user dealing with an // old name of a stream (from prior to a rename). - let stream_id = stream_ids_by_name.get(name); - if (!stream_id) { - stream_id = stream_ids_by_old_names.get(name); - } + const stream_id = stream_ids_by_name.get(name) ?? stream_ids_by_old_names.get(name); if (!stream_id) { return undefined; } diff --git a/web/src/submessage.ts b/web/src/submessage.ts index a63212f06d..63c65af1f4 100644 --- a/web/src/submessage.ts +++ b/web/src/submessage.ts @@ -165,9 +165,7 @@ export function update_message(submsg: Submessage): void { return; } - if (message.submessages === undefined) { - message.submessages = []; - } + message.submessages ??= []; const existing = message.submessages.find((sm) => sm.id === submsg.id);