Skip to content

Instantly share code, notes, and snippets.

@darvid
Last active December 4, 2024 03:23
Show Gist options
  • Save darvid/7d4350fbe926f90390996d267efaaff8 to your computer and use it in GitHub Desktop.
Save darvid/7d4350fbe926f90390996d267efaaff8 to your computer and use it in GitHub Desktop.
eslint flat config + next 15 + blood and tears πŸ’’
{
"eslint.lintTask.enable": true,
"eslint.lintTask.options": "--flag unstable_ts_config",
"eslint.options": {
"flags": [
"unstable_ts_config"
],
},
"eslint.workingDirectories": [
"./frontend"
],
"eslint.useFlatConfig": true
}
// @ts-check
import js from "@eslint/js";
import importAlias from "@limegrass/eslint-plugin-import-alias";
import tsParser from "@typescript-eslint/parser";
import eslintConfigPrettier from "eslint-config-prettier";
import * as importPlugin from "eslint-plugin-import";
import eslintPluginJsonc from "eslint-plugin-jsonc";
import jsxA11y from "eslint-plugin-jsx-a11y";
import perfectionist from "eslint-plugin-perfectionist";
// @ts-ignore
import preferArrowFunctions from "eslint-plugin-prefer-arrow-functions";
import prettier from "eslint-plugin-prettier";
import prettierRecommended from "eslint-plugin-prettier/recommended";
import react from "eslint-plugin-react";
// @ts-ignore
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import * as regexp from "eslint-plugin-regexp";
import tsdoc from "eslint-plugin-tsdoc";
import unusedImports from "eslint-plugin-unused-imports";
import globals from "globals";
import tseslint, { configs as tseslintConfigs } from "typescript-eslint";
export default tseslint.config(
{
ignores: ["!src/", ".next/"],
},
// global language options
{
languageOptions: {
ecmaVersion: "latest",
globals: {
...globals.browser,
},
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
sourceType: "module",
},
},
// include Typescript files
{
files: ["**/*.{ts,mts,tsx,mtsx}"],
languageOptions: {
parser: tsParser,
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
settings: {
"import/resolver": {
node: true,
typescript: true,
},
},
},
tseslint.configs.recommendedTypeChecked.map((config) => ({
...config,
files: ["**/*.{ts,mts,tsx,mtsx}"],
})),
// include Javascript files
{
files: ["**/*.{js,mjs,jsx,mjsx}"],
...js.configs.recommended,
...tseslintConfigs.disableTypeChecked,
},
// disable or override built-in rules
{
rules: {
"@typescript-eslint/no-unused-vars": "off",
"func-style": ["error", "expression"],
"import/order": "off",
"sort-imports": "off",
},
},
// import alias plugin
{
plugins: {
importAlias: importAlias,
},
rules: {
"importAlias/import-alias": "error",
},
},
// perfectionist config
{
...perfectionist.configs["recommended-natural"],
plugins: {
perfectionist,
},
rules: {
"perfectionist/sort-imports": [
"error",
{
internalPattern: ["^@/.*"],
tsconfigRootDir: import.meta.dirname,
type: "alphabetical",
},
],
},
},
// prefer arrow functions plugin
{
plugins: {
"prefer-arrow-functions": preferArrowFunctions,
},
rules: {
"prefer-arrow-functions/prefer-arrow-functions": [
"error",
{
allowNamedFunctions: false,
classPropertiesAllowed: false,
disallowPrototype: true,
singleReturnOnly: false,
},
],
},
},
// Prettier
eslintConfigPrettier,
{
plugins: {
prettier: prettier,
},
...prettierRecommended,
rules: {
...prettierRecommended.rules,
},
},
// TSDoc
{
files: ["**/*.{ts,mts,tsx,mtsx}"],
plugins: {
tsdoc: tsdoc,
},
rules: {
"tsdoc/syntax": "error",
},
},
// Regex
regexp.configs["flat/recommended"],
// JSX Accessibility
jsxA11y.flatConfigs.recommended,
// Unused imports
{
plugins: {
"unused-imports": unusedImports,
},
rules: {
"unused-imports/no-unused-imports": "error",
"unused-imports/no-unused-vars": [
"warn",
{
args: "after-used",
argsIgnorePattern: "^_",
vars: "all",
varsIgnorePattern: "^_",
},
],
},
},
// React: https://github.com/jsx-eslint/eslint-plugin-react/#shareable-configs
{
settings: {
react: {
version: "detect",
},
},
...react.configs.flat?.recommended,
plugins: {
import: importPlugin,
// @ts-ignore
react,
// @ts-ignore
"react-hooks": reactHooks,
"react-refresh": reactRefresh,
},
// @ts-ignore
rules: {
...react.configs.flat?.recommended?.rules,
...reactHooks.configs.recommended.rules,
// https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html#eslint
"react/jsx-uses-react": "off",
"react-refresh/only-export-components": "warn",
// Next.js recommended defaults
"import/no-anonymous-default-export": "warn",
"react/no-unknown-property": "off",
"react/react-in-jsx-scope": "off",
"react/prop-types": "off",
"jsx-a11y/alt-text": [
"warn",
{
elements: ["img"],
img: ["Image"],
},
],
"jsx-a11y/aria-props": "warn",
"jsx-a11y/aria-proptypes": "warn",
"jsx-a11y/aria-unsupported-elements": "warn",
"jsx-a11y/role-has-required-aria-props": "warn",
"jsx-a11y/role-supports-aria-props": "warn",
"react/jsx-no-target-blank": "off",
},
},
{
files: ["**/*.{json,jsonc,json5}"],
},
// JSON
...eslintPluginJsonc.configs["flat/prettier"],
...eslintPluginJsonc.configs["flat/recommended-with-jsonc"],
...eslintPluginJsonc.configs["flat/recommended-with-json5"],
...eslintPluginJsonc.configs["flat/recommended-with-json"].map((config) => ({
...config,
ignores: ["**/.vscode/*.json", "tsconfig*.json"],
})),
);
{
"name": "PAIN",
"version": "0.1.0",
"private": true,
"engines": {
"node": ">=20",
"pnpm": ">=8.7"
},
"scripts": {
"build": "next build",
"dev": "next dev --turbopack",
"lint": "next lint",
"start": "next start"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0"
},
"dependencies": {
"@clerk/nextjs": "^6.6.0",
"@clerk/themes": "^2.1.50",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.4",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^0.464.0",
"next": "15.0.3",
"react": "19.0.0-rc-66855b96-20241106",
"react-dom": "19.0.0-rc-66855b96-20241106",
"tailwind-merge": "^2.5.5",
"tailwindcss-animate": "^1.0.7"
},
"devDependencies": {
"@eslint/js": "^9.16.0",
"@eslint/json": "^0.8.0",
"@eslint/markdown": "^6.2.1",
"@limegrass/eslint-plugin-import-alias": "^1.5.0",
"@types/eslint-config-prettier": "^6.11.3",
"@types/eslint__js": "^8.42.3",
"@types/node": "^22.10.1",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@typescript-eslint/eslint-plugin": "^8.17.0",
"@typescript-eslint/parser": "^8.17.0",
"eslint": "^9.16.0",
"eslint-config-next": "^15.0.3",
"eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-typescript": "^3.7.0",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jsdoc": "^50.6.0",
"eslint-plugin-jsonc": "^2.18.2",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-perfectionist": "^4.2.0",
"eslint-plugin-prefer-arrow-functions": "^3.4.1",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-react": "^7.37.2",
"eslint-plugin-react-hooks": "5.0.0",
"eslint-plugin-react-refresh": "^0.4.16",
"eslint-plugin-regexp": "^2.7.0",
"eslint-plugin-tsdoc": "^0.4.0",
"eslint-plugin-unused-imports": "^4.1.4",
"globals": "^15.13.0",
"postcss": "^8.4.49",
"prettier": "3.4.1",
"prettier-plugin-css-order": "^2.1.2",
"prettier-plugin-pkg": "^0.18.1",
"prettier-plugin-sh": "^0.14.0",
"prettier-plugin-tailwindcss": "^0.6.9",
"react-hook-form": "^7.53.2",
"tailwindcss": "^3.4.16",
"typescript": "^5.7.2",
"typescript-eslint": "^8.17.0"
},
"pnpm": {
"peerDependencyRules": {
"allowedVersions": {
"react": "19"
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment