more tests, eslint work

This commit is contained in:
Max Leiter 2022-05-02 23:50:59 -07:00
parent 303c6ae7b3
commit ed02acfad4
No known key found for this signature in database
GPG key ID: A3512F2F2F17EBDA
44 changed files with 133 additions and 93 deletions

View file

@ -6,7 +6,8 @@ module.exports = {
// project: ["./eslint.tsconfig.json"],
// extraFileExtensions: [".vue", ".cjs"],
},
parser: "@typescript-eslint/parser",
// TODO: this should just be for client?
parser: "vue-eslint-parser",
plugins: ["vue", "@typescript-eslint"],
env: {
es6: true,
@ -84,5 +85,9 @@ module.exports = {
"vue/require-default-prop": "off",
"vue/v-slot-style": ["error", "longform"],
"vue/multi-word-component-names": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-this-alias": "off",
},
};

View file

@ -1,4 +1,4 @@
module.exports = {
presets: [["@babel/env", "babel-preset-typescript-vue"]],
presets: [["@babel/env", {bugfixes: true}], "babel-preset-typescript-vue"],
targets: "> 0.25%, not dead",
};

View file

@ -96,7 +96,7 @@
</template>
<script>
const constants = require("../js/constants");
import constants from "../js/constants";
import localetime from "../js/helpers/localetime";
import dayjs from "dayjs";
import Username from "./Username.vue";

View file

@ -18,7 +18,7 @@
</template>
<script>
const constants = require("../js/constants");
import constants from "../js/constants";
import Message from "./Message.vue";
export default {

View file

@ -58,7 +58,7 @@
</template>
<script>
const constants = require("../js/constants");
import constants from "../js/constants";
import eventbus from "../js/eventbus";
import clipboard from "../js/clipboard";
import socket from "../js/socket";

View file

@ -10,14 +10,14 @@ LinkifyIt.prototype.normalize = function normalize(match: OurMatch) {
if (!match.schema) {
match.schema = "http:";
match.url = "http://" + match.url;
//@ts-ignore
// @ts-ignore
match.noschema = true;
}
if (match.schema === "//") {
match.schema = "http:";
match.url = "http:" + match.url;
//@ts-ignore
// @ts-ignore
match.noschema = true;
}

View file

@ -1,6 +1,6 @@
"use strict";
const constants = require("./constants");
import constants from "./constants";
import Vue from "vue";
import VueRouter from "vue-router";
@ -138,7 +138,7 @@ router.beforeEach((to, from, next) => {
return;
}
const imageViewer = router.app.$root.$refs.app.$refs.imageViewer;
const imageViewer = router.app.$root.$refs.app?.$refs.imageViewer;
if (imageViewer && imageViewer.link) {
imageViewer.closeViewer();
@ -175,18 +175,20 @@ router.afterEach((to) => {
}
});
function navigate(routeName, params = {}) {
function navigate(routeName: string, params: any = {}) {
if (router.currentRoute.name) {
// eslint-disable-next-line @typescript-eslint/no-empty-function
router.push({name: routeName, params}).catch(() => {});
} else {
// 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
router.replace({name: routeName, params}).catch(() => {});
}
}
function switchToChannel(channel) {
function switchToChannel(channel: ClientChan) {
return navigate("RoutedChat", {id: channel.id});
}

View file

@ -1,4 +1,4 @@
const constants = require("../constants");
import constants from "../constants";
import socket from "../socket";
socket.on("commands", function (commands) {

View file

@ -23,7 +23,7 @@ export type State = {
appLoaded: boolean;
activeChannel?: {
network: Network;
channel: Channel;
channel: ClientChan;
};
currentUserVisibleError: string | null;
desktopNotificationState: "granted" | "blocked" | "nohttps" | "unsupported";

View file

@ -104,6 +104,7 @@ store.watch(
// TODO: investigate types
const nav = navigate as any;
if (nav.setAppBadge) {
if (highlightCount > 0) {
nav.setAppBadge(highlightCount);

4
client/types.d.ts vendored
View file

@ -5,3 +5,7 @@ declare module "*.vue" {
interface LoungeWindow extends Window {
g_TheLoungeRemoveLoading?: () => void;
}
type ClientChan = Chan & {
moreHistoryAvailable: boolean;
};

View file

@ -1,4 +1,7 @@
{
"extends": "./tsconfig.base.json",
"include": ["src/**/*.ts", "client/**/*.ts", "test/**/*.ts", "scripts/**/*.{ts,js}"]
// "compilerOptions": {
// "types": ["node", "jest"]
// }
}

View file

@ -8,7 +8,9 @@ process.chdir(__dirname);
// Doing this check as soon as possible allows us to
// avoid ES6 parser errors or other issues
import pkg from "./package.json";
if (!require("semver").satisfies(process.version, pkg.engines.node)) {
import {satisfies} from "semver";
if (!satisfies(process.version, pkg.engines.node)) {
/* eslint-disable no-console */
console.error(
"The Lounge requires Node.js " +
@ -24,10 +26,11 @@ if (!require("semver").satisfies(process.version, pkg.engines.node)) {
process.exit(1);
}
import dns from "dns";
import * as dns from "dns";
// Set DNS result order early before anything that may depend on it happens.
if (dns.setDefaultResultOrder) {
dns.setDefaultResultOrder("verbatim");
}
import "./src/command-line";

View file

@ -143,6 +143,7 @@
"typescript": "4.6.4",
"undate": "0.3.0",
"vue": "2.6.14",
"vue-eslint-parser": "8.3.0",
"vue-loader": "15.9.8",
"vue-router": "3.5.3",
"vue-server-renderer": "2.6.14",

View file

@ -200,7 +200,7 @@ class Client {
connect(args: any, isStartup = false) {
const client = this;
let channels: Chan[] = [];
const channels: Chan[] = [];
// Get channel id for lobby before creating other channels for nicer ids
const lobbyChannelId = client.idChan++;
@ -279,8 +279,11 @@ class Client {
network.createIrcFramework(client);
events.forEach((plugin) => {
require(`./plugins/irc-events/${plugin}`).apply(client, [network.irc, network]);
events.forEach(async (plugin) => {
(await import(`./plugins/irc-events/${plugin}`)).default.apply(client, [
network.irc,
network,
]);
});
if (network.userDisconnected) {
@ -732,11 +735,7 @@ class Client {
}
// TODO: type session to this.attachedClients
registerPushSubscription(
session: any,
subscription: ClientPushSubscription,
noSave: boolean = false
) {
registerPushSubscription(session: any, subscription: ClientPushSubscription, noSave = false) {
if (
!_.isPlainObject(subscription) ||
!_.isPlainObject(subscription.keys) ||

View file

@ -43,11 +43,15 @@ program.addCommand(require("./install").default);
program.addCommand(require("./uninstall").default);
program.addCommand(require("./upgrade").default);
program.addCommand(require("./outdated").default);
if (!Config.values.public) {
require("./users").default.forEach((command: Command) => {
if (command) program.addCommand(command);
if (command) {
program.addCommand(command);
}
});
}
// `parse` expects to be passed `process.argv`, but we need to remove to give it
// a version of `argv` that does not contain options already parsed by
// `parseOptions` above.

View file

@ -13,7 +13,7 @@ class Config {
values = require(path.resolve(
path.join(__dirname, "..", "defaults", "config.js")
)) as ConfigType;
#homePath: string = "";
#homePath = "";
getHomePath() {
return this.#homePath;

View file

@ -43,6 +43,7 @@ class Identification {
},
() => {
const address = server.address();
if (typeof address === "string") {
log.info(`Identd server available on ${colors.green(address)}`);
} else if (address?.address) {

2
src/index.d.ts vendored
View file

@ -1 +1 @@
/// <reference path="types/index.d.ts" />
// / <reference path="types/index.d.ts" />

View file

@ -32,7 +32,7 @@ class Chan {
closed?: boolean;
num_users?: number;
constructor(attr: Partial<Chan>) {
constructor(attr?: Partial<Chan>) {
_.defaults(this, attr, {
id: 0,
messages: [],
@ -125,7 +125,7 @@ class Chan {
}
});
}
getSortedUsers(irc) {
getSortedUsers(irc?: Network["irc"]) {
const users = Array.from(this.users.values());
if (!irc || !irc.network || !irc.network.options || !irc.network.options.PREFIX) {
@ -207,7 +207,7 @@ class Chan {
return;
}
let targetChannel: Chan = this;
const targetChannel: Chan = this;
// Is this particular message or channel loggable
if (!msg.isLoggable() || !this.isLoggable()) {

View file

@ -67,7 +67,7 @@ class Network {
// TODO: this is only available on export
hasSTSPolicy!: boolean;
constructor(attr: Partial<Network>) {
constructor(attr?: Partial<Network>) {
_.defaults(this, attr, {
name: "",
nick: "",
@ -237,7 +237,7 @@ class Network {
auto_reconnect_max_retries: 30,
});
//@ts-ignore TODO: `this` should now be a NetworkWithIrcFramework
// @ts-ignore TODO: `this` should now be a NetworkWithIrcFramework
this.setIrcFrameworkOptions(client);
this.irc.requestCap([
@ -391,9 +391,14 @@ class Network {
}
this.setIrcFrameworkOptions(client);
if (this.irc.options?.username) this.irc.user.username = this.irc.options.username;
if (this.irc.options?.gecos) this.irc.user.gecos = this.irc.options.gecos;
if (this.irc.options?.username) {
this.irc.user.username = this.irc.options.username;
}
if (this.irc.options?.gecos) {
this.irc.user.gecos = this.irc.options.gecos;
}
}
client.save();

View file

@ -11,7 +11,7 @@ class User {
nick!: string;
lastMessage!: number;
constructor(attr: Partial<User>, prefix: Prefix) {
constructor(attr: Partial<User>, prefix?: Prefix) {
_.defaults(this, attr, {
modes: [],
away: "",
@ -25,7 +25,7 @@ class User {
},
});
this.setModes(this.modes, prefix);
this.setModes(this.modes, prefix || new Prefix([]));
}
setModes(modes: string[], prefix: Prefix) {

View file

@ -191,8 +191,8 @@ function advancedLdapLoadUsers(users: string[], callbackLoadUser) {
}
res.on("searchEntry", function (entry) {
//@ts-ignore
//TODO
// @ts-ignore
// TODO
const user = entry.attributes[0]._vals[0].toString();
if (remainingUsers.has(user)) {

View file

@ -3,6 +3,7 @@
import Msg from "../../models/msg";
const commands = ["slap", "me"];
const input: PluginInputHandler = function ({irc}, chan, cmd, args) {
if (chan.type !== ChanType.CHANNEL && chan.type !== ChanType.QUERY) {
chan.pushMessage(

View file

@ -10,6 +10,7 @@ const input: PluginInputHandler = function (network, chan, cmd, args) {
let target: string;
// let hostmask: cmd === "ignoreList" ? string : undefined;
let hostmask: IgnoreListItem | undefined;
if (cmd !== "ignorelist" && (args.length === 0 || args[0].trim().length === 0)) {
chan.pushMessage(
client,

View file

@ -165,6 +165,7 @@ function parseHtmlMedia($: cheerio.CheerioAPI, preview, client) {
$(`meta[property="og:${type}:type"]`).each(function (i) {
const mimeType = $(this).attr("content");
if (!mimeType) {
return;
}
@ -172,6 +173,7 @@ function parseHtmlMedia($: cheerio.CheerioAPI, preview, client) {
if (mediaTypeRegex.test(mimeType)) {
// If we match a clean video or audio tag, parse that as a preview instead
let mediaUrl = $($(`meta[property="og:${type}"]`).get(i)).attr("content");
if (!mediaUrl) {
return;
}
@ -216,6 +218,7 @@ function parseHtmlMedia($: cheerio.CheerioAPI, preview, client) {
}
});
}
// TODO: type preview
function parse(msg: Msg, chan: Chan, preview: any, res, client: Client) {
let promise;

View file

@ -55,8 +55,8 @@ export default <IrcEventHandler>function (irc, network) {
index: network.addChannel(chan),
});
} else {
//TODO
//@ts-ignore
// TODO
// @ts-ignore
chan.data = msg;
client.emit("msg:special", {

View file

@ -73,7 +73,7 @@ export default <IrcEventHandler>function (irc, network) {
index: network.addChannel(chan),
});
} else {
//@ts-ignore TODO
// @ts-ignore TODO
chan.data = data;
client.emit("msg:special", {

View file

@ -126,9 +126,11 @@ function loadPackage(packageName: string) {
packageFile = require(packagePath);
} catch (e: any) {
log.error(`Package ${colors.bold(packageName)} could not be loaded: ${colors.red(e)}`);
if (e instanceof Error) {
log.debug(e.stack ? e.stack : e.message);
}
return;
}
@ -143,7 +145,7 @@ function loadPackage(packageName: string) {
if (packageInfo.type === "theme") {
// TODO: investigate
//@ts-ignore
// @ts-ignore
themes.addTheme(packageName, packageInfo);
if (packageInfo.files) {

View file

@ -260,9 +260,9 @@ class Uploader {
// abort the processing with an error
// TODO: fix types
//@ts-ignore
// @ts-ignore
fileStream.on("error", abortWithError);
//@ts-ignore
// @ts-ignore
fileStream.on("limit", () => {
fileStream.unpipe(streamWriter);
fileStream.on("readable", fileStream.read.bind(fileStream));

View file

@ -7,7 +7,7 @@ import path from "path";
import WebPushAPI from "web-push";
import Config from "../config";
import Client from "client";
import * as os from "os";
class WebPush {
vapidKeys?: {
publicKey: string;
@ -34,7 +34,7 @@ class WebPush {
"is world readable. The file contains secrets. Please fix the permissions"
);
if (require("os").platform() !== "win32") {
if (os.platform() !== "win32") {
log.warn(`run \`chmod o= ${vapidPath}\` to correct it`);
}
}

View file

@ -136,7 +136,7 @@ export default async function (
process.exit(1);
}
server = require("https");
server = await import("https");
server = server.createServer(
{
key: fs.readFileSync(keyPath),
@ -160,7 +160,7 @@ export default async function (
server.on("error", (err) => log.error(`${err}`));
server.listen(listenParams, () => {
server.listen(listenParams, async () => {
if (typeof listenParams === "string") {
log.info("Available on socket " + colors.green(listenParams));
} else {
@ -216,18 +216,18 @@ export default async function (
}
new Identification((identHandler, err) => {
if (err) {
if (err || !manager) {
log.error(`Could not start identd server, ${err.message}`);
process.exit(1);
}
manager!.init(identHandler, sockets);
manager.init(identHandler, sockets);
});
// Handle ctrl+c and kill gracefully
let suicideTimeout: NodeJS.Timeout | null = null;
const exitGracefully = function () {
const exitGracefully = async function () {
if (suicideTimeout !== null) {
return;
}
@ -235,12 +235,14 @@ export default async function (
log.info("Exiting...");
// Close all client and IRC connections
manager!.clients.forEach((client) => client.quit());
if (manager) {
manager.clients.forEach((client) => client.quit());
}
if (Config.values.prefetchStorage) {
log.info("Clearing prefetch storage folder, this might take a while...");
require("./plugins/storage").emptyDir();
(await import("./plugins/storage")).default.emptyDir();
}
// Forcefully exit after 3 seconds
@ -251,6 +253,7 @@ export default async function (
if (suicideTimeout !== null) {
clearTimeout(suicideTimeout);
}
process.exit(0);
});
};
@ -260,7 +263,7 @@ export default async function (
// Clear storage folder after server starts successfully
if (Config.values.prefetchStorage) {
require("./plugins/storage").emptyDir();
(await import("./plugins/storage")).default.emptyDir();
}
changelog.checkForUpdates(manager);
@ -949,7 +952,9 @@ function reverseDnsLookup(ip, callback) {
dns.resolve(hostnames[0], net.isIP(ip) === 6 ? "AAAA" : "A", (resolveErr, resolvedIps) => {
// TODO: investigate SoaRecord class
if (!Array.isArray(resolvedIps)) return callback(ip);
if (!Array.isArray(resolvedIps)) {
return callback(ip);
}
if (resolveErr || resolvedIps.length < 1) {
return callback(ip);

12
src/types/index.d.ts vendored
View file

@ -1,6 +1,6 @@
/// <reference path="models/index.d.ts" />
/// <reference path="plugins/index.d.ts" />
/// <reference path="config.d.ts" />
/// <reference path="helper.d.ts" />
/// <reference path="server.d.ts" />
/// <reference path="client.d.ts" />
// / <reference path="models/index.d.ts" />
// / <reference path="plugins/index.d.ts" />
// / <reference path="config.d.ts" />
// / <reference path="helper.d.ts" />
// / <reference path="server.d.ts" />
// / <reference path="client.d.ts" />

View file

@ -1,5 +1,5 @@
/// <reference path="channel.d.ts" />
/// <reference path="prefix.d.ts" />
/// <reference path="message.d.ts" />
/// <reference path="user.d.ts" />
/// <reference path="network.d.ts" />
// / <reference path="channel.d.ts" />
// / <reference path="prefix.d.ts" />
// / <reference path="message.d.ts" />
// / <reference path="user.d.ts" />
// / <reference path="network.d.ts" />

View file

@ -10,6 +10,7 @@ declare global {
type MessagePreview = {
shown: boolean;
link: string;
body: string;
};
export enum MessageType {

View file

@ -109,7 +109,7 @@ declare module "irc-framework" {
// TODO: typeof e?
invite(channel: string, nick: string): void;
addInvite(channel: String, mask: string): void;
addInvite(channel: string, mask: string): void;
removeInvite(channel: string, mask: string): void;
@ -353,7 +353,7 @@ declare module "irc-framework" {
* one_way (false) Only relay messages to target_chan, not the reverse
* replay_nicks (true) Include the sending nick as part of the relayed message
*/
relay(target_chan: IrcChannel | String, opts: Object): void;
relay(target_chan: IrcChannel | string, opts: Object): void;
// stream(stream_ops: Object): DuplexStream;

View file

@ -1,2 +1,2 @@
/// <reference path="themes.d.ts" />
/// <reference path="packages.d.ts" />
// / <reference path="themes.d.ts" />
// / <reference path="packages.d.ts" />

View file

@ -1,7 +1,7 @@
/// <reference path="sts.d.ts" />
/// <reference path="messageStorage/index.d.ts" />
/// <reference path="clientCertificate.d.ts" />
/// <reference path="preview.d.ts" />
/// <reference path="inputs/index.d.ts" />
/// <reference path="irc-events/index.d.ts" />
/// <reference path="auth/index.d.ts" />
// / <reference path="sts.d.ts" />
// / <reference path="messageStorage/index.d.ts" />
// / <reference path="clientCertificate.d.ts" />
// / <reference path="preview.d.ts" />
// / <reference path="inputs/index.d.ts" />
// / <reference path="irc-events/index.d.ts" />
// / <reference path="auth/index.d.ts" />

View file

@ -1,8 +1,8 @@
"use strict";
import {expect} from "chai";
const fs = require("fs");
const path = require("path");
import fs from "fs";
import path from "path";
describe("public folder", function () {
const publicFolder = path.join(__dirname, "..", "..", "public");

View file

@ -1,10 +1,10 @@
"use strict";
import {expect} from "chai";
const stub = require("sinon").stub;
const log = require("../../src/log");
const Client = require("../../src/client");
const TestUtil = require("../util");
import {stub} from "sinon";
import log from "../../src/log";
import Client from "../../src/client";
import TestUtil from "../util";
describe("Custom highlights", function () {
let userLoadedLog = "";
@ -19,7 +19,7 @@ describe("Custom highlights", function () {
newHash: "",
};
},
},
} as any,
"test",
{
clientSettings: {
@ -46,7 +46,7 @@ describe("Custom highlights", function () {
];
for (const teststring of teststrings) {
expect(teststring).to.not.match(client.highlightRegex);
expect(teststring).to.not.match(client.highlightRegex!);
}
});
@ -81,7 +81,7 @@ describe("Custom highlights", function () {
];
for (const teststring of teststrings) {
expect(teststring).to.match(client.highlightRegex);
expect(teststring).to.match(client.highlightRegex!);
}
});
@ -110,7 +110,7 @@ describe("Custom highlights", function () {
];
for (const teststring of teststrings) {
expect(teststring).to.match(client.highlightExceptionRegex);
expect(teststring).to.match(client.highlightExceptionRegex!);
}
});
@ -145,7 +145,7 @@ describe("Custom highlights", function () {
];
for (const teststring of teststrings) {
expect(teststring).to.not.match(client.highlightExceptionRegex);
expect(teststring).to.not.match(client.highlightExceptionRegex!);
}
});
});

View file

@ -1,7 +1,7 @@
"use strict";
import {expect} from "chai";
const Helper = require("../../src/helper");
import Helper from "../../src/helper";
describe("HexIP", function () {
it("should correctly convert IPv4 to hex", function () {

View file

@ -16,7 +16,7 @@
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
// "skipLibCheck": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
},
"files": ["./package.json", "./src/**/*.d.ts"]

View file

@ -5,7 +5,6 @@ import * as path from "path";
import CopyPlugin from "copy-webpack-plugin";
import MiniCssExtractPlugin from "mini-css-extract-plugin";
// TODO; we should add a declaration file
//@ts-ignore
import VueLoaderPlugin from "vue-loader/lib/plugin";
import babelConfig from "./babel.config.cjs";
import Helper from "./src/helper";
@ -158,9 +157,9 @@ export default (env: any, argv: any) => {
// Add the istanbul plugin to babel-loader options
for (const rule of config.module!.rules!) {
//@ts-ignore
// @ts-ignore
if (rule.use.loader === "babel-loader") {
//@ts-ignore
// @ts-ignore
rule.use.options.plugins = ["istanbul"];
}
}

View file

@ -8868,7 +8868,7 @@ verror@^1.8.1:
core-util-is "1.0.2"
extsprintf "^1.2.0"
vue-eslint-parser@^8.0.1:
vue-eslint-parser@8.3.0, vue-eslint-parser@^8.0.1:
version "8.3.0"
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz#5d31129a1b3dd89c0069ca0a1c88f970c360bd0d"
integrity sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g==