UNPKG

@hyperse/eslint-config-hyperse

Version:

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

403 lines (391 loc) • 12.8 kB
'use strict'; var eslintDefineConfig = require('eslint-define-config'); var appRoot = require('app-root-path'); var simpleImportSort = require('eslint-plugin-simple-import-sort'); var getTsconfig = require('get-tsconfig'); var pluginJsonc = require('eslint-plugin-jsonc'); var pluginMdx = require('eslint-plugin-mdx'); var pluginNext = require('@next/eslint-plugin-next'); var eslintPluginPrettier = require('eslint-plugin-prettier/recommended'); var pluginReact = require('eslint-plugin-react'); var pluginReactHooks = require('eslint-plugin-react-hooks'); var globals = require('globals'); var regexpPlugin = require('eslint-plugin-regexp'); var sonarjs = require('eslint-plugin-sonarjs'); var tseslint = require('typescript-eslint'); var eslint = require('@eslint/js'); var pluginVitest = require('@vitest/eslint-plugin'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } function _interopNamespace(e) { if (e && e.__esModule) return e; var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var appRoot__default = /*#__PURE__*/_interopDefault(appRoot); var simpleImportSort__default = /*#__PURE__*/_interopDefault(simpleImportSort); var pluginJsonc__default = /*#__PURE__*/_interopDefault(pluginJsonc); var pluginMdx__namespace = /*#__PURE__*/_interopNamespace(pluginMdx); var pluginNext__default = /*#__PURE__*/_interopDefault(pluginNext); var eslintPluginPrettier__default = /*#__PURE__*/_interopDefault(eslintPluginPrettier); var pluginReact__default = /*#__PURE__*/_interopDefault(pluginReact); var pluginReactHooks__default = /*#__PURE__*/_interopDefault(pluginReactHooks); var globals__default = /*#__PURE__*/_interopDefault(globals); var regexpPlugin__default = /*#__PURE__*/_interopDefault(regexpPlugin); var sonarjs__default = /*#__PURE__*/_interopDefault(sonarjs); var tseslint__default = /*#__PURE__*/_interopDefault(tseslint); var eslint__default = /*#__PURE__*/_interopDefault(eslint); var pluginVitest__default = /*#__PURE__*/_interopDefault(pluginVitest); // src/define-config.ts // src/getDefaultIgnorePatterns.ts var getDefaultIgnorePatterns = (ignores = []) => { return [ // Hacky way to silence @yarnpkg/doctor about node_modules detection `**/${"node"}_modules`, "**/node_modules", "**/.turbo", "**/.docusaurus", "**/.cache", "**/.changeset", "**/.github", "**/.husky", "**/.yarn", "**/.out", "**/.next", "**/_release", "**/.cache", "**/build", "**/dist", "**/public", "**/fixtures", "**/.storybook", "**/.vscode-test", "**/storybook-static", "**/miniprogram", "**/.husky", "**/.contentlayer", "**/.mini", ...ignores ]; }; // src/define-config.ts var defineConfig = (config, ignores = []) => { return eslintDefineConfig.defineFlatConfig( config.concat({ ignores: getDefaultIgnorePatterns(ignores) }) ); }; // 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"] }; }; function extractPaths(paths) { return Object.keys(paths).map((key) => { return key.split("/")[0]; }); } var tsConfig = getTsconfig.getTsconfig(appRoot__default.default.path, "tsconfig.json"); var jsConfig = getTsconfig.getTsconfig(appRoot__default.default.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 = eslintDefineConfig.defineFlatConfig([ { plugins: { "simple-import-sort": simpleImportSort__default.default }, 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 = eslintDefineConfig.defineFlatConfig([ ...pluginJsonc__default.default.configs["flat/recommended-with-jsonc"], { rules: { // override/add rules settings here, such as: // 'jsonc/rule-name': 'error' } } ]); var mdx = eslintDefineConfig.defineFlatConfig([ { ...pluginMdx__namespace.flat } ]); var next = eslintDefineConfig.defineFlatConfig([ { plugins: { "@next/next": pluginNext__default.default }, rules: { ...pluginNext__default.default.configs.recommended.rules, ...pluginNext__default.default.configs["core-web-vitals"].rules } }, { ignores: [".next/*"] } ]); var { ...prettierConfig } = getPrettierConfig(); var prettier = eslintDefineConfig.defineFlatConfig([ { ...eslintPluginPrettier__default.default, rules: { ...eslintPluginPrettier__default.default.rules, "prettier/prettier": ["error", prettierConfig] } } ]); var reactPatterns = { files: ["**/*.{jsx,tsx}"] }; var react = eslintDefineConfig.defineFlatConfig([ { files: reactPatterns.files, ...pluginReact__default.default.configs.flat.recommended, languageOptions: { ...pluginReact__default.default.configs.flat.recommended.languageOptions, globals: { ...globals__default.default.serviceworker, ...globals__default.default.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__default.default.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__default.default.configs["recommended-latest"] } ]); var regexpPatterns = { files: ["**/*.{js,jsx,jsx,tsx,mts,cts,mjs,cjs}"] }; var regexp = eslintDefineConfig.defineFlatConfig([ { files: regexpPatterns.files, plugins: { regexp: regexpPlugin__default.default }, rules: { ...regexpPlugin__default.default.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}" ] }; var sonar = eslintDefineConfig.defineFlatConfig([ { files: sonarPatterns.files, ignores: sonarPatterns.excludedFiles, plugins: { sonarjs: sonarjs__default.default }, rules: { ...sonarjs__default.default.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 = eslintDefineConfig.defineFlatConfig( tseslint__default.default.config( { languageOptions: { globals: { ...globals__default.default.node } } }, eslint__default.default.configs.recommended, ...tseslint__default.default.configs.recommended // ...tseslint.configs.recommendedTypeChecked, // ...tseslint.configs.stylisticTypeChecked ) ); var vitestPatterns = { files: ["**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"] }; var vitest = eslintDefineConfig.defineFlatConfig([ { files: vitestPatterns.files, plugins: { vitest: pluginVitest__default.default }, rules: { // you can also use vitest.configs.all.rules to enable all rules ...pluginVitest__default.default.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__default.default.environments.env.globals } } } ]); var overrides = eslintDefineConfig.defineFlatConfig([ { ...tseslint__default.default.configs.base, languageOptions: { // https://typescript-eslint.io/users/configs/#stylistic-type-checked parserOptions: { projectService: true, tsconfigRootDir: undefined, // 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 = eslintDefineConfig.defineFlatConfig([ ...typescript, ...vitest, ...imports, ...prettier, ...regexp, ...jsonc, ...mdx, ...overrides ]); var reactjs = eslintDefineConfig.defineFlatConfig([...base, ...react]); // src/main/nextjs.ts var nextjs = eslintDefineConfig.defineFlatConfig([...reactjs, ...next]); var sonarjs2 = eslintDefineConfig.defineFlatConfig([...sonar]); exports.base = base; exports.defineConfig = defineConfig; exports.getDefaultIgnorePatterns = getDefaultIgnorePatterns; exports.getPrettierConfig = getPrettierConfig; exports.nextjs = nextjs; exports.reactjs = reactjs; exports.sonarjs = sonarjs2;