eslint.config.js (158 lines of code) (raw):

/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import { dirname } from "node:path"; import { fileURLToPath } from "node:url"; import { FlatCompat } from "@eslint/eslintrc"; import checkFile from "eslint-plugin-check-file"; import header from "eslint-plugin-header"; import importPlugin from "eslint-plugin-import"; import jestPlugin from "eslint-plugin-jest"; import js from "@eslint/js"; import jsdoc from "eslint-plugin-jsdoc"; import tsEslint from "@typescript-eslint/eslint-plugin"; import tsParser from "@typescript-eslint/parser"; const __dirname = dirname(fileURLToPath(import.meta.url)); const compat = new FlatCompat({ baseDirectory: __dirname, recommendedConfig: js.configs.recommended, }); // Workaround for a compatibility issue between eslint-plugin-header and ESLint v9: // See https://github.com/Stuk/eslint-plugin-header/issues/59 // TODO: This line can be removed and the default header config can be used // again after the aforementioned issue has been fixed. header.rules.header.meta.schema = false; const config = [ ...compat.config({ extends: ["next"], }), { languageOptions: { ecmaVersion: "latest", sourceType: "module", parser: tsParser, parserOptions: { project: "tsconfig.json", }, }, ignores: ["coverage", "dist"], plugins: { jsdoc, "@typescript-eslint": tsEslint, import: importPlugin, header, "check-file": checkFile, jest: jestPlugin, }, settings: { "import/parsers": { "@typescript-eslint/parser": [".ts", ".tsx"], }, "import/resolver": { typescript: true, node: true, }, }, rules: { "header/header": [ "warn", "block", [ " This Source Code Form is subject to the terms of the Mozilla Public", " * License, v. 2.0. If a copy of the MPL was not distributed with this", " * file, You can obtain one at http://mozilla.org/MPL/2.0/. ", ], 2, ], // For some reason `eqeqeq` is not in the recommended set, but we try to // avoid implicit type casting, cause that’s where bugs lurk: eqeqeq: "error", "jsdoc/tag-lines": ["error", "any", { startLines: 1 }], "jsdoc/require-jsdoc": "off", "jsdoc/require-param-type": "off", "jsdoc/require-param-description": "off", "jsdoc/require-property-description": "off", "jsdoc/require-returns": "off", "jsdoc/require-returns-type": "off", "jsdoc/require-returns-description": "off", // Unused vars that start with an understore are allowed to be unused: "@typescript-eslint/no-unused-vars": [ "warn", { argsIgnorePattern: "^_", varsIgnorePattern: "^_", }, ], "no-restricted-imports": [ "error", { patterns: [ { group: ["**/hooks/*"], importNames: ["useGlean", "useGa"], message: "Please refrain from using this hook standalone. The preferred way to record telemetry is through `useTelemetry`.", }, ], paths: [ { name: "react-aria", importNames: ["VisuallyHidden"], message: "Please use the <VisuallyHidden> component from `/src/app/components/server/VisuallyHidden.tsx` instead of the one from react-aria, since the latter’s (inline) styles will be stripped by our Content Security Policy.", }, { name: "next-auth", importNames: ["getServerSession"], message: "Please use the `getServerSession` wrapper function from `/src/app/functions/server/getServerSession.ts` instead of the one from next-auth, since the latter’s doesn’t enforce passing the auth configuration object, resulting in broken sessions.", }, { name: "next-auth/next", importNames: ["getServerSession"], message: "Please use the `getServerSession` wrapper function from `/src/app/functions/server/getServerSession.ts` instead of the one from next-auth, since the latter’s doesn’t enforce passing the auth configuration object, resulting in broken sessions.", }, { name: "server-only", message: "Please import `/src/app/functions/server/notInClientComponent` instead of `server-only`, since the latter will also error in non-Next.js environments like cron jobs.", }, ], }, ], "@typescript-eslint/ban-ts-comment": [ "error", { "ts-ignore": "allow-with-description", }, ], "check-file/filename-naming-convention": [ "error", { "**/*.{js,css} !src/db/migrations": "CAMEL_CASE" }, { ignoreMiddleExtensions: true }, ], }, }, { files: ["next-env.d.ts"], rules: { "header/header": "off" }, }, { files: ["**/*.test.{ts,tsx,js}"], plugins: { jest: jestPlugin }, rules: jestPlugin.configs.recommended.rules, }, { // Only enable rules that depend on type checking on TS files. files: ["**/*.{ts,tsx}"], languageOptions: { // See https://typescript-eslint.io/linting/typed-linting/#specifying-tsconfigs // Needed for `plugin:@typescript-eslint/recommended-requiring-type-checking` // to avoid this error: // > You have used a rule which requires parserServices to be generated. // > You must therefore provide a value for the "parserOptions.project" // > property for @typescript-eslint/parser. parser: tsParser, parserOptions: { project: "tsconfig.json" }, }, plugins: { "@typescript-eslint": tsEslint }, rules: { ...tsEslint.configs["recommended"].rules, "@typescript-eslint/no-unsafe-argument": "off", "@typescript-eslint/no-unsafe-assignment": "off", "@typescript-eslint/no-unsafe-member-access": "off", "@typescript-eslint/no-unsafe-call": "off", }, }, // Next is not running ESLint on root files by default. The only way to // include those would be to explicitly add them one by one. Instead, we // run ESLint directly in addition to next lint on just the root files. // For more info see: // https://nextjs.org/docs/app/api-reference/config/eslint#linting-custom-directories-and-files { files: ["*.{js,cjs,ts}"], languageOptions: { parserOptions: { project: null }, }, }, ]; export default config;