diff --git a/.eslintignore b/.eslintignore
deleted file mode 100644
index 15a75b0e8..000000000
--- a/.eslintignore
+++ /dev/null
@@ -1,7 +0,0 @@
-node_modules
-dist
-README.md
-COPYING
-src/webrtc
-scripts/
-assets
\ No newline at end of file
diff --git a/.eslintrc b/.eslintrc
deleted file mode 100644
index 40eac134a..000000000
--- a/.eslintrc
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
- "parser": "@typescript-eslint/parser",
- "plugins": ["@typescript-eslint"],
- "root": true,
- "rules": {
- "no-mixed-spaces-and-tabs": "off",
- "@typescript-eslint/no-inferrable-types": "off", // Required by typeorm
- "@typescript-eslint/no-var-requires": "off" // Sometimes requred by typeorm to resolve circular deps
- },
- "env": {
- "node": true
- }
-}
diff --git a/eslint.config.mjs b/eslint.config.mjs
new file mode 100644
index 000000000..e321115cc
--- /dev/null
+++ b/eslint.config.mjs
@@ -0,0 +1,47 @@
+import typescriptEslint from "@typescript-eslint/eslint-plugin";
+import globals from "globals";
+import tsParser from "@typescript-eslint/parser";
+import path from "node:path";
+import { fileURLToPath } from "node:url";
+import js from "@eslint/js";
+import { FlatCompat } from "@eslint/eslintrc";
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+const compat = new FlatCompat({
+ baseDirectory: __dirname,
+ recommendedConfig: js.configs.recommended,
+ allConfig: js.configs.all
+});
+
+export default [{
+ ignores: [
+ "**/node_modules",
+ "**/dist",
+ "**/README.md",
+ "**/COPYING",
+ "src/webrtc",
+ "**/scripts/",
+ "**/assets",
+ ],
+}, ...compat.extends("eslint:recommended", "plugin:@typescript-eslint/recommended"), {
+ plugins: {
+ "@typescript-eslint": typescriptEslint,
+ },
+
+ languageOptions: {
+ globals: {
+ ...globals.node,
+ },
+
+ parser: tsParser,
+ },
+
+ rules: {
+ "no-mixed-spaces-and-tabs": "off",
+ "@typescript-eslint/no-inferrable-types": "off", // Required by typeorm
+ "@typescript-eslint/no-var-requires": "off", // Sometimes requred by typeorm to resolve circular deps
+ "@typescript-eslint/no-require-imports": "off",
+ "@typescript-eslint/no-unused-vars": "off",
+ },
+}];
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 9d91c0e6b..7ea21c4e7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -53,6 +53,8 @@
"ws": "^8.18.0"
},
"devDependencies": {
+ "@eslint/eslintrc": "^3.1.0",
+ "@eslint/js": "^9.14.0",
"@types/amqplib": "^0.10.5",
"@types/bcrypt": "^5.0.2",
"@types/body-parser": "^1.19.5",
@@ -76,6 +78,7 @@
"@typescript-eslint/parser": "^8.12.2",
"eslint": "^9.13.0",
"express": "^4.21.1",
+ "globals": "^15.12.0",
"husky": "^9.1.6",
"prettier": "^3.3.3",
"pretty-quick": "^4.0.0",
@@ -1202,7 +1205,6 @@
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz",
"integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
@@ -1249,6 +1251,18 @@
"concat-map": "0.0.1"
}
},
+ "node_modules/@eslint/eslintrc/node_modules/globals": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
+ "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -1270,11 +1284,10 @@
}
},
"node_modules/@eslint/js": {
- "version": "9.13.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.13.0.tgz",
- "integrity": "sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==",
+ "version": "9.14.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.14.0.tgz",
+ "integrity": "sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==",
"dev": true,
- "license": "MIT",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
@@ -5878,6 +5891,15 @@
"url": "https://opencollective.com/eslint"
}
},
+ "node_modules/eslint/node_modules/@eslint/js": {
+ "version": "9.13.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.13.0.tgz",
+ "integrity": "sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==",
+ "dev": true,
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
"node_modules/eslint/node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -6735,11 +6757,10 @@
}
},
"node_modules/globals": {
- "version": "14.0.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
- "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
+ "version": "15.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-15.12.0.tgz",
+ "integrity": "sha512-1+gLErljJFhbOVyaetcwJiJ4+eLe45S2E7P5UiZ9xGfeq3ATQf5DOv9G7MH3gGbKQLkzmNh2DxfZwLdw+j6oTQ==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=18"
},
diff --git a/package.json b/package.json
index b87dc6fc1..c2f3536dd 100644
--- a/package.json
+++ b/package.json
@@ -38,6 +38,8 @@
},
"homepage": "https://spacebar.chat",
"devDependencies": {
+ "@eslint/eslintrc": "^3.1.0",
+ "@eslint/js": "^9.14.0",
"@types/amqplib": "^0.10.5",
"@types/bcrypt": "^5.0.2",
"@types/body-parser": "^1.19.5",
@@ -61,6 +63,7 @@
"@typescript-eslint/parser": "^8.12.2",
"eslint": "^9.13.0",
"express": "^4.21.1",
+ "globals": "^15.12.0",
"husky": "^9.1.6",
"prettier": "^3.3.3",
"pretty-quick": "^4.0.0",
diff --git a/src/api/middlewares/Authentication.ts b/src/api/middlewares/Authentication.ts
index b5204ffcf..b4f484776 100644
--- a/src/api/middlewares/Authentication.ts
+++ b/src/api/middlewares/Authentication.ts
@@ -108,7 +108,6 @@ export async function Authentication(
req.rights = new Rights(Number(user.rights));
return next();
} catch (error) {
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return next(new HTTPError(error!.toString(), 400));
}
}
diff --git a/src/api/routes/auth/reset.ts b/src/api/routes/auth/reset.ts
index b3ca1e9e2..da4d3334b 100644
--- a/src/api/routes/auth/reset.ts
+++ b/src/api/routes/auth/reset.ts
@@ -72,7 +72,6 @@ router.post(
await User.update({ id: user.id }, data);
// come on, the user has to have an email to reset their password in the first place
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
await Email.sendPasswordChanged(user, user.email!);
res.json({ token: await generateToken(user.id) });
diff --git a/src/gateway/opcodes/Identify.ts b/src/gateway/opcodes/Identify.ts
index 94320eee0..c6f987fc7 100644
--- a/src/gateway/opcodes/Identify.ts
+++ b/src/gateway/opcodes/Identify.ts
@@ -171,7 +171,6 @@ export async function onIdentify(this: WebSocket, data: Payload) {
// but we do want almost everything from guild.
// How do you do that without just enumerating the guild props?
guild: Object.fromEntries(
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
getDatabase()!
.getMetadata(Guild)
.columns.map((x) => [x.propertyName, true]),
diff --git a/src/gateway/opcodes/LazyRequest.ts b/src/gateway/opcodes/LazyRequest.ts
index 45eaccfaf..eba284b2f 100644
--- a/src/gateway/opcodes/LazyRequest.ts
+++ b/src/gateway/opcodes/LazyRequest.ts
@@ -214,7 +214,6 @@ async function subscribeToMemberEvents(this: WebSocket, user_id: string) {
export async function onLazyRequest(this: WebSocket, { d }: Payload) {
// TODO: check data
check.call(this, LazyRequestSchema, d);
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
const { guild_id, typing, channels, activities, members } =
d as LazyRequestSchema;
diff --git a/src/gateway/opcodes/VoiceStateUpdate.ts b/src/gateway/opcodes/VoiceStateUpdate.ts
index ffc143eda..b45c82031 100644
--- a/src/gateway/opcodes/VoiceStateUpdate.ts
+++ b/src/gateway/opcodes/VoiceStateUpdate.ts
@@ -99,7 +99,6 @@ export async function onVoiceStateUpdate(this: WebSocket, data: Payload) {
voiceState.token = genVoiceToken();
voiceState.session_id = this.session_id;
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
const { id, ...newObj } = voiceState;
await Promise.all([
diff --git a/src/util/entities/BaseClass.ts b/src/util/entities/BaseClass.ts
index f4b3cf599..0171e0108 100644
--- a/src/util/entities/BaseClass.ts
+++ b/src/util/entities/BaseClass.ts
@@ -46,7 +46,7 @@ export class BaseClassWithoutId extends BaseEntity {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
toJSON(): any {
return Object.fromEntries(
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment, @typescript-eslint/no-non-null-assertion
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
this.metadata!.columns // @ts-ignore
.map((x) => [x.propertyName, this[x.propertyName]])
.concat(
diff --git a/src/util/schemas/MessageCreateSchema.ts b/src/util/schemas/MessageCreateSchema.ts
index 15537ca86..4eaf7c961 100644
--- a/src/util/schemas/MessageCreateSchema.ts
+++ b/src/util/schemas/MessageCreateSchema.ts
@@ -69,7 +69,6 @@ export interface MessageCreateSchema {
}
// TypeScript complains once this is used above
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface PollCreationSchema {
question: PollMedia;
answers: PollAnswer[];
diff --git a/src/util/schemas/responses/TeamListResponse.ts b/src/util/schemas/responses/TeamListResponse.ts
index 375f0ae63..c4a7d1775 100644
--- a/src/util/schemas/responses/TeamListResponse.ts
+++ b/src/util/schemas/responses/TeamListResponse.ts
@@ -18,4 +18,5 @@
import { Team } from "@spacebar/util";
+// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export interface TeamListResponse extends Array<Team> {}
diff --git a/src/util/util/AutoUpdate.ts b/src/util/util/AutoUpdate.ts
index b7721cdb7..9a3c0a2ab 100644
--- a/src/util/util/AutoUpdate.ts
+++ b/src/util/util/AutoUpdate.ts
@@ -70,7 +70,6 @@ export function enableAutoUpdate(opts: {
});
}
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
async function download(url: string, dir: string) {
try {
// TODO: use file stream instead of buffer (to prevent crash because of high memory usage for big files)
diff --git a/src/util/util/Event.ts b/src/util/util/Event.ts
index 01f4911a6..bbc93aacb 100644
--- a/src/util/util/Event.ts
+++ b/src/util/util/Event.ts
@@ -100,6 +100,7 @@ export async function listenEvent(
};
const listener = (msg: ProcessEvent) => {
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
msg.type === "event" &&
msg.id === event &&
callback({ ...msg.event, cancel });
diff --git a/src/util/util/Sentry.ts b/src/util/util/Sentry.ts
index 510ed4533..005b09e72 100644
--- a/src/util/util/Sentry.ts
+++ b/src/util/util/Sentry.ts
@@ -117,7 +117,7 @@ export const Sentry = {
Integrations.setupExpressErrorHandler(app);
// The typings for this are broken?
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
app.use(function onError(err: any, req: any, res: any, next: any) {
res.statusCode = 500;
res.end(res.sentry + "\n");
|