Update to eslint-plugin-matrix-org 0.8 (#23825)

* Update to eslint-plugin-matrix-org 0.8

* Exclude some eslint rules for specs

* Fix eslint tests path
This commit is contained in:
Michael Weimann 2022-11-23 17:24:36 +01:00 committed by GitHub
parent c1d4abbeb0
commit cbf5c43ae7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 104 additions and 95 deletions

View file

@ -72,5 +72,14 @@ module.exports = {
}], }],
}], }],
}, },
}, {
files: [
"test/**/*.{ts,tsx}",
],
rules: {
// We don't need super strict typing in test utilities
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-member-accessibility": "off",
},
}], }],
}; };

View file

@ -123,12 +123,12 @@ function readCurrentPackageDetails(): RawDependencies {
}; };
} }
function writePackageDetails(deps: RawDependencies) { function writePackageDetails(deps: RawDependencies): void {
fs.writeFileSync("./yarn.lock", deps.lockfile, "utf-8"); fs.writeFileSync("./yarn.lock", deps.lockfile, "utf-8");
fs.writeFileSync("./package.json", deps.packageJson, "utf-8"); fs.writeFileSync("./package.json", deps.packageJson, "utf-8");
} }
function callYarnAdd(dep: string) { function callYarnAdd(dep: string): void {
// Add the module to the optional dependencies section just in case something // Add the module to the optional dependencies section just in case something
// goes wrong in restoring the original package details. // goes wrong in restoring the original package details.
childProcess.execSync(`yarn add -O ${dep}`, { childProcess.execSync(`yarn add -O ${dep}`, {
@ -186,6 +186,6 @@ function isModuleVersionCompatible(ourApiVersion: string, moduleApiVersion: stri
return semver.satisfies(ourApiVersion, moduleApiVersion); return semver.satisfies(ourApiVersion, moduleApiVersion);
} }
function writeModulesTs(content: string) { function writeModulesTs(content: string): void {
fs.writeFileSync("./src/modules.ts", content, "utf-8"); fs.writeFileSync("./src/modules.ts", content, "utf-8");
} }

View file

@ -115,7 +115,7 @@
"eslint-config-google": "^0.14.0", "eslint-config-google": "^0.14.0",
"eslint-plugin-deprecate": "^0.7.0", "eslint-plugin-deprecate": "^0.7.0",
"eslint-plugin-import": "^2.25.4", "eslint-plugin-import": "^2.25.4",
"eslint-plugin-matrix-org": "^0.7.0", "eslint-plugin-matrix-org": "^0.8.0",
"eslint-plugin-react": "^7.28.0", "eslint-plugin-react": "^7.28.0",
"eslint-plugin-react-hooks": "^4.3.0", "eslint-plugin-react-hooks": "^4.3.0",
"eslint-plugin-unicorn": "^44.0.2", "eslint-plugin-unicorn": "^44.0.2",

View file

@ -15,11 +15,11 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import React from 'react'; import React, { ReactElement } from 'react';
import SdkConfig from 'matrix-react-sdk/src/SdkConfig'; import SdkConfig from 'matrix-react-sdk/src/SdkConfig';
import { _t } from 'matrix-react-sdk/src/languageHandler'; import { _t } from 'matrix-react-sdk/src/languageHandler';
const VectorAuthFooter = () => { const VectorAuthFooter = (): ReactElement => {
const brandingConfig = SdkConfig.getObject("branding"); const brandingConfig = SdkConfig.getObject("branding");
const links = brandingConfig?.get("auth_footer_links") ?? [ const links = brandingConfig?.get("auth_footer_links") ?? [
{ "text": "Blog", "url": "https://element.io/blog" }, { "text": "Blog", "url": "https://element.io/blog" },

View file

@ -19,7 +19,7 @@ import * as React from 'react';
import SdkConfig from 'matrix-react-sdk/src/SdkConfig'; import SdkConfig from 'matrix-react-sdk/src/SdkConfig';
export default class VectorAuthHeaderLogo extends React.PureComponent { export default class VectorAuthHeaderLogo extends React.PureComponent {
public render() { public render(): React.ReactElement {
const brandingConfig = SdkConfig.getObject("branding"); const brandingConfig = SdkConfig.getObject("branding");
const logoUrl = brandingConfig?.get("auth_header_logo_url") ?? "themes/element/img/logos/element-logo.svg"; const logoUrl = brandingConfig?.get("auth_header_logo_url") ?? "themes/element/img/logos/element-logo.svg";

View file

@ -23,7 +23,7 @@ export default class VectorAuthPage extends React.PureComponent {
private static welcomeBackgroundUrl; private static welcomeBackgroundUrl;
// cache the url as a static to prevent it changing without refreshing // cache the url as a static to prevent it changing without refreshing
private static getWelcomeBackgroundUrl() { private static getWelcomeBackgroundUrl(): string {
if (VectorAuthPage.welcomeBackgroundUrl) return VectorAuthPage.welcomeBackgroundUrl; if (VectorAuthPage.welcomeBackgroundUrl) return VectorAuthPage.welcomeBackgroundUrl;
const brandingConfig = SdkConfig.getObject("branding"); const brandingConfig = SdkConfig.getObject("branding");
@ -42,7 +42,7 @@ export default class VectorAuthPage extends React.PureComponent {
return VectorAuthPage.welcomeBackgroundUrl; return VectorAuthPage.welcomeBackgroundUrl;
} }
public render() { public render(): React.ReactElement {
const pageStyle = { const pageStyle = {
background: `center/cover fixed url(${VectorAuthPage.getWelcomeBackgroundUrl()})`, background: `center/cover fixed url(${VectorAuthPage.getWelcomeBackgroundUrl()})`,
}; };

View file

@ -56,7 +56,7 @@ export default class Favicon {
// callback to run once isReady is asserted, allows for a badge to be queued for when it can be shown // callback to run once isReady is asserted, allows for a badge to be queued for when it can be shown
private readyCb?: () => void; private readyCb?: () => void;
constructor(params: Partial<IParams> = {}) { public constructor(params: Partial<IParams> = {}) {
this.params = { ...defaults, ...params }; this.params = { ...defaults, ...params };
this.icons = Favicon.getIcons(); this.icons = Favicon.getIcons();
@ -68,7 +68,7 @@ export default class Favicon {
const lastIcon = this.icons[this.icons.length - 1]; const lastIcon = this.icons[this.icons.length - 1];
if (lastIcon.hasAttribute("href")) { if (lastIcon.hasAttribute("href")) {
this.baseImage.setAttribute("crossOrigin", "anonymous"); this.baseImage.setAttribute("crossOrigin", "anonymous");
this.baseImage.onload = () => { this.baseImage.onload = (): void => {
// get height and width of the favicon // get height and width of the favicon
this.canvas.height = (this.baseImage.height > 0) ? this.baseImage.height : 32; this.canvas.height = (this.baseImage.height > 0) ? this.baseImage.height : 32;
this.canvas.width = (this.baseImage.width > 0) ? this.baseImage.width : 32; this.canvas.width = (this.baseImage.width > 0) ? this.baseImage.width : 32;
@ -217,7 +217,7 @@ export default class Favicon {
public badge(content: number | string, opts?: Partial<IParams>): void { public badge(content: number | string, opts?: Partial<IParams>): void {
if (!this.isReady) { if (!this.isReady) {
this.readyCb = () => { this.readyCb = (): void => {
this.badge(content, opts); this.badge(content, opts);
}; };
return; return;

View file

@ -21,7 +21,7 @@ limitations under the License.
// To ensure we load the browser-matrix version first // To ensure we load the browser-matrix version first
import "matrix-js-sdk/src/browser-index"; import "matrix-js-sdk/src/browser-index";
import React from 'react'; import React, { ReactElement } from 'react';
import PlatformPeg from 'matrix-react-sdk/src/PlatformPeg'; import PlatformPeg from 'matrix-react-sdk/src/PlatformPeg';
import { _td, newTranslatableError } from 'matrix-react-sdk/src/languageHandler'; import { _td, newTranslatableError } from 'matrix-react-sdk/src/languageHandler';
import AutoDiscoveryUtils from 'matrix-react-sdk/src/utils/AutoDiscoveryUtils'; import AutoDiscoveryUtils from 'matrix-react-sdk/src/utils/AutoDiscoveryUtils';
@ -55,7 +55,7 @@ window.matrixLogger = logger;
// If we're in electron, we should never pass through a file:// URL otherwise // If we're in electron, we should never pass through a file:// URL otherwise
// the identity server will try to 302 the browser to it, which breaks horribly. // the identity server will try to 302 the browser to it, which breaks horribly.
// so in that instance, hardcode to use app.element.io for now instead. // so in that instance, hardcode to use app.element.io for now instead.
function makeRegistrationUrl(params: object) { function makeRegistrationUrl(params: object): string {
let url; let url;
if (window.location.protocol === "vector:") { if (window.location.protocol === "vector:") {
url = 'https://app.element.io/#/register'; url = 'https://app.element.io/#/register';
@ -81,7 +81,7 @@ function makeRegistrationUrl(params: object) {
return url; return url;
} }
function onTokenLoginCompleted() { function onTokenLoginCompleted(): void {
// if we did a token login, we're now left with the token, hs and is // if we did a token login, we're now left with the token, hs and is
// url as query params in the url; a little nasty but let's redirect to // url as query params in the url; a little nasty but let's redirect to
// clear them. // clear them.
@ -93,7 +93,7 @@ function onTokenLoginCompleted() {
window.history.replaceState(null, "", url.href); window.history.replaceState(null, "", url.href);
} }
export async function loadApp(fragParams: {}) { export async function loadApp(fragParams: {}): Promise<ReactElement> {
initRouting(); initRouting();
const platform = PlatformPeg.get(); const platform = PlatformPeg.get();

View file

@ -40,7 +40,7 @@ require('katex/dist/katex.css');
require('./devcss'); require('./devcss');
require('./localstorage-fix'); require('./localstorage-fix');
async function settled(...promises: Array<Promise<any>>) { async function settled(...promises: Array<Promise<any>>): Promise<void> {
for (const prom of promises) { for (const prom of promises) {
try { try {
await prom; await prom;
@ -50,7 +50,7 @@ async function settled(...promises: Array<Promise<any>>) {
} }
} }
function checkBrowserFeatures() { function checkBrowserFeatures(): boolean {
if (!window.Modernizr) { if (!window.Modernizr) {
logger.error("Cannot check features - Modernizr global is missing."); logger.error("Cannot check features - Modernizr global is missing.");
return false; return false;
@ -102,7 +102,7 @@ const supportedBrowser = checkBrowserFeatures();
// We start loading stuff but don't block on it until as late as possible to allow // We start loading stuff but don't block on it until as late as possible to allow
// the browser to use as much parallelism as it can. // the browser to use as much parallelism as it can.
// Load parallelism is based on research in https://github.com/vector-im/element-web/issues/12253 // Load parallelism is based on research in https://github.com/vector-im/element-web/issues/12253
async function start() { async function start(): Promise<void> {
// load init.ts async so that its code is not executed immediately and we can catch any exceptions // load init.ts async so that its code is not executed immediately and we can catch any exceptions
const { const {
rageshakePromise, rageshakePromise,

View file

@ -41,7 +41,7 @@ import { INSTALLED_MODULES } from "../modules";
export const rageshakePromise = initRageshake(); export const rageshakePromise = initRageshake();
export function preparePlatform() { export function preparePlatform(): void {
if (window.electron) { if (window.electron) {
logger.log("Using Electron platform"); logger.log("Using Electron platform");
PlatformPeg.set(new ElectronPlatform()); PlatformPeg.set(new ElectronPlatform());
@ -54,7 +54,7 @@ export function preparePlatform() {
} }
} }
export function setupLogStorage() { export function setupLogStorage(): Promise<void> {
if (SdkConfig.get().bug_report_endpoint_url) { if (SdkConfig.get().bug_report_endpoint_url) {
return initRageshakeStore(); return initRageshakeStore();
} }
@ -62,7 +62,7 @@ export function setupLogStorage() {
return Promise.resolve(); return Promise.resolve();
} }
export async function loadConfig() { export async function loadConfig(): Promise<void> {
// XXX: We call this twice, once here and once in MatrixChat as a prop. We call it here to ensure // XXX: We call this twice, once here and once in MatrixChat as a prop. We call it here to ensure
// granular settings are loaded correctly and to avoid duplicating the override logic for the theme. // granular settings are loaded correctly and to avoid duplicating the override logic for the theme.
// //
@ -112,7 +112,7 @@ export function loadOlm(): Promise<void> {
}); });
} }
export async function loadLanguage() { export async function loadLanguage(): Promise<void> {
const prefLang = SettingsStore.getValue("language", null, /*excludeDefault=*/true); const prefLang = SettingsStore.getValue("language", null, /*excludeDefault=*/true);
let langs = []; let langs = [];
@ -131,11 +131,11 @@ export async function loadLanguage() {
} }
} }
export async function loadTheme() { export async function loadTheme(): Promise<void> {
setTheme(); setTheme();
} }
export async function loadApp(fragParams: {}) { export async function loadApp(fragParams: {}): Promise<void> {
// load app.js async so that its code is not executed immediately and we can catch any exceptions // load app.js async so that its code is not executed immediately and we can catch any exceptions
const module = await import( const module = await import(
/* webpackChunkName: "element-web-app" */ /* webpackChunkName: "element-web-app" */
@ -145,7 +145,7 @@ export async function loadApp(fragParams: {}) {
document.getElementById('matrixchat')); document.getElementById('matrixchat'));
} }
export async function showError(title: string, messages?: string[]) { export async function showError(title: string, messages?: string[]): Promise<void> {
const ErrorView = (await import( const ErrorView = (await import(
/* webpackChunkName: "error-view" */ /* webpackChunkName: "error-view" */
"../async-components/structures/ErrorView")).default; "../async-components/structures/ErrorView")).default;
@ -153,7 +153,7 @@ export async function showError(title: string, messages?: string[]) {
document.getElementById('matrixchat')); document.getElementById('matrixchat'));
} }
export async function showIncompatibleBrowser(onAccept) { export async function showIncompatibleBrowser(onAccept): Promise<void> {
const CompatibilityView = (await import( const CompatibilityView = (await import(
/* webpackChunkName: "compatibility-view" */ /* webpackChunkName: "compatibility-view" */
"../async-components/structures/CompatibilityView")).default; "../async-components/structures/CompatibilityView")).default;
@ -161,7 +161,7 @@ export async function showIncompatibleBrowser(onAccept) {
document.getElementById('matrixchat')); document.getElementById('matrixchat'));
} }
export async function loadModules() { export async function loadModules(): Promise<void> {
for (const InstalledModule of INSTALLED_MODULES) { for (const InstalledModule of INSTALLED_MODULES) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore - we know the constructor exists even if TypeScript can't be convinced of that // @ts-ignore - we know the constructor exists even if TypeScript can't be convinced of that

View file

@ -61,7 +61,7 @@ let widgetApi: WidgetApi;
let meetApi: any; // JitsiMeetExternalAPI let meetApi: any; // JitsiMeetExternalAPI
let skipOurWelcomeScreen = false; let skipOurWelcomeScreen = false;
const setupCompleted = (async () => { const setupCompleted = (async (): Promise<string | void> => {
try { try {
// Queue a config.json lookup asap, so we can use it later on. We want this to be concurrent with // Queue a config.json lookup asap, so we can use it later on. We want this to be concurrent with
// other setup work and therefore do not block. // other setup work and therefore do not block.
@ -223,11 +223,11 @@ const setupCompleted = (async () => {
} }
})(); })();
function enableJoinButton() { function enableJoinButton(): void {
document.getElementById("joinButton").onclick = () => joinConference(); document.getElementById("joinButton").onclick = (): void => joinConference();
} }
function switchVisibleContainers() { function switchVisibleContainers(): void {
inConference = !inConference; inConference = !inConference;
// Our welcome screen is managed by other code, so just don't switch to it ever // Our welcome screen is managed by other code, so just don't switch to it ever
@ -237,14 +237,14 @@ function switchVisibleContainers() {
} }
} }
function toggleConferenceVisibility(inConference: boolean) { function toggleConferenceVisibility(inConference: boolean): void {
document.getElementById("jitsiContainer").style.visibility = inConference ? 'unset' : 'hidden'; document.getElementById("jitsiContainer").style.visibility = inConference ? 'unset' : 'hidden';
// Video rooms have a separate UI for joining, so they should never show our join button // Video rooms have a separate UI for joining, so they should never show our join button
document.getElementById("joinButtonContainer").style.visibility = document.getElementById("joinButtonContainer").style.visibility =
(inConference || isVideoChannel) ? 'hidden' : 'unset'; (inConference || isVideoChannel) ? 'hidden' : 'unset';
} }
function skipToJitsiSplashScreen() { function skipToJitsiSplashScreen(): void {
// really just a function alias for self-documenting code // really just a function alias for self-documenting code
joinConference(); joinConference();
} }
@ -254,7 +254,7 @@ function skipToJitsiSplashScreen() {
* *
* See https://github.com/matrix-org/prosody-mod-auth-matrix-user-verification * See https://github.com/matrix-org/prosody-mod-auth-matrix-user-verification
*/ */
function createJWTToken() { function createJWTToken(): string {
// Header // Header
const header = { alg: 'HS256', typ: 'JWT' }; const header = { alg: 'HS256', typ: 'JWT' };
// Payload // Payload
@ -289,7 +289,7 @@ function createJWTToken() {
); );
} }
async function notifyHangup(errorMessage?: string) { async function notifyHangup(errorMessage?: string): Promise<void> {
if (widgetApi) { if (widgetApi) {
// We send the hangup event before setAlwaysOnScreen, because the latter // We send the hangup event before setAlwaysOnScreen, because the latter
// can cause the receiving side to instantly stop listening. // can cause the receiving side to instantly stop listening.
@ -301,7 +301,7 @@ async function notifyHangup(errorMessage?: string) {
} }
} }
function closeConference() { function closeConference(): void {
switchVisibleContainers(); switchVisibleContainers();
document.getElementById("jitsiContainer").innerHTML = ""; document.getElementById("jitsiContainer").innerHTML = "";
@ -315,7 +315,7 @@ function closeConference() {
// audio input it can find, while an input of null instructs it to start muted, // audio input it can find, while an input of null instructs it to start muted,
// and a non-nullish input specifies the label of a specific device to use. // and a non-nullish input specifies the label of a specific device to use.
// Same for video inputs. // Same for video inputs.
function joinConference(audioInput?: string | null, videoInput?: string | null) { function joinConference(audioInput?: string | null, videoInput?: string | null): void {
let jwt; let jwt;
if (jitsiAuth === JITSI_OPENIDTOKEN_JWT_AUTH) { if (jitsiAuth === JITSI_OPENIDTOKEN_JWT_AUTH) {
if (!openIdToken?.access_token) { // eslint-disable-line camelcase if (!openIdToken?.access_token) { // eslint-disable-line camelcase
@ -408,7 +408,7 @@ function joinConference(audioInput?: string | null, videoInput?: string | null)
meetApi.on("log", onLog); meetApi.on("log", onLog);
} }
const onVideoConferenceJoined = () => { const onVideoConferenceJoined = (): void => {
// Although we set our displayName with the userInfo option above, that // Although we set our displayName with the userInfo option above, that
// option has a bug where it causes the name to be the HTML encoding of // option has a bug where it causes the name to be the HTML encoding of
// what was actually intended. So, we use the displayName command to at // what was actually intended. So, we use the displayName command to at
@ -432,12 +432,12 @@ const onVideoConferenceJoined = () => {
if (isVideoChannel) meetApi.executeCommand("setTileView", true); if (isVideoChannel) meetApi.executeCommand("setTileView", true);
}; };
const onVideoConferenceLeft = () => { const onVideoConferenceLeft = (): void => {
notifyHangup(); notifyHangup();
meetApi = null; meetApi = null;
}; };
const onErrorOccurred = ({ error }) => { const onErrorOccurred = ({ error }): void => {
if (error.isFatal) { if (error.isFatal) {
// We got disconnected. Since Jitsi Meet might send us back to the // We got disconnected. Since Jitsi Meet might send us back to the
// prejoin screen, we're forced to act as if we hung up entirely. // prejoin screen, we're forced to act as if we hung up entirely.
@ -447,12 +447,12 @@ const onErrorOccurred = ({ error }) => {
} }
}; };
const onAudioMuteStatusChanged = ({ muted }) => { const onAudioMuteStatusChanged = ({ muted }): void => {
const action = muted ? ElementWidgetActions.MuteAudio : ElementWidgetActions.UnmuteAudio; const action = muted ? ElementWidgetActions.MuteAudio : ElementWidgetActions.UnmuteAudio;
widgetApi?.transport.send(action, {}); widgetApi?.transport.send(action, {});
}; };
const onVideoMuteStatusChanged = ({ muted }) => { const onVideoMuteStatusChanged = ({ muted }): void => {
if (muted) { if (muted) {
// Jitsi Meet always sends a "video muted" event directly before // Jitsi Meet always sends a "video muted" event directly before
// hanging up, which we need to ignore by padding the timeout here, // hanging up, which we need to ignore by padding the timeout here,
@ -466,11 +466,11 @@ const onVideoMuteStatusChanged = ({ muted }) => {
} }
}; };
const updateParticipants = () => { const updateParticipants = (): void => {
widgetApi?.transport.send(ElementWidgetActions.CallParticipants, { widgetApi?.transport.send(ElementWidgetActions.CallParticipants, {
participants: meetApi.getParticipantsInfo(), participants: meetApi.getParticipantsInfo(),
}); });
}; };
const onLog = ({ logLevel, args }) => const onLog = ({ logLevel, args }): void =>
(parent as unknown as typeof global).mx_rage_logger?.log(logLevel, ...args); (parent as unknown as typeof global).mx_rage_logger?.log(logLevel, ...args);

View file

@ -92,7 +92,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
// this is the opaque token we pass to the HS which when we get it in our callback we can resolve to a profile // this is the opaque token we pass to the HS which when we get it in our callback we can resolve to a profile
private readonly ssoID: string = randomString(32); private readonly ssoID: string = randomString(32);
constructor() { public constructor() {
super(); super();
dis.register(onAction); dis.register(onAction);
@ -124,12 +124,12 @@ export default class ElectronPlatform extends VectorBasePlatform {
window.electron.on('userDownloadCompleted', (ev, { id, name }) => { window.electron.on('userDownloadCompleted', (ev, { id, name }) => {
const key = `DOWNLOAD_TOAST_${id}`; const key = `DOWNLOAD_TOAST_${id}`;
const onAccept = () => { const onAccept = (): void => {
window.electron.send('userDownloadAction', { id, open: true }); window.electron.send('userDownloadAction', { id, open: true });
ToastStore.sharedInstance().dismissToast(key); ToastStore.sharedInstance().dismissToast(key);
}; };
const onDismiss = () => { const onDismiss = (): void => {
window.electron.send('userDownloadAction', { id }); window.electron.send('userDownloadAction', { id });
}; };
@ -156,7 +156,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
return this.ipc.call('getConfig'); return this.ipc.call('getConfig');
} }
private onUpdateDownloaded = async (ev, { releaseNotes, releaseName }) => { private onUpdateDownloaded = async (ev, { releaseNotes, releaseName }): Promise<void> => {
dis.dispatch<CheckUpdatesPayload>({ dis.dispatch<CheckUpdatesPayload>({
action: Action.CheckUpdates, action: Action.CheckUpdates,
status: UpdateCheckStatus.Ready, status: UpdateCheckStatus.Ready,
@ -223,7 +223,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
); );
const handler = notification.onclick as Function; const handler = notification.onclick as Function;
notification.onclick = () => { notification.onclick = (): void => {
handler?.(); handler?.();
this.ipc.call('focusWindow'); this.ipc.call('focusWindow');
}; };
@ -231,7 +231,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
return notification; return notification;
} }
public loudNotification(ev: MatrixEvent, room: Room) { public loudNotification(ev: MatrixEvent, room: Room): void {
window.electron.send('loudNotification'); window.electron.send('loudNotification');
} }
@ -261,17 +261,17 @@ export default class ElectronPlatform extends VectorBasePlatform {
return this.ipc.call("setSettingValue", settingName, value); return this.ipc.call("setSettingValue", settingName, value);
} }
async canSelfUpdate(): Promise<boolean> { public async canSelfUpdate(): Promise<boolean> {
const feedUrl = await this.ipc.call('getUpdateFeedUrl'); const feedUrl = await this.ipc.call('getUpdateFeedUrl');
return Boolean(feedUrl); return Boolean(feedUrl);
} }
public startUpdateCheck() { public startUpdateCheck(): void {
super.startUpdateCheck(); super.startUpdateCheck();
window.electron.send('check_updates'); window.electron.send('check_updates');
} }
public installUpdate() { public installUpdate(): void {
// IPC to the main process to install the update, since quitAndInstall // IPC to the main process to install the update, since quitAndInstall
// doesn't fire the before-quit event so the main process needs to know // doesn't fire the before-quit event so the main process needs to know
// it should exit. // it should exit.
@ -290,7 +290,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
return Promise.resolve('granted'); return Promise.resolve('granted');
} }
public reload() { public reload(): void {
window.location.reload(); window.location.reload();
} }
@ -298,7 +298,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
return this.eventIndexManager; return this.eventIndexManager;
} }
public async setLanguage(preferredLangs: string[]) { public async setLanguage(preferredLangs: string[]): Promise<any> {
return this.ipc.call('setLanguage', preferredLangs); return this.ipc.call('setLanguage', preferredLangs);
} }
@ -353,7 +353,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
loginType: "sso" | "cas", loginType: "sso" | "cas",
fragmentAfterLogin: string, fragmentAfterLogin: string,
idpId?: string, idpId?: string,
) { ): void {
// this will get intercepted by electron-main will-navigate // this will get intercepted by electron-main will-navigate
super.startSingleSignOn(mxClient, loginType, fragmentAfterLogin, idpId); super.startSingleSignOn(mxClient, loginType, fragmentAfterLogin, idpId);
Modal.createDialog(InfoDialog, { Modal.createDialog(InfoDialog, {

View file

@ -43,7 +43,7 @@ export default abstract class VectorBasePlatform extends BasePlatform {
* it uses canvas, which can trigger a permission prompt in Firefox's resist fingerprinting mode. * it uses canvas, which can trigger a permission prompt in Firefox's resist fingerprinting mode.
* See https://github.com/vector-im/element-web/issues/9605. * See https://github.com/vector-im/element-web/issues/9605.
*/ */
public get favicon() { public get favicon(): Favicon {
if (this._favicon) { if (this._favicon) {
return this._favicon; return this._favicon;
} }
@ -51,7 +51,7 @@ export default abstract class VectorBasePlatform extends BasePlatform {
return this._favicon; return this._favicon;
} }
private updateFavicon() { private updateFavicon(): void {
let bgColor = "#d00"; let bgColor = "#d00";
let notif: string | number = this.notificationCount; let notif: string | number = this.notificationCount;
@ -63,13 +63,13 @@ export default abstract class VectorBasePlatform extends BasePlatform {
this.favicon.badge(notif, { bgColor }); this.favicon.badge(notif, { bgColor });
} }
public setNotificationCount(count: number) { public setNotificationCount(count: number): void {
if (this.notificationCount === count) return; if (this.notificationCount === count) return;
super.setNotificationCount(count); super.setNotificationCount(count);
this.updateFavicon(); this.updateFavicon();
} }
public setErrorStatus(errorDidOccur: boolean) { public setErrorStatus(errorDidOccur: boolean): void {
if (this.errorDidOccur === errorDidOccur) return; if (this.errorDidOccur === errorDidOccur) return;
super.setErrorStatus(errorDidOccur); super.setErrorStatus(errorDidOccur);
this.updateFavicon(); this.updateFavicon();
@ -78,7 +78,7 @@ export default abstract class VectorBasePlatform extends BasePlatform {
/** /**
* Begin update polling, if applicable * Begin update polling, if applicable
*/ */
public startUpdater() { public startUpdater(): void {
} }
/** /**

View file

@ -40,7 +40,7 @@ function getNormalizedAppVersion(version: string): string {
} }
export default class WebPlatform extends VectorBasePlatform { export default class WebPlatform extends VectorBasePlatform {
constructor() { public constructor() {
super(); super();
// Register service worker if available on this platform // Register service worker if available on this platform
if ('serviceWorker' in navigator) { if ('serviceWorker' in navigator) {

View file

@ -31,7 +31,7 @@ import SdkConfig from "matrix-react-sdk/src/SdkConfig";
import sendBugReport from "matrix-react-sdk/src/rageshake/submit-rageshake"; import sendBugReport from "matrix-react-sdk/src/rageshake/submit-rageshake";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
export function initRageshake() { export function initRageshake(): Promise<void> {
// we manually check persistence for rageshakes ourselves // we manually check persistence for rageshakes ourselves
const prom = rageshake.init(/*setUpPersistence=*/false); const prom = rageshake.init(/*setUpPersistence=*/false);
prom.then(() => { prom.then(() => {
@ -52,11 +52,11 @@ export function initRageshake() {
return prom; return prom;
} }
export function initRageshakeStore() { export function initRageshakeStore(): Promise<void> {
return rageshake.tryInitStorage(); return rageshake.tryInitStorage();
} }
window.mxSendRageshake = function(text: string, withLogs?: boolean) { window.mxSendRageshake = function(text: string, withLogs?: boolean): void {
const url = SdkConfig.get().bug_report_endpoint_url; const url = SdkConfig.get().bug_report_endpoint_url;
if (!url) { if (!url) {
logger.error("Cannot send a rageshake - no bug_report_endpoint_url configured"); logger.error("Cannot send a rageshake - no bug_report_endpoint_url configured");

View file

@ -17,13 +17,14 @@ limitations under the License.
// Parse the given window.location and return parameters that can be used when calling // Parse the given window.location and return parameters that can be used when calling
// MatrixChat.showScreen(screen, params) // MatrixChat.showScreen(screen, params)
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { QueryDict } from "matrix-js-sdk/src/utils";
import MatrixChatType from "matrix-react-sdk/src/components/structures/MatrixChat"; import MatrixChatType from "matrix-react-sdk/src/components/structures/MatrixChat";
import { parseQsFromFragment } from "./url_utils"; import { parseQsFromFragment } from "./url_utils";
let lastLocationHashSet: string = null; let lastLocationHashSet: string = null;
export function getScreenFromLocation(location: Location) { export function getScreenFromLocation(location: Location): { screen: string, params: QueryDict } {
const fragparts = parseQsFromFragment(location); const fragparts = parseQsFromFragment(location);
return { return {
screen: fragparts.location.substring(1), screen: fragparts.location.substring(1),
@ -33,7 +34,7 @@ export function getScreenFromLocation(location: Location) {
// Here, we do some crude URL analysis to allow // Here, we do some crude URL analysis to allow
// deep-linking. // deep-linking.
function routeUrl(location: Location) { function routeUrl(location: Location): void {
if (!window.matrixChat) return; if (!window.matrixChat) return;
logger.log("Routing URL ", location.href); logger.log("Routing URL ", location.href);
@ -41,7 +42,7 @@ function routeUrl(location: Location) {
(window.matrixChat as MatrixChatType).showScreen(s.screen, s.params); (window.matrixChat as MatrixChatType).showScreen(s.screen, s.params);
} }
function onHashChange() { function onHashChange(): void {
if (decodeURIComponent(window.location.hash) === lastLocationHashSet) { if (decodeURIComponent(window.location.hash) === lastLocationHashSet) {
// we just set this: no need to route it! // we just set this: no need to route it!
return; return;
@ -51,7 +52,7 @@ function onHashChange() {
// This will be called whenever the SDK changes screens, // This will be called whenever the SDK changes screens,
// so a web page can update the URL bar appropriately. // so a web page can update the URL bar appropriately.
export function onNewScreen(screen: string, replaceLast = false) { export function onNewScreen(screen: string, replaceLast = false): void {
logger.log("newscreen " + screen); logger.log("newscreen " + screen);
const hash = '#/' + screen; const hash = '#/' + screen;
lastLocationHashSet = hash; lastLocationHashSet = hash;
@ -71,6 +72,6 @@ export function onNewScreen(screen: string, replaceLast = false) {
} }
} }
export function init() { export function init(): void {
window.addEventListener('hashchange', onHashChange); window.addEventListener('hashchange', onHashChange);
} }

View file

@ -19,8 +19,7 @@ import { QueryDict, decodeParams } from "matrix-js-sdk/src/utils";
// We want to support some name / value pairs in the fragment // We want to support some name / value pairs in the fragment
// so we're re-using query string like format // so we're re-using query string like format
// //
// returns {location, params} export function parseQsFromFragment(location: Location): { location: string, params: QueryDict } {
export function parseQsFromFragment(location: Location) {
// if we have a fragment, it will start with '#', which we need to drop. // if we have a fragment, it will start with '#', which we need to drop.
// (if we don't, this will return ''). // (if we don't, this will return '').
const fragment = location.hash.substring(1); const fragment = location.hash.substring(1);

View file

@ -28,7 +28,7 @@ import MockHttpBackend from 'matrix-mock-request';
import { makeType } from "matrix-react-sdk/src/utils/TypeUtils"; import { makeType } from "matrix-react-sdk/src/utils/TypeUtils";
import { ValidatedServerConfig } from 'matrix-react-sdk/src/utils/ValidatedServerConfig'; import { ValidatedServerConfig } from 'matrix-react-sdk/src/utils/ValidatedServerConfig';
import { IndexedDBCryptoStore } from "matrix-js-sdk/src/crypto/store/indexeddb-crypto-store"; import { IndexedDBCryptoStore } from "matrix-js-sdk/src/crypto/store/indexeddb-crypto-store";
import { sleep } from "matrix-js-sdk/src/utils"; import { QueryDict, sleep } from "matrix-js-sdk/src/utils";
import "../jest-mocks"; import "../jest-mocks";
import WebPlatform from '../../src/vector/platform/WebPlatform'; import WebPlatform from '../../src/vector/platform/WebPlatform';
@ -84,7 +84,7 @@ describe('loading:', function() {
* TODO: it would be nice to factor some of this stuff out of index.js so * TODO: it would be nice to factor some of this stuff out of index.js so
* that we can test it rather than our own implementation of it. * that we can test it rather than our own implementation of it.
*/ */
function loadApp(opts?) { function loadApp(opts?): void {
opts = opts || {}; opts = opts || {};
const queryString = opts.queryString || ""; const queryString = opts.queryString || "";
const uriFragment = opts.uriFragment || ""; const uriFragment = opts.uriFragment || "";
@ -92,10 +92,10 @@ describe('loading:', function() {
windowLocation = { windowLocation = {
search: queryString, search: queryString,
hash: uriFragment, hash: uriFragment,
toString: function() { return this.search + this.hash; }, toString: function(): string { return this.search + this.hash; },
}; };
function onNewScreen(screen) { function onNewScreen(screen): void {
console.log(Date.now() + " newscreen "+screen); console.log(Date.now() + " newscreen "+screen);
const hash = '#/' + screen; const hash = '#/' + screen;
windowLocation.hash = hash; windowLocation.hash = hash;
@ -104,7 +104,7 @@ describe('loading:', function() {
// Parse the given window.location and return parameters that can be used when calling // Parse the given window.location and return parameters that can be used when calling
// MatrixChat.showScreen(screen, params) // MatrixChat.showScreen(screen, params)
function getScreenFromLocation(location) { function getScreenFromLocation(location): { screen: string, params: QueryDict } {
const fragparts = parseQsFromFragment(location); const fragparts = parseQsFromFragment(location);
return { return {
screen: fragparts.location.substring(1), screen: fragparts.location.substring(1),
@ -143,7 +143,7 @@ describe('loading:', function() {
enableGuest={true} enableGuest={true}
onTokenLoginCompleted={resolve} onTokenLoginCompleted={resolve}
initialScreenAfterLogin={getScreenFromLocation(windowLocation)} initialScreenAfterLogin={getScreenFromLocation(windowLocation)}
makeRegistrationUrl={() => {throw new Error('Not implemented');}} makeRegistrationUrl={(): string => {throw new Error('Not implemented');}}
/>, parentDiv, />, parentDiv,
); );
}); });
@ -153,7 +153,7 @@ describe('loading:', function() {
// http requests until we do. // http requests until we do.
// //
// returns a promise resolving to the received request // returns a promise resolving to the received request
async function expectAndAwaitSync(opts?) { async function expectAndAwaitSync(opts?): Promise<any> {
let syncRequest = null; let syncRequest = null;
httpBackend.when('GET', '/_matrix/client/versions') httpBackend.when('GET', '/_matrix/client/versions')
.respond(200, { .respond(200, {
@ -548,7 +548,7 @@ describe('loading:', function() {
// check that we have a Login component, send a 'user:pass' login, // check that we have a Login component, send a 'user:pass' login,
// and await the HTTP requests. // and await the HTTP requests.
async function completeLogin(matrixChat: RenderResult) { async function completeLogin(matrixChat: RenderResult): Promise<void> {
// When we switch to the login component, it'll hit the login endpoint // When we switch to the login component, it'll hit the login endpoint
// for proof of life and to get flows. We'll only give it one option. // for proof of life and to get flows. We'll only give it one option.
httpBackend.when('GET', '/login') httpBackend.when('GET', '/login')
@ -587,15 +587,15 @@ describe('loading:', function() {
}); });
// assert that we are on the loading page // assert that we are on the loading page
async function assertAtLoadingSpinner() { async function assertAtLoadingSpinner(): Promise<void> {
await screen.findByRole("progressbar"); await screen.findByRole("progressbar");
} }
async function awaitLoggedIn(matrixChat: RenderResult) { async function awaitLoggedIn(matrixChat: RenderResult): Promise<void> {
if (matrixChat.container.querySelector(".mx_MatrixChat_wrapper")) return; // already logged in if (matrixChat.container.querySelector(".mx_MatrixChat_wrapper")) return; // already logged in
return new Promise(resolve => { return new Promise(resolve => {
const onAction = ({ action }) => { const onAction = ({ action }): void => {
if (action !== "on_logged_in") { if (action !== "on_logged_in") {
return; return;
} }
@ -608,19 +608,19 @@ async function awaitLoggedIn(matrixChat: RenderResult) {
}); });
} }
async function awaitRoomView(matrixChat: RenderResult) { async function awaitRoomView(matrixChat: RenderResult): Promise<void> {
await waitFor(() => matrixChat.container.querySelector(".mx_RoomView")); await waitFor(() => matrixChat.container.querySelector(".mx_RoomView"));
} }
async function awaitLoginComponent(matrixChat: RenderResult) { async function awaitLoginComponent(matrixChat: RenderResult): Promise<void> {
await waitFor(() => matrixChat.container.querySelector(".mx_AuthPage")); await waitFor(() => matrixChat.container.querySelector(".mx_AuthPage"));
} }
async function awaitWelcomeComponent(matrixChat: RenderResult) { async function awaitWelcomeComponent(matrixChat: RenderResult): Promise<void> {
await waitFor(() => matrixChat.container.querySelector(".mx_Welcome")); await waitFor(() => matrixChat.container.querySelector(".mx_Welcome"));
} }
function moveFromWelcomeToLogin(matrixChat: RenderResult) { function moveFromWelcomeToLogin(matrixChat: RenderResult): Promise<void> {
dis.dispatch({ action: 'start_login' }); dis.dispatch({ action: 'start_login' });
return awaitLoginComponent(matrixChat); return awaitLoginComponent(matrixChat);
} }

View file

@ -29,17 +29,17 @@ export function deleteIndexedDB(dbName: string): Promise<void> {
console.log(`${startTime}: Removing indexeddb instance: ${dbName}`); console.log(`${startTime}: Removing indexeddb instance: ${dbName}`);
const req = window.indexedDB.deleteDatabase(dbName); const req = window.indexedDB.deleteDatabase(dbName);
req.onblocked = () => { req.onblocked = (): void => {
console.log(`${Date.now()}: can't yet delete indexeddb ${dbName} because it is open elsewhere`); console.log(`${Date.now()}: can't yet delete indexeddb ${dbName} because it is open elsewhere`);
}; };
req.onerror = (ev) => { req.onerror = (ev): void => {
reject(new Error( reject(new Error(
`${Date.now()}: unable to delete indexeddb ${dbName}: ${req.error}`, `${Date.now()}: unable to delete indexeddb ${dbName}: ${req.error}`,
)); ));
}; };
req.onsuccess = () => { req.onsuccess = (): void => {
const now = Date.now(); const now = Date.now();
console.log(`${now}: Removed indexeddb instance: ${dbName} in ${now-startTime} ms`); console.log(`${now}: Removed indexeddb instance: ${dbName} in ${now-startTime} ms`);
resolve(); resolve();

View file

@ -5155,10 +5155,10 @@ eslint-plugin-import@^2.25.4:
resolve "^1.22.0" resolve "^1.22.0"
tsconfig-paths "^3.14.1" tsconfig-paths "^3.14.1"
eslint-plugin-matrix-org@^0.7.0: eslint-plugin-matrix-org@^0.8.0:
version "0.7.0" version "0.8.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-matrix-org/-/eslint-plugin-matrix-org-0.7.0.tgz#4b7456b31e30e7575b62c2aada91915478829f88" resolved "https://registry.yarnpkg.com/eslint-plugin-matrix-org/-/eslint-plugin-matrix-org-0.8.0.tgz#daa1396900a8cb1c1d88f1a370e45fc32482cd9e"
integrity sha512-FLmwE4/cRalB7J+J1BBuTccaXvKtRgAoHlbqSCbdsRqhh27xpxEWXe08KlNiET7drEnnz+xMHXdmvW469gch7g== integrity sha512-/Poz/F8lXYDsmQa29iPSt+kO+Jn7ArvRdq10g0CCk8wbRS0sb2zb6fvd9xL1BgR5UDQL771V0l8X32etvY5yKA==
eslint-plugin-react-hooks@^4.3.0: eslint-plugin-react-hooks@^4.3.0:
version "4.6.0" version "4.6.0"