diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index b2352cd3..00000000 --- a/.eslintignore +++ /dev/null @@ -1,10 +0,0 @@ -# Paths ESLint should never check -!.github -dist -**/node_modules -out -test-artifacts/ -test-resources/ -submodules/ -.vscode-test/ -vscode.proposed.d.ts diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index fecaca7d..00000000 --- a/.eslintrc.js +++ /dev/null @@ -1,146 +0,0 @@ -module.exports = { - root: true, - env: { - es6: true, - node: true, - }, - extends: [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:prettier/recommended", - ], - globals: { - Atomics: "readonly", - SharedArrayBuffer: "readonly", - }, - parser: "@typescript-eslint/parser", - parserOptions: { - ecmaVersion: 6, - sourceType: "module", - }, - plugins: ["@typescript-eslint", "prettier", "sort-class-members"], - rules: { - "no-unused-vars": "off", - // unused vars are allowed if they start with an underscore - "@typescript-eslint/no-unused-vars": [ - "warn", - { - varsIgnorePattern: "^_", - argsIgnorePattern: "^_", - caughtErrorsIgnorePattern: "^_", - destructuredArrayIgnorePattern: "^_", - }, - ], - - "@typescript-eslint/ban-ts-comment": ["error", { "ts-ignore": "allow-with-description" }], - curly: "error", - "sort-imports": [ - "error", - { - ignoreCase: true, - ignoreDeclarationSort: true, - }, - ], - "@typescript-eslint/no-var-requires": "off", - // == disabled default configs from svelte template == - /* - "@typescript-eslint/no-use-before-define": [ - "error", - { - classes: false, - functions: false, - }, - ], - quotes: "off", - "@typescript-eslint/quotes": ["error", "double", { avoidEscape: true }], - "@typescript-eslint/explicit-function-return-type": "off", - "@typescript-eslint/explicit-module-boundary-types": "off", - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/no-var-requires": "off", - "@typescript-eslint/semi": ["error"], - "@typescript-eslint/lines-between-class-members": [ - "error", - "always", - { exceptAfterSingleLine: true }, - ], - "@typescript-eslint/naming-convention": [ - "error", - { - selector: "function", - format: ["camelCase"], - }, - { - selector: "method", - modifiers: ["public"], - format: ["camelCase"], - }, - { - selector: "method", - modifiers: ["private"], - format: ["camelCase"], - leadingUnderscore: "require", - }, - { - selector: "property", - modifiers: ["private"], - format: ["camelCase"], - leadingUnderscore: "require", - }, - { - selector: "typeLike", - format: ["PascalCase"], - }, - ], - "max-len": [ - "warn", - { - code: 130, - comments: 100, - ignoreComments: false, - }, - ], - eqeqeq: ["error"], - "sort-class-members/sort-class-members": [ - 2, - { - order: [ - "[static-properties]", - "[static-methods]", - "[properties]", - "[conventional-private-properties]", - "constructor", - "[methods]", - "[conventional-private-methods]", - "[everything-else]", - ], - accessorPairPositioning: "getThenSet", - }, - ], - "no-throw-literal": "warn", - semi: "off", - */ - }, - ignorePatterns: ["webview-ui/**"], - overrides: [ - { - files: ["*.ts", "*.tsx"], - rules: { - "@typescript-eslint/explicit-function-return-type": ["error"], - "@typescript-eslint/explicit-module-boundary-types": ["error"], - "@typescript-eslint/no-var-requires": ["error"], - }, - }, - { - files: ["*.test.ts", "*.spec.ts"], - rules: { - "@typescript-eslint/no-unused-expressions": "off", - }, - }, - { - files: ["*.js"], - rules: { - "@typescript-eslint/no-require-imports": "off", - }, - }, - ], -}; diff --git a/backend/controllers/oauth.ts b/backend/controllers/oauth.ts index 04de98a2..9e39e8ec 100644 --- a/backend/controllers/oauth.ts +++ b/backend/controllers/oauth.ts @@ -1,13 +1,11 @@ import { Response, Router } from "express"; -/* eslint-disable @typescript-eslint/naming-convention */ interface Token { access_token: string; token_type: "bearer"; scope: "public"; created_at: number; } -/* eslint-enable @typescript-eslint/naming-convention */ const USER = { username: "TestMyExtension", diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 00000000..cec83593 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,114 @@ +import typescriptEslint from "@typescript-eslint/eslint-plugin"; +import prettier from "eslint-plugin-prettier"; +import sortClassMembers from "eslint-plugin-sort-class-members"; +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: [ + "!**/.github", + "**/dist", + "**/node_modules", + "**/out", + "**/test-artifacts/", + "**/test-resources/", + "**/submodules/", + "**/.vscode-test/", + "**/vscode.proposed.d.ts", + "**/build/", + ], + }, + ...compat.extends( + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended", + ), + { + plugins: { + "@typescript-eslint": typescriptEslint, + prettier, + "sort-class-members": sortClassMembers, + }, + + languageOptions: { + globals: { + ...globals.node, + Atomics: "readonly", + SharedArrayBuffer: "readonly", + }, + + parser: tsParser, + ecmaVersion: 6, + sourceType: "module", + }, + + rules: { + "no-unused-vars": "off", + + "@typescript-eslint/no-unused-vars": [ + "warn", + { + varsIgnorePattern: "^_", + argsIgnorePattern: "^_", + caughtErrorsIgnorePattern: "^_", + destructuredArrayIgnorePattern: "^_", + }, + ], + + "@typescript-eslint/ban-ts-comment": [ + "error", + { + "ts-ignore": "allow-with-description", + }, + ], + + curly: "error", + + "sort-imports": [ + "error", + { + ignoreCase: true, + ignoreDeclarationSort: true, + }, + ], + + "@typescript-eslint/no-var-requires": "off", + }, + }, + { + files: ["**/*.ts", "**/*.tsx"], + + rules: { + "@typescript-eslint/explicit-function-return-type": ["error"], + "@typescript-eslint/explicit-module-boundary-types": ["error"], + "@typescript-eslint/no-var-requires": ["error"], + }, + }, + { + files: ["**/*.test.ts", "**/*.spec.ts"], + + rules: { + "@typescript-eslint/no-unused-expressions": "off", + }, + }, + { + files: ["**/*.js", "**/*.ts"], + + rules: { + "@typescript-eslint/no-require-imports": "off", + }, + }, +]; diff --git a/package-lock.json b/package-lock.json index bdb01d96..30e5ee64 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,8 @@ "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-react-jsx": "^7.25.2", "@babel/preset-env": "^7.25.4", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "^9.10.0", "@playwright/test": "1.46.1", "@types/chai": "^4.3.18", "@types/chai-as-promised": "^7.1.2", @@ -50,6 +52,7 @@ "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-sort-class-members": "^1.20.0", "glob": "^11.0.0", + "globals": "^15.9.0", "husky": "^9.1.5", "lint-staged": "^15.2.9", "mocha": "^10.7.3", @@ -1068,6 +1071,16 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-classes/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/plugin-transform-computed-properties": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", @@ -1948,6 +1961,16 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/types": { "version": "7.25.4", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.4.tgz", @@ -2124,9 +2147,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.9.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.1.tgz", - "integrity": "sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==", + "version": "9.10.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.10.0.tgz", + "integrity": "sha512-fuXtbiP5GWIn8Fz+LWoOMVf/Jxm+aajZYkhi6CuEm4SxymFM+eUWzbO9qXT+L0iCkL5+KGYMCSGxo686H19S1g==", "dev": true, "license": "MIT", "engines": { @@ -4373,6 +4396,16 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/@eslint/js": { + "version": "9.9.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.1.tgz", + "integrity": "sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/eslint/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -5079,13 +5112,16 @@ } }, "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "version": "15.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.9.0.tgz", + "integrity": "sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA==", "dev": true, "license": "MIT", "engines": { - "node": ">=4" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/globby": { @@ -10365,6 +10401,14 @@ "@babel/helper-replace-supers": "^7.25.0", "@babel/traverse": "^7.25.4", "globals": "^11.1.0" + }, + "dependencies": { + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + } } }, "@babel/plugin-transform-computed-properties": { @@ -10927,6 +10971,14 @@ "@babel/types": "^7.25.4", "debug": "^4.3.1", "globals": "^11.1.0" + }, + "dependencies": { + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + } } }, "@babel/types": { @@ -11059,9 +11111,9 @@ } }, "@eslint/js": { - "version": "9.9.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.1.tgz", - "integrity": "sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==", + "version": "9.10.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.10.0.tgz", + "integrity": "sha512-fuXtbiP5GWIn8Fz+LWoOMVf/Jxm+aajZYkhi6CuEm4SxymFM+eUWzbO9qXT+L0iCkL5+KGYMCSGxo686H19S1g==", "dev": true }, "@eslint/object-schema": { @@ -12493,6 +12545,12 @@ "text-table": "^0.2.0" }, "dependencies": { + "@eslint/js": { + "version": "9.9.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.1.tgz", + "integrity": "sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==", + "dev": true + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -13000,9 +13058,9 @@ } }, "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "version": "15.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.9.0.tgz", + "integrity": "sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA==", "dev": true }, "globby": { diff --git a/package.json b/package.json index f0c475b6..fde30be3 100644 --- a/package.json +++ b/package.json @@ -28,8 +28,8 @@ "backend:start": "cd backend && npm run start", "ci:all": "npm ci && cd backend && npm ci && cd ../webview-ui && npm ci", "clean-local-rust-config": "cd backend && cd cli && rm -rf tmc-vscode_plugin", - "eslint": "ESLINT_USE_FLAT_CONFIG=false eslint --fix . --ext .js,.ts", - "eslint-check": "ESLINT_USE_FLAT_CONFIG=false eslint . --ext .js,.ts", + "eslint": "eslint --fix .", + "eslint-check": "eslint .", "postinstall": "babel node_modules/ts-results --out-dir node_modules/ts-results --plugins=@babel/plugin-transform-modules-commonjs", "install:all": "npm install && cd backend && npm install && cd ../webview-ui && npm install", "playwright-test": "npm run webview:build && npm run webpack && xvfb-maybe playwright test", @@ -460,6 +460,8 @@ "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-react-jsx": "^7.25.2", "@babel/preset-env": "^7.25.4", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "^9.10.0", "@playwright/test": "1.46.1", "@types/chai": "^4.3.18", "@types/chai-as-promised": "^7.1.2", @@ -484,6 +486,7 @@ "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-sort-class-members": "^1.20.0", "glob": "^11.0.0", + "globals": "^15.9.0", "husky": "^9.1.5", "lint-staged": "^15.2.9", "mocha": "^10.7.3", diff --git a/src/api/types.ts b/src/api/types.ts index ca2acb8d..146d48bc 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ - /** * GET /api/v8/core/org/{organization_slug}/courses */ diff --git a/src/config/constants.ts b/src/config/constants.ts index 30b845eb..66962691 100644 --- a/src/config/constants.ts +++ b/src/config/constants.ts @@ -1,6 +1,3 @@ -// Some templates on this page are very specific, so this rule is disabled here. -/* eslint-disable max-len */ - // Build time only globals defined in webpack configuration. These values are inlined when // compiling. declare const __DEBUG_MODE__: boolean; diff --git a/src/migrate/migrateUserData.ts b/src/migrate/migrateUserData.ts index 61b32a99..36bd9672 100644 --- a/src/migrate/migrateUserData.ts +++ b/src/migrate/migrateUserData.ts @@ -34,7 +34,6 @@ export interface LocalCourseDataV0 { perhapsExamMode?: boolean; title?: string; notifyAfter?: number; - // eslint-disable-next-line @typescript-eslint/naming-convention material_url?: string | null; } diff --git a/webview-ui/rollup.config.js b/webview-ui/rollup.config.js index 6da07f3a..65fc6a55 100644 --- a/webview-ui/rollup.config.js +++ b/webview-ui/rollup.config.js @@ -13,12 +13,16 @@ function serve() { let server; function toExit() { - if (server) server.kill(0); + if (server) { + server.kill(0); + } } return { writeBundle() { - if (server) return; + if (server) { + return; + } server = require("child_process").spawn("npm", ["run", "start", "--", "--dev"], { stdio: ["ignore", "inherit", "inherit"], shell: true, diff --git a/webview-ui/src/utilities/script.ts b/webview-ui/src/utilities/script.ts index 0b06cba0..550be76d 100644 --- a/webview-ui/src/utilities/script.ts +++ b/webview-ui/src/utilities/script.ts @@ -7,8 +7,8 @@ import { ExtensionToWebview, MyCoursesPanel, Panel, - TargetPanel, Targeted, + TargetPanel, WebviewToExtension, } from "../shared/shared"; import { vscode } from "./vscode"; @@ -49,7 +49,7 @@ export function loadable(): Writable { export function addMessageListener( listeningPanel: T, callback: (message: TargetedMessage) => void, -) { +): void { window.addEventListener("message", (event) => { const message: Message = event.data; // if no target id is given, accept all messages @@ -64,7 +64,7 @@ export function addMessageListener( /** * Posts a message to another webview. */ -export function postMessageToWebview(message: WebviewToWebview) { +export function postMessageToWebview(message: WebviewToWebview): void { // relay the message through the extension host const webviewToExtension: WebviewToExtension = { type: "relayToWebview", @@ -73,6 +73,6 @@ export function postMessageToWebview(message: WebviewToWebview) { vscode.postMessage(webviewToExtension); } -export function savePanelState(panel: Panel) { +export function savePanelState(panel: Panel): void { vscode.setState({ panel }); } diff --git a/webview-ui/src/utilities/vscode.ts b/webview-ui/src/utilities/vscode.ts index d8b0e577..c9ce70d2 100644 --- a/webview-ui/src/utilities/vscode.ts +++ b/webview-ui/src/utilities/vscode.ts @@ -1,5 +1,5 @@ import type { WebviewApi } from "vscode-webview"; -import { WebviewToExtension, State } from "../shared/shared"; +import { State, WebviewToExtension } from "../shared/shared"; /** * A utility wrapper around the acquireVsCodeApi() function, which enables @@ -29,7 +29,7 @@ class VSCodeAPIWrapper { * * @param message Abitrary data (must be JSON serializable) to send to the extension context. */ - public postMessage(message: WebviewToExtension) { + public postMessage(message: WebviewToExtension): void { console.log("Message from webview", message); if (this.vsCodeApi) { this.vsCodeApi.postMessage(message);