mirror of
https://github.com/MichMich/MagicMirror.git
synced 2026-06-03 18:00:33 +00:00
We were running three separate lint tools (ESLint, Stylelint, markdownlint-cli2) and a separate Prettier step. This PR consolidates everything: `@eslint/css` and `@eslint/markdown` bring CSS and Markdown linting into ESLint, so one tool now covers JS, CSS, and Markdown. The Prettier step got merged into the lint scripts too, so there's now just `test:lint` to check things and `lint:fix` to fix them. Outcome: fewer tools to maintain, simpler/fewer scripts, fewer config files. As a side effect, the dependabot alerts https://github.com/MagicMirrorOrg/MagicMirror/security/dependabot/140 and https://github.com/MagicMirrorOrg/MagicMirror/security/dependabot/141 are resolved, as we no longer use the vulnerable `fast-uri` package (which was a dependency of `stylelint`).
197 lines
5.7 KiB
JavaScript
197 lines
5.7 KiB
JavaScript
import {defineConfig, globalIgnores} from "eslint/config";
|
|
import css from "@eslint/css";
|
|
import globals from "globals";
|
|
import {flatConfigs as importX} from "eslint-plugin-import-x";
|
|
import js from "@eslint/js";
|
|
import jsdocPlugin from "eslint-plugin-jsdoc";
|
|
import markdown from "@eslint/markdown";
|
|
import {configs as packageJsonConfigs} from "eslint-plugin-package-json";
|
|
import playwright from "eslint-plugin-playwright";
|
|
import stylistic from "@stylistic/eslint-plugin";
|
|
import vitest from "@vitest/eslint-plugin";
|
|
|
|
export default defineConfig([
|
|
globalIgnores(["config/**", "modules/**/*", "js/positions.js", "tests/configs/config_variables.js"]),
|
|
{
|
|
files: ["**/*.css"],
|
|
language: "css/css",
|
|
plugins: {css},
|
|
extends: ["css/recommended"],
|
|
rules: {
|
|
"css/no-invalid-properties": ["error", {allowUnknownVariables: true}],
|
|
"css/use-baseline": "off"
|
|
}
|
|
},
|
|
{
|
|
files: ["**/*.md"],
|
|
plugins: {markdown},
|
|
language: "markdown/gfm",
|
|
extends: ["markdown/recommended"],
|
|
rules: {
|
|
"markdown/no-missing-label-refs": "off"
|
|
}
|
|
},
|
|
{
|
|
files: ["**/*.js"],
|
|
languageOptions: {
|
|
ecmaVersion: "latest",
|
|
globals: {
|
|
...globals.browser,
|
|
...globals.node,
|
|
Log: "readonly",
|
|
MM: "readonly",
|
|
Module: "readonly",
|
|
config: "readonly",
|
|
moment: "readonly"
|
|
}
|
|
},
|
|
extends: [importX.recommended, js.configs.recommended, jsdocPlugin.configs["flat/recommended"], stylistic.configs.all],
|
|
rules: {
|
|
"@stylistic/array-element-newline": ["error", "consistent"],
|
|
"@stylistic/arrow-parens": ["error", "always"],
|
|
"@stylistic/brace-style": "off",
|
|
"@stylistic/dot-location": ["error", "property"],
|
|
"@stylistic/function-call-argument-newline": ["error", "consistent"],
|
|
"@stylistic/function-paren-newline": ["error", "consistent"],
|
|
"@stylistic/implicit-arrow-linebreak": ["error", "beside"],
|
|
"@stylistic/indent": ["error", "tab"],
|
|
"@stylistic/max-statements-per-line": ["error", {max: 2}],
|
|
"@stylistic/multiline-comment-style": "off",
|
|
"@stylistic/multiline-ternary": ["error", "always-multiline"],
|
|
"@stylistic/newline-per-chained-call": ["error", {ignoreChainWithDepth: 4}],
|
|
"@stylistic/no-extra-parens": "off",
|
|
"@stylistic/no-tabs": "off",
|
|
"@stylistic/object-curly-spacing": ["error", "always"],
|
|
"@stylistic/object-property-newline": ["error", {allowAllPropertiesOnSameLine: true}],
|
|
"@stylistic/operator-linebreak": ["error", "before"],
|
|
"@stylistic/padded-blocks": "off",
|
|
"@stylistic/quote-props": ["error", "as-needed"],
|
|
"@stylistic/quotes": ["error", "double"],
|
|
"@stylistic/semi": ["error", "always"],
|
|
"@stylistic/space-before-function-paren": ["error", "always"],
|
|
"@stylistic/spaced-comment": "off",
|
|
"dot-notation": "error",
|
|
eqeqeq: ["error", "always", {null: "ignore"}],
|
|
"id-length": "off",
|
|
"import-x/extensions": "error",
|
|
"import-x/newline-after-import": "error",
|
|
"import-x/order": "error",
|
|
"init-declarations": "off",
|
|
"max-lines-per-function": ["warn", 400],
|
|
"max-statements": "off",
|
|
"no-global-assign": "off",
|
|
"no-inline-comments": "off",
|
|
"no-magic-numbers": "off",
|
|
"no-param-reassign": "error",
|
|
"no-plusplus": "off",
|
|
"no-prototype-builtins": "off",
|
|
"no-ternary": "off",
|
|
"no-throw-literal": "error",
|
|
"no-undefined": "off",
|
|
"no-unneeded-ternary": "error",
|
|
"no-useless-return": "error",
|
|
"no-warning-comments": "off",
|
|
"object-shorthand": ["error", "methods"],
|
|
"one-var": "off",
|
|
"prefer-template": "error",
|
|
"require-await": "error",
|
|
"sort-keys": "off"
|
|
}
|
|
},
|
|
{
|
|
files: ["**/*.js"],
|
|
ignores: [
|
|
"clientonly/index.js",
|
|
"js/logger.js",
|
|
"tests/**/*.js"
|
|
],
|
|
rules: {"no-console": "error"}
|
|
},
|
|
{
|
|
files: ["**/package.json"],
|
|
extends: [packageJsonConfigs.recommended]
|
|
},
|
|
{
|
|
files: ["**/*.mjs"],
|
|
languageOptions: {
|
|
ecmaVersion: "latest",
|
|
globals: {
|
|
...globals.node
|
|
},
|
|
sourceType: "module"
|
|
},
|
|
extends: [importX.recommended, js.configs.all, stylistic.configs.all],
|
|
rules: {
|
|
"@stylistic/array-element-newline": "off",
|
|
"@stylistic/indent": ["error", "tab"],
|
|
"@stylistic/object-property-newline": ["error", {allowAllPropertiesOnSameLine: true}],
|
|
"@stylistic/padded-blocks": ["error", "never"],
|
|
"@stylistic/quote-props": ["error", "as-needed"],
|
|
"import-x/no-unresolved": ["error", {ignore: ["eslint/config"]}],
|
|
"max-lines-per-function": ["error", 100],
|
|
"no-magic-numbers": "off",
|
|
"one-var": ["error", "never"],
|
|
"sort-keys": "off"
|
|
}
|
|
},
|
|
{
|
|
files: ["tests/**/*.js"],
|
|
languageOptions: {
|
|
globals: {
|
|
...vitest.environments.env.globals
|
|
}
|
|
},
|
|
extends: [vitest.configs.recommended],
|
|
rules: {
|
|
"vitest/consistent-test-it": "error",
|
|
"vitest/expect-expect": [
|
|
"error",
|
|
{
|
|
assertFunctionNames: [
|
|
"expect",
|
|
"testElementLength",
|
|
"testTextContain",
|
|
"doTest",
|
|
"runAnimationTest",
|
|
"waitForAnimationClass",
|
|
"assertNoAnimationWithin"
|
|
]
|
|
}
|
|
],
|
|
"vitest/max-nested-describe": ["error", {max: 3}],
|
|
"vitest/prefer-to-be": "error",
|
|
"vitest/prefer-to-have-length": "error",
|
|
"max-lines-per-function": "off"
|
|
}
|
|
},
|
|
{
|
|
files: ["tests/unit/modules/default/weather/providers/*.js"],
|
|
rules: {
|
|
"import-x/namespace": "off",
|
|
"import-x/named": "off",
|
|
"import-x/default": "off",
|
|
"import-x/extensions": "off"
|
|
}
|
|
},
|
|
{
|
|
files: ["tests/configs/modules/weather/*.js"],
|
|
rules: {
|
|
"@stylistic/quotes": "off"
|
|
}
|
|
},
|
|
{
|
|
files: ["tests/e2e/**/*.js"],
|
|
extends: [playwright.configs["flat/recommended"]],
|
|
rules: {
|
|
|
|
/*
|
|
* Tests use Vitest-style plain beforeAll()/afterAll() calls, not Playwright's
|
|
* test.beforeAll() style. The rule incorrectly treats all plain hook calls
|
|
* as the same unnamed type, flagging the second hook as a duplicate.
|
|
*/
|
|
"playwright/no-duplicate-hooks": "off",
|
|
"playwright/no-standalone-expect": "off"
|
|
}
|
|
}
|
|
]);
|