Add eqeqeq rule but require == for null

This commit is contained in:
Jamie Kyle 2022-09-14 14:40:44 -07:00 committed by GitHub
parent 64a4d2e717
commit 0086216c9d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 64 additions and 63 deletions

View file

@ -19,6 +19,10 @@ const rules = {
'brace-style': ['error', '1tbs', { allowSingleLine: false }],
curly: ['error', 'all'],
// Always use === and !== except when directly comparing to null
// (which only will equal null or undefined)
eqeqeq: ['error', 'always', { null: 'never' }],
// prevents us from accidentally checking in exclusive tests (`.only`):
'mocha/no-exclusive-tests': 'error',

View file

@ -931,7 +931,7 @@ export class SignalProtocolStore extends EventsMixin {
throw new Error('loadSession: this.sessions not yet cached!');
}
if (qualifiedAddress === null || qualifiedAddress === undefined) {
if (qualifiedAddress == null) {
throw new Error('loadSession: qualifiedAddress was undefined/null');
}
@ -1049,7 +1049,7 @@ export class SignalProtocolStore extends EventsMixin {
throw new Error('storeSession: this.sessions not yet cached!');
}
if (qualifiedAddress === null || qualifiedAddress === undefined) {
if (qualifiedAddress == null) {
throw new Error('storeSession: qualifiedAddress was undefined/null');
}
const { uuid, deviceId } = qualifiedAddress;
@ -1225,7 +1225,7 @@ export class SignalProtocolStore extends EventsMixin {
throw new Error('removeAllSessions: this.sessions not yet cached!');
}
if (identifier === null || identifier === undefined) {
if (identifier == null) {
throw new Error('removeAllSessions: identifier was undefined/null');
}
@ -1491,7 +1491,7 @@ export class SignalProtocolStore extends EventsMixin {
throw new Error('isTrustedIdentity: this.identityKeys not yet cached!');
}
if (encodedAddress === null || encodedAddress === undefined) {
if (encodedAddress == null) {
throw new Error('isTrustedIdentity: encodedAddress was undefined/null');
}
const ourUuid = window.textsecure.storage.user.getCheckedUuid();
@ -1553,7 +1553,7 @@ export class SignalProtocolStore extends EventsMixin {
}
async loadIdentityKey(uuid: UUID): Promise<Uint8Array | undefined> {
if (uuid === null || uuid === undefined) {
if (uuid == null) {
throw new Error('loadIdentityKey: uuid was undefined/null');
}
const identityRecord = await this.getOrMigrateIdentityRecord(uuid);
@ -1566,7 +1566,7 @@ export class SignalProtocolStore extends EventsMixin {
}
async getFingerprint(uuid: UUID): Promise<string | undefined> {
if (uuid === null || uuid === undefined) {
if (uuid == null) {
throw new Error('loadIdentityKey: uuid was undefined/null');
}
@ -1606,7 +1606,7 @@ export class SignalProtocolStore extends EventsMixin {
throw new Error('saveIdentity: this.identityKeys not yet cached!');
}
if (encodedAddress === null || encodedAddress === undefined) {
if (encodedAddress == null) {
throw new Error('saveIdentity: encodedAddress was undefined/null');
}
if (!(publicKey instanceof Uint8Array)) {
@ -1703,7 +1703,7 @@ export class SignalProtocolStore extends EventsMixin {
uuid: UUID,
attributes: Partial<IdentityKeyType>
): Promise<void> {
if (uuid === null || uuid === undefined) {
if (uuid == null) {
throw new Error('saveIdentityWithAttributes: uuid was undefined/null');
}
@ -1728,7 +1728,7 @@ export class SignalProtocolStore extends EventsMixin {
}
async setApproval(uuid: UUID, nonblockingApproval: boolean): Promise<void> {
if (uuid === null || uuid === undefined) {
if (uuid == null) {
throw new Error('setApproval: uuid was undefined/null');
}
if (typeof nonblockingApproval !== 'boolean') {
@ -1750,7 +1750,7 @@ export class SignalProtocolStore extends EventsMixin {
verifiedStatus: number,
publicKey?: Uint8Array
): Promise<void> {
if (uuid === null || uuid === undefined) {
if (uuid == null) {
throw new Error('setVerified: uuid was undefined/null');
}
if (!validateVerifiedStatus(verifiedStatus)) {
@ -1775,7 +1775,7 @@ export class SignalProtocolStore extends EventsMixin {
}
async getVerified(uuid: UUID): Promise<number> {
if (uuid === null || uuid === undefined) {
if (uuid == null) {
throw new Error('getVerified: uuid was undefined/null');
}
@ -1799,7 +1799,7 @@ export class SignalProtocolStore extends EventsMixin {
verifiedStatus: number,
publicKey?: Uint8Array
): Promise<boolean> {
if (uuid === null || uuid === undefined) {
if (uuid == null) {
throw new Error('processVerifiedMessage: uuid was undefined/null');
}
if (!validateVerifiedStatus(verifiedStatus)) {
@ -1849,7 +1849,7 @@ export class SignalProtocolStore extends EventsMixin {
}
isUntrusted(uuid: UUID, timestampThreshold = TIMESTAMP_THRESHOLD): boolean {
if (uuid === null || uuid === undefined) {
if (uuid == null) {
throw new Error('isUntrusted: uuid was undefined/null');
}

View file

@ -3561,7 +3561,7 @@ export async function startApp(): Promise<void> {
const { storageServiceKey } = ev;
if (storageServiceKey === null) {
if (storageServiceKey == null) {
log.info('onKeysSync: deleting window.storageKey');
window.storage.remove('storageKey');
}

View file

@ -185,7 +185,7 @@ export function CompositionInput(props: Props): React.ReactElement {
const range = quill.getSelection();
const insertionRange = range || lastSelectionRange;
if (insertionRange === null) {
if (insertionRange == null) {
return;
}
@ -599,7 +599,7 @@ export function CompositionInput(props: Props): React.ReactElement {
quill.once('editor-change', () => {
const scroller = scrollerRef.current;
if (scroller !== null) {
if (scroller != null) {
quill.scrollingContainer = scroller;
}
@ -613,7 +613,7 @@ export function CompositionInput(props: Props): React.ReactElement {
'selection-change',
(newRange: RangeStatic, oldRange: RangeStatic) => {
// If we lose focus, store the last edit point for emoji insertion
if (newRange === null) {
if (newRange == null) {
setLastSelectionRange(oldRange);
}
}

View file

@ -226,7 +226,7 @@ export const MessageAudio: React.FC<Props> = (props: Props) => {
setActiveAudioID,
} = props;
assert(audio !== null, 'GlobalAudioContext always provides audio');
assert(audio != null, 'GlobalAudioContext always provides audio');
const isActive =
activeAudioID === id && activeAudioContext === renderingContext;

View file

@ -56,7 +56,7 @@ function parseOptionalString(name: string, value: unknown): undefined | string {
if (typeof value === 'string') {
return value;
}
if (value === undefined || value === null) {
if (value == null) {
return undefined;
}
throw new Error(`${name} was not a string`);

View file

@ -1895,11 +1895,11 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
attachments: quote.attachments.slice(),
bodyRanges: quote.bodyRanges.map(({ start, length, mentionUuid }) => {
strictAssert(
start !== undefined && start !== null,
start != null,
'Received quote with a bodyRange.start == null'
);
strictAssert(
length !== undefined && length !== null,
length != null,
'Received quote with a bodyRange.length == null'
);
@ -2564,7 +2564,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
}
let avatar = null;
if (downloadedAvatar && avatarAttachment !== null) {
if (downloadedAvatar && avatarAttachment != null) {
const onDiskAttachment =
await Attachment.migrateDataToFileSystem(downloadedAvatar, {
writeNewAttachmentData:

View file

@ -202,7 +202,7 @@ export class EmojiCompletion {
completeEmoji(): void {
const range = this.quill.getSelection();
if (range === null) {
if (range == null) {
return;
}
@ -211,7 +211,7 @@ export class EmojiCompletion {
const tokenTextMatch = /:([-+0-9a-z_]*)(:?)$/.exec(leafText);
if (tokenTextMatch === null) {
if (tokenTextMatch == null) {
return;
}
@ -277,7 +277,7 @@ export class EmojiCompletion {
getBoundingClientRect() {
const selection = window.getSelection();
// there's a selection and at least one range
if (selection !== null && selection.rangeCount !== 0) {
if (selection != null && selection.rangeCount !== 0) {
// grab the first range, the one the user is actually on right now
// clone it so we don't actually modify the user's selection/caret position
const range = selection.getRangeAt(0).cloneRange();

View file

@ -151,7 +151,7 @@ export class MentionCompletion {
const range = this.quill.getSelection();
if (range === null) {
if (range == null) {
return;
}

View file

@ -9,7 +9,7 @@ import { getTextFromOps } from '../util';
const getSelectionHTML = () => {
const selection = window.getSelection();
if (selection === null) {
if (selection == null) {
return '';
}
@ -49,19 +49,19 @@ export class SignalClipboard {
onCaptureCopy(event: ClipboardEvent, isCut = false): void {
event.preventDefault();
if (event.clipboardData === null) {
if (event.clipboardData == null) {
return;
}
const range = this.quill.getSelection();
if (range === null) {
if (range == null) {
return;
}
const contents = this.quill.getContents(range.index, range.length);
if (contents === null) {
if (contents == null) {
return;
}
@ -83,7 +83,7 @@ export class SignalClipboard {
}
onCapturePaste(event: ClipboardEvent): void {
if (event.clipboardData === null) {
if (event.clipboardData == null) {
return;
}
@ -92,7 +92,7 @@ export class SignalClipboard {
const clipboard = this.quill.getModule('clipboard');
const selection = this.quill.getSelection();
if (selection === null) {
if (selection == null) {
return;
}

View file

@ -89,7 +89,7 @@ async function main(
await wrapEventEmitterOnce(proxyServer, 'listening');
const addr = proxyServer.address();
strictAssert(
typeof addr === 'object' && addr !== null,
typeof addr === 'object' && addr != null,
'Address has to be an object'
);

View file

@ -1640,10 +1640,7 @@ async function sync(
return undefined;
}
strictAssert(
manifest.version !== undefined && manifest.version !== null,
'Manifest without version'
);
strictAssert(manifest.version != null, 'Manifest without version');
const version = manifest.version?.toNumber() ?? 0;
log.info(

View file

@ -540,6 +540,7 @@ function doRecordsConflict(
// false, empty string, or 0 for these records we do not count them as
// conflicting.
if (
// eslint-disable-next-line eqeqeq
remoteValue === null &&
(localValue === false ||
localValue === '' ||

View file

@ -65,6 +65,7 @@ function cleanDataInner(
// functions but don't mark them as cleaned.
return undefined;
case 'object': {
// eslint-disable-next-line eqeqeq
if (data === null) {
return null;
}
@ -73,7 +74,7 @@ function cleanDataInner(
const result: CleanedArray = [];
data.forEach((item, index) => {
const indexPath = `${path}.${index}`;
if (item === undefined || item === null) {
if (item == null) {
pathsChanged.push(indexPath);
} else {
result.push(cleanDataInner(item, indexPath, pathsChanged));

View file

@ -18,7 +18,7 @@ describe('getStreamWithTimeout', () => {
stream: Readable,
chunk: string | null
): Promise<unknown> => {
const promise = once(stream, chunk === null ? 'end' : 'data');
const promise = once(stream, chunk == null ? 'end' : 'data');
stream.push(chunk);
return promise;
};

View file

@ -76,7 +76,7 @@ describe('link preview fetching', () => {
const headersObj = new Headers();
Object.entries({
'Content-Type': 'text/html; charset=utf-8',
'Content-Length': bodyLength === null ? null : String(bodyLength),
'Content-Length': bodyLength == null ? null : String(bodyLength),
...headers,
}).forEach(([headerName, headerValue]) => {
if (headerValue) {

View file

@ -20,7 +20,7 @@ export default class EventTarget {
if (!(ev instanceof Event)) {
throw new Error('Expects an event');
}
if (this.listeners === null || typeof this.listeners !== 'object') {
if (this.listeners == null || typeof this.listeners !== 'object') {
this.listeners = {};
}
const listeners = this.listeners[ev.type];
@ -44,7 +44,7 @@ export default class EventTarget {
if (typeof callback !== 'function') {
throw new Error('Second argument expects a function');
}
if (this.listeners === null || typeof this.listeners !== 'object') {
if (this.listeners == null || typeof this.listeners !== 'object') {
this.listeners = {};
}
let listeners = this.listeners[eventName];
@ -62,7 +62,7 @@ export default class EventTarget {
if (typeof callback !== 'function') {
throw new Error('Second argument expects a function');
}
if (this.listeners === null || typeof this.listeners !== 'object') {
if (this.listeners == null || typeof this.listeners !== 'object') {
this.listeners = {};
}
const listeners = this.listeners[eventName];

View file

@ -56,7 +56,7 @@ function ensureStringed(thing: any): any {
return res;
}
if (thing === null) {
if (thing == null) {
return null;
}
throw new Error(`unsure of how to jsonify object of type ${typeof thing}`);

View file

@ -755,7 +755,7 @@ export default class MessageReceiver
id: item.id,
receivedAtCounter: item.receivedAtCounter ?? item.timestamp,
receivedAtDate:
item.receivedAtCounter === null ? Date.now() : item.timestamp,
item.receivedAtCounter == null ? Date.now() : item.timestamp,
messageAgeSec: item.messageAgeSec || 0,
// Proto.Envelope fields

View file

@ -293,7 +293,7 @@ class Message {
throw new Error('Invalid timestamp');
}
if (this.expireTimer !== undefined && this.expireTimer !== null) {
if (this.expireTimer != null) {
if (typeof this.expireTimer !== 'number' || !(this.expireTimer >= 0)) {
throw new Error('Invalid expireTimer');
}
@ -311,8 +311,8 @@ class Message {
}
if (this.isEndSession()) {
if (
this.body !== null ||
this.group !== null ||
this.body != null ||
this.group != null ||
this.attachments.length !== 0
) {
throw new Error('Invalid end session message');
@ -674,7 +674,7 @@ export default class MessageSender {
>
): Promise<Proto.IAttachmentPointer> {
assert(
typeof attachment === 'object' && attachment !== null,
typeof attachment === 'object' && attachment != null,
'Got null attachment in `makeAttachmentPointer`'
);

View file

@ -76,10 +76,7 @@ function processGroupContext(
}
strictAssert(group.id, 'group context without id');
strictAssert(
group.type !== undefined && group.type !== null,
'group context without type'
);
strictAssert(group.type != null, 'group context without type');
const masterKey = deriveMasterKeyFromGroupV1(group.id);
const data = deriveGroupFields(masterKey);

View file

@ -19,7 +19,7 @@ export class Address {
public static parse(value: string): Address {
const match = value.match(ADDRESS_REGEXP);
strictAssert(match !== null, `Invalid Address: ${value}`);
strictAssert(match != null, `Invalid Address: ${value}`);
const [whole, uuid, deviceId] = match;
strictAssert(whole === value, 'Integrity check');
return Address.create(uuid, parseInt(deviceId, 10));

View file

@ -39,7 +39,7 @@ export class QualifiedAddress {
public static parse(value: string): QualifiedAddress {
const match = value.match(QUALIFIED_ADDRESS_REGEXP);
strictAssert(match !== null, `Invalid QualifiedAddress: ${value}`);
strictAssert(match != null, `Invalid QualifiedAddress: ${value}`);
const [whole, ourUuid, uuid, deviceId] = match;
strictAssert(whole === value, 'Integrity check');

View file

@ -319,7 +319,7 @@ async function downloadSticker(
{ ephemeral }: { ephemeral?: boolean } = {}
): Promise<Omit<StickerFromDBType, 'isCoverOnly'>> {
const { id, emoji } = proto;
strictAssert(id !== undefined && id !== null, "Sticker id can't be null");
strictAssert(id != null, "Sticker id can't be null");
const { messaging } = window.textsecure;
if (!messaging) {

View file

@ -8,6 +8,7 @@ export type NullToUndefined<T> = Extract<T, null> extends never
export function dropNull<T>(
value: NonNullable<T> | null | undefined
): T | undefined {
// eslint-disable-next-line eqeqeq
if (value === null) {
return undefined;
}
@ -22,7 +23,7 @@ export function shallowDropNull<O extends { [key: string]: any }>(
[Property in keyof O]: NullToUndefined<O[Property]>;
}
| undefined {
if (value === null || value === undefined) {
if (value == null) {
return undefined;
}

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
export function isNotNil<T>(value: T | null | undefined): value is T {
if (value === null || value === undefined) {
if (value == null) {
return false;
}
return true;

View file

@ -2,4 +2,4 @@
// SPDX-License-Identifier: AGPL-3.0-only
export const isRecord = (value: unknown): value is Record<string, unknown> =>
typeof value === 'object' && !Array.isArray(value) && value !== null;
typeof value === 'object' && !Array.isArray(value) && value != null;

View file

@ -7,7 +7,7 @@ import { getOwn } from './getOwn';
export function isIterable(value: unknown): value is Iterable<unknown> {
return (
(typeof value === 'object' && value !== null && Symbol.iterator in value) ||
(typeof value === 'object' && value != null && Symbol.iterator in value) ||
typeof value === 'string'
);
}

View file

@ -27,7 +27,7 @@ export function memoizeByRoot<F extends Function>(
const wrap = (root: unknown, ...rest: Array<unknown>): unknown => {
strictAssert(
typeof root === 'object' && root !== null,
typeof root === 'object' && root != null,
'Root is not object'
);

View file

@ -336,7 +336,7 @@ function binaryToUint8Array(
length: number
): Uint8Array {
const target = get(object, path);
if (target === null || target === undefined) {
if (target == null) {
throw new Error(`binaryToUint8Array: Falsey path ${path}`);
}
@ -357,7 +357,7 @@ function binaryToUint8Array(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function getInteger(object: any, path: string): number {
const target = get(object, path);
if (target === null || target === undefined) {
if (target == null) {
throw new Error(`getInteger: Falsey path ${path}`);
}