client: fix all new linter errros

This commit is contained in:
Reto Brunner 2024-05-02 08:21:51 +02:00
parent 3fbbc39cd6
commit 3259ac596d
36 changed files with 76 additions and 78 deletions

View file

@ -93,6 +93,7 @@ const tsRules = defineConfig({
// note you must disable the base rule as it can report incorrect errors
"no-shadow": "off",
"@typescript-eslint/no-shadow": ["error"],
"@typescript-eslint/no-redundant-type-constituents": "off",
},
}).rules;

View file

@ -136,6 +136,7 @@ import ListIgnored from "./Special/ListIgnored.vue";
import {defineComponent, PropType, ref, computed, watch, nextTick, onMounted, Component} from "vue";
import type {ClientNetwork, ClientChan} from "../js/types";
import {useStore} from "../js/store";
import {SpecialChanType, ChanType} from "../../shared/types/chan";
export default defineComponent({
name: "Chat",
@ -161,13 +162,13 @@ export default defineComponent({
const specialComponent = computed(() => {
switch (props.channel.special) {
case "list_bans":
case SpecialChanType.BANLIST:
return ListBans as Component;
case "list_invites":
case SpecialChanType.INVITELIST:
return ListInvites as Component;
case "list_channels":
case SpecialChanType.CHANNELLIST:
return ListChannels as Component;
case "list_ignored":
case SpecialChanType.IGNORELIST:
return ListIgnored as Component;
}
@ -194,7 +195,7 @@ export default defineComponent({
};
const editTopic = () => {
if (props.channel.type === "channel") {
if (props.channel.type === ChanType.CHANNEL) {
props.channel.editTopic = true;
}
};

View file

@ -63,6 +63,7 @@ import eventbus from "../js/eventbus";
import {watch, defineComponent, nextTick, onMounted, PropType, ref, onUnmounted} from "vue";
import type {ClientNetwork, ClientChan} from "../js/types";
import {useStore} from "../js/store";
import {ChanType} from "../../shared/types/chan";
const formattingHotkeys = {
"mod+k": "\x03",
@ -130,7 +131,7 @@ export default defineComponent({
};
const getInputPlaceholder = (channel: ClientChan) => {
if (channel.type === "channel" || channel.type === "query") {
if (channel.type === ChanType.CHANNEL || channel.type === ChanType.QUERY) {
return `Write to ${channel.name}`;
}

View file

@ -20,6 +20,7 @@
<script lang="ts">
import {computed, defineComponent, PropType, ref} from "vue";
import {condensedTypes} from "../../shared/irc";
import {MessageType} from "../../shared/types/msg";
import {ClientMessage, ClientNetwork} from "../js/types";
import Message from "./Message.vue";
@ -57,16 +58,23 @@ export default defineComponent({
for (const message of props.messages) {
// special case since one MODE message can change multiple modes
if (message.type === "mode") {
if (message.type === MessageType.MODE) {
// syntax: +vv-t maybe-some targets
// we want the number of mode changes in the message, so count the
// number of chars other than + and - before the first space
const modeChangesCount = message.text
const text = message.text ? message.text : "";
const modeChangesCount = text
.split(" ")[0]
.split("")
.filter((char) => char !== "+" && char !== "-").length;
obj[message.type] += modeChangesCount;
} else {
if (!message.type) {
/* eslint-disable no-console */
console.log(`empty message type, this should not happen: ${message.id}`);
continue;
}
obj[message.type]++;
}
}

View file

@ -59,6 +59,8 @@
<script lang="ts">
import {condensedTypes} from "../../shared/irc";
import {ChanType} from "../../shared/types/chan";
import {MessageType, SharedMsg} from "../../shared/types/msg";
import eventbus from "../js/eventbus";
import clipboard from "../js/clipboard";
import socket from "../js/socket";
@ -79,7 +81,6 @@ import {
} from "vue";
import {useStore} from "../js/store";
import {ClientChan, ClientMessage, ClientNetwork, ClientLinkPreview} from "../js/types";
import {SharedMsg} from "../../shared/types/msg";
type CondensedMessageContainer = {
type: "condensed";
@ -103,7 +104,7 @@ export default defineComponent({
channel: {type: Object as PropType<ClientChan>, required: true},
focused: Number,
},
setup(props, {emit}) {
setup(props) {
const store = useStore();
const chat = ref<HTMLDivElement | null>(null);
@ -177,14 +178,14 @@ export default defineComponent({
});
const condensedMessages = computed(() => {
if (props.channel.type !== "channel" && props.channel.type !== "query") {
if (props.channel.type !== ChanType.CHANNEL && props.channel.type !== ChanType.QUERY) {
return props.channel.messages;
}
// If actions are hidden, just return a message list with them excluded
if (store.state.settings.statusMessages === "hidden") {
return props.channel.messages.filter(
(message) => !condensedTypes.has(message.type)
(message) => !condensedTypes.has(message.type || "")
);
}
@ -200,7 +201,7 @@ export default defineComponent({
for (const message of props.channel.messages) {
// If this message is not condensable, or its an action affecting our user,
// then just append the message to container and be done with it
if (message.self || message.highlight || !condensedTypes.has(message.type)) {
if (message.self || message.highlight || !condensedTypes.has(message.type || "")) {
lastCondensedContainer = null;
condensed.push(message);
@ -242,7 +243,7 @@ export default defineComponent({
});
const shouldDisplayDateMarker = (
message: SharedMsg | ClientMessage | CondensedMessageContainer,
message: SharedMsg | CondensedMessageContainer,
id: number
) => {
const previousMessage = condensedMessages.value[id - 1];
@ -270,12 +271,13 @@ export default defineComponent({
return false;
};
const isPreviousSource = (currentMessage: ClientMessage | SharedMsg, id: number) => {
const isPreviousSource = (currentMessage: ClientMessage, id: number) => {
const previousMessage = condensedMessages.value[id - 1];
return !!(
return (
previousMessage &&
currentMessage.type === "message" &&
previousMessage.type === "message" &&
currentMessage.type === MessageType.MESSAGE &&
previousMessage.type === MessageType.MESSAGE &&
currentMessage.from &&
previousMessage.from &&
currentMessage.from.nick === previousMessage.from.nick
);

View file

@ -48,7 +48,7 @@ export default defineComponent({
watch(
() => route.params.uuid,
(newValue) => {
() => {
setNetworkData();
}
);

View file

@ -1,13 +1,14 @@
import constants from "./constants";
import Mousetrap from "mousetrap";
import {Strategy, Textcomplete, StrategyProps} from "@textcomplete/core";
import {Textcomplete, StrategyProps} from "@textcomplete/core";
import {TextareaEditor} from "@textcomplete/textarea";
import fuzzy from "fuzzy";
import emojiMap from "./helpers/simplemap.json";
import {store} from "./store";
import {ChanType} from "../../shared/types/chan";
export default enableAutocomplete;
@ -38,7 +39,6 @@ const nicksStrategy: StrategyProps = {
if (term[0] === "@") {
// TODO: type
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
callback(completeNicks(term.slice(1), true).map((val) => ["@" + val[0], "@" + val[1]]));
} else {
callback(completeNicks(term, true));
@ -292,7 +292,7 @@ function rawNicks() {
const otherUser = store.state.activeChannel.channel.name;
// If this is a query, add their name to autocomplete
if (me !== otherUser && store.state.activeChannel.channel.type === "query") {
if (me !== otherUser && store.state.activeChannel.channel.type === ChanType.QUERY) {
return [otherUser, me];
}
@ -332,7 +332,7 @@ function completeChans(word: string) {
if (store.state.activeChannel) {
for (const channel of store.state.activeChannel.network.channels) {
// Push all channels that start with the same CHANTYPE
if (channel.type === "channel" && channel.name[0] === word[0]) {
if (channel.type === ChanType.CHANNEL && channel.name[0] === word[0]) {
words.push(channel.name);
}
}

View file

@ -1,11 +1,12 @@
import {ClientChan, ClientMessage} from "./types";
import {SharedNetworkChan} from "../../shared/types/network";
import {SharedMsg} from "../../shared/types/msg";
import {SharedMsg, MessageType} from "../../shared/types/msg";
import {ChanType} from "../../shared/types/chan";
export function toClientChan(shared: SharedNetworkChan): ClientChan {
const history: string[] = [""].concat(
shared.messages
.filter((m) => m.self && m.text && m.type === "message")
.filter((m) => m.self && m.text && m.type === MessageType.MESSAGE)
// TS is too stupid to see the nil guard on filter... so we monkey patch it
.map((m): string => (m.text ? m.text : ""))
.reverse()
@ -21,7 +22,7 @@ export function toClientChan(shared: SharedNetworkChan): ClientChan {
historyLoading: false,
scrolledToBottom: true,
users: [],
usersOutdated: shared.type === "channel" ? true : false,
usersOutdated: shared.type === ChanType.CHANNEL ? true : false,
moreHistoryAvailable: shared.totalMessages > shared.messages.length,
inputHistory: history,
messages: sharedMsgToClientMsg(messages),

View file

@ -4,6 +4,7 @@ import type {ClientChan, ClientNetwork, ClientUser} from "../types";
import {switchToChannel} from "../router";
import {TypedStore} from "../store";
import useCloseChannel from "../hooks/use-close-channel";
import {ChanType} from "../../../shared/types/chan";
type BaseContextMenuItem = {
label: string;
@ -61,7 +62,7 @@ export function generateChannelContextMenu(
];
// Add menu items for lobbies
if (channel.type === "lobby") {
if (channel.type === ChanType.LOBBY) {
items = [
...items,
{
@ -121,7 +122,7 @@ export function generateChannelContextMenu(
}
// Add menu items for channels
if (channel.type === "channel") {
if (channel.type === ChanType.CHANNEL) {
items.push({
label: "Edit topic",
type: "item",
@ -145,7 +146,7 @@ export function generateChannelContextMenu(
}
// Add menu items for queries
if (channel.type === "query") {
if (channel.type === ChanType.QUERY) {
items.push(
{
label: "User information",
@ -173,7 +174,7 @@ export function generateChannelContextMenu(
);
}
if (channel.type === "channel" || channel.type === "query") {
if (channel.type === ChanType.CHANNEL || channel.type === ChanType.QUERY) {
items.push({
label: "Clear history",
type: "item",

View file

@ -185,8 +185,7 @@ function parse(text: string, message?: ClientMessage, network?: ClientNetwork) {
} else if (textPart.emoji) {
const emojiWithoutModifiers = textPart.emoji.replace(emojiModifiersRegex, "");
const title = emojiMap[emojiWithoutModifiers]
? // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
`Emoji: ${emojiMap[emojiWithoutModifiers]}`
? `Emoji: ${emojiMap[emojiWithoutModifiers]}`
: null;
return createElement(

View file

@ -1,10 +1,11 @@
import eventbus from "../eventbus";
import socket from "../socket";
import {ClientChan} from "../types";
import {ChanType} from "../../../shared/types/chan";
export default function useCloseChannel(channel: ClientChan) {
return () => {
if (channel.type === "lobby") {
if (channel.type === ChanType.LOBBY) {
eventbus.emit(
"confirm-dialog",
{

View file

@ -6,6 +6,7 @@ import isChannelCollapsed from "./helpers/isChannelCollapsed";
import isIgnoredKeybind from "./helpers/isIgnoredKeybind";
import listenForTwoFingerSwipes from "./helpers/listenForTwoFingerSwipes";
import {ClientChan} from "./types";
import {ChanType} from "../../shared/types/chan";
// Switch to the next/previous window in the channel list.
Mousetrap.bind(["alt+up", "alt+down"], function (e, keys) {
@ -73,7 +74,7 @@ Mousetrap.bind(["alt+shift+up", "alt+shift+down"], function (e, keys) {
index = store.state.networks.findIndex((n) => n === store.state.activeChannel?.network);
// If we're in a channel, and it's not the lobby, jump to lobby of this network when going up
if (direction !== -1 || store.state.activeChannel?.channel.type === "lobby") {
if (direction !== -1 || store.state.activeChannel?.channel.type === ChanType.LOBBY) {
index = (((index + direction) % length) + length) % length;
}
}

View file

@ -162,7 +162,6 @@ async function navigate(routeName: string, params: any = {}) {
// If current route is null, replace the history entry
// This prevents invalid entries from lingering in history,
// and then the route guard preventing proper navigation
// eslint-disable-next-line @typescript-eslint/no-empty-function
await router.replace({name: routeName, params}).catch(() => {});
}
}

View file

@ -2,7 +2,6 @@ import socket from "./socket";
import type {TypedStore} from "./store";
const defaultSettingConfig = {
// eslint-disable-next-line @typescript-eslint/no-empty-function
apply() {},
default: null,
sync: null,

View file

@ -2,7 +2,7 @@ import {nextTick} from "vue";
import socket from "../socket";
import {store} from "../store";
import type {ClientChan, ClientMessage} from "../types";
import {MessageType} from "../../../shared/types/msg";
socket.on("more", async (data) => {
const channel = store.getters.findChannel(data.chan)?.channel;
@ -13,7 +13,7 @@ socket.on("more", async (data) => {
channel.inputHistory = channel.inputHistory.concat(
data.messages
.filter((m) => m.self && m.text && m.type === "message")
.filter((m) => m.self && m.text && m.type === MessageType.MESSAGE)
// TS is too stupid to see the guard in .filter(), so we monkey patch it
// to please the compiler
.map((m) => (m.text ? m.text : ""))

View file

@ -1,10 +1,10 @@
/* eslint-disable @typescript-eslint/restrict-plus-operands */
import socket from "../socket";
import {cleanIrcMessage} from "../../../shared/irc";
import {store} from "../store";
import {switchToChannel} from "../router";
import {ClientChan, NetChan, ClientMessage} from "../types";
import {SharedMsg} from "../../../shared/types/msg";
import {SharedMsg, MessageType} from "../../../shared/types/msg";
import {ChanType} from "../../../shared/types/chan";
let pop;
@ -13,7 +13,6 @@ try {
pop.src = "audio/pop.wav";
} catch (e) {
pop = {
// eslint-disable-next-line @typescript-eslint/no-empty-function
play() {},
};
}
@ -91,7 +90,7 @@ socket.on("msg", function (data) {
channel.moreHistoryAvailable = true;
}
if (channel.type === "channel") {
if (channel.type === ChanType.CHANNEL) {
updateUserList(channel, data.msg);
}
});
@ -114,7 +113,10 @@ function notifyMessage(
return;
}
if (msg.highlight || (store.state.settings.notifyAllMessages && msg.type === "message")) {
if (
msg.highlight ||
(store.state.settings.notifyAllMessages && msg.type === MessageType.MESSAGE)
) {
if (!document.hasFocus() || !activeChannel || activeChannel.channel !== channel) {
if (store.state.settings.notification) {
try {
@ -134,17 +136,17 @@ function notifyMessage(
// TODO: fix msg type and get rid of that conditional
const nick = msg.from && msg.from.nick ? msg.from.nick : "unkonown";
if (msg.type === "invite") {
if (msg.type === MessageType.INVITE) {
title = "New channel invite:";
body = nick + " invited you to " + msg.channel;
} else {
title = nick;
if (channel.type !== "query") {
if (channel.type !== ChanType.QUERY) {
title += ` (${channel.name})`;
}
if (msg.type === "message") {
if (msg.type === MessageType.MESSAGE) {
title += " says:";
}
@ -198,9 +200,9 @@ function notifyMessage(
function updateUserList(channel: ClientChan, msg: SharedMsg) {
switch (msg.type) {
case "message": // fallthrough
case MessageType.MESSAGE: // fallthrough
case "action": {
case MessageType.ACTION: {
const user = channel.users.find((u) => u.nick === msg.from?.nick);
if (user) {
@ -210,9 +212,9 @@ function updateUserList(channel: ClientChan, msg: SharedMsg) {
break;
}
case "quit": // fallthrough
case MessageType.QUIT: // fallthrough
case "part": {
case MessageType.PART: {
const idx = channel.users.findIndex((u) => u.nick === msg.from?.nick);
if (idx > -1) {
@ -222,7 +224,7 @@ function updateUserList(channel: ClientChan, msg: SharedMsg) {
break;
}
case "kick": {
case MessageType.KICK: {
const idx = channel.users.findIndex((u) => u.nick === msg.target?.nick);
if (idx > -1) {

View file

@ -1,14 +1,15 @@
import socket from "../socket";
import {store} from "../store";
import {ChanType} from "../../../shared/types/chan";
socket.on("mute:changed", (response) => {
const {target, status} = response;
const netChan = store.getters.findChannel(target);
if (netChan?.channel.type === "lobby") {
if (netChan?.channel.type === ChanType.LOBBY) {
for (const chan of netChan.network.channels) {
if (chan.type !== "special") {
if (chan.type !== ChanType.SPECIAL) {
chan.muted = status;
}
}

View file

@ -61,10 +61,10 @@ store.watch(
if (nav.setAppBadge) {
if (highlightCount > 0) {
nav.setAppBadge(highlightCount);
nav.setAppBadge(highlightCount).catch(() => {});
} else {
if (nav.clearAppBadge) {
nav.clearAppBadge();
nav.clearAppBadge().catch(() => {});
}
}
}

View file

@ -7,7 +7,6 @@ import path from "path";
import Auth from "./plugins/auth";
import Client, {UserConfig} from "./client";
import Config from "./config";
import {NetworkConfig} from "./models/network";
import WebPush from "./plugins/webpush";
import log from "./log";
import {Server} from "./server";
@ -185,7 +184,6 @@ class ClientManager {
mode: 0o600,
});
} catch (e: any) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
log.error(`Failed to create user ${colors.green(name)} (${e})`);
throw e;
}
@ -253,7 +251,6 @@ class ClientManager {
return callback ? callback() : true;
} catch (e: any) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
log.error(`Failed to update user ${colors.green(client.name)} (${e})`);
if (callback) {
@ -287,7 +284,6 @@ class ClientManager {
const data = fs.readFileSync(userPath, "utf-8");
return JSON.parse(data) as UserConfig;
} catch (e: any) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
log.error(`Failed to read user ${colors.bold(name)}: ${e}`);
}

View file

@ -3,7 +3,7 @@ import log from "../../log";
import Helper from "../../helper";
import type {AuthHandler} from "../auth";
const localAuth: AuthHandler = (manager, client, user, password, callback) => {
const localAuth: AuthHandler = (_manager, client, user, password, callback) => {
// If no user is found, or if the client has not provided a password,
// fail the authentication straight away
if (!client || !password) {
@ -40,7 +40,6 @@ const localAuth: AuthHandler = (manager, client, user, password, callback) => {
callback(matching);
})
.catch((error) => {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
log.error(`Error while checking users password. Error: ${error}`);
});
};

View file

@ -95,7 +95,6 @@ function generate() {
// Set notAfter 100 years into the future just in case
// the server actually validates this field
cert.validity.notAfter = new Date();
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 100);
const attrs = [

View file

@ -29,6 +29,7 @@ export default (app: express.Application) => {
const compiler = webpack(webpackConfig);
app.use(
// eslint-disable-next-line @typescript-eslint/no-misused-promises
webpackDevMiddleware(compiler, {
index: "/",
publicPath: webpackConfig.output?.publicPath,

View file

@ -6,6 +6,7 @@ import Msg from "../../models/msg";
import Client from "../../client";
import {MessageType} from "../../../shared/types/msg";
import {ChanType} from "../../../shared/types/chan";
const commands = ["mute", "unmute"];
const allowDisconnected = true;
@ -25,7 +26,7 @@ function args_to_channels(network: Network, args: string[]) {
}
function change_mute_state(client: Client, target: Chan, valueToSet: boolean) {
if (target.type === "special") {
if (target.type === ChanType.SPECIAL) {
return;
}

View file

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/restrict-plus-operands */
import _ from "lodash";
import {IrcEventHandler} from "../../client";

View file

@ -79,7 +79,6 @@ export default <IrcEventHandler>function (irc, network) {
type: MessageType.CTCP_REQUEST,
time: data.time,
from: new User({nick: target}),
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
hostmask: data.ident + "@" + data.hostname,
ctcpMessage: data.message,
});

View file

@ -58,7 +58,6 @@ export default <IrcEventHandler>function (irc, network) {
if (irc.connection.registered === false) {
const nickLen = parseInt(network.irc.network.options.NICKLEN, 10) || 16;
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
const random = (data.nick || irc.user.nick) + Math.floor(Math.random() * 10);
// Safeguard nick changes up to allowed length

View file

@ -35,7 +35,6 @@ export default <IrcEventHandler>function (irc, network) {
const msg = new Msg({
type: MessageType.MODE_CHANNEL,
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
text: `${data.raw_modes} ${data.raw_params.join(" ")}`,
});
targetChan.pushMessage(client, msg);

View file

@ -14,7 +14,6 @@ export default <IrcEventHandler>function (irc, network) {
const lobby = network.getLobby();
const msg = new Msg({
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
text: `You're now known as ${data.new_nick}`,
});
lobby.pushMessage(client, msg, true);

View file

@ -11,7 +11,6 @@ export default <IrcEventHandler>function (irc, network) {
const msg = new Msg({
type: MessageType.LOGIN,
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
text: "Logged in as: " + data.account,
});
lobby.pushMessage(client, msg, true);

View file

@ -44,7 +44,6 @@ export default <IrcEventHandler>function (irc, network) {
if (data.error) {
msg = new Msg({
type: MessageType.ERROR,
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
text: "No such nick: " + data.nick,
});
} else {

View file

@ -223,7 +223,6 @@ class Uploader {
try {
fs.mkdirSync(destDir, {recursive: true});
} catch (err: any) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
log.error(`Error ensuring ${destDir} exists for uploads: ${err.message}`);
return abortWithError(err);
@ -324,7 +323,6 @@ class Uploader {
return "application/octet-stream";
} catch (e: any) {
if (e.code !== "ENOENT") {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
log.warn(`Failed to read ${filePath}: ${e.message}`);
}
}

View file

@ -174,8 +174,6 @@ interface ClientToServerEvents {
search: EventHandler<SearchQuery>;
}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface InterServerEvents {}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface SocketData {}

View file

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-empty-function */
import {expect} from "chai";
import sinon from "ts-sinon";
import Chan from "../../server/models/chan";

View file

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/restrict-template-expressions */
import path from "path";
import {expect} from "chai";
import util from "../util";

View file

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/restrict-template-expressions */
import fs from "fs";
import path from "path";
import crypto from "crypto";

View file

@ -47,7 +47,6 @@ describe("Server", function () {
server.close(done);
});
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
const webURL = `http://${Config.values.host}:${Config.values.port}/`;
describe("Express", () => {