UNPKG

@hyperse/eslint-config-hyperse

Version:

🛠 These are settings for TypeScript / ESLint / Prettier in a project

206 lines (205 loc) • 6.54 kB
import { defineConfig } from "eslint/config"; import appRoot from "app-root-path"; import simpleImportSort from "eslint-plugin-simple-import-sort"; import { getTsconfig } from "get-tsconfig"; import pluginJsonc from "eslint-plugin-jsonc"; import * as pluginMdx from "eslint-plugin-mdx"; import pluginNext from "@next/eslint-plugin-next"; import eslintPluginPrettier from "eslint-plugin-prettier/recommended"; import tseslint from "typescript-eslint"; import eslintJs from "@eslint/js"; import eslintReact from "@eslint-react/eslint-plugin"; import regexpPlugin from "eslint-plugin-regexp"; import sonarjs from "eslint-plugin-sonarjs"; import globals from "globals"; import pluginVitest from "@vitest/eslint-plugin"; //#region src/rules/imports.ts function extractPaths(paths) { return Object.keys(paths).map((key) => { return key.split("/")[0]; }); } const tsConfig = getTsconfig(appRoot.path, "tsconfig.json"); const jsConfig = getTsconfig(appRoot.path, "jsconfig.json"); let pathsNames = []; if (tsConfig && tsConfig.config.compilerOptions?.paths) pathsNames = extractPaths(tsConfig.config.compilerOptions.paths); else if (jsConfig && jsConfig.config.compilerOptions?.paths) pathsNames = extractPaths(jsConfig.config.compilerOptions.paths); const imports = defineConfig([{ plugins: { "simple-import-sort": simpleImportSort }, rules: { "simple-import-sort/exports": "error", "simple-import-sort/imports": ["error", { groups: [[ "^react", "^next", "^[a-z]", `^(${pathsNames.join("|")})(/.*|$)`, "^@", "^\\.", "^\\u0000", "^\\u0000\\." ]] }] } }]); //#endregion //#region src/rules/jsonc.ts const jsonc = defineConfig([...pluginJsonc.configs["flat/recommended-with-jsonc"], { rules: {} }]); //#endregion //#region src/rules/mdx.ts const mdx = defineConfig([{ ...pluginMdx.flat }]); defineConfig([{ plugins: { "@next/next": pluginNext }, rules: { ...pluginNext.configs.recommended.rules, ...pluginNext.configs["core-web-vitals"].rules } }, { ignores: [".next/*"] }]); //#endregion //#region src/prettierShared.ts const TAILWIND_PLUGIN = "prettier-plugin-tailwindcss"; const prettierBaseOptions = { semi: true, singleQuote: true, trailingComma: "es5" }; /** * Ensures `prettier-plugin-tailwindcss` is present exactly once and last, per * https://github.com/tailwindlabs/prettier-plugin-tailwindcss#compatibility-with-other-prettier-plugins */ function finalizePrettierPlugins(plugins) { return [...normalizePlugins(plugins).filter((p) => p !== TAILWIND_PLUGIN), TAILWIND_PLUGIN]; } function normalizePlugins(plugins) { if (plugins === void 0) return []; return Array.isArray(plugins) ? [...plugins] : [plugins]; } //#endregion //#region src/definePrettierConfig.ts const definePrettierConfig = (config = {}) => { const { plugins, ...rest } = config; return { ...prettierBaseOptions, ...rest, plugins: finalizePrettierPlugins(plugins) }; }; //#endregion //#region src/rules/prettier.ts const { ...prettierConfig } = definePrettierConfig(); const prettier = defineConfig([{ ...eslintPluginPrettier, rules: { ...eslintPluginPrettier.rules, "prettier/prettier": ["error", prettierConfig] } }]); const react = defineConfig([{ files: { files: ["**/*.{jsx,tsx}"] }.files, extends: [ eslintJs.configs.recommended, tseslint.configs.recommended, eslintReact.configs["recommended-typescript"] ], languageOptions: { parser: tseslint.parser, parserOptions: { projectService: true, tsconfigRootDir: import.meta.dirname } }, rules: {}, settings: { react: { version: "detect" } } }]); const regexp = defineConfig([{ files: { files: ["**/*.{js,jsx,jsx,tsx,mts,cts,mjs,cjs}"] }.files, plugins: { regexp: regexpPlugin }, rules: { ...regexpPlugin.configs.recommended.rules, "regexp/prefer-result-array-groups": "off" } }]); //#endregion //#region src/rules/sonar.ts const sonarPatterns = { files: ["**/*.{js,jsx,ts,tsx,mts,cts,mjs,cjs}"], excludedFiles: [ "**/?(*.)+(test).{js,jsx,ts,tsx,mts,cts,mjs,cjs}", "**/?(*.)+(spec).{js,jsx,ts,tsx,mts,cts,mjs,cjs}", "*.stories.{js,ts,jsx,tsx,mts,cts,mjs,cjs}" ] }; defineConfig([{ files: sonarPatterns.files, ignores: sonarPatterns.excludedFiles, plugins: { sonarjs }, rules: { ...sonarjs.configs.recommended.rules, "sonarjs/cognitive-complexity": ["error", 20], "sonarjs/max-switch-cases": ["error", 20], "sonarjs/no-all-duplicated-branches": "error", "sonarjs/no-element-overwrite": "error", "sonarjs/no-identical-functions": "error", "sonarjs/no-identical-expressions": "error", "sonarjs/no-hook-setter-in-body": "off", "sonarjs/public-static-readonly": "off", "sonarjs/no-nested-conditional": "off", "sonarjs/fixme-tag": "warn", "sonarjs/todo-tag": "warn", "sonarjs/no-commented-code": "off", "sonarjs/deprecation": "off" } }]); //#endregion //#region src/rules/typescript.ts const typescript = defineConfig({ languageOptions: { globals: { ...globals.node } } }, eslintJs.configs.recommended, ...tseslint.configs.recommended); const vitest = defineConfig([{ files: { files: ["**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"] }.files, plugins: { vitest: pluginVitest }, rules: { ...pluginVitest.configs.recommended.rules, "vitest/max-nested-describe": ["error", { max: 3 }], "vitest/no-disabled-tests": 2, "vitest/valid-title": "off", "@typescript-eslint/no-non-null-assertion": "off", "@typescript-eslint/no-object-literal-type-assertion": "off", "@typescript-eslint/no-empty-function": "off", "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/ban-ts-comment": "off" }, settings: { vitest: { typecheck: true } }, languageOptions: { globals: { ...pluginVitest.environments.env.globals } } }]); //#endregion //#region src/main/overrides.ts const overrides = defineConfig([{ ...tseslint.configs.base, languageOptions: { parserOptions: { projectService: true, tsconfigRootDir: import.meta.dirname, emitDecoratorMetadata: true } }, files: ["**/*.ts", "**/*.tsx"], rules: { "@typescript-eslint/no-unused-vars": ["warn", { args: "all", argsIgnorePattern: "^_", varsIgnorePattern: "^_", caughtErrorsIgnorePattern: "^_" }], "@typescript-eslint/consistent-type-imports": ["error", { disallowTypeAnnotations: false }], "@typescript-eslint/no-deprecated": "warn" } }]); //#endregion //#region src/main/reactjs.ts const reactjs = defineConfig([...defineConfig([ ...typescript, ...vitest, ...imports, ...prettier, ...regexp, ...jsonc, ...mdx, ...overrides ]), ...react]); //#endregion export { reactjs };