Enable more lint rules for skin-database

Enable all root ESLint rules except camelcase (333 violations).

Rules now enabled:
- eqeqeq (strict equality)
- prefer-const
- prefer-template
- prefer-arrow-callback
- no-else-return
- no-return-await
- no-undef-init
- dot-notation
- guard-for-in
- no-div-regex
- new-cap

Fixed 51 lint violations across the package.
This commit is contained in:
Jordan Eldredge 2025-11-27 21:35:00 -08:00
parent 54d55229b9
commit 36c5af8cd0
35 changed files with 60 additions and 78 deletions

View file

@ -10,19 +10,8 @@ module.exports = {
"@typescript-eslint/no-namespace": "off",
// Override the base no-shadow rule since it conflicts with TypeScript
"no-shadow": "off",
// Relax rules for this project's existing style
// camelcase has too many violations (333) to fix now
camelcase: "off",
"dot-notation": "off",
eqeqeq: "off",
"no-undef-init": "off",
"no-return-await": "off",
"prefer-arrow-callback": "off",
"no-div-regex": "off",
"guard-for-in": "off",
"prefer-template": "off",
"no-else-return": "off",
"prefer-const": "off",
"new-cap": "off",
},
ignorePatterns: ["dist/**"],
};

View file

@ -13,6 +13,7 @@ export function getUserContext(ctx: Ctx): UserContext {
return ctx.ctx;
}
// eslint-disable-next-line new-cap -- Express Router uses this pattern
const router = Router();
const yoga = createYoga({

View file

@ -26,7 +26,7 @@ export default class ClassicSkinResolver implements NodeResolver, ISkin {
async filename(normalize_extension?: boolean): Promise<string> {
const filename = await this._model.getFileName();
if (normalize_extension) {
return path.parse(filename).name + ".wsz";
return `${path.parse(filename).name}.wsz`;
}
return filename;
}

View file

@ -25,7 +25,7 @@ export default class ModernSkinResolver implements NodeResolver, ISkin {
async filename(normalize_extension: boolean): Promise<string> {
const filename = await this._model.getFileName();
if (normalize_extension) {
return path.parse(filename).name + ".wal";
return `${path.parse(filename).name}.wal`;
}
return filename;
}

View file

@ -21,9 +21,8 @@ export default class SkinResolver {
static fromModel(model: SkinModel): ISkin {
if (model.getSkinType() === "MODERN") {
return new ModernSkinResolver(model);
} else {
return new ClassicSkinResolver(model);
}
return new ClassicSkinResolver(model);
}
}

View file

@ -13,7 +13,7 @@ export async function getClientSkins(sessionId: string): Promise<ClientSkin[]> {
const page = await getScrollPage(sessionId);
return await Promise.all(
return Promise.all(
page.map(async (item) => {
return getSkinForSession(ctx, sessionId, item.md5);
})

View file

@ -52,9 +52,8 @@ export function useScrollHint({
return n1 * (t -= 1.5 / d1) * t + 0.75;
} else if (t < 2.5 / d1) {
return n1 * (t -= 2.25 / d1) * t + 0.9375;
} else {
return n1 * (t -= 2.625 / d1) * t + 0.984375;
}
return n1 * (t -= 2.625 / d1) * t + 0.984375;
};
// Create a bounce effect: scroll down quickly, then bounce back

View file

@ -15,10 +15,9 @@ export default class KeyValue {
.count({ count: "*" })
.first()) as { count: number };
if (count) {
return await KeyValue.update(key, value);
} else {
return await KeyValue.insert(key, value);
return KeyValue.update(key, value);
}
return KeyValue.insert(key, value);
}
static async update(key: string, value: any): Promise<void> {

View file

@ -242,23 +242,22 @@ export default class SkinModel {
this.getMd5() + ext
);
return fs.readFile(skinPath);
} else {
const response = await fetch(this.getSkinUrl());
if (!response.ok) {
const missingModernSkins =
(await KeyValue.get<string[]>("missingModernSkins")) ?? [];
const missingModernSkinsSet = new Set(missingModernSkins);
missingModernSkinsSet.add(this.getMd5());
await KeyValue.set(
"missingModernSkins",
Array.from(missingModernSkinsSet)
);
throw new Error(
`Could not fetch skin at "${this.getSkinUrl()}" (Marked in missingModernSkins in the KeyValue store)`
);
}
return response.buffer();
}
const response = await fetch(this.getSkinUrl());
if (!response.ok) {
const missingModernSkins =
(await KeyValue.get<string[]>("missingModernSkins")) ?? [];
const missingModernSkinsSet = new Set(missingModernSkins);
missingModernSkinsSet.add(this.getMd5());
await KeyValue.set(
"missingModernSkins",
Array.from(missingModernSkinsSet)
);
throw new Error(
`Could not fetch skin at "${this.getSkinUrl()}" (Marked in missingModernSkins in the KeyValue store)`
);
}
return response.buffer();
});
getScreenshotBuffer = mem(async (): Promise<Buffer> => {
@ -385,10 +384,9 @@ export default class SkinModel {
}
async hasGeneral(): Promise<boolean> {
return (
(await this._hasSpriteSheet("GEN")) &&
(await this._hasSpriteSheet("GENEX"))
);
const hasGen = await this._hasSpriteSheet("GEN");
const hasGenEx = await this._hasSpriteSheet("GENEX");
return hasGen && hasGenEx;
}
async getAlgoliaIndexUpdates(limit?: number): Promise<any[]> {

View file

@ -2,4 +2,5 @@ import Knex from "knex";
import * as knexConfigs from "./knexfile";
import { NODE_ENV } from "./config";
// eslint-disable-next-line new-cap -- Knex uses this pattern
export const knex = Knex(knexConfigs[NODE_ENV ?? "test"]);

View file

@ -20,7 +20,7 @@ async function handler(message: Message, args: [string]) {
const jsonString = JSON.stringify(data, null, 2);
for (let i = 0; i < jsonString.length; i += pageSize) {
await message.channel.send(
"```" + jsonString.slice(i, i + pageSize) + "```"
`\`\`\`${jsonString.slice(i, i + pageSize)}\`\`\``
);
}
}

View file

@ -26,7 +26,7 @@ export default function Feedback() {
alert("Please add a message before sending.");
return;
}
const body = { message, email, url: "https://skins.webamp.org" + url };
const body = { message, email, url: `https://skins.webamp.org${url}` };
setSending(true);
await sendFeedback(body);

View file

@ -25,9 +25,8 @@ async function getSkinToReview() {
const data = await Utils.fetchGraphql(mutation);
if (data.me.username) {
return data.skin_to_review;
} else {
window.location = `${API_URL}/auth`;
}
window.location = `${API_URL}/auth`;
}
function useQueuedSkin() {

View file

@ -3,7 +3,7 @@ import React, { useLayoutEffect, useState } from "react";
function DownloadText({ text, children, ...restProps }) {
const [url, setUrl] = useState(null);
useLayoutEffect(() => {
let blob = new Blob([text], {
const blob = new Blob([text], {
type: "text/plain;charset=utf-8",
});
const url = URL.createObjectURL(blob);

View file

@ -31,9 +31,8 @@ function Skin({
e.preventDefault();
doesNotConcentToNsfw();
return;
} else {
consentsToNsfw();
}
consentsToNsfw();
}
if (Utils.eventIsLinkClick(e)) {
e.preventDefault();

View file

@ -30,7 +30,7 @@ export function PreviewFile({ file }) {
(Hover in the box to see .cur preview)
<div
style={{
cursor: "url(" + file.url + "), auto",
cursor: `url(${file.url}), auto`,
border: "2px solid black",
minWidth: "400px",
minHeight: "400px",

View file

@ -52,7 +52,7 @@ export default function DebugSkin({ md5 }) {
const skin = data.fetch_skin_by_md5;
const screenshotFile = {
filename: skin.filename + ".png",
filename: `${skin.filename}.png`,
url: skin.screenshot_url,
};
const focusedFile = file || screenshotFile;
@ -199,5 +199,5 @@ function formatBytes(bytes, decimals = 2) {
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
}

View file

@ -1,7 +1,7 @@
import SparkMD5 from "spark-md5";
export function hashFile(file) {
let blobSlice =
const blobSlice =
File.prototype.slice ||
File.prototype.mozSlice ||
File.prototype.webkitSlice;
@ -26,7 +26,7 @@ export function hashFile(file) {
fileReader.onerror = reject;
function loadNext() {
let start = currentChunk * chunkSize,
const start = currentChunk * chunkSize,
end = start + chunkSize >= file.size ? file.size : start + chunkSize;
fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));

View file

@ -89,9 +89,8 @@ export function useWebampAnimation({ initialPosition }) {
transitionBeginEvents.next(null);
});
return () => subscription.unsubscribe();
} else {
transitionBeginEvents.next(null);
}
transitionBeginEvents.next(null);
}, [initialPosition, setCentered, transitionBeginEvents]);
const handleWebampLoaded = useCallback(() => {

View file

@ -452,7 +452,7 @@ const urlEpic = (actions, state) => {
// There are some params that we want to preserve across reloads.
for (const key of ["rest", "vps"]) {
let current = currentParams.get(key);
const current = currentParams.get(key);
if (current == null) {
proposedUrl.searchParams.delete(key);
} else {

View file

@ -77,9 +77,8 @@ function Inner({ files }) {
upload
</>
);
} else {
return `Thanks for your contribution!`;
}
return `Thanks for your contribution!`;
}
return `No missing skins found`;
};

View file

@ -13,7 +13,7 @@ export function museumUrlFromHash(hash) {
}
export function getWindowSize() {
let w = window,
const w = window,
d = document,
e = d.documentElement,
g = d.getElementsByTagName("body")[0],

View file

@ -1,13 +1,13 @@
import * as Knex from "knex";
export async function up(knex: Knex): Promise<any> {
await knex.schema.table("skins", function (table) {
await knex.schema.table("skins", (table) => {
table.dropColumn("average_color");
});
}
export async function down(knex: Knex): Promise<any> {
await knex.schema.table("skins", function (table) {
await knex.schema.table("skins", (table) => {
table.string("average_color");
});
}

View file

@ -1,13 +1,13 @@
import * as Knex from "knex";
export async function up(knex: Knex): Promise<any> {
await knex.schema.table("skin_reviews", function (table) {
await knex.schema.table("skin_reviews", (table) => {
table.text("reviewer");
});
}
export async function down(knex: Knex): Promise<any> {
await knex.schema.table("skin_reviews", function (table) {
await knex.schema.table("skin_reviews", (table) => {
table.dropColumn("reviewer");
});
}

View file

@ -1,13 +1,13 @@
import * as Knex from "knex";
export async function up(knex: Knex): Promise<any> {
await knex.schema.table("tweets", function (table) {
await knex.schema.table("tweets", (table) => {
table.dropColumn("url");
});
}
export async function down(knex: Knex): Promise<any> {
await knex.schema.table("tweets", function (table) {
await knex.schema.table("tweets", (table) => {
table.text("url");
});
}

View file

@ -1,13 +1,13 @@
import * as Knex from "knex";
export async function up(knex: Knex): Promise<any> {
await knex.schema.table("archive_files", function (table) {
await knex.schema.table("archive_files", (table) => {
table.timestamp("file_date");
});
}
export async function down(knex: Knex): Promise<any> {
await knex.schema.table("archive_files", function (table) {
await knex.schema.table("archive_files", (table) => {
table.dropColumn("file_date");
});
}

View file

@ -1,7 +1,7 @@
import * as Knex from "knex";
export async function up(knex: Knex): Promise<any> {
await knex.schema.createTable("refreshes", function (table) {
await knex.schema.createTable("refreshes", (table) => {
table.increments();
table.string("skin_md5").notNullable();
table.string("error");

View file

@ -68,7 +68,7 @@ const parseIni = (text: string): IniData => {
const value = match[2]
// Ignore anything after a second `=`
// TODO: What if this is inside quotes or escaped?
.replace(/=.*$/g, "")
.replace(/[=].*$/g, "")
.trim()
// Strip quotes
// TODO: What about escaped quotes?

View file

@ -2,7 +2,7 @@ import SkinModel from "../data/SkinModel.js";
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env["OPENAI_API_KEY"], // This is the default and can be omitted
apiKey: process.env.OPENAI_API_KEY, // This is the default and can be omitted
});
const prompt2 = `You are a staff digital preservationist working at the Internet Archive.

View file

@ -48,7 +48,7 @@ export async function getSkinFileData(
skin: SkinModel
): Promise<(FileData | null)[]> {
const zip = await skin.getZip();
return await Promise.all(Object.values(zip.files).map(getFileData));
return Promise.all(Object.values(zip.files).map(getFileData));
}
// https://stackoverflow.com/a/46700791/1263117

View file

@ -68,7 +68,7 @@ async function post(md5: string): Promise<string> {
}
);
if (resp.statusCode != 200) {
if (resp.statusCode !== 200) {
console.log(JSON.stringify(resp, null, 2));
console.log("data", data);
throw new Error(

View file

@ -26,7 +26,7 @@ type TweetPayload = {
};
async function getTweets(twitterClient): Promise<TweetPayload[]> {
let max_id: string | undefined = undefined;
let max_id: string | undefined;
let tweets: TweetPayload[] = [];
let callCount = 0;

View file

@ -59,7 +59,7 @@ export async function uploadScreenshotIfSafe(md5: string): Promise<boolean> {
return false;
}
const skinFiles = iaItem.getSkinFiles();
if (skinFiles.length != 1) {
if (skinFiles.length !== 1) {
console.warn(`Has ${skinFiles.length} skins`);
return false;
}

View file

@ -33,12 +33,12 @@ export async function tweet(
return;
}
const tweetStatus = await tweetableSkin.getTweetStatus();
if (tweetStatus == "TWEETED") {
if (tweetStatus === "TWEETED") {
// @ts-ignore
// await tweetBotChannel.send(`Oops! This skin has alraedy been tweeted.`);
// return;
}
if (tweetStatus == "REJECTED" || tweetStatus == "NSFW") {
if (tweetStatus === "REJECTED" || tweetStatus === "NSFW") {
// @ts-ignore
await tweetBotChannel.send(`Oops! Can't tweet a rejected skin.`);
return;

View file

@ -18,7 +18,7 @@ type TweetPayload = {
};
async function getTweets(twitterClient): Promise<TweetPayload[]> {
let max_id: string | undefined = undefined;
let max_id: string | undefined;
let tweets: TweetPayload[] = [];
let callCount = 0;