UNPKG

@hyperse/eslint-config-hyperse

Version:

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

317 lines (311 loc) • 9.29 kB
import { defineFlatConfig } from 'eslint-define-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 pluginReact from 'eslint-plugin-react'; import pluginReactHooks from 'eslint-plugin-react-hooks'; import globals from 'globals'; import regexpPlugin from 'eslint-plugin-regexp'; import sonarjs from 'eslint-plugin-sonarjs'; import tseslint from 'typescript-eslint'; import eslint from '@eslint/js'; import pluginVitest from '@vitest/eslint-plugin'; // src/main/reactjs.ts function extractPaths(paths) { return Object.keys(paths).map((key) => { return key.split("/")[0]; }); } var tsConfig = getTsconfig(appRoot.path, "tsconfig.json"); var jsConfig = getTsconfig(appRoot.path, "jsconfig.json"); var 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); } var imports = defineFlatConfig([ { plugins: { "simple-import-sort": simpleImportSort }, rules: { "simple-import-sort/exports": "error", "simple-import-sort/imports": [ "error", { groups: [ [ // Anything that starts with react // e.g: import { useState } from 'react' // e.g: import { useFela } from 'react-fela' "^react", // Anything that starts with next // e.g: import { useRouter } from 'next/router' "^next", // Anything that starts with a letter // e.g: import Downshift from 'downshift' "^[a-z]", // Anything that starts with an alias (see jsconfig.json) // e.g: import ListDropdown from '@shared/components/ListDropdown' `^(${pathsNames.join("|")})(/.*|$)`, // Anything that starts with @ // e.g: import { yupResolver } from '@hookform/resolvers/yup' "^@", // Anything that starts with a dot // e.g: import { matchIsDate } from './utils/date "^\\.", // Side effect imports from lib // e.g: import 'react-toastify/dist/ReactToastify.css' "^\\u0000", // Side effect import that starts with a dot // e.g: import './setup-config' "^\\u0000\\." ] ] } ] } } ]); var jsonc = defineFlatConfig([ ...pluginJsonc.configs["flat/recommended-with-jsonc"], { rules: { // override/add rules settings here, such as: // 'jsonc/rule-name': 'error' } } ]); var mdx = defineFlatConfig([ { ...pluginMdx.flat } ]); defineFlatConfig([ { plugins: { "@next/next": pluginNext }, rules: { ...pluginNext.configs.recommended.rules, ...pluginNext.configs["core-web-vitals"].rules } }, { ignores: [".next/*"] } ]); // src/getPrettierConfig.ts var prettierBaseConfig = { // add semicolons at the end of statements semi: true, // use single quotes instead of double quotes singleQuote: true, // add trailing commas where valid in ES5 (objects, arrays, etc.) trailingComma: "es5" // keep it as default value for windows, mac endOfLine(lf). }; var getPrettierConfig = (config = {}) => { return { ...prettierBaseConfig, ...config, // highlight priority on .prettierrc plugins: ["prettier-plugin-tailwindcss"] }; }; var { ...prettierConfig } = getPrettierConfig(); var prettier = defineFlatConfig([ { ...eslintPluginPrettier, rules: { ...eslintPluginPrettier.rules, "prettier/prettier": ["error", prettierConfig] } } ]); var reactPatterns = { files: ["**/*.{jsx,tsx}"] }; var react = defineFlatConfig([ { files: reactPatterns.files, ...pluginReact.configs.flat.recommended, languageOptions: { ...pluginReact.configs.flat.recommended.languageOptions, globals: { ...globals.serviceworker, ...globals.browser } }, rules: { // The full available rules before can be found here // https://github.com/hyperse-io/eslint-config-hyperse/blob/1e23efbfb64f4e5a8b0c6387d187b7f6341f1e61/src/rules/react.ts ...pluginReact.configs.flat.recommended.rules, "react/react-in-jsx-scope": "off", "react-hooks/exhaustive-deps": "off", "react/prop-types": "off" }, settings: { react: { version: "detect" // Automatically detect React version } } }, { files: reactPatterns.files, ...pluginReactHooks.configs["recommended-latest"] } ]); var regexpPatterns = { files: ["**/*.{js,jsx,jsx,tsx,mts,cts,mjs,cjs}"] }; var regexp = defineFlatConfig([ { files: regexpPatterns.files, plugins: { regexp: regexpPlugin }, rules: { ...regexpPlugin.configs.recommended.rules, "regexp/prefer-result-array-groups": "off" } } ]); var 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}" ] }; defineFlatConfig([ { 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", // NOTE: performance issue for this rule // https://community.sonarsource.com/t/eslint-plugin-sonarjs-performance-issues-on-large-codebase/138392 "sonarjs/no-commented-code": "off", // NOTE: This rule has performance issue and now use `@typescript-eslint/no-deprecated` instead "sonarjs/deprecation": "off" } } ]); var typescript = defineFlatConfig( tseslint.config( { languageOptions: { globals: { ...globals.node } } }, eslint.configs.recommended, ...tseslint.configs.recommended // ...tseslint.configs.recommendedTypeChecked, // ...tseslint.configs.stylisticTypeChecked ) ); var vitestPatterns = { files: ["**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"] }; var vitest = defineFlatConfig([ { files: vitestPatterns.files, plugins: { vitest: pluginVitest }, rules: { // you can also use vitest.configs.all.rules to enable all rules ...pluginVitest.configs.recommended.rules, // you can also modify rules' behavior using option like this "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 } } } ]); var overrides = defineFlatConfig([ { ...tseslint.configs.base, languageOptions: { // https://typescript-eslint.io/users/configs/#stylistic-type-checked parserOptions: { projectService: true, tsconfigRootDir: import.meta.dirname, // https://github.com/typescript-eslint/typescript-eslint/issues/10200 // Support `nestjs` decorator metadata, constructor DI class, we can not import type for `nestjs` 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 } ], // Use this rule instead of `sonarjs/deprecation` "@typescript-eslint/no-deprecated": "warn" } } ]); // src/main/base.ts var base = defineFlatConfig([ ...typescript, ...vitest, ...imports, ...prettier, ...regexp, ...jsonc, ...mdx, ...overrides ]); // src/main/reactjs.ts var reactjs = defineFlatConfig([...base, ...react]); export { reactjs };