chore(deps): update dependency eslint to v9 (#452)

* chore(deps): update dependency eslint to v9

* chore: migrate eslint to v9

* fix: dependency issues

* fix: unit tests not working

* chore: disable lint check for Image component that does not work in ci

* fix: lint issue

---------

Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
Co-authored-by: Meier Lukas <meierschlumpf@gmail.com>
This commit is contained in:
homarr-renovate[bot]
2024-06-08 20:49:57 +02:00
committed by GitHub
parent d7ecdf5567
commit 1bae7352dc
117 changed files with 686 additions and 604 deletions

View File

@@ -1,80 +1,90 @@
/** @type {import("eslint").Linter.Config} */
const config = {
extends: [
"turbo",
"eslint:recommended",
"plugin:@typescript-eslint/recommended-type-checked",
"plugin:@typescript-eslint/stylistic-type-checked",
"prettier",
],
env: {
es2022: true,
node: true,
},
parser: "@typescript-eslint/parser",
parserOptions: {
project: true,
},
plugins: ["@typescript-eslint", "import"],
rules: {
"id-length": [
"warn",
{
min: 3,
exceptions: ["_", "i", "z", "t", "id", "db"], // _ for unused variables, i for index, z for zod, t for translation
properties: "never", // This allows for example the use of <Grid.Col span={{ sm: 12, md: 6 }}> as sm and md would be too short
},
],
"@typescript-eslint/prefer-nullish-coalescing": "off",
"turbo/no-undeclared-env-vars": "off",
"@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }],
"@typescript-eslint/consistent-type-imports": [
"warn",
{ prefer: "type-imports", fixStyle: "separate-type-imports" },
],
"@typescript-eslint/no-misused-promises": [2, { checksVoidReturn: { attributes: false } }],
"import/consistent-type-specifier-style": ["error", "prefer-top-level"],
"no-restricted-syntax": [
"error",
{
selector: "FunctionDeclaration[async=false][id.name=/Async$/]",
message: "Function ending in 'Async' must be declared async",
},
{
selector:
"FunctionDeclaration[async=true][id.name=/^[a-z].*$/][id.name=/ ^(?!generateMetadata$)[a-z].*$/][id.name!=/Async$/]",
message: "Async function name must end in 'Async' (function declaration)",
},
{
selector: "MethodDefinition[value.async=false][key.name=/Async$/]",
message: "Method ending in 'Async' must be declared async",
},
{
selector: "MethodDefinition[value.async=true][key.name!=/Async$/]",
message: "Async method name must end in 'Async'",
},
{
selector: "Property[value.type=/FunctionExpression$/][value.async=false][key.name=/Async$/]",
message: "Function ending in 'Async' must be declared async",
},
{
selector:
"Property[value.type=/FunctionExpression$/][value.async=true][key.name!=/^on(Success|Settled)$/][key.name!=/Async$/]",
message: "Async function name must end in 'Async' (property)",
},
{
selector: "VariableDeclarator[init.type=/FunctionExpression$/][init.async=false][id.name=/Async$/]",
message: "Function ending in 'Async' must be declared async",
},
{
selector:
"VariableDeclarator[init.type=/FunctionExpression$/][init.async=true][id.name=/^[a-z].*$/][id.name!=/Async$/]",
message: "Async function name must end in 'Async' (variable declarator)",
},
],
},
ignorePatterns: ["**/.eslintrc.cjs", "**/*.config.js", "**/*.config.cjs", ".next", "dist", "pnpm-lock.yaml"],
reportUnusedDisableDirectives: true,
};
/// <reference types="./types.d.ts" />
module.exports = config;
import eslint from "@eslint/js";
import importPlugin from "eslint-plugin-import";
import tseslint from "typescript-eslint";
export default tseslint.config(
{
// Globally ignored files
ignores: ["**/*.config.js"],
},
{
files: ["**/*.js", "**/*.ts", "**/*.tsx"],
plugins: {
import: importPlugin,
},
extends: [
eslint.configs.recommended,
...tseslint.configs.recommended,
...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.stylisticTypeChecked,
],
rules: {
"@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }],
"@typescript-eslint/consistent-type-imports": [
"warn",
{ prefer: "type-imports", fixStyle: "separate-type-imports" },
],
"@typescript-eslint/no-misused-promises": [2, { checksVoidReturn: { attributes: false } }],
"@typescript-eslint/no-unnecessary-condition": [
"error",
{
allowConstantLoopConditions: true,
},
],
"@typescript-eslint/no-non-null-assertion": "error",
"import/consistent-type-specifier-style": ["error", "prefer-top-level"],
"id-length": [
"warn",
{
min: 3,
exceptions: ["_", "i", "z", "t", "id", "db"], // _ for unused variables, i for index, z for zod, t for translation
properties: "never", // This allows for example the use of <Grid.Col span={{ sm: 12, md: 6 }}> as sm and md would be too short
},
],
"no-restricted-syntax": [
"error",
{
selector: "FunctionDeclaration[async=false][id.name=/Async$/]",
message: "Function ending in 'Async' must be declared async",
},
{
selector:
"FunctionDeclaration[async=true][id.name=/^[a-z].*$/][id.name=/ ^(?!generateMetadata$)[a-z].*$/][id.name!=/Async$/]",
message: "Async function name must end in 'Async' (function declaration)",
},
{
selector: "MethodDefinition[value.async=false][key.name=/Async$/]",
message: "Method ending in 'Async' must be declared async",
},
{
selector: "MethodDefinition[value.async=true][key.name!=/Async$/]",
message: "Async method name must end in 'Async'",
},
{
selector: "Property[value.type=/FunctionExpression$/][value.async=false][key.name=/Async$/]",
message: "Function ending in 'Async' must be declared async",
},
{
selector:
"Property[value.type=/FunctionExpression$/][value.async=true][key.name!=/^on(Success|Settled)$/][key.name!=/Async$/]",
message: "Async function name must end in 'Async' (property)",
},
{
selector: "VariableDeclarator[init.type=/FunctionExpression$/][init.async=false][id.name=/Async$/]",
message: "Function ending in 'Async' must be declared async",
},
{
selector:
"VariableDeclarator[init.type=/FunctionExpression$/][init.async=true][id.name=/^[a-z].*$/][id.name!=/Async$/]",
message: "Async function name must end in 'Async' (variable declarator)",
},
],
},
},
{
linterOptions: { reportUnusedDisableDirectives: true },
languageOptions: { parserOptions: { project: true } },
},
);

View File

@@ -0,0 +1,4 @@
import baseConfig from "@homarr/eslint-config/base";
/** @type {import('typescript-eslint').Config} */
export default [...baseConfig];

View File

@@ -1,9 +1,17 @@
/** @type {import('eslint').Linter.Config} */
const config = {
extends: ["plugin:@next/next/recommended"],
rules: {
"@next/next/no-html-link-for-pages": "off",
},
};
import nextPlugin from "@next/eslint-plugin-next";
module.exports = config;
/** @type {Awaited<import('typescript-eslint').Config>} */
export default [
{
files: ["**/*.ts", "**/*.tsx"],
plugins: {
"@next/next": nextPlugin,
},
rules: {
...nextPlugin.configs.recommended.rules,
...nextPlugin.configs["core-web-vitals"].rules,
// TypeError: context.getAncestors is not a function
"@next/next/no-duplicate-head": "off",
},
},
];

View File

@@ -3,40 +3,33 @@
"version": "0.2.0",
"private": true,
"license": "MIT",
"files": [
"./base.js",
"./nextjs.js",
"./react.js"
],
"type": "module",
"exports": {
"./base": "./base.js",
"./nextjs": "./nextjs.js",
"./react": "./react.js"
},
"scripts": {
"clean": "rm -rf .turbo node_modules",
"lint": "eslint .",
"lint": "eslint",
"format": "prettier --check . --ignore-path ../../.gitignore",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@next/eslint-plugin-next": "^14.2.3",
"@typescript-eslint/eslint-plugin": "^7.12.0",
"@typescript-eslint/parser": "^7.12.0",
"eslint-config-prettier": "^9.1.0",
"eslint-config-turbo": "^2.0.3",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-react": "^7.34.2",
"eslint-plugin-react-hooks": "^4.6.2"
"eslint-plugin-react-hooks": "^4.6.2",
"typescript-eslint": "^7.12.0"
},
"devDependencies": {
"@types/eslint": "^8.56.10",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^8.57.0",
"eslint": "^9.4.0",
"typescript": "^5.4.5"
},
"eslintConfig": {
"root": true,
"extends": [
"./base.js"
]
},
"prettier": "@homarr/prettier-config"
}

View File

@@ -1,20 +1,24 @@
/** @type {import('eslint').Linter.Config} */
const config = {
extends: ["plugin:react/recommended", "plugin:react-hooks/recommended", "plugin:jsx-a11y/recommended"],
rules: {
"react/prop-types": "off",
},
globals: {
React: "writable",
},
settings: {
react: {
version: "detect",
import reactPlugin from "eslint-plugin-react";
import hooksPlugin from "eslint-plugin-react-hooks";
/** @type {Awaited<import('typescript-eslint').Config>} */
export default [
{
files: ["**/*.ts", "**/*.tsx"],
plugins: {
react: reactPlugin,
"react-hooks": hooksPlugin,
},
rules: {
...reactPlugin.configs["jsx-runtime"].rules,
...hooksPlugin.configs.recommended.rules,
// context.getSource is not a function
"react-hooks/exhaustive-deps": "off",
},
languageOptions: {
globals: {
React: "writable",
},
},
},
env: {
browser: true,
},
};
module.exports = config;
];

58
tooling/eslint/types.d.ts vendored Normal file
View File

@@ -0,0 +1,58 @@
/**
* Since the ecosystem hasn't fully migrated to ESLint's new FlatConfig system yet,
* we "need" to type some of the plugins manually :(
*/
declare module "@eslint/js" {
// Why the hell doesn't eslint themselves export their types?
import type { Linter } from "eslint";
export const configs: {
readonly recommended: { readonly rules: Readonly<Linter.RulesRecord> };
readonly all: { readonly rules: Readonly<Linter.RulesRecord> };
};
}
declare module "eslint-plugin-import" {
import type { Linter, Rule } from "eslint";
export const configs: {
recommended: { rules: Linter.RulesRecord };
};
export const rules: Record<string, Rule.RuleModule>;
}
declare module "eslint-plugin-react" {
import type { Linter, Rule } from "eslint";
export const configs: {
recommended: { rules: Linter.RulesRecord };
all: { rules: Linter.RulesRecord };
"jsx-runtime": { rules: Linter.RulesRecord };
};
export const rules: Record<string, Rule.RuleModule>;
}
declare module "eslint-plugin-react-hooks" {
import type { Linter, Rule } from "eslint";
export const configs: {
recommended: {
rules: {
"rules-of-hooks": Linter.RuleEntry;
"exhaustive-deps": Linter.RuleEntry;
};
};
};
export const rules: Record<string, Rule.RuleModule>;
}
declare module "@next/eslint-plugin-next" {
import type { Linter, Rule } from "eslint";
export const configs: {
recommended: { rules: Linter.RulesRecord };
"core-web-vitals": { rules: Linter.RulesRecord };
};
export const rules: Record<string, Rule.RuleModule>;
}

View File

@@ -2,7 +2,11 @@
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"target": "ES2022",
"lib": ["dom", "dom.iterable", "ES2022"],
"lib": [
"dom",
"dom.iterable",
"ES2022"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
@@ -16,6 +20,7 @@
"jsx": "preserve",
"incremental": true,
"noUncheckedIndexedAccess": true,
"strictNullChecks": true,
"baseUrl": ".",
"paths": {
"*": [
@@ -23,5 +28,10 @@
]
}
},
"exclude": ["node_modules", "build", "dist", ".next"]
}
"exclude": [
"node_modules",
"build",
"dist",
".next"
]
}