tsc:allowUnreachableCode, eslint:no-unreachable, assert->assertDev

This commit is contained in:
Jamie Kyle 2022-09-15 12:17:15 -07:00 committed by GitHub
parent f627a05cf8
commit eb10aafd7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 213 additions and 176 deletions

View File

@ -36,6 +36,9 @@ const rules = {
// useful for unused or internal fields // useful for unused or internal fields
'no-underscore-dangle': 'off', 'no-underscore-dangle': 'off',
// Temp: We have because TypeScript's `allowUnreachableCode` option is on.
'no-unreachable': 'error',
// though we have a logger, we still remap console to log to disk // though we have a logger, we still remap console to log to disk
'no-console': 'error', 'no-console': 'error',

View File

@ -18,7 +18,7 @@ import * as log from './logging/log';
import * as Errors from './types/errors'; import * as Errors from './types/errors';
import { getContactId } from './messages/helpers'; import { getContactId } from './messages/helpers';
import { maybeDeriveGroupV2Id } from './groups'; import { maybeDeriveGroupV2Id } from './groups';
import { assert, strictAssert } from './util/assert'; import { assertDev, strictAssert } from './util/assert';
import { isGroupV1, isGroupV2 } from './util/whatTypeOfConversation'; import { isGroupV1, isGroupV2 } from './util/whatTypeOfConversation';
import { getConversationUnreadCountForAppBadge } from './util/getConversationUnreadCountForAppBadge'; import { getConversationUnreadCountForAppBadge } from './util/getConversationUnreadCountForAppBadge';
import { UUID, isValidUuid, UUIDKind } from './types/UUID'; import { UUID, isValidUuid, UUIDKind } from './types/UUID';
@ -686,7 +686,7 @@ export class ConversationController {
// conflict case, to keep the one with activity the most recently. // conflict case, to keep the one with activity the most recently.
for (let i = models.length - 1; i >= 0; i -= 1) { for (let i = models.length - 1; i >= 0; i -= 1) {
const conversation = models[i]; const conversation = models[i];
assert( assertDev(
conversation, conversation,
'Expected conversation to be found in array during iteration' 'Expected conversation to be found in array during iteration'
); );
@ -781,7 +781,7 @@ export class ConversationController {
if (isGroupV1(conversation.attributes)) { if (isGroupV1(conversation.attributes)) {
maybeDeriveGroupV2Id(conversation); maybeDeriveGroupV2Id(conversation);
groupV2Id = conversation.get('derivedGroupV2Id'); groupV2Id = conversation.get('derivedGroupV2Id');
assert( assertDev(
groupV2Id, groupV2Id,
'checkForConflicts: expected the group V2 ID to have been derived, but it was falsy' 'checkForConflicts: expected the group V2 ID to have been derived, but it was falsy'
); );
@ -842,7 +842,7 @@ export class ConversationController {
} }
if (obsolete.get('type') !== conversationType) { if (obsolete.get('type') !== conversationType) {
assert( assertDev(
false, false,
`${logId}: cannot combine a private and group conversation. Doing nothing` `${logId}: cannot combine a private and group conversation. Doing nothing`
); );

View File

@ -18,7 +18,7 @@ import {
import * as Bytes from './Bytes'; import * as Bytes from './Bytes';
import { constantTimeEqual, sha256 } from './Crypto'; import { constantTimeEqual, sha256 } from './Crypto';
import { assert, strictAssert } from './util/assert'; import { assertDev, strictAssert } from './util/assert';
import { isNotNil } from './util/isNotNil'; import { isNotNil } from './util/isNotNil';
import { Zone } from './util/Zone'; import { Zone } from './util/Zone';
import { isMoreRecentThan } from './util/timestamp'; import { isMoreRecentThan } from './util/timestamp';
@ -836,13 +836,16 @@ export class SignalProtocolStore extends EventsMixin {
// Apply changes to in-memory storage after successful DB write. // Apply changes to in-memory storage after successful DB write.
const { sessions } = this; const { sessions } = this;
assert(sessions !== undefined, "Can't commit unhydrated session storage"); assertDev(
sessions !== undefined,
"Can't commit unhydrated session storage"
);
pendingSessions.forEach((value, key) => { pendingSessions.forEach((value, key) => {
sessions.set(key, value); sessions.set(key, value);
}); });
const { senderKeys } = this; const { senderKeys } = this;
assert( assertDev(
senderKeys !== undefined, senderKeys !== undefined,
"Can't commit unhydrated sender key storage" "Can't commit unhydrated sender key storage"
); );
@ -871,7 +874,7 @@ export class SignalProtocolStore extends EventsMixin {
private enterZone(zone: Zone, name: string): void { private enterZone(zone: Zone, name: string): void {
this.currentZoneDepth += 1; this.currentZoneDepth += 1;
if (this.currentZoneDepth === 1) { if (this.currentZoneDepth === 1) {
assert(this.currentZone === undefined, 'Should not be in the zone'); assertDev(this.currentZone === undefined, 'Should not be in the zone');
this.currentZone = zone; this.currentZone = zone;
if (zone !== GLOBAL_ZONE) { if (zone !== GLOBAL_ZONE) {
@ -881,10 +884,13 @@ export class SignalProtocolStore extends EventsMixin {
} }
private leaveZone(zone: Zone): void { private leaveZone(zone: Zone): void {
assert(this.currentZone === zone, 'Should be in the correct zone'); assertDev(this.currentZone === zone, 'Should be in the correct zone');
this.currentZoneDepth -= 1; this.currentZoneDepth -= 1;
assert(this.currentZoneDepth >= 0, 'Unmatched number of leaveZone calls'); assertDev(
this.currentZoneDepth >= 0,
'Unmatched number of leaveZone calls'
);
// Since we allow re-entering zones we might actually be in two overlapping // Since we allow re-entering zones we might actually be in two overlapping
// async calls. Leave the zone and yield to another one only if there are // async calls. Leave the zone and yield to another one only if there are
@ -908,7 +914,7 @@ export class SignalProtocolStore extends EventsMixin {
while (this.zoneQueue[0]?.zone === next.zone) { while (this.zoneQueue[0]?.zone === next.zone) {
const elem = this.zoneQueue.shift(); const elem = this.zoneQueue.shift();
assert(elem, 'Zone element should be present'); assertDev(elem, 'Zone element should be present');
toEnter.push(elem); toEnter.push(elem);
} }
@ -1080,7 +1086,7 @@ export class SignalProtocolStore extends EventsMixin {
item: record, item: record,
}; };
assert(this.currentZone, 'Must run in the zone'); assertDev(this.currentZone, 'Must run in the zone');
this.pendingSessions.set(id, newSession); this.pendingSessions.set(id, newSession);
@ -1388,7 +1394,7 @@ export class SignalProtocolStore extends EventsMixin {
const conversation = window.ConversationController.lookupOrCreate({ const conversation = window.ConversationController.lookupOrCreate({
uuid: uuid.toString(), uuid: uuid.toString(),
}); });
assert(conversation, `lightSessionReset/${id}: missing conversation`); assertDev(conversation, `lightSessionReset/${id}: missing conversation`);
log.warn(`lightSessionReset/${id}: Resetting session`); log.warn(`lightSessionReset/${id}: Resetting session`);

View File

@ -35,7 +35,7 @@ import { ChallengeHandler } from './challenge';
import * as durations from './util/durations'; import * as durations from './util/durations';
import { explodePromise } from './util/explodePromise'; import { explodePromise } from './util/explodePromise';
import { isWindowDragElement } from './util/isWindowDragElement'; import { isWindowDragElement } from './util/isWindowDragElement';
import { assert, strictAssert } from './util/assert'; import { assertDev, strictAssert } from './util/assert';
import { normalizeUuid } from './util/normalizeUuid'; import { normalizeUuid } from './util/normalizeUuid';
import { filter } from './util/iterables'; import { filter } from './util/iterables';
import { isNotNil } from './util/isNotNil'; import { isNotNil } from './util/isNotNil';
@ -3359,7 +3359,7 @@ export async function startApp(): Promise<void> {
data: MessageEventData, data: MessageEventData,
descriptor: MessageDescriptor descriptor: MessageDescriptor
) { ) {
assert( assertDev(
Boolean(data.receivedAtCounter), Boolean(data.receivedAtCounter),
`Did not receive receivedAtCounter for message: ${data.timestamp}` `Did not receive receivedAtCounter for message: ${data.timestamp}`
); );

View File

@ -12,7 +12,7 @@
// are not immediately retried, however, until `.onOnline()` is called from // are not immediately retried, however, until `.onOnline()` is called from
// when we are actually online. // when we are actually online.
import { assert } from './util/assert'; import { assertDev } from './util/assert';
import { isOlderThan } from './util/timestamp'; import { isOlderThan } from './util/timestamp';
import { parseRetryAfterWithDefault } from './util/parseRetryAfter'; import { parseRetryAfterWithDefault } from './util/parseRetryAfter';
import { clearTimeoutIfNecessary } from './util/clearTimeoutIfNecessary'; import { clearTimeoutIfNecessary } from './util/clearTimeoutIfNecessary';
@ -311,7 +311,7 @@ export class ChallengeHandler {
} }
private async persist(): Promise<void> { private async persist(): Promise<void> {
assert( assertDev(
this.isLoaded, this.isLoaded,
'ChallengeHandler has to be loaded before persisting new data' 'ChallengeHandler has to be loaded before persisting new data'
); );

View File

@ -20,7 +20,7 @@ import { BadgeImageTheme } from '../badges/BadgeImageTheme';
import { HasStories } from '../types/Stories'; import { HasStories } from '../types/Stories';
import { Spinner } from './Spinner'; import { Spinner } from './Spinner';
import { ThemeType } from '../types/Util'; import { ThemeType } from '../types/Util';
import { assert } from '../util/assert'; import { assertDev } from '../util/assert';
import { getBadgeImageFileLocalPath } from '../badges/getBadgeImageFileLocalPath'; import { getBadgeImageFileLocalPath } from '../badges/getBadgeImageFileLocalPath';
import { getInitials } from '../util/getInitials'; import { getInitials } from '../util/getInitials';
import { isBadgeVisible } from '../badges/isBadgeVisible'; import { isBadgeVisible } from '../badges/isBadgeVisible';
@ -169,9 +169,9 @@ export const Avatar: FunctionComponent<Props> = ({
</div> </div>
); );
} else if (hasImage) { } else if (hasImage) {
assert(avatarPath, 'avatarPath should be defined here'); assertDev(avatarPath, 'avatarPath should be defined here');
assert( assertDev(
blur !== AvatarBlur.BlurPictureWithClickToView || size >= 100, blur !== AvatarBlur.BlurPictureWithClickToView || size >= 100,
'Rendering "click to view" for a small avatar. This may not render correctly' 'Rendering "click to view" for a small avatar. This may not render correctly'
); );

View File

@ -11,7 +11,7 @@ import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import type { Theme } from '../util/theme'; import type { Theme } from '../util/theme';
import { assert } from '../util/assert'; import { assertDev } from '../util/assert';
import { themeClassName } from '../util/theme'; import { themeClassName } from '../util/theme';
export enum ButtonSize { export enum ButtonSize {
@ -126,10 +126,10 @@ export const Button = React.forwardRef<HTMLButtonElement, PropsType>(
} }
const sizeClassName = SIZE_CLASS_NAMES.get(size); const sizeClassName = SIZE_CLASS_NAMES.get(size);
assert(sizeClassName, '<Button> size not found'); assertDev(sizeClassName, '<Button> size not found');
const variantClassName = VARIANT_CLASS_NAMES.get(variant); const variantClassName = VARIANT_CLASS_NAMES.get(variant);
assert(variantClassName, '<Button> variant not found'); assertDev(variantClassName, '<Button> variant not found');
const buttonElement = ( const buttonElement = (
<button <button

View File

@ -9,7 +9,7 @@ import classNames from 'classnames';
import { get, pick } from 'lodash'; import { get, pick } from 'lodash';
import { missingCaseError } from '../util/missingCaseError'; import { missingCaseError } from '../util/missingCaseError';
import { assert } from '../util/assert'; import { assertDev } from '../util/assert';
import type { ParsedE164Type } from '../util/libphonenumberInstance'; import type { ParsedE164Type } from '../util/libphonenumberInstance';
import type { LocalizerType, ThemeType } from '../types/Util'; import type { LocalizerType, ThemeType } from '../types/Util';
import { ScrollBehavior } from '../types/Util'; import { ScrollBehavior } from '../types/Util';
@ -205,7 +205,7 @@ export const ConversationList: React.FC<PropsType> = ({
({ index }: { index: number }): number => { ({ index }: { index: number }): number => {
const row = getRow(index); const row = getRow(index);
if (!row) { if (!row) {
assert(false, `Expected a row at index ${index}`); assertDev(false, `Expected a row at index ${index}`);
return NORMAL_ROW_HEIGHT; return NORMAL_ROW_HEIGHT;
} }
switch (row.type) { switch (row.type) {
@ -223,7 +223,7 @@ export const ConversationList: React.FC<PropsType> = ({
({ key, index, style }) => { ({ key, index, style }) => {
const row = getRow(index); const row = getRow(index);
if (!row) { if (!row) {
assert(false, `Expected a row at index ${index}`); assertDev(false, `Expected a row at index ${index}`);
return <div key={key} style={style} />; return <div key={key} style={style} />;
} }

View File

@ -129,7 +129,6 @@ const GroupCallMessage = ({
}} }}
/> />
); );
break;
case 3: case 3:
return ( return (
<Intl <Intl
@ -142,7 +141,6 @@ const GroupCallMessage = ({
}} }}
/> />
); );
break;
default: default:
return ( return (
<Intl <Intl

View File

@ -20,7 +20,7 @@ import { ContactSpoofingReviewDialogPerson } from './ContactSpoofingReviewDialog
import { Button, ButtonVariant } from '../Button'; import { Button, ButtonVariant } from '../Button';
import { Intl } from '../Intl'; import { Intl } from '../Intl';
import { Emojify } from './Emojify'; import { Emojify } from './Emojify';
import { assert } from '../../util/assert'; import { assertDev } from '../../util/assert';
import { missingCaseError } from '../../util/missingCaseError'; import { missingCaseError } from '../../util/missingCaseError';
import { isInSystemContacts } from '../../util/isInSystemContacts'; import { isInSystemContacts } from '../../util/isInSystemContacts';
@ -133,7 +133,7 @@ export const ContactSpoofingReviewDialog: FunctionComponent<
}); });
break; break;
case MessageRequestState.unblocking: case MessageRequestState.unblocking:
assert( assertDev(
false, false,
'Got unexpected MessageRequestState.unblocking state. Clearing confiration state' 'Got unexpected MessageRequestState.unblocking state. Clearing confiration state'
); );
@ -175,11 +175,11 @@ export const ContactSpoofingReviewDialog: FunctionComponent<
switch (props.type) { switch (props.type) {
case ContactSpoofingType.DirectConversationWithSameTitle: { case ContactSpoofingType.DirectConversationWithSameTitle: {
const { possiblyUnsafeConversation, safeConversation } = props; const { possiblyUnsafeConversation, safeConversation } = props;
assert( assertDev(
possiblyUnsafeConversation.type === 'direct', possiblyUnsafeConversation.type === 'direct',
'<ContactSpoofingReviewDialog> expected a direct conversation for the "possibly unsafe" conversation' '<ContactSpoofingReviewDialog> expected a direct conversation for the "possibly unsafe" conversation'
); );
assert( assertDev(
safeConversation.type === 'direct', safeConversation.type === 'direct',
'<ContactSpoofingReviewDialog> expected a direct conversation for the "safe" conversation' '<ContactSpoofingReviewDialog> expected a direct conversation for the "safe" conversation'
); );

View File

@ -7,7 +7,7 @@ import React from 'react';
import type { ConversationType } from '../../state/ducks/conversations'; import type { ConversationType } from '../../state/ducks/conversations';
import type { LocalizerType, ThemeType } from '../../types/Util'; import type { LocalizerType, ThemeType } from '../../types/Util';
import type { PreferredBadgeSelectorType } from '../../state/selectors/badges'; import type { PreferredBadgeSelectorType } from '../../state/selectors/badges';
import { assert } from '../../util/assert'; import { assertDev } from '../../util/assert';
import { Avatar, AvatarSize } from '../Avatar'; import { Avatar, AvatarSize } from '../Avatar';
import { ContactName } from './ContactName'; import { ContactName } from './ContactName';
@ -25,7 +25,7 @@ type PropsType = {
export const ContactSpoofingReviewDialogPerson: FunctionComponent< export const ContactSpoofingReviewDialogPerson: FunctionComponent<
PropsType PropsType
> = ({ children, conversation, getPreferredBadge, i18n, onClick, theme }) => { > = ({ children, conversation, getPreferredBadge, i18n, onClick, theme }) => {
assert( assertDev(
conversation.type === 'direct', conversation.type === 'direct',
'<ContactSpoofingReviewDialogPerson> expected a direct conversation' '<ContactSpoofingReviewDialogPerson> expected a direct conversation'
); );

View File

@ -11,7 +11,7 @@ import React, {
import classNames from 'classnames'; import classNames from 'classnames';
import { noop } from 'lodash'; import { noop } from 'lodash';
import { assert } from '../../util/assert'; import { assertDev } from '../../util/assert';
import type { LocalizerType } from '../../types/Util'; import type { LocalizerType } from '../../types/Util';
import type { AttachmentType } from '../../types/Attachment'; import type { AttachmentType } from '../../types/Attachment';
import { isDownloaded } from '../../types/Attachment'; import { isDownloaded } from '../../types/Attachment';
@ -226,7 +226,7 @@ export const MessageAudio: React.FC<Props> = (props: Props) => {
setActiveAudioID, setActiveAudioID,
} = props; } = props;
assert(audio != null, 'GlobalAudioContext always provides audio'); assertDev(audio != null, 'GlobalAudioContext always provides audio');
const isActive = const isActive =
activeAudioID === id && activeAudioContext === renderingContext; activeAudioID === id && activeAudioContext === renderingContext;
@ -365,7 +365,7 @@ export const MessageAudio: React.FC<Props> = (props: Props) => {
}; };
const onLoadedMetadata = () => { const onLoadedMetadata = () => {
assert( assertDev(
!Number.isNaN(audio.duration), !Number.isNaN(audio.duration),
'Audio should have definite duration on `loadedmetadata` event' 'Audio should have definite duration on `loadedmetadata` event'
); );

View File

@ -13,7 +13,7 @@ import { ScrollDownButton } from './ScrollDownButton';
import type { AssertProps, LocalizerType, ThemeType } from '../../types/Util'; import type { AssertProps, LocalizerType, ThemeType } from '../../types/Util';
import type { ConversationType } from '../../state/ducks/conversations'; import type { ConversationType } from '../../state/ducks/conversations';
import type { PreferredBadgeSelectorType } from '../../state/selectors/badges'; import type { PreferredBadgeSelectorType } from '../../state/selectors/badges';
import { assert, strictAssert } from '../../util/assert'; import { assertDev, strictAssert } from '../../util/assert';
import { missingCaseError } from '../../util/missingCaseError'; import { missingCaseError } from '../../util/missingCaseError';
import { clearTimeoutIfNecessary } from '../../util/clearTimeoutIfNecessary'; import { clearTimeoutIfNecessary } from '../../util/clearTimeoutIfNecessary';
import { WidthBreakpoint } from '../_util'; import { WidthBreakpoint } from '../_util';
@ -522,7 +522,7 @@ export class Timeline extends React.Component<
this.intersectionObserver = new IntersectionObserver( this.intersectionObserver = new IntersectionObserver(
(entries, observer) => { (entries, observer) => {
assert( assertDev(
this.intersectionObserver === observer, this.intersectionObserver === observer,
'observer.disconnect() should prevent callbacks from firing' 'observer.disconnect() should prevent callbacks from firing'
); );
@ -630,7 +630,7 @@ export class Timeline extends React.Component<
return { scrollBottom: 0 }; return { scrollBottom: 0 };
case ScrollAnchor.ScrollToIndex: case ScrollAnchor.ScrollToIndex:
if (scrollToIndex === undefined) { if (scrollToIndex === undefined) {
assert( assertDev(
false, false,
'<Timeline> got "scroll to index" scroll anchor, but no index' '<Timeline> got "scroll to index" scroll anchor, but no index'
); );
@ -674,7 +674,7 @@ export class Timeline extends React.Component<
lastSeenIndicatorEl.scrollIntoView(); lastSeenIndicatorEl.scrollIntoView();
} else { } else {
scrollToBottom(containerEl); scrollToBottom(containerEl);
assert( assertDev(
false, false,
'<Timeline> expected a last seen indicator but it was not found' '<Timeline> expected a last seen indicator but it was not found'
); );
@ -942,7 +942,7 @@ export class Timeline extends React.Component<
const messageId = items[itemIndex]; const messageId = items[itemIndex];
if (!messageId) { if (!messageId) {
assert( assertDev(
false, false,
'<Timeline> iterated through items and got an empty message ID' '<Timeline> iterated through items and got an empty message ID'
); );
@ -1058,7 +1058,7 @@ export class Timeline extends React.Component<
bounds bounds
onResize={({ bounds }) => { onResize={({ bounds }) => {
if (!bounds) { if (!bounds) {
assert(false, 'We should be measuring the bounds'); assertDev(false, 'We should be measuring the bounds');
return; return;
} }
this.setState({ lastMeasuredWarningHeight: bounds.height }); this.setState({ lastMeasuredWarningHeight: bounds.height });

View File

@ -5,7 +5,7 @@ import type { FunctionComponent, ReactNode } from 'react';
import React from 'react'; import React from 'react';
import type { LocalizerType } from '../../../../types/Util'; import type { LocalizerType } from '../../../../types/Util';
import { assert } from '../../../../util/assert'; import { assertDev } from '../../../../util/assert';
import { ModalHost } from '../../../ModalHost'; import { ModalHost } from '../../../ModalHost';
import { Button, ButtonVariant } from '../../../Button'; import { Button, ButtonVariant } from '../../../Button';
import { Spinner } from '../../../Spinner'; import { Spinner } from '../../../Spinner';
@ -35,7 +35,7 @@ export const ConfirmAdditionsModal: FunctionComponent<PropsType> = ({
selectedContacts, selectedContacts,
}) => { }) => {
const firstContact = selectedContacts[0]; const firstContact = selectedContacts[0];
assert( assertDev(
firstContact, firstContact,
'Expected at least one conversation to be selected but none were picked' 'Expected at least one conversation to be selected but none were picked'
); );

View File

@ -10,7 +10,7 @@ import type { ConversationType } from '../../../state/ducks/conversations';
import type { PreferredBadgeSelectorType } from '../../../state/selectors/badges'; import type { PreferredBadgeSelectorType } from '../../../state/selectors/badges';
import type { SmartChooseGroupMembersModalPropsType } from '../../../state/smart/ChooseGroupMembersModal'; import type { SmartChooseGroupMembersModalPropsType } from '../../../state/smart/ChooseGroupMembersModal';
import type { SmartConfirmAdditionsModalPropsType } from '../../../state/smart/ConfirmAdditionsModal'; import type { SmartConfirmAdditionsModalPropsType } from '../../../state/smart/ConfirmAdditionsModal';
import { assert } from '../../../util/assert'; import { assertDev } from '../../../util/assert';
import { getMutedUntilText } from '../../../util/getMutedUntilText'; import { getMutedUntilText } from '../../../util/getMutedUntilText';
import type { LocalizerType, ThemeType } from '../../../types/Util'; import type { LocalizerType, ThemeType } from '../../../types/Util';
@ -237,7 +237,7 @@ export const ConversationDetails: React.ComponentType<Props> = ({
renderConfirmAdditionsModal={renderConfirmAdditionsModal} renderConfirmAdditionsModal={renderConfirmAdditionsModal}
clearRequestError={() => { clearRequestError={() => {
setAddGroupMembersRequestState(oldRequestState => { setAddGroupMembersRequestState(oldRequestState => {
assert( assertDev(
oldRequestState !== RequestState.Active, oldRequestState !== RequestState.Active,
'Should not be clearing an active request state' 'Should not be clearing an active request state'
); );

View File

@ -8,7 +8,7 @@ import { escapeRegExp } from 'lodash';
import { MessageBodyHighlight } from './MessageBodyHighlight'; import { MessageBodyHighlight } from './MessageBodyHighlight';
import { ContactName } from '../conversation/ContactName'; import { ContactName } from '../conversation/ContactName';
import { assert } from '../../util/assert'; import { assertDev } from '../../util/assert';
import type { import type {
BodyRangesType, BodyRangesType,
LocalizerType, LocalizerType,
@ -99,7 +99,7 @@ function getFilteredBodyRanges(
const rx = new RegExp(escapeRegExp(stripped)); const rx = new RegExp(escapeRegExp(stripped));
const match = rx.exec(body); const match = rx.exec(body);
assert(Boolean(match), `No match found for "${snippet}" inside "${body}"`); assertDev(Boolean(match), `No match found for "${snippet}" inside "${body}"`);
const delta = match ? match.index + snippet.length : 0; const delta = match ? match.index + snippet.length : 0;
@ -125,7 +125,7 @@ function getFilteredBodyRanges(
start: bodyRangeMatch.index, start: bodyRangeMatch.index,
}); });
} else { } else {
assert( assertDev(
false, false,
`Body range does not exist? Count: ${i}, Length: ${filteredBodyRanges.length}` `Body range does not exist? Count: ${i}, Length: ${filteredBodyRanges.length}`
); );

View File

@ -251,6 +251,7 @@ export class LeftPaneComposeHelper extends LeftPaneHelper<LeftPaneComposePropsTy
), ),
}; };
// eslint-disable-next-line no-unreachable -- Why is this here, its unreachable
virtualRowIndex -= 1; virtualRowIndex -= 1;
} }
} }
@ -275,6 +276,7 @@ export class LeftPaneComposeHelper extends LeftPaneHelper<LeftPaneComposePropsTy
), ),
}; };
// eslint-disable-next-line no-unreachable -- Why is this here, its unreachable
virtualRowIndex -= 1; virtualRowIndex -= 1;
} }
} }

View File

@ -19,7 +19,7 @@ import { LeftPaneSearchInput } from '../LeftPaneSearchInput';
import { Intl } from '../Intl'; import { Intl } from '../Intl';
import { Emojify } from '../conversation/Emojify'; import { Emojify } from '../conversation/Emojify';
import { assert } from '../../util/assert'; import { assertDev } from '../../util/assert';
// The "correct" thing to do is to measure the size of the left pane and render enough // The "correct" thing to do is to measure the size of the left pane and render enough
// search results for the container height. But (1) that's slow (2) the list is // search results for the container height. But (1) that's slow (2) the list is
@ -228,7 +228,7 @@ export class LeftPaneSearchHelper extends LeftPaneHelper<LeftPaneSearchPropsType
i18nKey: 'conversationsHeader', i18nKey: 'conversationsHeader',
}; };
} }
assert( assertDev(
!conversationResults.isLoading, !conversationResults.isLoading,
"We shouldn't get here with conversation results still loading" "We shouldn't get here with conversation results still loading"
); );
@ -249,7 +249,7 @@ export class LeftPaneSearchHelper extends LeftPaneHelper<LeftPaneSearchPropsType
i18nKey: 'contactsHeader', i18nKey: 'contactsHeader',
}; };
} }
assert( assertDev(
!contactResults.isLoading, !contactResults.isLoading,
"We shouldn't get here with contact results still loading" "We shouldn't get here with contact results still loading"
); );
@ -273,7 +273,7 @@ export class LeftPaneSearchHelper extends LeftPaneHelper<LeftPaneSearchPropsType
i18nKey: 'messagesHeader', i18nKey: 'messagesHeader',
}; };
} }
assert( assertDev(
!messageResults.isLoading, !messageResults.isLoading,
"We shouldn't get here with message results still loading" "We shouldn't get here with message results still loading"
); );
@ -379,7 +379,7 @@ function getRowCountForLoadedSearchResults(
// We could change the parameter of this function, but that adds a bunch of redundant // We could change the parameter of this function, but that adds a bunch of redundant
// checks that are, in the author's opinion, less clear. // checks that are, in the author's opinion, less clear.
if (searchResults.isLoading) { if (searchResults.isLoading) {
assert( assertDev(
false, false,
'getRowCountForLoadedSearchResults: Expected this to be called with loaded search results. Returning 0' 'getRowCountForLoadedSearchResults: Expected this to be called with loaded search results. Returning 0'
); );

View File

@ -20,7 +20,7 @@ import {
} from './services/groupCredentialFetcher'; } from './services/groupCredentialFetcher';
import dataInterface from './sql/Client'; import dataInterface from './sql/Client';
import { toWebSafeBase64, fromWebSafeBase64 } from './util/webSafeBase64'; import { toWebSafeBase64, fromWebSafeBase64 } from './util/webSafeBase64';
import { assert, strictAssert } from './util/assert'; import { assertDev, strictAssert } from './util/assert';
import { isMoreRecentThan } from './util/timestamp'; import { isMoreRecentThan } from './util/timestamp';
import * as durations from './util/durations'; import * as durations from './util/durations';
import { normalizeUuid } from './util/normalizeUuid'; import { normalizeUuid } from './util/normalizeUuid';
@ -671,7 +671,7 @@ export async function buildAddMembersChange(
conversationIds.map(async conversationId => { conversationIds.map(async conversationId => {
const contact = window.ConversationController.get(conversationId); const contact = window.ConversationController.get(conversationId);
if (!contact) { if (!contact) {
assert( assertDev(
false, false,
`buildAddMembersChange/${logId}: missing local contact, skipping` `buildAddMembersChange/${logId}: missing local contact, skipping`
); );
@ -680,7 +680,10 @@ export async function buildAddMembersChange(
const uuid = contact.getUuid(); const uuid = contact.getUuid();
if (!uuid) { if (!uuid) {
assert(false, `buildAddMembersChange/${logId}: missing UUID; skipping`); assertDev(
false,
`buildAddMembersChange/${logId}: missing UUID; skipping`
);
return; return;
} }
@ -1788,7 +1791,7 @@ export async function createGroupV2(
...conversationIds.map(async conversationId => { ...conversationIds.map(async conversationId => {
const contact = window.ConversationController.get(conversationId); const contact = window.ConversationController.get(conversationId);
if (!contact) { if (!contact) {
assert( assertDev(
false, false,
`createGroupV2/${logId}: missing local contact, skipping` `createGroupV2/${logId}: missing local contact, skipping`
); );
@ -1797,7 +1800,7 @@ export async function createGroupV2(
const contactUuid = contact.get('uuid'); const contactUuid = contact.get('uuid');
if (!contactUuid) { if (!contactUuid) {
assert(false, `createGroupV2/${logId}: missing UUID; skipping`); assertDev(false, `createGroupV2/${logId}: missing UUID; skipping`);
return; return;
} }
@ -4143,7 +4146,7 @@ async function integrateGroupChange({
canApplyChange && canApplyChange &&
(groupChangeMessages.length !== 0 || newMembers.length !== 0) (groupChangeMessages.length !== 0 || newMembers.length !== 0)
) { ) {
assert( assertDev(
groupChangeMessages.length === 0, groupChangeMessages.length === 0,
'Fallback group state processing should not kick in' 'Fallback group state processing should not kick in'
); );

View File

@ -4,7 +4,7 @@
import type { KeyboardEvent } from 'react'; import type { KeyboardEvent } from 'react';
import React, { useState } from 'react'; import React, { useState } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { assert } from '../util/assert'; import { assertDev } from '../util/assert';
import { getClassNamesFor } from '../util/getClassNamesFor'; import { getClassNamesFor } from '../util/getClassNamesFor';
type Tab = { type Tab = {
@ -28,7 +28,7 @@ export function useTabs({
selectedTab: string; selectedTab: string;
tabsHeaderElement: JSX.Element; tabsHeaderElement: JSX.Element;
} { } {
assert(tabs.length, 'Tabs needs more than 1 tab present'); assertDev(tabs.length, 'Tabs needs more than 1 tab present');
const getClassName = getClassNamesFor('Tabs', moduleClassName); const getClassName = getClassNamesFor('Tabs', moduleClassName);

View File

@ -8,7 +8,7 @@ import { noop } from 'lodash';
import { Job } from './Job'; import { Job } from './Job';
import { JobError } from './JobError'; import { JobError } from './JobError';
import type { ParsedJob, StoredJob, JobQueueStore } from './types'; import type { ParsedJob, StoredJob, JobQueueStore } from './types';
import { assert } from '../util/assert'; import { assertDev } from '../util/assert';
import * as log from '../logging/log'; import * as log from '../logging/log';
import { JobLogger } from './JobLogger'; import { JobLogger } from './JobLogger';
import * as Errors from '../types/errors'; import * as Errors from '../types/errors';
@ -67,15 +67,15 @@ export abstract class JobQueue<T> {
private started = false; private started = false;
constructor(options: Readonly<JobQueueOptions>) { constructor(options: Readonly<JobQueueOptions>) {
assert( assertDev(
Number.isInteger(options.maxAttempts) && options.maxAttempts >= 1, Number.isInteger(options.maxAttempts) && options.maxAttempts >= 1,
'maxAttempts should be a positive integer' 'maxAttempts should be a positive integer'
); );
assert( assertDev(
options.maxAttempts <= Number.MAX_SAFE_INTEGER, options.maxAttempts <= Number.MAX_SAFE_INTEGER,
'maxAttempts is too large' 'maxAttempts is too large'
); );
assert( assertDev(
options.queueType.trim().length, options.queueType.trim().length,
'queueType should be a non-blank string' 'queueType should be a non-blank string'
); );
@ -188,7 +188,7 @@ export abstract class JobQueue<T> {
} }
private async enqueueStoredJob(storedJob: Readonly<StoredJob>) { private async enqueueStoredJob(storedJob: Readonly<StoredJob>) {
assert( assertDev(
storedJob.queueType === this.queueType, storedJob.queueType === this.queueType,
'Received a mis-matched queue type' 'Received a mis-matched queue type'
); );
@ -265,7 +265,7 @@ export abstract class JobQueue<T> {
await this.store.delete(storedJob.id); await this.store.delete(storedJob.id);
assert( assertDev(
result, result,
'The job never ran. This indicates a developer error in the job queue' 'The job never ran. This indicates a developer error in the job queue'
); );

View File

@ -1,7 +1,7 @@
// Copyright 2021 Signal Messenger, LLC // Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { assert } from '../../util/assert'; import { assertDev } from '../../util/assert';
import * as log from '../../logging/log'; import * as log from '../../logging/log';
import type { ConversationType } from '../../state/ducks/conversations'; import type { ConversationType } from '../../state/ducks/conversations';
import type { reportSpamJobQueue } from '../reportSpamJobQueue'; import type { reportSpamJobQueue } from '../reportSpamJobQueue';
@ -17,7 +17,7 @@ export async function addReportSpamJob({
) => Promise<Array<string>>; ) => Promise<Array<string>>;
jobQueue: Pick<typeof reportSpamJobQueue, 'add'>; jobQueue: Pick<typeof reportSpamJobQueue, 'add'>;
}>): Promise<void> { }>): Promise<void> {
assert( assertDev(
conversation.type === 'direct', conversation.type === 'direct',
'addReportSpamJob: cannot report spam for non-direct conversations' 'addReportSpamJob: cannot report spam for non-direct conversations'
); );

View File

@ -92,7 +92,6 @@ function logAtLevel(level: LogLevel, ...args: ReadonlyArray<unknown>): void {
if (!globalLogger) { if (!globalLogger) {
throw new Error('Logger has not been initialized yet'); throw new Error('Logger has not been initialized yet');
return;
} }
globalLogger[levelString](msg); globalLogger[levelString](msg);

View File

@ -5,7 +5,7 @@ import { isNil, sortBy } from 'lodash';
import PQueue from 'p-queue'; import PQueue from 'p-queue';
import * as log from './logging/log'; import * as log from './logging/log';
import { assert } from './util/assert'; import { assertDev } from './util/assert';
import { sleep } from './util/sleep'; import { sleep } from './util/sleep';
import { missingCaseError } from './util/missingCaseError'; import { missingCaseError } from './util/missingCaseError';
import { isNormalNumber } from './util/isNormalNumber'; import { isNormalNumber } from './util/isNormalNumber';
@ -177,7 +177,7 @@ function timeUntilNextRefresh(storage: Pick<StorageInterface, 'get'>): number {
return Math.min(Math.max(0, planned - now), WEEK); return Math.min(Math.max(0, planned - now), WEEK);
} }
assert( assertDev(
false, false,
`An invalid value was stored in ${STORAGE_KEY}; treating it as nil` `An invalid value was stored in ${STORAGE_KEY}; treating it as nil`
); );

View File

@ -99,7 +99,7 @@ import {
FALLBACK_NOTIFICATION_TITLE, FALLBACK_NOTIFICATION_TITLE,
} from './notifications'; } from './notifications';
import * as log from '../logging/log'; import * as log from '../logging/log';
import { assert } from '../util/assert'; import { assertDev } from '../util/assert';
const { const {
processGroupCallRingRequest, processGroupCallRingRequest,
@ -433,7 +433,7 @@ export class CallingClass {
switch (callMode) { switch (callMode) {
case CallMode.Direct: case CallMode.Direct:
// We could easily support this in the future if we need to. // We could easily support this in the future if we need to.
assert( assertDev(
hasLocalAudio, hasLocalAudio,
'Expected local audio to be enabled for direct call lobbies' 'Expected local audio to be enabled for direct call lobbies'
); );

View File

@ -86,6 +86,7 @@ export async function runWithRetry(
// It's important to schedule our next run here instead of the level above; otherwise we // It's important to schedule our next run here instead of the level above; otherwise we
// could end up with multiple endlessly-retrying runs. // could end up with multiple endlessly-retrying runs.
// eslint-disable-next-line no-unreachable -- Why is this here, its unreachable
const duration = options.scheduleAnother; const duration = options.scheduleAnother;
if (duration) { if (duration) {
log.info( log.info(

View File

@ -1,7 +1,7 @@
// Copyright 2021 Signal Messenger, LLC // Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { assert } from '../util/assert'; import { assertDev } from '../util/assert';
import * as log from '../logging/log'; import * as log from '../logging/log';
import type { StorageInterface } from '../types/Storage.d'; import type { StorageInterface } from '../types/Storage.d';
@ -40,7 +40,7 @@ export class OurProfileKeyService {
async set(newValue: undefined | Uint8Array): Promise<void> { async set(newValue: undefined | Uint8Array): Promise<void> {
log.info('Our profile key service: updating profile key'); log.info('Our profile key service: updating profile key');
assert(this.storage, 'OurProfileKeyService was not initialized'); assertDev(this.storage, 'OurProfileKeyService was not initialized');
if (newValue) { if (newValue) {
await this.storage.put('profileKey', newValue); await this.storage.put('profileKey', newValue);
} else { } else {
@ -62,7 +62,7 @@ export class OurProfileKeyService {
delete this.getPromise; delete this.getPromise;
assert(this.storage, 'OurProfileKeyService was not initialized'); assertDev(this.storage, 'OurProfileKeyService was not initialized');
log.info('Our profile key service: fetching profile key from storage'); log.info('Our profile key service: fetching profile key from storage');
const result = this.storage.get('profileKey'); const result = this.storage.get('profileKey');
@ -70,7 +70,7 @@ export class OurProfileKeyService {
return result; return result;
} }
assert( assertDev(
false, false,
'Profile key in storage was defined, but not an Uint8Array. Returning undefined' 'Profile key in storage was defined, but not an Uint8Array. Returning undefined'
); );

View File

@ -7,7 +7,7 @@ import {
serializedCertificateSchema, serializedCertificateSchema,
} from '../textsecure/OutgoingMessage'; } from '../textsecure/OutgoingMessage';
import * as Bytes from '../Bytes'; import * as Bytes from '../Bytes';
import { assert } from '../util/assert'; import { assertDev } from '../util/assert';
import { missingCaseError } from '../util/missingCaseError'; import { missingCaseError } from '../util/missingCaseError';
import { waitForOnline } from '../util/waitForOnline'; import { waitForOnline } from '../util/waitForOnline';
import * as log from '../logging/log'; import * as log from '../logging/log';
@ -84,7 +84,7 @@ export class SenderCertificateService {
await Promise.all(this.fetchPromises.values()); await Promise.all(this.fetchPromises.values());
const { storage } = this; const { storage } = this;
assert( assertDev(
storage, storage,
'Sender certificate service method was called before it was initialized' 'Sender certificate service method was called before it was initialized'
); );
@ -96,7 +96,7 @@ export class SenderCertificateService {
mode: SenderCertificateMode mode: SenderCertificateMode
): undefined | SerializedCertificateType { ): undefined | SerializedCertificateType {
const { storage } = this; const { storage } = this;
assert( assertDev(
storage, storage,
'Sender certificate service method was called before it was initialized' 'Sender certificate service method was called before it was initialized'
); );
@ -129,7 +129,7 @@ export class SenderCertificateService {
let promise: Promise<undefined | SerializedCertificateType>; let promise: Promise<undefined | SerializedCertificateType>;
const doFetch = async () => { const doFetch = async () => {
const result = await this.fetchAndSaveCertificate(mode); const result = await this.fetchAndSaveCertificate(mode);
assert( assertDev(
this.fetchPromises.get(mode) === promise, this.fetchPromises.get(mode) === promise,
'Sender certificate service was deleting a different promise than expected' 'Sender certificate service was deleting a different promise than expected'
); );
@ -138,7 +138,7 @@ export class SenderCertificateService {
}; };
promise = doFetch(); promise = doFetch();
assert( assertDev(
!this.fetchPromises.has(mode), !this.fetchPromises.has(mode),
'Sender certificate service somehow already had a promise for this mode' 'Sender certificate service somehow already had a promise for this mode'
); );
@ -150,7 +150,7 @@ export class SenderCertificateService {
mode: SenderCertificateMode mode: SenderCertificateMode
): Promise<undefined | SerializedCertificateType> { ): Promise<undefined | SerializedCertificateType> {
const { storage, navigator, onlineEventTarget } = this; const { storage, navigator, onlineEventTarget } = this;
assert( assertDev(
storage && navigator && onlineEventTarget, storage && navigator && onlineEventTarget,
'Sender certificate service method was called before it was initialized' 'Sender certificate service method was called before it was initialized'
); );
@ -205,7 +205,7 @@ export class SenderCertificateService {
mode: SenderCertificateMode mode: SenderCertificateMode
): Promise<string> { ): Promise<string> {
const { server } = this; const { server } = this;
assert( assertDev(
server, server,
'Sender certificate service method was called before it was initialized' 'Sender certificate service method was called before it was initialized'
); );

View File

@ -15,7 +15,7 @@ import {
waitThenMaybeUpdateGroup, waitThenMaybeUpdateGroup,
waitThenRespondToGroupV2Migration, waitThenRespondToGroupV2Migration,
} from '../groups'; } from '../groups';
import { assert } from '../util/assert'; import { assertDev } from '../util/assert';
import { dropNull } from '../util/dropNull'; import { dropNull } from '../util/dropNull';
import { normalizeUuid } from '../util/normalizeUuid'; import { normalizeUuid } from '../util/normalizeUuid';
import { missingCaseError } from '../util/missingCaseError'; import { missingCaseError } from '../util/missingCaseError';
@ -1098,7 +1098,7 @@ export async function mergeAccountRecord(
phoneNumberSharingModeToStore = PhoneNumberSharingMode.Nobody; phoneNumberSharingModeToStore = PhoneNumberSharingMode.Nobody;
break; break;
default: default:
assert( assertDev(
false, false,
`storageService.mergeAccountRecord: Got an unexpected phone number sharing mode: ${phoneNumberSharingMode}. Falling back to default` `storageService.mergeAccountRecord: Got an unexpected phone number sharing mode: ${phoneNumberSharingMode}. Falling back to default`
); );
@ -1505,14 +1505,14 @@ export async function mergeStickerPackRecord(
); );
if (localStickerPack && !wasUninstalled && isUninstalled) { if (localStickerPack && !wasUninstalled && isUninstalled) {
assert(localStickerPack.key, 'Installed sticker pack has no key'); assertDev(localStickerPack.key, 'Installed sticker pack has no key');
window.reduxActions.stickers.uninstallStickerPack( window.reduxActions.stickers.uninstallStickerPack(
localStickerPack.id, localStickerPack.id,
localStickerPack.key, localStickerPack.key,
{ fromStorageService: true } { fromStorageService: true }
); );
} else if ((!localStickerPack || wasUninstalled) && !isUninstalled) { } else if ((!localStickerPack || wasUninstalled) && !isUninstalled) {
assert(stickerPack.key, 'Sticker pack does not have key'); assertDev(stickerPack.key, 'Sticker pack does not have key');
const status = Stickers.getStickerPackStatus(stickerPack.id); const status = Stickers.getStickerPackStatus(stickerPack.id);
if (status === 'downloaded') { if (status === 'downloaded') {

View File

@ -27,7 +27,7 @@ import { tapToViewMessagesDeletionService } from '../services/tapToViewMessagesD
import * as Bytes from '../Bytes'; import * as Bytes from '../Bytes';
import { CURRENT_SCHEMA_VERSION } from '../types/Message2'; import { CURRENT_SCHEMA_VERSION } from '../types/Message2';
import { createBatcher } from '../util/batcher'; import { createBatcher } from '../util/batcher';
import { assert, softAssert, strictAssert } from '../util/assert'; import { assertDev, softAssert, strictAssert } from '../util/assert';
import { mapObjectWithSpec } from '../util/mapObjectWithSpec'; import { mapObjectWithSpec } from '../util/mapObjectWithSpec';
import type { ObjectMappingSpecType } from '../util/mapObjectWithSpec'; import type { ObjectMappingSpecType } from '../util/mapObjectWithSpec';
import { cleanDataForIpc } from './cleanDataForIpc'; import { cleanDataForIpc } from './cleanDataForIpc';
@ -460,7 +460,7 @@ export function _cleanMessageData(data: MessageType): MessageType {
const result = { ...data }; const result = { ...data };
// Ensure that all messages have the received_at set properly // Ensure that all messages have the received_at set properly
if (!data.received_at) { if (!data.received_at) {
assert(false, 'received_at was not set on the message'); assertDev(false, 'received_at was not set on the message');
result.received_at = window.Signal.Util.incrementMessageCounter(); result.received_at = window.Signal.Util.incrementMessageCounter();
} }
if (data.attachments) { if (data.attachments) {
@ -1052,7 +1052,7 @@ const updateConversationBatcher = createBatcher<ConversationType>({
const ids = Object.keys(byId); const ids = Object.keys(byId);
const mostRecent = ids.map((id: string): ConversationType => { const mostRecent = ids.map((id: string): ConversationType => {
const maybeLast = last(byId[id]); const maybeLast = last(byId[id]);
assert(maybeLast !== undefined, 'Empty array in `groupBy` result'); assertDev(maybeLast !== undefined, 'Empty array in `groupBy` result');
return maybeLast; return maybeLast;
}); });
@ -1068,7 +1068,7 @@ async function updateConversations(
array: Array<ConversationType> array: Array<ConversationType>
): Promise<void> { ): Promise<void> {
const { cleaned, pathsChanged } = cleanDataForIpc(array); const { cleaned, pathsChanged } = cleanDataForIpc(array);
assert( assertDev(
!pathsChanged.length, !pathsChanged.length,
`Paths were cleaned: ${JSON.stringify(pathsChanged)}` `Paths were cleaned: ${JSON.stringify(pathsChanged)}`
); );

View File

@ -34,7 +34,7 @@ import { STORAGE_UI_KEYS } from '../types/StorageUIKeys';
import { UUID } from '../types/UUID'; import { UUID } from '../types/UUID';
import type { UUIDStringType } from '../types/UUID'; import type { UUIDStringType } from '../types/UUID';
import type { StoredJob } from '../jobs/types'; import type { StoredJob } from '../jobs/types';
import { assert, assertSync, strictAssert } from '../util/assert'; import { assertDev, assertSync, strictAssert } from '../util/assert';
import { combineNames } from '../util/combineNames'; import { combineNames } from '../util/combineNames';
import { consoleLogger } from '../util/consoleLogger'; import { consoleLogger } from '../util/consoleLogger';
import { dropNull } from '../util/dropNull'; import { dropNull } from '../util/dropNull';
@ -376,7 +376,7 @@ function rowToConversation(row: ConversationRow): ConversationType {
if (isNormalNumber(row.profileLastFetchedAt)) { if (isNormalNumber(row.profileLastFetchedAt)) {
profileLastFetchedAt = row.profileLastFetchedAt; profileLastFetchedAt = row.profileLastFetchedAt;
} else { } else {
assert( assertDev(
isNil(row.profileLastFetchedAt), isNil(row.profileLastFetchedAt),
'profileLastFetchedAt contained invalid data; defaulting to undefined' 'profileLastFetchedAt contained invalid data; defaulting to undefined'
); );

View File

@ -7,7 +7,7 @@ import { omit } from 'lodash';
import type { LoggerType } from '../../types/Logging'; import type { LoggerType } from '../../types/Logging';
import type { UUIDStringType } from '../../types/UUID'; import type { UUIDStringType } from '../../types/UUID';
import { isNotNil } from '../../util/isNotNil'; import { isNotNil } from '../../util/isNotNil';
import { assert } from '../../util/assert'; import { assertDev } from '../../util/assert';
import { import {
TableIterator, TableIterator,
getCountFromTable, getCountFromTable,
@ -225,7 +225,7 @@ export default function updateToSchemaVersion43(
let result = message; let result = message;
if (groupV2Change) { if (groupV2Change) {
assert(result.groupV2Change, 'Pacify typescript'); assertDev(result.groupV2Change, 'Pacify typescript');
const from: UUIDStringType | undefined = getConversationUuid.get({ const from: UUIDStringType | undefined = getConversationUuid.get({
conversationId: groupV2Change.from, conversationId: groupV2Change.from,
@ -250,7 +250,7 @@ export default function updateToSchemaVersion43(
const details = groupV2Change.details const details = groupV2Change.details
.map((legacyDetail, i) => { .map((legacyDetail, i) => {
const oldDetail = result.groupV2Change?.details[i]; const oldDetail = result.groupV2Change?.details[i];
assert(oldDetail, 'Pacify typescript'); assertDev(oldDetail, 'Pacify typescript');
let newDetail = oldDetail; let newDetail = oldDetail;
for (const key of ['conversationId' as const, 'inviter' as const]) { for (const key of ['conversationId' as const, 'inviter' as const]) {
@ -276,7 +276,10 @@ export default function updateToSchemaVersion43(
return undefined; return undefined;
} }
assert(newDetail.type === legacyDetail.type, 'Pacify typescript'); assertDev(
newDetail.type === legacyDetail.type,
'Pacify typescript'
);
newDetail = { newDetail = {
...omit(newDetail, key), ...omit(newDetail, key),
[newKey]: newValue, [newKey]: newValue,
@ -319,7 +322,7 @@ export default function updateToSchemaVersion43(
}); });
const oldMember = const oldMember =
result.invitedGV2Members && result.invitedGV2Members[i]; result.invitedGV2Members && result.invitedGV2Members[i];
assert(oldMember !== undefined, 'Pacify typescript'); assertDev(oldMember !== undefined, 'Pacify typescript');
if (!uuid) { if (!uuid) {
logger.warn( logger.warn(

View File

@ -19,7 +19,7 @@ import * as groups from '../../groups';
import * as log from '../../logging/log'; import * as log from '../../logging/log';
import { calling } from '../../services/calling'; import { calling } from '../../services/calling';
import { getOwn } from '../../util/getOwn'; import { getOwn } from '../../util/getOwn';
import { assert, strictAssert } from '../../util/assert'; import { assertDev, strictAssert } from '../../util/assert';
import * as universalExpireTimer from '../../util/universalExpireTimer'; import * as universalExpireTimer from '../../util/universalExpireTimer';
import type { import type {
ShowSendAnywayDialogActiontype, ShowSendAnywayDialogActiontype,
@ -1533,7 +1533,7 @@ function createGroup(
composer?.step !== ComposerStep.SetGroupMetadata || composer?.step !== ComposerStep.SetGroupMetadata ||
composer.isCreating composer.isCreating
) { ) {
assert(false, 'Cannot create group in this stage; doing nothing'); assertDev(false, 'Cannot create group in this stage; doing nothing');
return; return;
} }
@ -1915,7 +1915,7 @@ function toggleConversationInChooseMembers(
maxRecommendedGroupSize + 1 maxRecommendedGroupSize + 1
); );
assert( assertDev(
maxGroupSize > maxRecommendedGroupSize, maxGroupSize > maxRecommendedGroupSize,
'Expected the hard max group size to be larger than the recommended maximum' 'Expected the hard max group size to be larger than the recommended maximum'
); );
@ -2157,7 +2157,10 @@ function closeComposerModal(
): ConversationsStateType { ): ConversationsStateType {
const { composer } = state; const { composer } = state;
if (composer?.step !== ComposerStep.ChooseGroupMembers) { if (composer?.step !== ComposerStep.ChooseGroupMembers) {
assert(false, "Can't close the modal in this composer step. Doing nothing"); assertDev(
false,
"Can't close the modal in this composer step. Doing nothing"
);
return state; return state;
} }
if (composer[modalToClose] !== OneTimeModalState.Showing) { if (composer[modalToClose] !== OneTimeModalState.Showing) {
@ -2292,7 +2295,7 @@ export function reducer(
if (action.type === 'CLEAR_GROUP_CREATION_ERROR') { if (action.type === 'CLEAR_GROUP_CREATION_ERROR') {
const { composer } = state; const { composer } = state;
if (composer?.step !== ComposerStep.SetGroupMetadata) { if (composer?.step !== ComposerStep.SetGroupMetadata) {
assert( assertDev(
false, false,
"Can't clear group creation error in this composer state. Doing nothing" "Can't clear group creation error in this composer state. Doing nothing"
); );
@ -3263,7 +3266,7 @@ export function reducer(
case ComposerStep.SetGroupMetadata: case ComposerStep.SetGroupMetadata:
return state; return state;
default: default:
assert( assertDev(
false, false,
'Cannot transition to setting group metadata from this state' 'Cannot transition to setting group metadata from this state'
); );
@ -3285,7 +3288,10 @@ export function reducer(
}, },
}; };
default: default:
assert(false, 'Setting compose group avatar at this step is a no-op'); assertDev(
false,
'Setting compose group avatar at this step is a no-op'
);
return state; return state;
} }
} }
@ -3304,7 +3310,7 @@ export function reducer(
}, },
}; };
default: default:
assert(false, 'Setting compose group name at this step is a no-op'); assertDev(false, 'Setting compose group name at this step is a no-op');
return state; return state;
} }
} }
@ -3323,7 +3329,7 @@ export function reducer(
}, },
}; };
default: default:
assert(false, 'Setting compose group name at this step is a no-op'); assertDev(false, 'Setting compose group name at this step is a no-op');
return state; return state;
} }
} }
@ -3331,7 +3337,7 @@ export function reducer(
if (action.type === 'SET_COMPOSE_SEARCH_TERM') { if (action.type === 'SET_COMPOSE_SEARCH_TERM') {
const { composer } = state; const { composer } = state;
if (!composer) { if (!composer) {
assert( assertDev(
false, false,
'Setting compose search term with the composer closed is a no-op' 'Setting compose search term with the composer closed is a no-op'
); );
@ -3341,7 +3347,7 @@ export function reducer(
composer.step !== ComposerStep.StartDirectConversation && composer.step !== ComposerStep.StartDirectConversation &&
composer.step !== ComposerStep.ChooseGroupMembers composer.step !== ComposerStep.ChooseGroupMembers
) { ) {
assert( assertDev(
false, false,
`Setting compose search term at step ${composer.step} is a no-op` `Setting compose search term at step ${composer.step} is a no-op`
); );
@ -3360,7 +3366,7 @@ export function reducer(
if (action.type === 'SET_IS_FETCHING_UUID') { if (action.type === 'SET_IS_FETCHING_UUID') {
const { composer } = state; const { composer } = state;
if (!composer) { if (!composer) {
assert( assertDev(
false, false,
'Setting compose uuid fetch state with the composer closed is a no-op' 'Setting compose uuid fetch state with the composer closed is a no-op'
); );
@ -3370,7 +3376,10 @@ export function reducer(
composer.step !== ComposerStep.StartDirectConversation && composer.step !== ComposerStep.StartDirectConversation &&
composer.step !== ComposerStep.ChooseGroupMembers composer.step !== ComposerStep.ChooseGroupMembers
) { ) {
assert(false, 'Setting compose uuid fetch state at this step is a no-op'); assertDev(
false,
'Setting compose uuid fetch state at this step is a no-op'
);
return state; return state;
} }
const { identifier, isFetching } = action.payload; const { identifier, isFetching } = action.payload;
@ -3404,7 +3413,7 @@ export function reducer(
}, },
}; };
default: default:
assert(false, 'Setting editing avatar at this step is a no-op'); assertDev(false, 'Setting editing avatar at this step is a no-op');
return state; return state;
} }
} }
@ -3430,7 +3439,7 @@ export function reducer(
}, },
}; };
default: default:
assert(false, 'Adding an avatar at this step is a no-op'); assertDev(false, 'Adding an avatar at this step is a no-op');
return state; return state;
} }
} }
@ -3450,7 +3459,7 @@ export function reducer(
}, },
}; };
default: default:
assert(false, 'Removing an avatar at this step is a no-op'); assertDev(false, 'Removing an avatar at this step is a no-op');
return state; return state;
} }
} }
@ -3478,7 +3487,7 @@ export function reducer(
}, },
}; };
default: default:
assert(false, 'Replacing an avatar at this step is a no-op'); assertDev(false, 'Replacing an avatar at this step is a no-op');
return state; return state;
} }
} }
@ -3486,7 +3495,7 @@ export function reducer(
if (action.type === 'TOGGLE_CONVERSATION_IN_CHOOSE_MEMBERS') { if (action.type === 'TOGGLE_CONVERSATION_IN_CHOOSE_MEMBERS') {
const { composer } = state; const { composer } = state;
if (composer?.step !== ComposerStep.ChooseGroupMembers) { if (composer?.step !== ComposerStep.ChooseGroupMembers) {
assert( assertDev(
false, false,
'Toggling conversation members is a no-op in this composer step' 'Toggling conversation members is a no-op in this composer step'
); );

View File

@ -25,7 +25,7 @@ import { SafetyNumberChangeSource } from '../../components/SafetyNumberChangeDia
import { StoryViewDirectionType, StoryViewModeType } from '../../types/Stories'; import { StoryViewDirectionType, StoryViewModeType } from '../../types/Stories';
import { StoryRecipientUpdateEvent } from '../../textsecure/messageReceiverEvents'; import { StoryRecipientUpdateEvent } from '../../textsecure/messageReceiverEvents';
import { ToastReactionFailed } from '../../components/ToastReactionFailed'; import { ToastReactionFailed } from '../../components/ToastReactionFailed';
import { assert } from '../../util/assert'; import { assertDev } from '../../util/assert';
import { blockSendUntilConversationsAreVerified } from '../../util/blockSendUntilConversationsAreVerified'; import { blockSendUntilConversationsAreVerified } from '../../util/blockSendUntilConversationsAreVerified';
import { enqueueReactionForSend } from '../../reactions/enqueueReactionForSend'; import { enqueueReactionForSend } from '../../reactions/enqueueReactionForSend';
import { getMessageById } from '../../messages/getMessageById'; import { getMessageById } from '../../messages/getMessageById';
@ -611,11 +611,11 @@ function sendStoryMessage(
return async (dispatch, getState) => { return async (dispatch, getState) => {
const { stories } = getState(); const { stories } = getState();
const { openedAtTimestamp, sendStoryModalData } = stories; const { openedAtTimestamp, sendStoryModalData } = stories;
assert( assertDev(
openedAtTimestamp, openedAtTimestamp,
'sendStoryMessage: openedAtTimestamp is undefined, cannot send' 'sendStoryMessage: openedAtTimestamp is undefined, cannot send'
); );
assert( assertDev(
sendStoryModalData, sendStoryModalData,
'sendStoryMessage: sendStoryModalData is not defined, cannot send' 'sendStoryMessage: sendStoryModalData is not defined, cannot send'
); );

View File

@ -28,7 +28,7 @@ import type { UUIDFetchStateType } from '../../util/uuidFetchState';
import { deconstructLookup } from '../../util/deconstructLookup'; import { deconstructLookup } from '../../util/deconstructLookup';
import type { PropsDataType as TimelinePropsType } from '../../components/conversation/Timeline'; import type { PropsDataType as TimelinePropsType } from '../../components/conversation/Timeline';
import type { TimelineItemType } from '../../components/conversation/TimelineItem'; import type { TimelineItemType } from '../../components/conversation/TimelineItem';
import { assert } from '../../util/assert'; import { assertDev } from '../../util/assert';
import { isConversationUnregistered } from '../../util/isConversationUnregistered'; import { isConversationUnregistered } from '../../util/isConversationUnregistered';
import { filterAndSortConversationsByRecent } from '../../util/filterAndSortConversations'; import { filterAndSortConversationsByRecent } from '../../util/filterAndSortConversations';
import type { ContactNameColorType } from '../../types/Colors'; import type { ContactNameColorType } from '../../types/Colors';
@ -344,7 +344,7 @@ export const getMaximumGroupSizeModalState = createSelector(
case ComposerStep.SetGroupMetadata: case ComposerStep.SetGroupMetadata:
return composerState.maximumGroupSizeModalState; return composerState.maximumGroupSizeModalState;
default: default:
assert( assertDev(
false, false,
'Can\'t get the maximum group size modal state in this composer state; returning "never shown"' 'Can\'t get the maximum group size modal state in this composer state; returning "never shown"'
); );
@ -361,7 +361,7 @@ export const getRecommendedGroupSizeModalState = createSelector(
case ComposerStep.SetGroupMetadata: case ComposerStep.SetGroupMetadata:
return composerState.recommendedGroupSizeModalState; return composerState.recommendedGroupSizeModalState;
default: default:
assert( assertDev(
false, false,
'Can\'t get the recommended group size modal state in this composer state; returning "never shown"' 'Can\'t get the recommended group size modal state in this composer state; returning "never shown"'
); );
@ -388,11 +388,14 @@ export const getComposerConversationSearchTerm = createSelector(
getComposerState, getComposerState,
(composer): string => { (composer): string => {
if (!composer) { if (!composer) {
assert(false, 'getComposerConversationSearchTerm: composer is not open'); assertDev(
false,
'getComposerConversationSearchTerm: composer is not open'
);
return ''; return '';
} }
if (composer.step === ComposerStep.SetGroupMetadata) { if (composer.step === ComposerStep.SetGroupMetadata) {
assert( assertDev(
false, false,
'getComposerConversationSearchTerm: composer does not have a search term' 'getComposerConversationSearchTerm: composer does not have a search term'
); );
@ -406,14 +409,14 @@ export const getComposerUUIDFetchState = createSelector(
getComposerState, getComposerState,
(composer): UUIDFetchStateType => { (composer): UUIDFetchStateType => {
if (!composer) { if (!composer) {
assert(false, 'getIsFetchingUsername: composer is not open'); assertDev(false, 'getIsFetchingUsername: composer is not open');
return {}; return {};
} }
if ( if (
composer.step !== ComposerStep.StartDirectConversation && composer.step !== ComposerStep.StartDirectConversation &&
composer.step !== ComposerStep.ChooseGroupMembers composer.step !== ComposerStep.ChooseGroupMembers
) { ) {
assert( assertDev(
false, false,
`getComposerUUIDFetchState: step ${composer.step} ` + `getComposerUUIDFetchState: step ${composer.step} ` +
'has no uuidFetchState key' 'has no uuidFetchState key'
@ -583,7 +586,7 @@ const getGroupCreationComposerState = createSelector(
case ComposerStep.SetGroupMetadata: case ComposerStep.SetGroupMetadata:
return composerState; return composerState;
default: default:
assert( assertDev(
false, false,
'getSetGroupMetadataComposerState: expected step to be SetGroupMetadata' 'getSetGroupMetadataComposerState: expected step to be SetGroupMetadata'
); );

View File

@ -3,7 +3,7 @@
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { assert } from '../../util/assert'; import { assertDev } from '../../util/assert';
import { getDomain } from '../../types/LinkPreview'; import { getDomain } from '../../types/LinkPreview';
import type { LinkPreviewSourceType } from '../../types/LinkPreview'; import type { LinkPreviewSourceType } from '../../types/LinkPreview';
@ -22,7 +22,10 @@ export const getLinkPreview = createSelector(
} }
const domain = getDomain(linkPreview.url); const domain = getDomain(linkPreview.url);
assert(domain !== undefined, "Domain of linkPreview can't be undefined"); assertDev(
domain !== undefined,
"Domain of linkPreview can't be undefined"
);
return { return {
...linkPreview, ...linkPreview,

View File

@ -21,7 +21,7 @@ import {
getBadgesSelector, getBadgesSelector,
getPreferredBadgeSelector, getPreferredBadgeSelector,
} from '../selectors/badges'; } from '../selectors/badges';
import { assert } from '../../util/assert'; import { assertDev } from '../../util/assert';
import { SignalService as Proto } from '../../protobuf'; import { SignalService as Proto } from '../../protobuf';
import { getConversationColorAttributes } from '../../util/getConversationColorAttributes'; import { getConversationColorAttributes } from '../../util/getConversationColorAttributes';
import type { SmartChooseGroupMembersModalPropsType } from './ChooseGroupMembersModal'; import type { SmartChooseGroupMembersModalPropsType } from './ChooseGroupMembersModal';
@ -78,7 +78,7 @@ const mapStateToProps = (
): StateProps => { ): StateProps => {
const conversationSelector = getConversationByIdSelector(state); const conversationSelector = getConversationByIdSelector(state);
const conversation = conversationSelector(props.conversationId); const conversation = conversationSelector(props.conversationId);
assert( assertDev(
conversation, conversation,
'<SmartConversationDetails> expected a conversation to be found' '<SmartConversationDetails> expected a conversation to be found'
); );

View File

@ -10,7 +10,7 @@ import { getIntl } from '../selectors/user';
import * as log from '../../logging/log'; import * as log from '../../logging/log';
import type { Loadable } from '../../util/loadable'; import type { Loadable } from '../../util/loadable';
import { LoadingState } from '../../util/loadable'; import { LoadingState } from '../../util/loadable';
import { assert } from '../../util/assert'; import { assertDev } from '../../util/assert';
import { explodePromise } from '../../util/explodePromise'; import { explodePromise } from '../../util/explodePromise';
import { missingCaseError } from '../../util/missingCaseError'; import { missingCaseError } from '../../util/missingCaseError';
import { import {
@ -134,7 +134,7 @@ export function SmartInstallScreen(): ReactElement {
let deviceName: string = normalizeDeviceName(state.deviceName); let deviceName: string = normalizeDeviceName(state.deviceName);
if (!deviceName.length) { if (!deviceName.length) {
// This should be impossible, but we have it here just in case. // This should be impossible, but we have it here just in case.
assert( assertDev(
false, false,
'Unexpected empty device name. Falling back to placeholder value' 'Unexpected empty device name. Falling back to placeholder value'
); );
@ -149,7 +149,7 @@ export function SmartInstallScreen(): ReactElement {
let hasCleanedUp = false; let hasCleanedUp = false;
const accountManager = window.getAccountManager(); const accountManager = window.getAccountManager();
assert(accountManager, 'Expected an account manager'); assertDev(accountManager, 'Expected an account manager');
const updateProvisioningUrl = (value: string): void => { const updateProvisioningUrl = (value: string): void => {
if (hasCleanedUp) { if (hasCleanedUp) {

View File

@ -14,7 +14,7 @@ import {
getConversationByUuidSelector, getConversationByUuidSelector,
} from '../selectors/conversations'; } from '../selectors/conversations';
import { getGroupMemberships } from '../../util/getGroupMemberships'; import { getGroupMemberships } from '../../util/getGroupMemberships';
import { assert } from '../../util/assert'; import { assertDev } from '../../util/assert';
import type { UUIDStringType } from '../../types/UUID'; import type { UUIDStringType } from '../../types/UUID';
export type SmartPendingInvitesProps = { export type SmartPendingInvitesProps = {
@ -32,7 +32,7 @@ const mapStateToProps = (
const conversationByUuidSelector = getConversationByUuidSelector(state); const conversationByUuidSelector = getConversationByUuidSelector(state);
const conversation = conversationSelector(props.conversationId); const conversation = conversationSelector(props.conversationId);
assert( assertDev(
conversation, conversation,
'<SmartPendingInvites> expected a conversation to be found' '<SmartPendingInvites> expected a conversation to be found'
); );

View File

@ -38,7 +38,7 @@ import { renderEmojiPicker } from './renderEmojiPicker';
import { renderReactionPicker } from './renderReactionPicker'; import { renderReactionPicker } from './renderReactionPicker';
import { getOwn } from '../../util/getOwn'; import { getOwn } from '../../util/getOwn';
import { assert } from '../../util/assert'; import { assertDev } from '../../util/assert';
import { missingCaseError } from '../../util/missingCaseError'; import { missingCaseError } from '../../util/missingCaseError';
import { getGroupMemberships } from '../../util/getGroupMemberships'; import { getGroupMemberships } from '../../util/getGroupMemberships';
import { import {
@ -177,7 +177,7 @@ const getWarning = (
const conversationsWithSameTitle = getConversationsWithTitle( const conversationsWithSameTitle = getConversationsWithTitle(
conversation.title conversation.title
); );
assert( assertDev(
conversationsWithSameTitle.length, conversationsWithSameTitle.length,
'Expected at least 1 conversation with the same title (this one)' 'Expected at least 1 conversation with the same title (this one)'
); );

View File

@ -3,17 +3,17 @@
import { assert as chaiAssert } from 'chai'; import { assert as chaiAssert } from 'chai';
import { assert, strictAssert } from '../../util/assert'; import { assertDev, strictAssert } from '../../util/assert';
describe('assert utilities', () => { describe('assert utilities', () => {
describe('assert', () => { describe('assert', () => {
it('does nothing if the assertion passes', () => { it('does nothing if the assertion passes', () => {
assert(true, 'foo bar'); assertDev(true, 'foo bar');
}); });
it("throws if the assertion fails, because we're in a test environment", () => { it("throws if the assertion fails, because we're in a test environment", () => {
chaiAssert.throws(() => { chaiAssert.throws(() => {
assert(false, 'foo bar'); assertDev(false, 'foo bar');
}, 'foo bar'); }, 'foo bar');
}); });
}); });

View File

@ -304,7 +304,6 @@ describe('JobQueue', () => {
case 'bar': case 'bar':
barAttempts += 1; barAttempts += 1;
throw new Error('bar job always fails in this test'); throw new Error('bar job always fails in this test');
break;
default: default:
throw missingCaseError(data); throw missingCaseError(data);
} }

View File

@ -30,7 +30,7 @@ import {
import { UUID, UUIDKind } from '../types/UUID'; import { UUID, UUIDKind } from '../types/UUID';
import { isMoreRecentThan, isOlderThan } from '../util/timestamp'; import { isMoreRecentThan, isOlderThan } from '../util/timestamp';
import { ourProfileKeyService } from '../services/ourProfileKey'; import { ourProfileKeyService } from '../services/ourProfileKey';
import { assert, strictAssert } from '../util/assert'; import { assertDev, strictAssert } from '../util/assert';
import { getRegionCodeForNumber } from '../util/libphonenumberUtil'; import { getRegionCodeForNumber } from '../util/libphonenumberUtil';
import { getProvisioningUrl } from '../util/getProvisioningUrl'; import { getProvisioningUrl } from '../util/getProvisioningUrl';
import { isNotNil } from '../util/isNotNil'; import { isNotNil } from '../util/isNotNil';
@ -114,7 +114,7 @@ export default class AccountManager extends EventTarget {
const bytes = Bytes.fromBase64(base64); const bytes = Bytes.fromBase64(base64);
const proto = Proto.DeviceName.decode(bytes); const proto = Proto.DeviceName.decode(bytes);
assert( assertDev(
proto.ephemeralPublic && proto.syntheticIv && proto.ciphertext, proto.ephemeralPublic && proto.syntheticIv && proto.ciphertext,
'Missing required fields in DeviceName' 'Missing required fields in DeviceName'
); );

View File

@ -16,7 +16,7 @@ import {
import type { QuotedMessageType } from '../model-types.d'; import type { QuotedMessageType } from '../model-types.d';
import type { ConversationModel } from '../models/conversations'; import type { ConversationModel } from '../models/conversations';
import { GLOBAL_ZONE } from '../SignalProtocolStore'; import { GLOBAL_ZONE } from '../SignalProtocolStore';
import { assert, strictAssert } from '../util/assert'; import { assertDev, strictAssert } from '../util/assert';
import { parseIntOrThrow } from '../util/parseIntOrThrow'; import { parseIntOrThrow } from '../util/parseIntOrThrow';
import { Address } from '../types/Address'; import { Address } from '../types/Address';
import { QualifiedAddress } from '../types/QualifiedAddress'; import { QualifiedAddress } from '../types/QualifiedAddress';
@ -673,7 +673,7 @@ export default class MessageSender {
Pick<AttachmentType, 'data' | 'size' | 'contentType'> Pick<AttachmentType, 'data' | 'size' | 'contentType'>
> >
): Promise<Proto.IAttachmentPointer> { ): Promise<Proto.IAttachmentPointer> {
assert( assertDev(
typeof attachment === 'object' && attachment != null, typeof attachment === 'object' && attachment != null,
'Got null attachment in `makeAttachmentPointer`' 'Got null attachment in `makeAttachmentPointer`'
); );
@ -1300,7 +1300,7 @@ export default class MessageSender {
timestamp: number; timestamp: number;
urgent: boolean; urgent: boolean;
}>): Promise<CallbackResultType> { }>): Promise<CallbackResultType> {
assert(identifier, "Identifier can't be undefined"); assertDev(identifier, "Identifier can't be undefined");
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const callback = (res: CallbackResultType) => { const callback = (res: CallbackResultType) => {
if (res && res.errors && res.errors.length > 0) { if (res && res.errors && res.errors.length > 0) {

View File

@ -8,7 +8,7 @@ import type {
import { User } from './storage/User'; import { User } from './storage/User';
import { Blocked } from './storage/Blocked'; import { Blocked } from './storage/Blocked';
import { assert } from '../util/assert'; import { assertDev } from '../util/assert';
import Data from '../sql/Client'; import Data from '../sql/Client';
import type { SignalProtocolStore } from '../SignalProtocolStore'; import type { SignalProtocolStore } from '../SignalProtocolStore';
import * as log from '../logging/log'; import * as log from '../logging/log';
@ -34,7 +34,7 @@ export class Storage implements StorageInterface {
} }
get protocol(): SignalProtocolStore { get protocol(): SignalProtocolStore {
assert( assertDev(
this.privProtocol !== undefined, this.privProtocol !== undefined,
'SignalProtocolStore not initialized' 'SignalProtocolStore not initialized'
); );

View File

@ -9,7 +9,7 @@ import EventTarget from './EventTarget';
import MessageReceiver from './MessageReceiver'; import MessageReceiver from './MessageReceiver';
import type { ContactSyncEvent, GroupSyncEvent } from './messageReceiverEvents'; import type { ContactSyncEvent, GroupSyncEvent } from './messageReceiverEvents';
import MessageSender from './SendMessage'; import MessageSender from './SendMessage';
import { assert } from '../util/assert'; import { assertDev } from '../util/assert';
import * as log from '../logging/log'; import * as log from '../logging/log';
import { singleProtoJobQueue } from '../jobs/singleProtoJobQueue'; import { singleProtoJobQueue } from '../jobs/singleProtoJobQueue';
import * as Errors from '../types/errors'; import * as Errors from '../types/errors';
@ -49,7 +49,10 @@ class SyncRequestInner extends EventTarget {
async start(): Promise<void> { async start(): Promise<void> {
if (this.started) { if (this.started) {
assert(false, 'SyncRequestInner: started more than once. Doing nothing'); assertDev(
false,
'SyncRequestInner: started more than once. Doing nothing'
);
return; return;
} }
this.started = true; this.started = true;

View File

@ -18,7 +18,7 @@ import { v4 as getGuid } from 'uuid';
import { z } from 'zod'; import { z } from 'zod';
import type { Readable } from 'stream'; import type { Readable } from 'stream';
import { assert, strictAssert } from '../util/assert'; import { assertDev, strictAssert } from '../util/assert';
import { isRecord } from '../util/isRecord'; import { isRecord } from '../util/isRecord';
import * as durations from '../util/durations'; import * as durations from '../util/durations';
import type { ExplodePromiseResultType } from '../util/explodePromise'; import type { ExplodePromiseResultType } from '../util/explodePromise';
@ -391,7 +391,7 @@ async function _promiseAjax(
log.info(logId, response.status, 'Success'); log.info(logId, response.status, 'Success');
if (options.responseType === 'byteswithdetails') { if (options.responseType === 'byteswithdetails') {
assert(result instanceof Uint8Array, 'Expected Uint8Array result'); assertDev(result instanceof Uint8Array, 'Expected Uint8Array result');
const fullResult: BytesWithDetailsType = { const fullResult: BytesWithDetailsType = {
data: result, data: result,
contentType: getContentType(response), contentType: getContentType(response),

View File

@ -5,7 +5,7 @@ import Long from 'long';
import { ReceiptCredentialPresentation } from '@signalapp/libsignal-client/zkgroup'; import { ReceiptCredentialPresentation } from '@signalapp/libsignal-client/zkgroup';
import { isNumber } from 'lodash'; import { isNumber } from 'lodash';
import { assert, strictAssert } from '../util/assert'; import { assertDev, strictAssert } from '../util/assert';
import { dropNull, shallowDropNull } from '../util/dropNull'; import { dropNull, shallowDropNull } from '../util/dropNull';
import { SignalService as Proto } from '../protobuf'; import { SignalService as Proto } from '../protobuf';
import { deriveGroupFields } from '../groups'; import { deriveGroupFields } from '../groups';
@ -331,7 +331,7 @@ export async function processDataMessage(
isExpirationTimerUpdate, isExpirationTimerUpdate,
isProfileKeyUpdate, isProfileKeyUpdate,
].filter(Boolean).length; ].filter(Boolean).length;
assert( assertDev(
flagCount <= 1, flagCount <= 1,
`Expected exactly <=1 flags to be set, but got ${flagCount}` `Expected exactly <=1 flags to be set, but got ${flagCount}`
); );

View File

@ -4,7 +4,7 @@
import type { ConversationController } from './ConversationController'; import type { ConversationController } from './ConversationController';
import type { ConversationModel } from './models/conversations'; import type { ConversationModel } from './models/conversations';
import type { WebAPIType } from './textsecure/WebAPI'; import type { WebAPIType } from './textsecure/WebAPI';
import { assert } from './util/assert'; import { assertDev } from './util/assert';
import { isNotNil } from './util/isNotNil'; import { isNotNil } from './util/isNotNil';
import { getUuidsForE164s } from './util/getUuidsForE164s'; import { getUuidsForE164s } from './util/getUuidsForE164s';
@ -47,7 +47,7 @@ export async function updateConversationsWithUuidLookup({
e164, e164,
reason: 'updateConversationsWithUuidLookup', reason: 'updateConversationsWithUuidLookup',
}); });
assert( assertDev(
maybeFinalConversation, maybeFinalConversation,
'updateConversationsWithUuidLookup: expected a conversation to be found or created' 'updateConversationsWithUuidLookup: expected a conversation to be found or created'
); );

View File

@ -22,7 +22,10 @@ export function softAssert(condition: unknown, message: string): void {
/** /**
* In production, logs an error and continues. In all other environments, throws an error. * In production, logs an error and continues. In all other environments, throws an error.
*/ */
export function assert(condition: unknown, message: string): asserts condition { export function assertDev(
condition: unknown,
message: string
): asserts condition {
if (!condition) { if (!condition) {
const err = new Error(message); const err = new Error(message);
if (getEnvironment() !== Environment.Production) { if (getEnvironment() !== Environment.Production) {

View File

@ -31,7 +31,7 @@ import { renderClearingDataView } from '../shims/renderClearingDataView';
import * as universalExpireTimer from './universalExpireTimer'; import * as universalExpireTimer from './universalExpireTimer';
import { PhoneNumberDiscoverability } from './phoneNumberDiscoverability'; import { PhoneNumberDiscoverability } from './phoneNumberDiscoverability';
import { PhoneNumberSharingMode } from './phoneNumberSharingMode'; import { PhoneNumberSharingMode } from './phoneNumberSharingMode';
import { assert } from './assert'; import { assertDev } from './assert';
import * as durations from './durations'; import * as durations from './durations';
import { isPhoneNumberSharingEnabled } from './isPhoneNumberSharingEnabled'; import { isPhoneNumberSharingEnabled } from './isPhoneNumberSharingEnabled';
import { parseE164FromSignalDotMeHash } from './sgnlHref'; import { parseE164FromSignalDotMeHash } from './sgnlHref';
@ -360,7 +360,7 @@ export function createIPCEvents(
const conversationId = const conversationId =
window.ConversationController.getOurConversationIdOrThrow(); window.ConversationController.getOurConversationIdOrThrow();
const account = window.ConversationController.get(conversationId); const account = window.ConversationController.get(conversationId);
assert(account, "Account wasn't found"); assertDev(account, "Account wasn't found");
account.captureChange('universalExpireTimer'); account.captureChange('universalExpireTimer');
@ -369,7 +369,7 @@ export function createIPCEvents(
const selectedId = state.conversations.selectedConversationId; const selectedId = state.conversations.selectedConversationId;
if (selectedId) { if (selectedId) {
const conversation = window.ConversationController.get(selectedId); const conversation = window.ConversationController.get(selectedId);
assert(conversation, "Conversation wasn't found"); assertDev(conversation, "Conversation wasn't found");
await conversation.updateLastMessage(); await conversation.updateLastMessage();
} }

View File

@ -2,7 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { getOwn } from './getOwn'; import { getOwn } from './getOwn';
import { assert } from './assert'; import { assertDev } from './assert';
export const deconstructLookup = <T>( export const deconstructLookup = <T>(
lookup: Record<string, T>, lookup: Record<string, T>,
@ -14,7 +14,7 @@ export const deconstructLookup = <T>(
if (value) { if (value) {
result.push(value); result.push(value);
} else { } else {
assert(false, `deconstructLookup: lookup failed for ${key}; dropping`); assertDev(false, `deconstructLookup: lookup failed for ${key}; dropping`);
} }
}); });
return result; return result;

View File

@ -3,7 +3,7 @@
import emojiRegex from 'emoji-regex'; import emojiRegex from 'emoji-regex';
import { assert } from './assert'; import { assertDev } from './assert';
import { take } from './iterables'; import { take } from './iterables';
const REGEXP = emojiRegex(); const REGEXP = emojiRegex();
@ -31,7 +31,7 @@ export function splitByEmoji(value: string): ReadonlyArray<SplitElement> {
result.push({ type: 'emoji', value: match[0] }); result.push({ type: 'emoji', value: match[0] });
assert(match.index !== undefined, '`matchAll` should provide indices'); assertDev(match.index !== undefined, '`matchAll` should provide indices');
lastIndex = match.index + match[0].length; lastIndex = match.index + match[0].length;
} }

View File

@ -3,7 +3,7 @@
import type { ConversationType } from '../state/ducks/conversations'; import type { ConversationType } from '../state/ducks/conversations';
import type { ProfileRequestDataType } from '../textsecure/WebAPI'; import type { ProfileRequestDataType } from '../textsecure/WebAPI';
import { assert } from './assert'; import { assertDev } from './assert';
import * as Bytes from '../Bytes'; import * as Bytes from '../Bytes';
import { import {
PaddedLengths, PaddedLengths,
@ -27,8 +27,8 @@ export async function encryptProfileData(
uuid, uuid,
} = conversation; } = conversation;
assert(profileKey, 'profileKey'); assertDev(profileKey, 'profileKey');
assert(uuid, 'uuid'); assertDev(uuid, 'uuid');
const keyBuffer = Bytes.fromBase64(profileKey); const keyBuffer = Bytes.fromBase64(profileKey);

View File

@ -5,7 +5,7 @@ import { PublicKey, Fingerprint } from '@signalapp/libsignal-client';
import type { ConversationType } from '../state/ducks/conversations'; import type { ConversationType } from '../state/ducks/conversations';
import { UUID } from '../types/UUID'; import { UUID } from '../types/UUID';
import { assert } from './assert'; import { assertDev } from './assert';
import * as log from '../logging/log'; import * as log from '../logging/log';
export async function generateSecurityNumber( export async function generateSecurityNumber(
@ -63,7 +63,7 @@ export async function generateSecurityNumberBlock(
return []; return [];
} }
assert(ourNumber, 'Should have our number'); assertDev(ourNumber, 'Should have our number');
const securityNumber = await generateSecurityNumber( const securityNumber = await generateSecurityNumber(
ourNumber, ourNumber,
ourKey, ourKey,

View File

@ -1,10 +1,10 @@
// Copyright 2021-2022 Signal Messenger, LLC // Copyright 2021-2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { assert } from './assert'; import { assertDev } from './assert';
export function shouldNeverBeCalled(..._args: ReadonlyArray<unknown>): void { export function shouldNeverBeCalled(..._args: ReadonlyArray<unknown>): void {
assert(false, 'This should never be called. Doing nothing'); assertDev(false, 'This should never be called. Doing nothing');
} }
export async function asyncShouldNeverBeCalled( export async function asyncShouldNeverBeCalled(

View File

@ -29,6 +29,8 @@
// As a temporary measure // As a temporary measure
"useUnknownInCatchVariables": false, "useUnknownInCatchVariables": false,
// Temp: The `assertDev()` function doesn't run in production so we can't rely on this
"allowUnreachableCode": true,
// Additional Checks // Additional Checks
"noUnusedLocals": true, // Report errors on unused locals. "noUnusedLocals": true, // Report errors on unused locals.