Enable oxlint restriction ruleset (#34307)

* Remove stale max-len disablements

* Remove stale camelCase & naming-convention disablements

* Remove stale ban-ts-comment disablements

* Remove stale no-var disablements

* Remove stale no-empty-property disablements

* Remove stale react rule disablements

* Remove stale no-constant-condition disablements

* Remove stale no-unused-vars disablements

* Remove stale disablements for disabled rules

* fixup camelcase

* Remove dead code

* Tidy code

* Tweak oxlint config

* Use oxlint to apply jsx/tsx extension consistently

* Fix import

* Fix imports

* Rename affected snapshots

* Update more imports

* Enable restriction ruleset

* Make code comply with new rules

* Make code comply with react/button-has-type

* Make code comply with typescript/non-nullable-type-assertion-style

* Comply with node/no-process-env

* Comply with unicorn/prefer-node-protocol

* Comply with unicorn/import-style

* Comply with unicorn/no-process-exit

* Comply with no-proto

* Comply with node/handle-callback-err

* Comply with import/no-commonjs

* Comply with node/no-path-concat

* Comply with unicorn/no-length-as-slice-end

* Comply with unicorn/no-document-cookie

* Comply with unicorn/prefer-module

* Comply with typescript/prefer-literal-enum-member

* Comply with jsx-a11y/anchor-ambiguous-text

* Tweak oxlint config

* Fix resolves

* Iterate

* Iterate

* Iterate

* Iterate

* Iterate

* Iterate

* Iterate
This commit is contained in:
Michael Telatynski
2026-08-04 09:15:07 +00:00
committed by GitHub
parent c091ebec6e
commit 4aa1a3549e
167 changed files with 526 additions and 346 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ Please see LICENSE in the repository root for full details.
import * as os from "node:os";
import * as fs from "node:fs";
import * as path from "node:path";
import path from "node:path";
import { type Configuration as BaseConfiguration } from "electron-builder";
/**
@@ -5,19 +5,16 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
import { resolve, dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { test, expect } from "../../element-desktop-test.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
test.describe("App config options", () => {
test.describe("Should load custom config via env", () => {
test.slow();
test.use({
extraEnv: {
ELEMENT_DESKTOP_CONFIG_JSON: resolve(__dirname, "../..", "fixtures/custom-config.json"),
ELEMENT_DESKTOP_CONFIG_JSON: fileURLToPath(import.meta.resolve("../../fixtures/custom-config.json")),
},
});
test("should launch and use configured homeserver", async ({ page }) => {
@@ -31,7 +28,7 @@ test.describe("App config options", () => {
test.describe("Should load custom config via argument", () => {
test.slow();
test.use({
extraArgs: ["--config", resolve(__dirname, "../..", "fixtures/custom-config.json")],
extraArgs: ["--config", fileURLToPath(import.meta.resolve("../../fixtures/custom-config.json"))],
});
test("should launch and use configured homeserver", async ({ page }) => {
await page.locator("#matrixchat").waitFor();
@@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.
import { _electron as electron, test as base, expect as baseExpect, type ElectronApplication } from "@playwright/test";
import fs from "node:fs/promises";
import path, { dirname } from "node:path";
import path from "node:path";
import os from "node:os";
import { fileURLToPath } from "node:url";
import { PassThrough } from "node:stream";
@@ -44,7 +44,7 @@ interface Fixtures {
stderr: CapturedPassThrough;
}
const __dirname = dirname(fileURLToPath(import.meta.url));
const __dirname = path.dirname(fileURLToPath(import.meta.url));
export const test = base.extend<Fixtures>({
extraEnv: {},
+1 -1
View File
@@ -11,7 +11,7 @@ Please see LICENSE in the repository root for full details.
import parseArgs from "minimist";
import * as chokidar from "chokidar";
import * as path from "node:path";
import path from "node:path";
import * as fs from "node:fs";
const argv = parseArgs(process.argv.slice(2), {});
+1 -1
View File
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
import * as path from "node:path";
import path from "node:path";
import { createWriteStream, promises as fs } from "node:fs";
import * as childProcess from "node:child_process";
import * as tar from "tar";
+2 -2
View File
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
import path, { dirname } from "node:path";
import path from "node:path";
import { fileURLToPath } from "node:url";
import HakEnv from "./hakEnv.ts";
@@ -28,7 +28,7 @@ const METACOMMANDS: Record<string, string[]> = {
// Scripts valid in a hak.json 'scripts' section
const HAKSCRIPTS = ["check", "fetch", "build"];
const __dirname = dirname(fileURLToPath(import.meta.url));
const __dirname = path.dirname(fileURLToPath(import.meta.url));
async function main(): Promise<void> {
const prefix = path.join(__dirname, "..", "..");
+2 -2
View File
@@ -6,11 +6,11 @@ Please see LICENSE files in the repository root for full details.
*/
import { fileURLToPath } from "node:url";
import { dirname } from "node:path";
import path from "node:path";
import { tryPaths } from "./utils.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
const __dirname = path.dirname(fileURLToPath(import.meta.url));
let asarPathPromise: Promise<string> | undefined;
// Get the webapp resource file path, memoizes result
+2 -2
View File
@@ -7,12 +7,12 @@ Please see LICENSE files in the repository root for full details.
import { expect, describe, it, beforeEach, vi } from "vitest";
import { fs as memfs, vol } from "memfs";
import { dirname } from "node:path";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { getBuildConfig } from "./build-config.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
const __dirname = path.dirname(fileURLToPath(import.meta.url));
vi.mock("node:fs", () => ({ default: memfs }));
+2 -2
View File
@@ -5,13 +5,13 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
import path, { dirname } from "node:path";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { type JsonObject } from "shared-types";
import { loadJsonFile } from "./utils.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
const __dirname = path.dirname(fileURLToPath(import.meta.url));
let buildConfig: BuildConfig;
+3 -3
View File
@@ -7,13 +7,13 @@ Please see LICENSE files in the repository root for full details.
import { expect, describe, it, beforeEach, vi } from "vitest";
import { fs as memfs, vol } from "memfs";
import { dirname, resolve } from "node:path";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { dialog } from "electron";
import { type ConfigOptions } from "./config.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
const __dirname = path.dirname(fileURLToPath(import.meta.url));
vi.mock("node:fs", () => ({ default: memfs }));
vi.mock("node:fs/promises", () => ({ default: memfs.promises }));
@@ -52,7 +52,7 @@ describe("loadConfig", () => {
});
it("should ignore localConfigPath if does not exist", async () => {
const config = await loadConfig(resolve(__dirname, "../custom-config.json"));
const config = await loadConfig("/invalid-path/custom-config.json");
expect(config.brand).toBe("Element");
expect(config.web_base_url).toBe("https://chat.org.com");
expect(config.default_hs_url).toBe("https://matrix.org.com");
+2 -2
View File
@@ -23,7 +23,7 @@ import {
desktopCapturer,
} from "electron";
import * as Sentry from "@sentry/electron/main";
import path, { dirname } from "node:path";
import path from "node:path";
import windowStateKeeper from "electron-window-state";
import { URL, fileURLToPath } from "node:url";
@@ -48,7 +48,7 @@ import { getIconPath } from "./icon.js";
import { getArgs } from "./args.js";
import { type ConfigOptions, loadConfig } from "./config.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const buildConfig = getBuildConfig();
const protocolHandler = new ProtocolHandler(buildConfig.protocol);
+5 -8
View File
@@ -7,12 +7,9 @@ Please see LICENSE files in the repository root for full details.
import { expect, describe, it, beforeEach, vi } from "vitest";
import { fs as memfs, vol } from "memfs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { getIconPath } from "./icon.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
import { fileURLToPath } from "node:url";
vi.mock("node:fs/promises", () => ({ default: memfs.promises }));
@@ -28,20 +25,20 @@ describe("getIconPath", () => {
"build/icon.png": "png",
"build/icon.ico": "ico",
},
resolve(__dirname, "../webapp"),
fileURLToPath(import.meta.resolve("../webapp")),
);
});
it("should use .ico on Windows", async () => {
vi.spyOn(process, "platform", "get").mockReturnValue("win32");
await expect(getIconPath()).resolves.toEqual(resolve(__dirname, "../build/icon.ico"));
await expect(getIconPath()).resolves.toEqual(fileURLToPath(import.meta.resolve("../build/icon.ico")));
});
it("should use .png on macOS", async () => {
vi.spyOn(process, "platform", "get").mockReturnValue("darwin");
await expect(getIconPath()).resolves.toEqual(resolve(__dirname, "../build/icon.png"));
await expect(getIconPath()).resolves.toEqual(fileURLToPath(import.meta.resolve("../build/icon.png")));
});
it("should use .png on Linux", async () => {
vi.spyOn(process, "platform", "get").mockReturnValue("linux");
await expect(getIconPath()).resolves.toEqual(resolve(__dirname, "../build/icon.png"));
await expect(getIconPath()).resolves.toEqual(fileURLToPath(import.meta.resolve("../build/icon.png")));
});
});
+2 -2
View File
@@ -7,14 +7,14 @@ Please see LICENSE files in the repository root for full details.
import counterpart from "counterpart";
import { type TranslationKey as TKey } from "matrix-web-i18n";
import { dirname } from "node:path";
import path from "node:path";
import { fileURLToPath } from "node:url";
import type EN from "./i18n/strings/en_EN.json";
import { loadJsonFile } from "./utils.js";
import type Store from "./store.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const FALLBACK_LOCALE = "en";
+1 -1
View File
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
import webpack from "webpack";
import * as fs from "node:fs/promises";
import * as path from "node:path";
import path from "node:path";
import _ from "lodash";
import { type Translations } from "matrix-web-i18n";
+1 -1
View File
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
const EventEmitter = require("events");
const EventEmitter = require("node:events");
const { LngLat, NavigationControl, LngLatBounds } = require("maplibre-gl");
class MockMap extends EventEmitter {
+2 -2
View File
@@ -7,12 +7,12 @@ Please see LICENSE files in the repository root for full details.
*/
import { env } from "node:process";
import path, { dirname } from "node:path";
import path from "node:path";
import { fileURLToPath } from "node:url";
import type { Config } from "jest";
const __dirname = dirname(fileURLToPath(import.meta.url));
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const config: Config = {
testEnvironment: "jest-fixed-jsdom",
@@ -6,14 +6,13 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
import path from "path";
import path from "node:path";
import { readFile } from "node:fs/promises";
import { dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { expect, test } from "../../element-web-test";
const __dirname = dirname(fileURLToPath(import.meta.url));
const __dirname = path.dirname(fileURLToPath(import.meta.url));
test.describe("migration", { tag: "@no-webkit" }, function () {
test.use({
+17 -9
View File
@@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.
import { type Locator, type Page, expect } from "@playwright/test";
import { readFile } from "node:fs/promises";
import { basename } from "node:path";
import path from "node:path";
import { rejectToast, rejectToastIfExists } from "@element-hq/element-web-playwright-common";
import { Settings } from "./settings";
@@ -197,15 +197,19 @@ export class ElementAppPage {
/**
* Drags a "file" into the specified composer and automatically uploads it.
* @param location Should the drop target the main room or the thread.
* @param path The path to the sample file so it can be read.
* @param samplePath The path to the sample file so it can be read.
* @param type The mimetype of the file.
*/
public async composerDragAndUploadFiles(location: "room" | "thread", path: string, type: string): Promise<void> {
public async composerDragAndUploadFiles(
location: "room" | "thread",
samplePath: string,
type: string,
): Promise<void> {
// Based on https://github.com/microsoft/playwright/issues/10667#issuecomment-2742123424
// This read a file, encodes it into base64 and then sends it along to the page to be treated
// as a DataTransfer (the mechanism for drag and dropped files).
const buffer = await readFile(path);
const name = basename(path);
const buffer = await readFile(samplePath);
const name = path.basename(samplePath);
const dataTransfer = await this.page.evaluateHandle(
async ([buffer, name, type]) => {
@@ -227,15 +231,19 @@ export class ElementAppPage {
/**
* Paste a "file" into the specified locator and automatically uploads it.
* @param location Should the drop target the main room or the thread.
* @param path The path to the sample file so it can be read.
* @param samplePath The path to the sample file so it can be read.
* @param type The mimetype of the file.
*/
public async composerDragAndPasteFile(location: "room" | "thread", path: string, type: string): Promise<void> {
public async composerDragAndPasteFile(
location: "room" | "thread",
samplePath: string,
type: string,
): Promise<void> {
// Based on https://github.com/microsoft/playwright/issues/10667#issuecomment-2742123424
// This read a file, encodes it into base64 and then sends it along to the page to be treated
// as a DataTransfer (the mechanism for drag and dropped files).
const buffer = await readFile(path);
const name = basename(path);
const buffer = await readFile(samplePath);
const name = path.basename(samplePath);
const composer = this.getComposerField(location === "thread");
await composer.evaluate(
@@ -7,18 +7,18 @@ Please see LICENSE files in the repository root for full details.
*/
import { type SynapseContainer } from "@element-hq/element-web-playwright-common/lib/testcontainers/index.js";
import { dirname, join } from "node:path";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { type Fixtures } from "../../../element-web-test.ts";
const __dirname = dirname(fileURLToPath(import.meta.url));
const __dirname = path.dirname(fileURLToPath(import.meta.url));
export const consentHomeserver: Fixtures = {
_homeserver: [
async ({ _homeserver: container, mailpit }, use) => {
(container as SynapseContainer)
.withCopyDirectoriesToContainer([{ source: join(__dirname, "res"), target: "/data/res" }])
.withCopyDirectoriesToContainer([{ source: path.join(__dirname, "res"), target: "/data/res" }])
.withSmtpServer(mailpit)
.withConfig({
user_consent: {
@@ -6,15 +6,15 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
import http from "http";
import http from "node:http";
import express from "express";
import { type AddressInfo } from "net";
import { type AddressInfo } from "node:net";
import { type TestInfo } from "@playwright/test";
import { randB64Bytes } from "@element-hq/element-web-playwright-common/lib/utils/rand.js";
import { dirname } from "node:path";
import path from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url));
const __dirname = path.dirname(fileURLToPath(import.meta.url));
export class OAuthServer {
private server?: http.Server;
@@ -19,6 +19,7 @@ export default class ExampleModule {
}
async load() {
const brand = this.api.config.get("brand");
// oxlint-disable-next-line no-alert
alert(this.api.i18n.translate("key", { brand }));
}
}
+3 -3
View File
@@ -5,15 +5,15 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
import { dirname, join } from "node:path";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { readFile } from "node:fs/promises";
import { readFileSync } from "node:fs";
const __dirname = dirname(fileURLToPath(import.meta.url));
const __dirname = path.dirname(fileURLToPath(import.meta.url));
export function getSampleFilePath(file: string): string {
return join(__dirname, file);
return path.join(__dirname, file);
}
export function readSampleFile(file: string, encoding: null): Promise<Buffer>;
@@ -11,6 +11,7 @@ export default class SettingsModule {
this.api = api;
}
async load() {
// oxlint-disable-next-line no-alert
alert(this.api.settings.getValue("language"));
}
}
+1 -1
View File
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
// @vitest-environment happy-dom
import { EventEmitter } from "events";
import { EventEmitter } from "node:events";
import { vi, describe, it, expect, beforeEach, afterEach } from "vitest";
import type { MatrixClient } from "matrix-js-sdk/src/matrix";
+1
View File
@@ -7,6 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
// oxlint-disable-next-line no-restricted-imports
import EventEmitter from "events";
import { logger } from "matrix-js-sdk/src/logger";
+1
View File
@@ -56,6 +56,7 @@ export async function startAnyRegistrationFlow(
modal.close();
dis.dispatch({ action: "start_registration", screenAfterLogin: options.screen_after });
}}
type="button"
>
{_t("auth|register_action")}
</button>,
+1 -1
View File
@@ -827,7 +827,7 @@ async function readEvents(
const effectiveStateKey = stateKey === true ? undefined : stateKey;
let events: MatrixEvent[] = [];
events = events.concat(room.currentState.getStateEvents(eventType, effectiveStateKey as string) || []);
events = events.concat(room.currentState.getStateEvents(eventType, effectiveStateKey!) || []);
events = events.slice(0, effectiveLimit);
sendResponse(event, {
+1 -1
View File
@@ -12,7 +12,7 @@ import { vi, describe, it, expect, beforeEach } from "vitest";
import { type SlidingSync, SlidingSyncEvent, SlidingSyncState } from "matrix-js-sdk/src/sliding-sync";
import { ClientEvent, type MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
import fetchMock from "@fetch-mock/vitest";
import EventEmitter from "events";
import EventEmitter from "node:events";
import { waitFor } from "test-utils-rtl";
import { mkStubRoom, stubClient } from "test-utils";
+3 -1
View File
@@ -101,7 +101,9 @@ export default class UserActivity {
// as we fork the promise here,
// avoid unhandled rejection warnings
})
.catch((err) => {});
.catch(() => {
// Do nothing
});
}
}
@@ -211,7 +211,7 @@ export default class ExportE2eKeysDialog extends React.Component<IProps, IState>
value={_t("action|export")}
disabled={disableForm}
/>
<button onClick={this.onCancelClick} disabled={disableForm}>
<button onClick={this.onCancelClick} disabled={disableForm} type="button">
{_t("action|cancel")}
</button>
</div>
@@ -180,7 +180,7 @@ export default class ImportE2eKeysDialog extends React.Component<IProps, IState>
value={_t("action|import")}
disabled={!this.state.enableSubmit || disableForm}
/>
<button onClick={this.onCancelClick} disabled={disableForm}>
<button onClick={this.onCancelClick} disabled={disableForm} type="button">
{_t("action|cancel")}
</button>
</div>
+1
View File
@@ -6,6 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
// oxlint-disable-next-line no-restricted-imports
import EventEmitter from "events";
import { SimpleObservable } from "matrix-widget-api";
import { logger } from "matrix-js-sdk/src/logger";
+1
View File
@@ -9,6 +9,7 @@ Please see LICENSE files in the repository root for full details.
import Recorder from "opus-recorder/dist/recorder.min.js";
import encoderPath from "opus-recorder/dist/encoderWorker.min.js";
import { SimpleObservable } from "matrix-widget-api";
// oxlint-disable-next-line no-restricted-imports
import EventEmitter from "events";
import { logger } from "matrix-js-sdk/src/logger";
import { clamp } from "@element-hq/web-shared-components";
@@ -8,6 +8,7 @@ Please see LICENSE files in the repository root for full details.
import { EventType, type MatrixEvent } from "matrix-js-sdk/src/matrix";
import { CallEvent, CallState, CallType, type MatrixCall } from "matrix-js-sdk/src/webrtc/call";
// oxlint-disable-next-line no-restricted-imports
import { EventEmitter } from "events";
import { LegacyCallHandlerEvent } from "../../LegacyCallHandler";
+14 -16
View File
@@ -712,19 +712,19 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
// Add watchers for each of the settings we just looked up
this.settingWatchers = this.settingWatchers.concat([
SettingsStore.watchSetting("showReadReceipts", roomId, (...[, , , value]) =>
this.setState({ showReadReceipts: value as boolean }),
this.setState({ showReadReceipts: value! }),
),
SettingsStore.watchSetting("showRedactions", roomId, (...[, , , value]) =>
this.setState({ showRedactions: value as boolean }),
this.setState({ showRedactions: value! }),
),
SettingsStore.watchSetting("showJoinLeaves", roomId, (...[, , , value]) =>
this.setState({ showJoinLeaves: value as boolean }),
this.setState({ showJoinLeaves: value! }),
),
SettingsStore.watchSetting("showAvatarChanges", roomId, (...[, , , value]) =>
this.setState({ showAvatarChanges: value as boolean }),
this.setState({ showAvatarChanges: value! }),
),
SettingsStore.watchSetting("showDisplaynameChanges", roomId, (...[, , , value]) =>
this.setState({ showDisplaynameChanges: value as boolean }),
this.setState({ showDisplaynameChanges: value! }),
),
]);
@@ -985,34 +985,32 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
this.context.resizeNotifier.on("isResizing", this.onIsResizing);
this.settingWatchers = [
SettingsStore.watchSetting("layout", null, (...[, , , value]) =>
this.setState({ layout: value as Layout }),
),
SettingsStore.watchSetting("layout", null, (...[, , , value]) => this.setState({ layout: value! })),
SettingsStore.watchSetting("lowBandwidth", null, (...[, , , value]) =>
this.setState({ lowBandwidth: value as boolean }),
this.setState({ lowBandwidth: value! }),
),
SettingsStore.watchSetting("alwaysShowTimestamps", null, (...[, , , value]) =>
this.setState({ alwaysShowTimestamps: value as boolean }),
this.setState({ alwaysShowTimestamps: value! }),
),
SettingsStore.watchSetting("showTwelveHourTimestamps", null, (...[, , , value]) =>
this.setState({ showTwelveHourTimestamps: value as boolean }),
this.setState({ showTwelveHourTimestamps: value! }),
),
SettingsStore.watchSetting(TimezoneHandler.USER_TIMEZONE_KEY, null, (...[, , , value]) =>
this.setState({ userTimezone: value as string }),
this.setState({ userTimezone: value! }),
),
SettingsStore.watchSetting("readMarkerInViewThresholdMs", null, (...[, , , value]) =>
this.setState({ readMarkerInViewThresholdMs: value as number }),
this.setState({ readMarkerInViewThresholdMs: value! }),
),
SettingsStore.watchSetting("readMarkerOutOfViewThresholdMs", null, (...[, , , value]) =>
this.setState({ readMarkerOutOfViewThresholdMs: value as number }),
this.setState({ readMarkerOutOfViewThresholdMs: value! }),
),
SettingsStore.watchSetting("showHiddenEventsInTimeline", null, (...[, , , value]) =>
this.setState({ showHiddenEvents: value as boolean }),
this.setState({ showHiddenEvents: value! }),
),
SettingsStore.watchSetting("urlPreviewsEnabled", null, this.onUrlPreviewsEnabledChange),
SettingsStore.watchSetting("urlPreviewsEnabled_e2ee", null, this.onUrlPreviewsEnabledChange),
SettingsStore.watchSetting("feature_dynamic_room_predecessors", null, (...[, , , value]) =>
this.setState({ msc3946ProcessDynamicPredecessor: value as boolean }),
this.setState({ msc3946ProcessDynamicPredecessor: value! }),
),
];
@@ -158,7 +158,7 @@ export default class ScrollPanel extends React.Component<IProps> {
return Promise.resolve(false);
},
onUnfillRequest: function (backwards: boolean, scrollToken: string) {},
onScroll: function () {},
onScroll: function (): void {},
};
private readonly pendingFillRequests: Record<"b" | "f", boolean | null> = {
@@ -102,8 +102,6 @@ function TabLabel<T extends string>({ tab, isActive, showToolip, onClick }: ITab
const label = _t(tab.label);
return (
// The RovingAccessibleComponent correctly sets the tabIndex based on roving context
// oxlint-disable-next-line jsx-a11y/interactive-supports-focus
<RovingAccessibleButton
className={classes}
onClick={onClick}
@@ -106,7 +106,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
this.setupThreadListeners(this.state.thread);
this.layoutWatcherRef = SettingsStore.watchSetting("layout", null, (...[, , , value]) =>
this.setState({ layout: value as Layout }),
this.setState({ layout: value! }),
);
if (this.state.thread) {
@@ -172,7 +172,9 @@ export default class ViewSource extends React.Component<IProps, IState> {
{isEditing ? this.editSourceContent() : this.viewSourceContent()}
{!isEditing && canEdit && (
<div className="mx_Dialog_buttons">
<button onClick={() => this.onEdit()}>{_t("action|edit")}</button>
<button onClick={() => this.onEdit()} type="button">
{_t("action|edit")}
</button>
</div>
)}
</BaseDialog>
@@ -10,7 +10,7 @@ Please see LICENSE files in the repository root for full details.
import { vi, describe, it, expect, beforeEach, afterEach } from "vitest";
import React from "react";
import { act, render, screen } from "test-utils-rtl";
import EventEmitter from "events";
import EventEmitter from "node:events";
import { stubClient } from "test-utils";
import CompleteSecurity from "./CompleteSecurity";
@@ -11,7 +11,7 @@ Please see LICENSE files in the repository root for full details.
import { vi, describe, it, expect, beforeEach } from "vitest";
import { act, render, type RenderResult } from "test-utils-rtl";
import React, { type ComponentProps } from "react";
import EventEmitter from "events";
import EventEmitter from "node:events";
import { CryptoEvent } from "matrix-js-sdk/src/crypto-api";
import { sleep } from "matrix-js-sdk/src/utils";
@@ -64,10 +64,10 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
private [LoginField.Password]: Field | null = null;
public static defaultProps = {
onUsernameChanged: function () {},
onUsernameBlur: function () {},
onPhoneCountryChanged: function () {},
onPhoneNumberChanged: function () {},
onUsernameChanged: function (): void {},
onUsernameBlur: function (): void {},
onPhoneCountryChanged: function (): void {},
onPhoneNumberChanged: function (): void {},
loginIncorrect: false,
disableSubmit: false,
};
@@ -77,11 +77,13 @@ export default function AskInviteAnywayDialog({
</div>
<div className="mx_Dialog_buttons">
<button onClick={onGiveUpClicked}>{_t("action|close")}</button>
<button onClick={onInviteNeverWarnClicked}>
<button onClick={onGiveUpClicked} type="button">
{_t("action|close")}
</button>
<button onClick={onInviteNeverWarnClicked} type="button">
{inviteNeverWarnLabel ?? _t("invite|unable_find_profiles_invite_never_warn_label_default")}
</button>
<button onClick={onInviteClicked} autoFocus={true}>
<button onClick={onInviteClicked} autoFocus={true} type="button">
{inviteLabel ?? _t("invite|unable_find_profiles_invite_label_default")}
</button>
</div>
@@ -97,7 +97,7 @@ const DevtoolsDialog: React.FC<IProps> = ({ roomId, threadRootId, onFinished })
setTool([label, tool]);
};
return (
<button className="mx_DevTools_button" key={label} onClick={onClick}>
<button className="mx_DevTools_button" key={label} onClick={onClick} type="button">
{_t(label)}
</button>
);
@@ -74,7 +74,12 @@ export default class ErrorDialog extends React.Component<IProps, IState> {
{this.props.description || _t("error|dialog_description_default")}
</div>
<div className="mx_Dialog_buttons">
<button className="mx_Dialog_primary" onClick={this.onClick} autoFocus={this.props.focus}>
<button
className="mx_Dialog_primary"
onClick={this.onClick}
autoFocus={this.props.focus}
type="button"
>
{this.props.button || _t("action|ok")}
</button>
</div>
@@ -50,7 +50,7 @@ export default class SessionRestoreErrorDialog extends React.Component<IProps> {
const brand = SdkConfig.get().brand;
const clearStorageButton = (
<button onClick={this.onClearStorageClick} className="danger">
<button onClick={this.onClearStorageClick} className="danger" type="button">
{_t("error|session_restore|clear_storage_button")}
</button>
);
@@ -104,7 +104,11 @@ export default class UploadConfirmDialog extends React.Component<IProps, IState>
let uploadAllButton: JSX.Element | undefined;
if (this.props.currentIndex + 1 < this.props.totalFiles) {
uploadAllButton = <button onClick={this.onUploadAllClick}>{_t("upload_file|upload_all_button")}</button>;
uploadAllButton = (
<button onClick={this.onUploadAllClick} type="button">
{_t("upload_file|upload_all_button")}
</button>
);
}
return (
@@ -78,7 +78,7 @@ const BaseAccountDataExplorer: React.FC<IProps> = ({ events, Editor, actionLabel
};
return (
<button className="mx_DevTools_button" key={eventType} onClick={onClick}>
<button className="mx_DevTools_button" key={eventType} onClick={onClick} type="button">
{eventType}
</button>
);
@@ -61,7 +61,11 @@ const BaseTool: React.FC<XOR<IMinProps, IProps>> = ({
});
};
actionButton = <button onClick={onActionClick}>{_t(actionLabel)}</button>;
actionButton = (
<button onClick={onActionClick} type="button">
{_t(actionLabel)}
</button>
);
}
return (
@@ -69,7 +73,9 @@ const BaseTool: React.FC<XOR<IMinProps, IProps>> = ({
<div className={classNames("mx_DevTools_content", className)}>{children}</div>
<div className="mx_Dialog_buttons">
{extraButton}
<button onClick={onBackClick}>{_t("action|back")}</button>
<button onClick={onBackClick} type="button">
{_t("action|back")}
</button>
{actionButton}
</div>
</>
@@ -50,7 +50,7 @@ const FilteredList: React.FC<IProps> = ({ children, query, onChange }) => {
};
return (
<button className="mx_DevTools_button" onClick={showMore}>
<button className="mx_DevTools_button" onClick={showMore} type="button">
{_t("common|and_n_others", { count: overflowCount })}
</button>
);
@@ -100,6 +100,7 @@ const StateEventButton: React.FC<StateEventButtonProps> = ({ label, onClick }) =
mx_DevTools_RoomStateExplorer_button_emptyString: !trimmed,
})}
onClick={onClick}
type="button"
>
{content}
</button>
@@ -148,7 +149,11 @@ const RoomStateExplorerEventType: React.FC<IEventTypeProps> = ({ eventType, onBa
const onHistoryClick = (): void => {
setHistory(true);
};
const extraButton = <button onClick={onHistoryClick}>{_t("devtools|see_history")}</button>;
const extraButton = (
<button onClick={onHistoryClick} type="button">
{_t("devtools|see_history")}
</button>
);
return <EventViewer mxEvent={event} onBack={_onBack} Editor={StateEventEditor} extraButton={extraButton} />;
}
@@ -56,7 +56,11 @@ export const StickyStateExplorer: React.FC<IDevtoolsProps> = ({ onBack, setTool
<Alert
type="critical"
title={_t("common|error")}
actions={<button onClick={onBack}>{_t("action|back")}</button>}
actions={
<button onClick={onBack} type="button">
{_t("action|back")}
</button>
}
>
{_t("devtools|sticky_events_not_supported")}
</Alert>
@@ -107,7 +111,12 @@ export const StickyStateExplorer: React.FC<IDevtoolsProps> = ({ onBack, setTool
<BaseTool onBack={onBack} actionLabel={_td("devtools|send_custom_sticky_event")} onAction={onAction}>
<p>
{uniqueEventTypes.map((eventType) => (
<button key={eventType} className="mx_DevTools_button" onClick={() => setEventType(eventType)}>
<button
key={eventType}
className="mx_DevTools_button"
onClick={() => setEventType(eventType)}
type="button"
>
{eventType.length > 0 ? eventType : _t("devtools|empty_string")}
</button>
))}
@@ -88,7 +88,7 @@ interface UserButtonProps {
*/
const UserButton: React.FC<UserButtonProps> = ({ member, onClick }) => {
return (
<button className="mx_DevTools_button" onClick={onClick}>
<button className="mx_DevTools_button" onClick={onClick} type="button">
{member.userId}
</button>
);
@@ -273,7 +273,7 @@ const DeviceButton: React.FC<DeviceButtonProps> = ({ crypto, device, onClick })
null,
);
return (
<button className="mx_DevTools_button" onClick={onClick}>
<button className="mx_DevTools_button" onClick={onClick} type="button">
{verificationIcon}
{device.deviceId}
</button>
@@ -53,7 +53,12 @@ const WidgetExplorer: React.FC<IDevtoolsProps> = ({ onBack }) => {
<BaseTool onBack={onBack}>
<FilteredList query={query} onChange={setQuery}>
{widgets.map((w) => (
<button className="mx_DevTools_button" key={w.url + w.eventId} onClick={() => setWidget(w)}>
<button
className="mx_DevTools_button"
key={w.url + w.eventId}
onClick={() => setWidget(w)}
type="button"
>
{w.url}
</button>
))}
@@ -538,7 +538,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
});
// we intentionally ignore changes to the rovingContext for the purpose of this hook
// we only want to reset the focus whenever the results or filters change
// eslint-disable-next-line
// oxlint-disable-next-line react-hooks/exhaustive-deps
}, [results, filter]);
const viewRoom = (
@@ -238,9 +238,7 @@ export default class Dropdown extends React.Component<DropdownProps, IState> {
highlightedOption: nextKey,
});
(
this.dropdownRootElement?.querySelector(`#${this.props.id}__${nextKey}`) as HTMLLIElement
)?.focus();
this.dropdownRootElement?.querySelector<HTMLLIElement>(`#${this.props.id}__${nextKey}`)?.focus();
} else {
this.setState({ expanded: true });
}
@@ -251,9 +249,7 @@ export default class Dropdown extends React.Component<DropdownProps, IState> {
this.setState({
highlightedOption: prevKey,
});
(
this.dropdownRootElement?.querySelector(`#${this.props.id}__${prevKey}`) as HTMLLIElement
)?.focus();
this.dropdownRootElement?.querySelector<HTMLLIElement>(`#${this.props.id}__${prevKey}`)?.focus();
} else {
this.setState({ expanded: true });
}
@@ -319,7 +315,7 @@ export default class Dropdown extends React.Component<DropdownProps, IState> {
<MenuOption
id={`${this.props.id}__${child.key}`}
key={child.key}
dropdownKey={child.key as string}
dropdownKey={child.key!}
highlighted={highlighted}
onMouseEnter={this.setHighlightedOption}
onClick={this.onMenuOptionClick}
@@ -42,6 +42,7 @@ export default class Spoiler extends React.Component<IProps, IState> {
<button
className={"mx_EventTile_spoiler" + (this.state.visible ? " visible" : "")}
onClick={this.toggleVisible}
type="button"
>
{reason}
&nbsp;
@@ -100,6 +100,7 @@ class Header extends React.PureComponent<IProps> {
tabIndex={category.firstVisible ? 0 : -1} // roving
aria-selected={category.visible}
aria-controls={`mx_EmojiPicker_category_${category.id}`}
type="button"
>
{category.emoji}
</button>
@@ -55,6 +55,7 @@ class Search extends React.PureComponent<IProps> {
onClick={() => this.props.onChange("")}
className="mx_EmojiPicker_search_clear"
title={_t("emoji_picker|cancel_search_label")}
type="button"
>
<CloseIcon />
</button>
@@ -296,7 +296,7 @@ const MESSAGE_BODY_TYPES = new Map<string, MBodyComponent>([
// Render a body using the picked factory.
// Falls back to the provided factory when msgtype has no specific handler.
export function renderMBody(props: IBodyProps, fallbackFactory?: MBodyComponent): JSX.Element | null {
const BodyType = MESSAGE_BODY_TYPES.get(props.mxEvent.getContent().msgtype as string) ?? fallbackFactory;
const BodyType = MESSAGE_BODY_TYPES.get(props.mxEvent.getContent().msgtype!) ?? fallbackFactory;
if (!BodyType) {
return null;
}
@@ -92,10 +92,10 @@ export default class TimelineCard extends React.Component<IProps, IState> {
this.context.roomViewStore.addListener(UPDATE_EVENT, this.onRoomViewStoreUpdate);
this.dispatcherRef = dis.register(this.onAction);
this.readReceiptsSettingWatcher = SettingsStore.watchSetting("showReadReceipts", null, (...[, , , value]) =>
this.setState({ showReadReceipts: value as boolean }),
this.setState({ showReadReceipts: value! }),
);
this.layoutWatcherRef = SettingsStore.watchSetting("layout", null, (...[, , , value]) =>
this.setState({ layout: value as Layout }),
this.setState({ layout: value! }),
);
}
@@ -195,7 +195,7 @@ const UserInfo: React.FC<IProps> = ({ user, room, onClose, phase = RightPanelPha
let content: JSX.Element | undefined;
switch (phase) {
case RightPanelPhases.MemberInfo:
content = <UserInfoBasicView room={room as Room} member={member} />;
content = <UserInfoBasicView room={room!} member={member} />;
break;
case RightPanelPhases.EncryptionPanel:
classes.push("mx_UserInfo_smallAvatar");
@@ -485,6 +485,7 @@ export default function RoomHeader({
: () => sdkContext.rightPanelStore.showOrHidePhase(RightPanelPhases.RoomSummary)
}
className="mx_RoomHeader_infoWrapper"
type="button"
>
<Box flex="1" className="mx_RoomHeader_info">
<Text
@@ -23,6 +23,7 @@ exports[`RoomHeader > dm > does not show the face pile for DMs 1`] = `
aria-label="Room info"
class="mx_RoomHeader_infoWrapper"
tabindex="0"
type="button"
>
<div
class="mx_RoomHeader_info _box-flex_1odfs_9"
@@ -232,7 +232,7 @@ export default class Notifications extends React.PureComponent<EmptyObject, ISta
public componentDidMount(): void {
this.settingWatchers = [
SettingsStore.watchSetting("deviceNotificationsEnabled", null, (...[, , , , value]) => {
this.setState({ deviceNotificationsEnabled: value as boolean });
this.setState({ deviceNotificationsEnabled: value! });
}),
];
@@ -78,7 +78,7 @@ export default class VoiceUserSettingsTab extends React.Component<EmptyObject, I
this.legacyCallsEnabledWatcherRef = SettingsStore.watchSetting(
"enableLegacyCallsVoip",
null,
(...[, , , , value]) => this.setState({ enableLegacyCallsVoip: value as boolean }),
(...[, , , , value]) => this.setState({ enableLegacyCallsVoip: value! }),
);
const canSeeDeviceLabels = await MediaDeviceHandler.hasAnyLabeledDevices();
@@ -501,38 +501,20 @@ export default class LegacyCallView extends React.Component<IProps, IState> {
// We've already checked that we have feeds so we cast away the optional when passing the feed
return (
<div className="mx_LegacyCallView_content" onMouseMove={this.onMouseMove}>
<VideoFeed
feed={primaryFeed as CallFeed}
call={call}
pipMode={pipMode}
onResize={onResize}
primary={true}
/>
<VideoFeed feed={primaryFeed!} call={call} pipMode={pipMode} onResize={onResize} primary={true} />
</div>
);
} else if (secondaryFeed) {
return (
<div className="mx_LegacyCallView_content" onMouseMove={this.onMouseMove}>
<VideoFeed
feed={primaryFeed as CallFeed}
call={call}
pipMode={pipMode}
onResize={onResize}
primary={true}
/>
<VideoFeed feed={primaryFeed!} call={call} pipMode={pipMode} onResize={onResize} primary={true} />
{secondaryFeedElement}
</div>
);
} else {
return (
<div className="mx_LegacyCallView_content" onMouseMove={this.onMouseMove}>
<VideoFeed
feed={primaryFeed as CallFeed}
call={call}
pipMode={pipMode}
onResize={onResize}
primary={true}
/>
<VideoFeed feed={primaryFeed!} call={call} pipMode={pipMode} onResize={onResize} primary={true} />
{sidebarShown && (
<LegacyCallViewSidebar feeds={sidebarFeeds} call={call} pipMode={Boolean(pipMode)} />
)}
+1
View File
@@ -9,6 +9,7 @@ Please see LICENSE files in the repository root for full details.
import { useRef, useEffect, useState, useCallback, type DependencyList } from "react";
import { type ListenerMap, type TypedEventEmitter } from "matrix-js-sdk/src/matrix";
// oxlint-disable-next-line no-restricted-imports
import type { EventEmitter } from "events";
type Handler = (...args: any[]) => void;
+1
View File
@@ -42,6 +42,7 @@ export async function setLanguage(...preferredLangs: string[]): Promise<void> {
await SettingsStore.setValue("language", null, SettingLevel.DEVICE, chosenLanguage);
// Adds a lot of noise to test runs, so disable logging there.
// oxlint-disable-next-line node/no-process-env
if (process.env.NODE_ENV !== "test") {
logger.log("set language to " + chosenLanguage);
}
+1
View File
@@ -6,6 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
// oxlint-disable-next-line no-restricted-imports
import { EventEmitter } from "events";
import {
RoomMember,
+1
View File
@@ -26,6 +26,7 @@ import {
MatrixRTCSessionManagerEvents,
} from "matrix-js-sdk/src/matrixrtc";
// oxlint-disable-next-line no-restricted-imports
import type EventEmitter from "events";
import type { IApp } from "../stores/WidgetStore";
import SettingsStore from "../settings/SettingsStore";
+1
View File
@@ -201,6 +201,7 @@ export async function initSentry(sentryConfig: IConfigOptions["sentry"]): Promis
Sentry.init({
dsn: sentryConfig.dsn,
// oxlint-disable-next-line node/no-process-env
release: process.env.VERSION,
environment: sentryConfig.environment,
defaultIntegrations: false,
+1
View File
@@ -5,6 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
// oxlint-disable-next-line no-restricted-imports
import EventEmitter from "events";
import { type MatrixEvent, RoomStateEvent, type RoomState } from "matrix-js-sdk/src/matrix";
+1
View File
@@ -6,6 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
// oxlint-disable-next-line no-restricted-imports
import { EventEmitter } from "events";
import AwaitLock from "await-lock";
@@ -5,6 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
// oxlint-disable-next-line no-restricted-imports
import EventEmitter from "events";
import { type MatrixClient } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
@@ -9,7 +9,7 @@
import { describe, it, expect, vi } from "vitest";
import { type EventTimeline, EventType, RoomEvent } from "matrix-js-sdk/src/matrix";
import { EventEmitter } from "stream";
import { EventEmitter } from "node:events";
import { mkEvent, mkRoom, mkRoomMember, stubClient } from "../../test/test-utils";
import { CallStoreEvent, type CallStore } from "./CallStore";
@@ -6,6 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
// oxlint-disable-next-line no-restricted-imports
import EventEmitter from "events";
import { type ComponentClass } from "../@types/common";
@@ -7,6 +7,7 @@
*/
import { type MatrixClient, SyncState } from "matrix-js-sdk/src/matrix";
// oxlint-disable-next-line no-restricted-imports
import { EventEmitter } from "events";
import { MatrixClientPeg } from "../MatrixClientPeg";
+1
View File
@@ -15,6 +15,7 @@ import { KnownMembership } from "matrix-js-sdk/src/types";
import { logger } from "matrix-js-sdk/src/logger";
import { type ViewRoom as ViewRoomEvent } from "@matrix-org/analytics-events/types/typescript/ViewRoom";
import { type JoinedRoom as JoinedRoomEvent } from "@matrix-org/analytics-events/types/typescript/JoinedRoom";
// oxlint-disable-next-line no-restricted-imports
import EventEmitter from "events";
import {
RoomViewLifecycle,
@@ -6,6 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
// oxlint-disable-next-line no-restricted-imports
import EventEmitter from "events";
import {
type KeyBackupInfo,
@@ -6,6 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
// oxlint-disable-next-line no-restricted-imports
import EventEmitter from "events";
import { base32 } from "rfc4648";
import { type RoomType } from "matrix-js-sdk/src/matrix";
+1
View File
@@ -6,6 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
// oxlint-disable-next-line no-restricted-imports
import EventEmitter from "events";
import { logger } from "matrix-js-sdk/src/logger";
import { type JSX } from "react";
+1
View File
@@ -6,6 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
// oxlint-disable-next-line no-restricted-imports
import EventEmitter from "events";
export enum UI_EVENTS {
+1
View File
@@ -6,6 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
// oxlint-disable-next-line no-restricted-imports
import EventEmitter from "events";
import { type IWidget } from "matrix-widget-api";
import { type MatrixEvent } from "matrix-js-sdk/src/matrix";
@@ -7,6 +7,7 @@ Please see LICENSE files in the repository root for full details.
*/
import { type MatrixClient } from "matrix-js-sdk/src/matrix";
// oxlint-disable-next-line no-restricted-imports
import { EventEmitter } from "events";
import { type EchoContext } from "./EchoContext";
@@ -9,7 +9,7 @@ Please see LICENSE files in the repository root for full details.
// @vitest-environment happy-dom
import { vi, describe, it, expect, beforeAll, beforeEach, afterEach } from "vitest";
import { type EventEmitter } from "events";
import { type EventEmitter } from "node:events";
import {
EventType,
RoomMember,
+2 -1
View File
@@ -9,10 +9,11 @@ Please see LICENSE files in the repository root for full details.
import { describe, it, expect } from "vitest";
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { blobIsAnimated, mayBeAnimated } from "./Image";
const imagesDir = path.resolve(__dirname, "../../test/unit-tests/images");
const imagesDir = fileURLToPath(import.meta.resolve("../../test/unit-tests/images"));
describe("Image", () => {
describe("mayBeAnimated", () => {
+1
View File
@@ -15,6 +15,7 @@ Please see LICENSE files in the repository root for full details.
* @event module:utils~ResizeNotifier#"middlePanelResizedNoisy"
*/
// oxlint-disable-next-line no-restricted-imports
import { EventEmitter } from "events";
import { throttle } from "lodash";
+15 -16
View File
@@ -212,17 +212,6 @@ export class UrlPreviewFetcher {
* Convert an MSC4095 URL preview bundle item to a UrlPreview
*/
public previewFromBundle(single: UnstableBundledUrlPreviewSingle): UrlPreview {
// missing fields from the bundle because backend does provide it:
// - siteName (can be computed)
// - favicon
// - media is a video or audio?
// TODO in next PR: URL previews in encrypted chat?
const hasImage =
typeof single["og:image"] === "string" &&
typeof single["og:image:type"] === "string" &&
typeof single["og:image:width"] === "number" &&
typeof single["og:image:height"] === "number";
const preview: UrlPreview = {
link: single.matched_url,
title: single["og:title"] ?? single.matched_url,
@@ -232,7 +221,17 @@ export class UrlPreviewFetcher {
ogUrl: single["og:url"],
};
if (hasImage) {
// missing fields from the bundle because backend does provide it:
// - siteName (can be computed)
// - favicon
// - media is a video or audio?
// TODO in next PR: URL previews in encrypted chat?
if (
typeof single["og:image"] === "string" &&
typeof single["og:image:type"] === "string" &&
typeof single["og:image:width"] === "number" &&
typeof single["og:image:height"] === "number"
) {
const media = mediaFromMxc(single["og:image"], this.client);
const thumb = media.getThumbnailOfSourceHttp(PREVIEW_WIDTH_PX, PREVIEW_HEIGHT_PX, "scale");
@@ -245,10 +244,10 @@ export class UrlPreviewFetcher {
preview.image = {
imageThumb: thumb,
imageFull: media.srcHttp,
imageType: single["og:image:type"] as string,
mxcImageFull: single["og:image"] as string,
width: single["og:image:width"] as number,
height: single["og:image:height"] as number,
imageType: single["og:image:type"],
mxcImageFull: single["og:image"],
width: single["og:image:width"],
height: single["og:image:height"],
playable: false, // TODO: do we know?
};
}
+1 -1
View File
@@ -135,7 +135,7 @@ export function arrayTrimFill<T>(a: T[], len: number, seed: T[]): T[] {
* @returns A copy of the array.
*/
export function arrayFastClone<T>(a: T[]): T[] {
return a.slice(0, a.length);
return a.slice(0);
}
/**
+1 -1
View File
@@ -63,7 +63,7 @@ export async function createThumbnail(
let context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;
try {
canvas = new window.OffscreenCanvas(targetWidth, targetHeight);
context = canvas.getContext("2d") as OffscreenCanvasRenderingContext2D;
context = canvas.getContext("2d")!;
} catch {
// Fallback support for other browsers (Safari and Firefox for now)
canvas = document.createElement("canvas");
@@ -10,7 +10,7 @@ Please see LICENSE files in the repository root for full details.
import { vi, describe, it, expect, afterAll, beforeEach } from "vitest";
import { getMockClientWithEventEmitter } from "test-utils/client";
import { type EventEmitter } from "events";
import { type EventEmitter } from "node:events";
import { Room, RoomMember, EventType, MatrixEvent } from "matrix-js-sdk/src/matrix";
import { KnownMembership } from "matrix-js-sdk/src/types";
+1
View File
@@ -36,6 +36,7 @@ import { ModuleNotificationDecoration } from "../modules/components/ModuleNotifi
import Login from "../Login.ts";
import { startOAuthLogin } from "../utils/oauth/authorize.ts";
// oxlint-disable-next-line node/no-process-env
logger.log(`Application is running in ${process.env.NODE_ENV} mode`);
window.matrixLogger = logger;
+2 -2
View File
@@ -22,10 +22,10 @@ import "../../res/css/_index.pcss";
// Require common CSS here; this will make webpack process it into bundle.css.
// Our own CSS (which is themed) is imported via separate webpack entry points
// in webpack.config.js
// eslint-disable-next-line @typescript-eslint/no-require-imports
// eslint-disable-next-line @typescript-eslint/no-require-imports,import/no-commonjs,unicorn/prefer-module
require("katex/dist/katex.css");
// eslint-disable-next-line @typescript-eslint/no-require-imports
// eslint-disable-next-line @typescript-eslint/no-require-imports,import/no-commonjs,unicorn/prefer-module
require("./localstorage-fix");
// Patch a fake window.TouchEvent for re-resizable's unguarded `instanceof TouchEvent`.
@@ -59,7 +59,7 @@ export const mobileApps: Record<MobileAppVariant, MobileAppMetadata> = {
};
export function updateMobilePage(metadata: MobileAppMetadata, deepLinkUrl: string, server: string | undefined): void {
const appleMeta = document.querySelector('meta[name="apple-itunes-app"]') as Element;
const appleMeta = document.querySelector('meta[name="apple-itunes-app"]')!;
appleMeta.setAttribute("content", `app-id=${metadata.appleAppId}`);
if (server) {
@@ -136,6 +136,7 @@ describe("WebPlatform", () => {
});
describe("app version", () => {
// oxlint-disable-next-line node/no-process-env
const envVersion = process.env.VERSION;
const prodVersion = "1.10.13";
@@ -35,6 +35,7 @@ function getNormalizedAppVersion(version: string): string {
}
export default class WebPlatform extends BasePlatform {
// oxlint-disable-next-line node/no-process-env
private static readonly VERSION = process.env.VERSION!; // baked in by Webpack
private readonly registerServiceWorkerPromise: Promise<void>;
+1 -1
View File
@@ -48,7 +48,7 @@ describe("mxSendRageshake", () => {
});
it.each(["", " ", undefined, null])("Does not send a rageshake if text is '%s'", async (text) => {
await window.mxSendRageshake(text as string);
await window.mxSendRageshake(text!);
expect(fetchMock).not.toHaveFetched();
});
@@ -122,7 +122,7 @@ export class ImageBodyViewModel
this.state = initialState;
const imageSizeWatcherRef = SettingsStore.watchSetting("Images.size", null, (_s, _r, _l, _nvl, value) => {
this.setImageSize(value as ImageSize);
this.setImageSize(value!);
});
this.disposables.track(() => SettingsStore.unwatchSetting(imageSizeWatcherRef));
}
@@ -109,7 +109,7 @@ export class VideoBodyViewModel
this.state = initialState;
const imageSizeWatcherRef = SettingsStore.watchSetting("Images.size", null, (_s, _r, _l, _nvl, value) => {
this.setImageSize(value as ImageSize);
this.setImageSize(value!);
});
this.disposables.track(() => SettingsStore.unwatchSetting(imageSizeWatcherRef));
}

Some files were not shown because too many files have changed in this diff Show More