Remove underscore

This commit is contained in:
Fedor Indutny 2022-11-29 16:53:39 -08:00 committed by GitHub
parent 704107a256
commit 9d8ad21819
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 111 additions and 226 deletions

View file

@ -1,32 +0,0 @@
// Copyright 2015-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
/*
* Defines a default definition for render() which allows sub-classes
* to simply specify a template property and renderAttributes which are plugged
* into Mustache.render
*/
// eslint-disable-next-line func-names
(function () {
window.Whisper = window.Whisper || {};
window.Whisper.View = Backbone.View.extend({
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
constructor(...params: Array<any>) {
window.Backbone.View.call(this, ...params);
// Checks for syntax errors
window.Mustache.parse(_.result(this, 'template'));
},
render_attributes() {
return _.result(this.model, 'attributes', {});
},
render() {
const attrs = window._.result(this, 'render_attributes', {});
const template = window._.result(this, 'template', '');
this.$el.html(window.Mustache.render(template, attrs));
return this;
},
});
})();

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { webFrame } from 'electron';
import { isNumber } from 'lodash';
import { isNumber, clone, debounce } from 'lodash';
import { bindActionCreators } from 'redux';
import { render } from 'react-dom';
import { batch as batchDispatch } from 'react-redux';
@ -197,7 +197,7 @@ export async function startApp(): Promise<void> {
await KeyboardLayout.initialize();
window.Whisper.events = window._.clone(window.Backbone.Events);
window.Whisper.events = clone(window.Backbone.Events);
window.Signal.Util.MessageController.install();
window.Signal.conversationControllerStart();
window.startupProcessingQueue = new window.Signal.Util.StartupQueue();
@ -1753,7 +1753,7 @@ export async function startApp(): Promise<void> {
window.Whisper.events.on(
'mightBeUnlinked',
window._.debounce(enqueueReconnectToWebSocket, 1000, { maxWait: 5000 })
debounce(enqueueReconnectToWebSocket, 1000, { maxWait: 5000 })
);
window.Whisper.events.on('unlinkAndDisconnect', () => {
@ -3137,10 +3137,8 @@ export async function startApp(): Promise<void> {
let unidentifiedDeliveries: Array<string> = [];
if (unidentifiedStatus.length) {
const unidentified = window._.filter(data.unidentifiedStatus, item =>
Boolean(item.unidentified)
);
unidentifiedDeliveries = unidentified
unidentifiedDeliveries = unidentifiedStatus
.filter(item => Boolean(item.unidentified))
.map(item => item.destinationUuid || item.destination)
.filter(isNotNil);
}

4
ts/model-types.d.ts vendored
View file

@ -435,10 +435,6 @@ export type GroupV2PendingAdminApprovalType = {
timestamp: number;
};
export type VerificationOptions = {
key?: null | Uint8Array;
};
export type ShallowChallengeError = CustomError & {
readonly retryAfter: number;
readonly data: SendMessageChallengeData;

View file

@ -1,7 +1,15 @@
// Copyright 2020-2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { compact, has, isNumber, throttle, debounce } from 'lodash';
import {
compact,
has,
isNumber,
throttle,
debounce,
head,
sortBy,
} from 'lodash';
import { batch as batchDispatch } from 'react-redux';
import { v4 as generateGuid } from 'uuid';
import PQueue from 'p-queue';
@ -13,7 +21,6 @@ import type {
MessageAttributesType,
QuotedMessageType,
SenderKeyInfoType,
VerificationOptions,
} from '../model-types.d';
import { getInitials } from '../util/getInitials';
import { normalizeUuid } from '../util/normalizeUuid';
@ -468,7 +475,7 @@ export class ConversationModel extends window.Backbone
return false;
}
return window._.any(membersV2, item => item.uuid === uuid.toString());
return membersV2.some(item => item.uuid === uuid.toString());
}
async updateExpirationTimerInGroupV2(
@ -1792,10 +1799,8 @@ export class ConversationModel extends window.Backbone
}
}
const typingValues = window._.values(this.contactTypingTimers || {});
const typingMostRecent = window._.first(
window._.sortBy(typingValues, 'timestamp')
);
const typingValues = Object.values(this.contactTypingTimers || {});
const typingMostRecent = head(sortBy(typingValues, 'timestamp'));
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const timestamp = this.get('timestamp')!;
@ -2675,36 +2680,24 @@ export class ConversationModel extends window.Backbone
);
}
setVerifiedDefault(options?: VerificationOptions): Promise<boolean> {
setVerifiedDefault(): Promise<boolean> {
const { DEFAULT } = this.verifiedEnum;
return this.queueJob('setVerifiedDefault', () =>
this._setVerified(DEFAULT, options)
this._setVerified(DEFAULT)
);
}
setVerified(options?: VerificationOptions): Promise<boolean> {
setVerified(): Promise<boolean> {
const { VERIFIED } = this.verifiedEnum;
return this.queueJob('setVerified', () =>
this._setVerified(VERIFIED, options)
);
return this.queueJob('setVerified', () => this._setVerified(VERIFIED));
}
setUnverified(options: VerificationOptions): Promise<boolean> {
setUnverified(): Promise<boolean> {
const { UNVERIFIED } = this.verifiedEnum;
return this.queueJob('setUnverified', () =>
this._setVerified(UNVERIFIED, options)
);
return this.queueJob('setUnverified', () => this._setVerified(UNVERIFIED));
}
private async _setVerified(
verified: number,
providedOptions?: VerificationOptions
): Promise<boolean> {
const options = providedOptions || {};
window._.defaults(options, {
key: null,
});
private async _setVerified(verified: number): Promise<boolean> {
const { VERIFIED, DEFAULT } = this.verifiedEnum;
if (!isDirectConversation(this.attributes)) {
@ -2886,13 +2879,13 @@ export class ConversationModel extends window.Backbone
if (isDirectConversation(this.attributes)) {
return this.safeIsUntrusted(timestampThreshold);
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
if (!this.contactCollection!.length) {
const { contactCollection } = this;
if (!contactCollection?.length) {
return false;
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return this.contactCollection!.any(contact => {
return contactCollection.some(contact => {
if (isMe(contact.attributes)) {
return false;
}
@ -3166,7 +3159,7 @@ export class ConversationModel extends window.Backbone
if (isDirectConversation(this.attributes) && uuid) {
window.ConversationController.getAllGroupsInvolvingUuid(uuid).then(
groups => {
window._.forEach(groups, group => {
groups.forEach(group => {
group.addVerifiedChange(this.id, verified, options);
});
}
@ -3303,7 +3296,7 @@ export class ConversationModel extends window.Backbone
if (isDirectConversation(this.attributes) && uuid) {
window.ConversationController.getAllGroupsInvolvingUuid(uuid).then(
groups => {
window._.forEach(groups, group => {
groups.forEach(group => {
group.addProfileChange(profileChange, this.id);
});
}

View file

@ -2,14 +2,21 @@
// SPDX-License-Identifier: AGPL-3.0-only
import {
groupBy,
difference,
isEmpty,
isEqual,
isNumber,
isObject,
mapValues,
maxBy,
noop,
omit,
partition,
pick,
reject,
union,
without,
} from 'lodash';
import type {
CustomError,
@ -262,8 +269,6 @@ type PropsForMessageDetail = Pick<
| 'expirationTimestamp'
>;
declare const _: typeof window._;
window.Whisper = window.Whisper || {};
const { Message: TypedMessage } = window.Signal.Types;
@ -309,7 +314,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
cachedOutgoingStickerData?: StickerWithHydratedData;
override initialize(attributes: unknown): void {
if (_.isObject(attributes)) {
if (isObject(attributes)) {
this.set(
TypedMessage.initializeSchemaVersion({
message: attributes as MessageAttributesType,
@ -516,10 +521,10 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
// If an error has a specific number it's associated with, we'll show it next to
// that contact. Otherwise, it will be a standalone entry.
const errors = _.reject(allErrors, error =>
const errors = reject(allErrors, error =>
Boolean(error.identifier || error.number)
);
const errorsGroupedById = _.groupBy(allErrors, error => {
const errorsGroupedById = groupBy(allErrors, error => {
const identifier = error.identifier || error.number;
if (!identifier) {
return null;
@ -747,7 +752,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
}
if (groupUpdate.joined && groupUpdate.joined.length) {
const joinedContacts = _.map(groupUpdate.joined, item =>
const joinedContacts = groupUpdate.joined.map(item =>
window.ConversationController.getOrCreate(item, 'private')
);
const joinedWithoutMe = joinedContacts.filter(
@ -757,7 +762,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
if (joinedContacts.length > 1) {
messages.push(
window.i18n('multipleJoinedTheGroup', [
_.map(joinedWithoutMe, contact => contact.getTitle()).join(', '),
joinedWithoutMe.map(contact => contact.getTitle()).join(', '),
])
);
@ -1026,7 +1031,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
override validate(attributes: Record<string, unknown>): void {
const required = ['conversationId', 'received_at', 'sent_at'];
const missing = _.filter(required, attr => !attributes[attr]);
const missing = required.filter(attr => !attributes[attr]);
if (missing.length) {
log.warn(`Message missing attributes: ${missing}`);
}
@ -1366,7 +1371,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
// We check instanceof second because typescript believes that anything that comes
// through here must be an instance of Error, so e is 'never' after that check.
if ((e.message && e.stack) || e instanceof Error) {
return _.pick(
return pick(
e,
'name',
'message',
@ -1523,7 +1528,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
removeOutgoingErrors(incomingIdentifier: string): CustomError {
const incomingConversationId =
window.ConversationController.getConversationId(incomingIdentifier);
const errors = _.partition(
const errors = partition(
this.get('errors'),
e =>
window.ConversationController.getConversationId(
@ -2386,12 +2391,12 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
});
const existingRevision = conversation.get('revision');
const isFirstUpdate = !_.isNumber(existingRevision);
const isFirstUpdate = !isNumber(existingRevision);
// Standard GroupV2 modification codepath
const isV2GroupUpdate =
initialMessage.groupV2 &&
_.isNumber(initialMessage.groupV2.revision) &&
isNumber(initialMessage.groupV2.revision) &&
(isFirstUpdate ||
initialMessage.groupV2.revision > existingRevision);
@ -2708,7 +2713,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
attributes = {
...attributes,
name: initialMessage.group.name,
members: _.union(members, conversation.get('members')),
members: union(members, conversation.get('members')),
};
if (initialMessage.group.name !== conversation.get('name')) {
@ -2776,14 +2781,14 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
);
}
const difference = _.difference(
const differentMembers = difference(
members,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
conversation.get('members')!
);
if (difference.length > 0) {
if (differentMembers.length > 0) {
// Because GroupV1 groups are based on e164 only
const maybeE164s = map(difference, id =>
const maybeE164s = map(differentMembers, id =>
window.ConversationController.get(id)?.get('e164')
);
const e164s = filter(maybeE164s, isNotNil);
@ -2813,7 +2818,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
} else {
pendingGroupUpdate.left = sender.get('id');
}
attributes.members = _.without(
attributes.members = without(
conversation.get('members'),
sender.get('id')
);

View file

@ -14,7 +14,6 @@ const CONCAT_TARGET = join(__dirname, '../../js/components.js');
const CONCAT_SOURCES = [
join(BASE_NODE, 'jquery/dist/jquery.js'),
join(BASE_NODE, 'mustache/mustache.js'),
join(BASE_NODE, 'underscore/underscore.js'),
join(BASE_BOWER, 'webaudiorecorder/lib/WebAudioRecorder.js'),
];

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { connect } from 'react-redux';
import { pick } from 'underscore';
import { pick } from 'lodash';
import { MessageAudio } from '../../components/conversation/MessageAudio';
import type { OwnProps as MessageAudioOwnProps } from '../../components/conversation/MessageAudio';

View file

@ -5,6 +5,7 @@
import chai, { assert } from 'chai';
import chaiAsPromised from 'chai-as-promised';
import { clone } from 'lodash';
import {
Direction,
IdentityKeyPair,
@ -563,7 +564,7 @@ describe('SignalProtocolStore', () => {
describe('with invalid attributes', () => {
let attributes: IdentityKeyType;
beforeEach(() => {
attributes = window._.clone(validAttributes);
attributes = clone(validAttributes);
});
async function testInvalidAttributes() {

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import { pick } from 'lodash';
import { isOverHourIntoPast, cleanupSessionResets } from '../background';
@ -38,7 +39,7 @@ describe('#cleanupSessionResets', () => {
cleanupSessionResets();
const actual = window.storage.get('sessionResets');
const expected = window._.pick(startValue, ['one', 'two']);
const expected = pick(startValue, ['one', 'two']);
assert.deepEqual(actual, expected);
});
it('filters out falsey items', () => {
@ -50,7 +51,7 @@ describe('#cleanupSessionResets', () => {
cleanupSessionResets();
const actual = window.storage.get('sessionResets');
const expected = window._.pick(startValue, ['two']);
const expected = pick(startValue, ['two']);
assert.deepEqual(actual, expected);
assert.deepEqual(Object.keys(startValue), ['two']);

View file

@ -1,41 +0,0 @@
// Copyright 2015-2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
describe('Whisper.View', () => {
it('renders a template with render_attributes', () => {
const ViewClass = window.Whisper.View.extend({
template: '<div>{{ variable }}</div>',
render_attributes: {
variable: 'value',
},
});
const view = new ViewClass();
view.render();
assert.strictEqual(view.$el.html(), '<div>value</div>');
});
it('renders a template with no render_attributes', () => {
const ViewClass = window.Whisper.View.extend({
template: '<div>static text</div>',
});
const view = new ViewClass();
view.render();
assert.strictEqual(view.$el.html(), '<div>static text</div>');
});
it('renders a template function with render_attributes function', () => {
const ViewClass = window.Whisper.View.extend({
template() {
return '<div>{{ variable }}</div>';
},
render_attributes() {
return { variable: 'value' };
},
});
const view = new ViewClass();
view.render();
assert.strictEqual(view.$el.html(), '<div>value</div>');
});
});

View file

@ -399,13 +399,24 @@ export function createIPCEvents(
},
addDarkOverlay: () => {
if ($('.dark-overlay').length) {
const elems = document.querySelectorAll('.dark-overlay');
if (elems.length) {
return;
}
$(document.body).prepend('<div class="dark-overlay"></div>');
$('.dark-overlay').on('click', () => $('.dark-overlay').remove());
const newOverlay = document.createElement('div');
newOverlay.className = 'dark-overlay';
newOverlay.addEventListener('click', () => {
newOverlay.remove();
});
document.body.prepend(newOverlay);
},
removeDarkOverlay: () => {
const elems = document.querySelectorAll('.dark-overlay');
for (const elem of elems) {
elem.remove();
}
},
removeDarkOverlay: () => $('.dark-overlay').remove(),
showKeyboardShortcuts: () => window.showKeyboardShortcuts(),
deleteAllData: async () => {

View file

@ -8522,14 +8522,6 @@
"reasonCategory": "falseMatch",
"updated": "2020-07-21T18:34:59.251Z"
},
{
"rule": "jQuery-html(",
"path": "ts/backbone/views/whisper_view.ts",
"line": " this.$el.html(window.Mustache.render(template, attrs));",
"reasonCategory": "usageTrusted",
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Rendered template has been sanitized"
},
{
"rule": "React-useRef",
"path": "ts/calling/useGetCallingFrameBuffer.ts",
@ -9390,45 +9382,12 @@
"reasonCategory": "usageTrusted",
"updated": "2021-08-03T21:17:38.615Z"
},
{
"rule": "jQuery-$(",
"path": "ts/util/createIPCEvents.tsx",
"line": " if ($('.dark-overlay').length) {",
"reasonCategory": "usageTrusted",
"updated": "2021-08-18T18:22:55.307Z",
"reasonDetail": "Legacy code"
},
{
"rule": "jQuery-$(",
"path": "ts/util/createIPCEvents.tsx",
"line": " $(document.body).prepend('<div class=\"dark-overlay\"></div>');",
"reasonCategory": "usageTrusted",
"updated": "2021-08-18T18:22:55.307Z",
"reasonDetail": "Legacy code"
},
{
"rule": "jQuery-$(",
"path": "ts/util/createIPCEvents.tsx",
"line": " $('.dark-overlay').on('click', () => $('.dark-overlay').remove());",
"reasonCategory": "usageTrusted",
"updated": "2021-08-18T18:22:55.307Z",
"reasonDetail": "Legacy code"
},
{
"rule": "jQuery-$(",
"path": "ts/util/createIPCEvents.tsx",
"line": " removeDarkOverlay: () => $('.dark-overlay').remove(),",
"reasonCategory": "usageTrusted",
"updated": "2021-08-18T18:22:55.307Z",
"reasonDetail": "Legacy code"
},
{
"rule": "jQuery-prepend(",
"path": "ts/util/createIPCEvents.tsx",
"line": " $(document.body).prepend('<div class=\"dark-overlay\"></div>');",
"reasonCategory": "usageTrusted",
"updated": "2021-08-18T18:22:55.307Z",
"reasonDetail": "Legacy code"
"line": " document.body.prepend(newOverlay);",
"reasonCategory": "falseMatch",
"updated": "2022-11-30T00:14:31.394Z"
},
{
"rule": "jQuery-load(",

3
ts/window.d.ts vendored
View file

@ -5,7 +5,6 @@
import type { Store } from 'redux';
import type * as Backbone from 'backbone';
import type * as Underscore from 'underscore';
import type PQueue from 'p-queue/dist';
import type { assert } from 'chai';
import type * as Mustache from 'mustache';
@ -229,7 +228,6 @@ declare global {
) => Promise<void>;
FontFace: typeof FontFace;
_: typeof Underscore;
$: typeof jQuery;
imageToBlurHash: typeof imageToBlurHash;
@ -393,5 +391,4 @@ export type WhisperType = {
// 'extend View' syntax. Thus, we'll need to typescriptify most of it at once.
InboxView: typeof Backbone.View;
View: typeof Backbone.View;
};

View file

@ -6,7 +6,6 @@
import '../../models/messages';
import '../../models/conversations';
import '../../backbone/views/whisper_view';
import '../../views/conversation_view';
import '../../SignalProtocolStore';
import '../../background';